%PDF- %PDF-
Direktori : /data/www_bck/varak.net_bck/recepty.varak.net/data/cache/0/ |
Current File : //data/www_bck/varak.net_bck/recepty.varak.net/data/cache/0/07f2ece6afbd569c0cf876102d71ff4f.js |
var DOKU_BASE = '/';var DOKU_TPL = '/lib/tpl/dokuwiki/';var DOKU_COOKIE_PARAM = {"path":"\/","secure":true};Object.defineProperty(window, 'DOKU_UHN', { get: function() {console.warn('Using DOKU_UHN is deprecated. Please use JSINFO.useHeadingNavigation instead');return JSINFO.useHeadingNavigation; } });Object.defineProperty(window, 'DOKU_UHC', { get: function() {console.warn('Using DOKU_UHC is deprecated. Please use JSINFO.useHeadingContent instead');return JSINFO.useHeadingContent; } });LANG = {"search_toggle_tools":"Toggle Search Tools","willexpire":"Your lock for editing this page is about to expire in a minute.\\nTo avoid conflicts use the preview button to reset the locktimer.","notsavedyet":"Unsaved changes will be lost.","searchmedia":"Search for files","keepopen":"Keep window open on selection","hidedetails":"Hide Details","mediatitle":"Link settings","mediadisplay":"Link type","mediaalign":"Alignment","mediasize":"Image size","mediatarget":"Link target","mediaclose":"Close","mediainsert":"Insert","mediadisplayimg":"Show the image.","mediadisplaylnk":"Show only the link.","mediasmall":"Small version","mediamedium":"Medium version","medialarge":"Large version","mediaoriginal":"Original version","medialnk":"Link to detail page","mediadirect":"Direct link to original","medianolnk":"No link","medianolink":"Do not link the image","medialeft":"Align the image on the left.","mediaright":"Align the image on the right.","mediacenter":"Align the image in the middle.","medianoalign":"Use no align.","nosmblinks":"Linking to Windows shares only works in Microsoft Internet Explorer.\\nYou still can copy and paste the link.","linkwiz":"Link Wizard","linkto":"Link to:","del_confirm":"Really delete selected item(s)?","restore_confirm":"Really restore this version?","media_diff":"View differences:","media_diff_both":"Side by Side","media_diff_opacity":"Shine-through","media_diff_portions":"Swipe","media_select":"Select files\u2026","media_upload_btn":"Upload","media_done_btn":"Done","media_drop":"Drop files here to upload","media_cancel":"remove","media_overwrt":"Overwrite existing files","plugins":{"extension":{"reallydel":"Really uninstall this extension?","display_viewoptions":"View Options:","display_enabled":"enabled","display_disabled":"disabled","display_updatable":"updatable"},"styling":{"loader":"Preview is loading...<br \/>if this does not goes away, your values may be faulty","popup":"Open as a popup"}}}; var toolbar = [{"type":"format","title":"Bold Text","icon":"bold.png","key":"b","open":"**","close":"**","block":false},{"type":"format","title":"Italic Text","icon":"italic.png","key":"i","open":"\/\/","close":"\/\/","block":false},{"type":"format","title":"Underlined Text","icon":"underline.png","key":"u","open":"__","close":"__","block":false},{"type":"format","title":"Monospaced Text","icon":"mono.png","key":"m","open":"''","close":"''","block":false},{"type":"format","title":"Strike-through Text","icon":"strike.png","key":"d","open":"<del>","close":"<\/del>","block":false},{"type":"autohead","title":"Same Level Headline","icon":"hequal.png","key":"8","text":"Headline","mod":0,"block":true},{"type":"autohead","title":"Lower Headline","icon":"hminus.png","key":"9","text":"Headline","mod":1,"block":true},{"type":"autohead","title":"Higher Headline","icon":"hplus.png","key":"0","text":"Headline","mod":-1,"block":true},{"type":"picker","title":"Select Headline","icon":"h.png","class":"pk_hl","list":[{"type":"format","title":"Level 1 Headline","icon":"h1.png","key":"1","open":"====== ","close":" ======\\n"},{"type":"format","title":"Level 2 Headline","icon":"h2.png","key":"2","open":"===== ","close":" =====\\n"},{"type":"format","title":"Level 3 Headline","icon":"h3.png","key":"3","open":"==== ","close":" ====\\n"},{"type":"format","title":"Level 4 Headline","icon":"h4.png","key":"4","open":"=== ","close":" ===\\n"},{"type":"format","title":"Level 5 Headline","icon":"h5.png","key":"5","open":"== ","close":" ==\\n"}],"block":true},{"type":"linkwiz","title":"Internal Link","icon":"link.png","key":"l","open":"[[","close":"]]","block":false},{"type":"format","title":"External Link","icon":"linkextern.png","open":"[[","close":"]]","sample":"http:\/\/example.com|External Link","block":false},{"type":"formatln","title":"Ordered List Item","icon":"ol.png","open":" - ","close":"","key":"-","block":true},{"type":"formatln","title":"Unordered List Item","icon":"ul.png","open":" * ","close":"","key":".","block":true},{"type":"insert","title":"Horizontal Rule","icon":"hr.png","insert":"\\n----\\n","block":true},{"type":"mediapopup","title":"Add Images and other files (opens in a new window)","icon":"image.png","url":"lib\/exe\/mediamanager.php?ns=","name":"mediaselect","options":"width=750,height=500,left=20,top=20,scrollbars=yes,resizable=yes","block":false},{"type":"picker","title":"Smileys","icon":"smiley.png","list":{"8-)":"icon_cool.gif","8-O":"icon_eek.gif","8-o":"icon_eek.gif",":-(":"icon_sad.gif",":-)":"icon_smile.gif","=)":"icon_smile2.gif",":-\/":"icon_doubt.gif",":-\\":"icon_doubt2.gif",":-?":"icon_confused.gif",":-D":"icon_biggrin.gif",":-P":"icon_razz.gif",":-o":"icon_surprised.gif",":-O":"icon_surprised.gif",":-x":"icon_silenced.gif",":-X":"icon_silenced.gif",":-|":"icon_neutral.gif",";-)":"icon_wink.gif","m(":"facepalm.gif","^_^":"icon_fun.gif",":?:":"icon_question.gif",":!:":"icon_exclaim.gif","LOL":"icon_lol.gif","FIXME":"fixme.gif","DELETEME":"delete.gif"},"icobase":"smileys","block":false},{"type":"picker","title":"Special Chars","icon":"chars.png","list":["\u00c0","\u00e0","\u00c1","\u00e1","\u00c2","\u00e2","\u00c3","\u00e3","\u00c4","\u00e4","\u01cd","\u01ce","\u0102","\u0103","\u00c5","\u00e5","\u0100","\u0101","\u0104","\u0105","\u00c6","\u00e6","\u0106","\u0107","\u00c7","\u00e7","\u010c","\u010d","\u0108","\u0109","\u010a","\u010b","\u00d0","\u0111","\u00f0","\u010e","\u010f","\u00c8","\u00e8","\u00c9","\u00e9","\u00ca","\u00ea","\u00cb","\u00eb","\u011a","\u011b","\u0112","\u0113","\u0116","\u0117","\u0118","\u0119","\u0122","\u0123","\u011c","\u011d","\u011e","\u011f","\u0120","\u0121","\u0124","\u0125","\u00cc","\u00ec","\u00cd","\u00ed","\u00ce","\u00ee","\u00cf","\u00ef","\u01cf","\u01d0","\u012a","\u012b","\u0130","\u0131","\u012e","\u012f","\u0134","\u0135","\u0136","\u0137","\u0139","\u013a","\u013b","\u013c","\u013d","\u013e","\u0141","\u0142","\u013f","\u0140","\u0143","\u0144","\u00d1","\u00f1","\u0145","\u0146","\u0147","\u0148","\u00d2","\u00f2","\u00d3","\u00f3","\u00d4","\u00f4","\u00d5","\u00f5","\u00d6","\u00f6","\u01d1","\u01d2","\u014c","\u014d","\u0150","\u0151","\u0152","\u0153","\u00d8","\u00f8","\u0154","\u0155","\u0156","\u0157","\u0158","\u0159","\u015a","\u015b","\u015e","\u015f","\u0160","\u0161","\u015c","\u015d","\u0162","\u0163","\u0164","\u0165","\u00d9","\u00f9","\u00da","\u00fa","\u00db","\u00fb","\u00dc","\u00fc","\u01d3","\u01d4","\u016c","\u016d","\u016a","\u016b","\u016e","\u016f","\u01d6","\u01d8","\u01da","\u01dc","\u0172","\u0173","\u0170","\u0171","\u0174","\u0175","\u00dd","\u00fd","\u0178","\u00ff","\u0176","\u0177","\u0179","\u017a","\u017d","\u017e","\u017b","\u017c","\u00de","\u00fe","\u00df","\u0126","\u0127","\u00bf","\u00a1","\u00a2","\u00a3","\u00a4","\u00a5","\u20ac","\u00a6","\u00a7","\u00aa","\u00ac","\u00af","\u00b0","\u00b1","\u00f7","\u2030","\u00bc","\u00bd","\u00be","\u00b9","\u00b2","\u00b3","\u00b5","\u00b6","\u2020","\u2021","\u00b7","\u2022","\u00ba","\u2200","\u2202","\u2203","\u018f","\u0259","\u2205","\u2207","\u2208","\u2209","\u220b","\u220f","\u2211","\u203e","\u2212","\u2217","\u00d7","\u2044","\u221a","\u221d","\u221e","\u2220","\u2227","\u2228","\u2229","\u222a","\u222b","\u2234","\u223c","\u2245","\u2248","\u2260","\u2261","\u2264","\u2265","\u2282","\u2283","\u2284","\u2286","\u2287","\u2295","\u2297","\u22a5","\u22c5","\u25ca","\u2118","\u2111","\u211c","\u2135","\u2660","\u2663","\u2665","\u2666","\u03b1","\u03b2","\u0393","\u03b3","\u0394","\u03b4","\u03b5","\u03b6","\u03b7","\u0398","\u03b8","\u03b9","\u03ba","\u039b","\u03bb","\u03bc","\u039e","\u03be","\u03a0","\u03c0","\u03c1","\u03a3","\u03c3","\u03a4","\u03c4","\u03c5","\u03a6","\u03c6","\u03c7","\u03a8","\u03c8","\u03a9","\u03c9","\u2605","\u2606","\u260e","\u261a","\u261b","\u261c","\u261d","\u261e","\u261f","\u2639","\u263a","\u2714","\u2718","\u201e","\u201c","\u201d","\u201a","\u2018","\u2019","\u00ab","\u00bb","\u2039","\u203a","\u2014","\u2013","\u2026","\u2190","\u2191","\u2192","\u2193","\u2194","\u21d0","\u21d1","\u21d2","\u21d3","\u21d4","\u00a9","\u2122","\u00ae","\u2032","\u2033","[","]","{","}","~","(",")","%","\u00a7","$","#","|","@"],"block":false},{"type":"signature","title":"Insert Signature","icon":"sig.png","key":"y","block":false}]; /* XXXXXXXXXX begin of lib/scripts/jquery/jquery.cookie.js XXXXXXXXXX */ /*! * jQuery Cookie Plugin v1.4.1 * https://github.com/carhartl/jquery-cookie * * Copyright 2013 Klaus Hartl * Released under the MIT license */ (function (factory) { if (typeof define === 'function' && define.amd) { // AMD define(['jquery'], factory); } else if (typeof exports === 'object') { // CommonJS factory(require('jquery')); } else { // Browser globals factory(jQuery); } }(function ($) { var pluses = /\+/g; function encode(s) { return config.raw ? s : encodeURIComponent(s); } function decode(s) { return config.raw ? s : decodeURIComponent(s); } function stringifyCookieValue(value) { return encode(config.json ? JSON.stringify(value) : String(value)); } function parseCookieValue(s) { if (s.indexOf('"') === 0) { // This is a quoted cookie as according to RFC2068, unescape... s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); } try { // Replace server-side written pluses with spaces. // If we can't decode the cookie, ignore it, it's unusable. // If we can't parse the cookie, ignore it, it's unusable. s = decodeURIComponent(s.replace(pluses, ' ')); return config.json ? JSON.parse(s) : s; } catch(e) {} } function read(s, converter) { var value = config.raw ? s : parseCookieValue(s); return $.isFunction(converter) ? converter(value) : value; } var config = $.cookie = function (key, value, options) { // Write if (value !== undefined && !$.isFunction(value)) { options = $.extend({}, config.defaults, options); if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setTime(+t + days * 864e+5); } return (document.cookie = [ encode(key), '=', stringifyCookieValue(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // Read var result = key ? undefined : {}; // To prevent the for loop in the first place assign an empty array // in case there are no cookies at all. Also prevents odd result when // calling $.cookie(). var cookies = document.cookie ? document.cookie.split('; ') : []; for (var i = 0, l = cookies.length; i < l; i++) { var parts = cookies[i].split('='); var name = decode(parts.shift()); var cookie = parts.join('='); if (key && key === name) { // If second argument (value) is a function it's a converter... result = read(cookie, value); break; } // Prevent storing a cookie that we couldn't decode. if (!key && (cookie = read(cookie)) !== undefined) { result[name] = cookie; } } return result; }; config.defaults = {}; $.removeCookie = function (key, options) { if ($.cookie(key) === undefined) { return false; } // Must not alter options, thus extending a fresh object... $.cookie(key, '', $.extend({}, options, { expires: -1 })); return !$.cookie(key); }; })); /* XXXXXXXXXX end of lib/scripts/jquery/jquery.cookie.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/fileuploader.js XXXXXXXXXX */ /** * http://github.com/valums/file-uploader * * Multiple file upload component with progress-bar, drag-and-drop. * © 2010 Andrew Valums ( andrew(at)valums.com ) * * Licensed under GNU GPL 2 or later and GNU LGPL 2 or later, see license.txt. */ // // Helper functions // var qq = qq || {}; /** * Adds all missing properties from second obj to first obj */ qq.extend = function(first, second){ for (var prop in second){ first[prop] = second[prop]; } }; /** * Searches for a given element in the array, returns -1 if it is not present. * @param {Number} [from] The index at which to begin the search */ qq.indexOf = function(arr, elt, from){ if (arr.indexOf) return arr.indexOf(elt, from); from = from || 0; var len = arr.length; if (from < 0) from += len; for (; from < len; from++){ if (from in arr && arr[from] === elt){ return from; } } return -1; }; qq.getUniqueId = (function(){ var id = 0; return function(){ return id++; }; })(); // // Events qq.attach = function(element, type, fn){ if (element.addEventListener){ element.addEventListener(type, fn, false); } else if (element.attachEvent){ element.attachEvent('on' + type, fn); } }; qq.detach = function(element, type, fn){ if (element.removeEventListener){ element.removeEventListener(type, fn, false); } else if (element.attachEvent){ element.detachEvent('on' + type, fn); } }; qq.preventDefault = function(e){ if (e.preventDefault){ e.preventDefault(); } else{ e.returnValue = false; } }; // // Node manipulations /** * Insert node a before node b. */ qq.insertBefore = function(a, b){ b.parentNode.insertBefore(a, b); }; qq.remove = function(element){ element.parentNode.removeChild(element); }; qq.contains = function(parent, descendant){ // compareposition returns false in this case if (parent == descendant) return true; if (parent.contains){ return parent.contains(descendant); } else { return !!(descendant.compareDocumentPosition(parent) & 8); } }; /** * Creates and returns element from html string * Uses innerHTML to create an element */ qq.toElement = (function(){ var div = document.createElement('div'); return function(html){ div.innerHTML = html; var element = div.firstChild; div.removeChild(element); return element; }; })(); // // Node properties and attributes /** * Sets styles for an element. * Fixes opacity in IE6-8. */ qq.css = function(element, styles){ if (styles.opacity != null){ if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){ styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')'; } } qq.extend(element.style, styles); }; qq.hasClass = function(element, name){ var re = new RegExp('(^| )' + name + '( |$)'); return re.test(element.className); }; qq.addClass = function(element, name){ if (!qq.hasClass(element, name)){ element.className += ' ' + name; } }; qq.removeClass = function(element, name){ var re = new RegExp('(^| )' + name + '( |$)'); element.className = element.className.replace(re, ' ').replace(/^\s+|\s+$/g, ""); }; qq.setText = function(element, text){ element.innerText = text; element.textContent = text; }; // // Selecting elements qq.children = function(element){ var children = [], child = element.firstChild; while (child){ if (child.nodeType == 1){ children.push(child); } child = child.nextSibling; } return children; }; qq.getByClass = function(element, className){ if (element.querySelectorAll){ return element.querySelectorAll('.' + className); } var result = []; var candidates = element.getElementsByTagName("*"); var len = candidates.length; for (var i = 0; i < len; i++){ if (qq.hasClass(candidates[i], className)){ result.push(candidates[i]); } } return result; }; /** * obj2url() takes a json-object as argument and generates * a querystring. pretty much like jQuery.param() * * how to use: * * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');` * * will result in: * * `http://any.url/upload?otherParam=value&a=b&c=d` * * @param Object JSON-Object * @param String current querystring-part * @return String encoded querystring */ qq.obj2url = function(obj, temp, prefixDone){ var uristrings = [], prefix = '&', add = function(nextObj, i){ var nextTemp = temp ? (/\[\]$/.test(temp)) // prevent double-encoding ? temp : temp+'['+i+']' : i; if ((nextTemp != 'undefined') && (i != 'undefined')) { uristrings.push( (typeof nextObj === 'object') ? qq.obj2url(nextObj, nextTemp, true) : (Object.prototype.toString.call(nextObj) === '[object Function]') ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj) ); } }; if (!prefixDone && temp) { prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?'; uristrings.push(temp); uristrings.push(qq.obj2url(obj)); } else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) { // we wont use a for-in-loop on an array (performance) for (var i = 0, len = obj.length; i < len; ++i){ add(obj[i], i); } } else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === "object")){ // for anything else but a scalar, we will use for-in-loop for (var i in obj){ if(obj.hasOwnProperty(i) && typeof obj[i] != 'function') { add(obj[i], i); } } } else { uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj)); } return uristrings.join(prefix) .replace(/^&/, '') .replace(/%20/g, '+'); }; // // // Uploader Classes // // var qq = qq || {}; /** * Creates upload button, validates upload, but doesn't create file list or dd. */ qq.FileUploaderBasic = function(o){ this._options = { // set to true to see the server response debug: false, action: '/server/upload', params: {}, button: null, multiple: true, maxConnections: 3, // validation allowedExtensions: [], sizeLimit: 0, minSizeLimit: 0, // events // return false to cancel submit onSubmit: function(id, fileName){}, onProgress: function(id, fileName, loaded, total){}, onComplete: function(id, fileName, responseJSON){}, onCancel: function(id, fileName){}, // messages messages: { typeError: "{file} has invalid extension. Only {extensions} are allowed.", sizeError: "{file} is too large, maximum file size is {sizeLimit}.", minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.", emptyError: "{file} is empty, please select files again without it.", onLeave: "The files are being uploaded, if you leave now the upload will be cancelled." }, showMessage: function(message){ alert(message); } }; qq.extend(this._options, o); // number of files being uploaded this._filesInProgress = 0; this._handler = this._createUploadHandler(); if (this._options.button){ this._button = this._createUploadButton(this._options.button); } this._preventLeaveInProgress(); }; qq.FileUploaderBasic.prototype = { setParams: function(params){ this._options.params = params; }, getInProgress: function(){ return this._filesInProgress; }, _createUploadButton: function(element){ var self = this; return new qq.UploadButton({ element: element, multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(), onChange: function(input){ self._onInputChange(input); } }); }, _createUploadHandler: function(){ var self = this, handlerClass; if(qq.UploadHandlerXhr.isSupported()){ handlerClass = 'UploadHandlerXhr'; } else { handlerClass = 'UploadHandlerForm'; } var handler = new qq[handlerClass]({ debug: this._options.debug, action: this._options.action, maxConnections: this._options.maxConnections, onProgress: function(id, fileName, loaded, total){ self._onProgress(id, fileName, loaded, total); self._options.onProgress(id, fileName, loaded, total); }, onComplete: function(id, fileName, result){ self._onComplete(id, fileName, result); self._options.onComplete(id, fileName, result); }, onCancel: function(id, fileName){ self._onCancel(id, fileName); self._options.onCancel(id, fileName); } }); return handler; }, _preventLeaveInProgress: function(){ var self = this; qq.attach(window, 'beforeunload', function(e){ if (!self._filesInProgress){return;} var e = e || window.event; // for ie, ff e.returnValue = self._options.messages.onLeave; // for webkit return self._options.messages.onLeave; }); }, _onSubmit: function(id, fileName){ this._filesInProgress++; }, _onProgress: function(id, fileName, loaded, total){ }, _onComplete: function(id, fileName, result){ this._filesInProgress--; if (result.error){ this._options.showMessage(result.error); } }, _onCancel: function(id, fileName){ this._filesInProgress--; }, _onInputChange: function(input){ if (this._handler instanceof qq.UploadHandlerXhr){ this._uploadFileList(input.files); } else { if (this._validateFile(input)){ this._uploadFile(input); } } this._button.reset(); }, _uploadFileList: function(files){ for (var i=0; i<files.length; i++){ if ( !this._validateFile(files[i])){ return; } } for (var i=0; i<files.length; i++){ this._uploadFile(files[i]); } }, _uploadFile: function(fileContainer){ var id = this._handler.add(fileContainer); var fileName = this._handler.getName(id); if (this._options.onSubmit(id, fileName) !== false){ this._onSubmit(id, fileName); this._handler.upload(id, this._options.params); } }, _validateFile: function(file){ var name, size; if (file.value){ // it is a file input // get input value and remove path to normalize name = file.value.replace(/.*(\/|\\)/, ""); } else { // fix missing properties in Safari name = file.fileName != null ? file.fileName : file.name; size = file.fileSize != null ? file.fileSize : file.size; } if (! this._isAllowedExtension(name)){ this._error('typeError', name); return false; } else if (size === 0){ this._error('emptyError', name); return false; } else if (size && this._options.sizeLimit && size > this._options.sizeLimit){ this._error('sizeError', name); return false; } else if (size && size < this._options.minSizeLimit){ this._error('minSizeError', name); return false; } return true; }, _error: function(code, fileName){ var message = this._options.messages[code]; function r(name, replacement){ message = message.replace(name, replacement); } r('{file}', this._formatFileName(fileName)); r('{extensions}', this._options.allowedExtensions.join(', ')); r('{sizeLimit}', this._formatSize(this._options.sizeLimit)); r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit)); this._options.showMessage(message); }, _formatFileName: function(name){ if (name.length > 33){ name = name.slice(0, 19) + '...' + name.slice(-13); } return name; }, _isAllowedExtension: function(fileName){ var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : ''; var allowed = this._options.allowedExtensions; if (!allowed.length){return true;} for (var i=0; i<allowed.length; i++){ if (allowed[i].toLowerCase() == ext){ return true;} } return false; }, _formatSize: function(bytes){ var i = -1; do { bytes = bytes / 1024; i++; } while (bytes > 99); return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i]; } }; /** * Class that creates upload widget with drag-and-drop and file list * @inherits qq.FileUploaderBasic */ qq.FileUploader = function(o){ // call parent constructor qq.FileUploaderBasic.apply(this, arguments); // additional options qq.extend(this._options, { element: null, // if set, will be used instead of qq-upload-list in template listElement: null, template: '<div class="qq-uploader">' + '<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' + '<div class="qq-upload-button">Upload a file</div>' + '<ul class="qq-upload-list"></ul>' + '</div>', // template for one item in file list fileTemplate: '<li>' + '<span class="qq-upload-file"></span>' + '<span class="qq-upload-spinner"></span>' + '<span class="qq-upload-size"></span>' + '<a class="qq-upload-cancel" href="#">Cancel</a>' + '<span class="qq-upload-failed-text">Failed</span>' + '</li>', classes: { // used to get elements from templates button: 'qq-upload-button', drop: 'qq-upload-drop-area', dropActive: 'qq-upload-drop-area-active', list: 'qq-upload-list', file: 'qq-upload-file', spinner: 'qq-upload-spinner', size: 'qq-upload-size', cancel: 'qq-upload-cancel', // added to list item when upload completes // used in css to hide progress spinner success: 'qq-upload-success', fail: 'qq-upload-fail' } }); // overwrite options with user supplied qq.extend(this._options, o); this._element = this._options.element; this._element.innerHTML = this._options.template; this._listElement = this._options.listElement || this._find(this._element, 'list'); this._classes = this._options.classes; this._button = this._createUploadButton(this._find(this._element, 'button')); this._bindCancelEvent(); this._setupDragDrop(); }; // inherit from Basic Uploader qq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype); qq.extend(qq.FileUploader.prototype, { /** * Gets one of the elements listed in this._options.classes **/ _find: function(parent, type){ var element = qq.getByClass(parent, this._options.classes[type])[0]; if (!element){ throw new Error('element not found ' + type); } return element; }, _setupDragDrop: function(){ var self = this, dropArea = this._find(this._element, 'drop'); var dz = new qq.UploadDropZone({ element: dropArea, onEnter: function(e){ qq.addClass(dropArea, self._classes.dropActive); e.stopPropagation(); }, onLeave: function(e){ e.stopPropagation(); }, onLeaveNotDescendants: function(e){ qq.removeClass(dropArea, self._classes.dropActive); }, onDrop: function(e){ dropArea.style.display = 'none'; qq.removeClass(dropArea, self._classes.dropActive); self._uploadFileList(e.dataTransfer.files); } }); dropArea.style.display = 'none'; qq.attach(document, 'dragenter', function(e){ if (!dz._isValidFileDrag(e)) return; dropArea.style.display = 'block'; }); qq.attach(document, 'dragleave', function(e){ if (!dz._isValidFileDrag(e)) return; var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); // only fire when leaving document out if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){ dropArea.style.display = 'none'; } }); }, _onSubmit: function(id, fileName){ qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments); this._addToList(id, fileName); }, _onProgress: function(id, fileName, loaded, total){ qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments); var item = this._getItemByFileId(id); var size = this._find(item, 'size'); size.style.display = 'inline'; var text; if (loaded != total){ text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total); } else { text = this._formatSize(total); } qq.setText(size, text); }, _onComplete: function(id, fileName, result){ qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments); // mark completed var item = this._getItemByFileId(id); qq.remove(this._find(item, 'cancel')); qq.remove(this._find(item, 'spinner')); if (result.success){ qq.addClass(item, this._classes.success); } else { qq.addClass(item, this._classes.fail); } }, _addToList: function(id, fileName){ var item = qq.toElement(this._options.fileTemplate); item.qqFileId = id; var fileElement = this._find(item, 'file'); qq.setText(fileElement, this._formatFileName(fileName)); this._find(item, 'size').style.display = 'none'; this._listElement.appendChild(item); }, _getItemByFileId: function(id){ var item = this._listElement.firstChild; // there can't be txt nodes in dynamically created list // and we can use nextSibling while (item){ if (item.qqFileId == id) return item; item = item.nextSibling; } }, /** * delegate click event for cancel link **/ _bindCancelEvent: function(){ var self = this, list = this._listElement; qq.attach(list, 'click', function(e){ e = e || window.event; var target = e.target || e.srcElement; if (qq.hasClass(target, self._classes.cancel)){ qq.preventDefault(e); var item = target.parentNode; self._handler.cancel(item.qqFileId); qq.remove(item); } }); } }); qq.UploadDropZone = function(o){ this._options = { element: null, onEnter: function(e){}, onLeave: function(e){}, // is not fired when leaving element by hovering descendants onLeaveNotDescendants: function(e){}, onDrop: function(e){} }; qq.extend(this._options, o); this._element = this._options.element; this._disableDropOutside(); this._attachEvents(); }; qq.UploadDropZone.prototype = { _disableDropOutside: function(e){ // run only once for all instances if (!qq.UploadDropZone.dropOutsideDisabled ){ qq.attach(document, 'dragover', function(e){ if (e.dataTransfer){ e.dataTransfer.dropEffect = 'none'; e.preventDefault(); } }); qq.UploadDropZone.dropOutsideDisabled = true; } }, _attachEvents: function(){ var self = this; qq.attach(self._element, 'dragover', function(e){ if (!self._isValidFileDrag(e)) return; var effect = e.dataTransfer.effectAllowed; if (effect == 'move' || effect == 'linkMove'){ e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed) } else { e.dataTransfer.dropEffect = 'copy'; // for Chrome } e.stopPropagation(); e.preventDefault(); }); qq.attach(self._element, 'dragenter', function(e){ if (!self._isValidFileDrag(e)) return; self._options.onEnter(e); }); qq.attach(self._element, 'dragleave', function(e){ if (!self._isValidFileDrag(e)) return; self._options.onLeave(e); var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); // do not fire when moving a mouse over a descendant if (qq.contains(this, relatedTarget)) return; self._options.onLeaveNotDescendants(e); }); qq.attach(self._element, 'drop', function(e){ if (!self._isValidFileDrag(e)) return; e.preventDefault(); self._options.onDrop(e); }); }, _isValidFileDrag: function(e){ var dt = e.dataTransfer, // do not check dt.types.contains in webkit, because it crashes safari 4 isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1; // dt.effectAllowed is none in Safari 5 // dt.types.contains check is for firefox return dt && dt.effectAllowed != 'none' && (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files'))); } }; qq.UploadButton = function(o){ this._options = { element: null, // if set to true adds multiple attribute to file input multiple: false, // name attribute of file input name: 'file', onChange: function(input){}, hoverClass: 'qq-upload-button-hover', focusClass: 'qq-upload-button-focus' }; qq.extend(this._options, o); this._element = this._options.element; // make button suitable container for input qq.css(this._element, { position: 'relative', overflow: 'hidden', // Make sure browse button is in the right side // in Internet Explorer direction: 'ltr' }); this._input = this._createInput(); }; qq.UploadButton.prototype = { /* returns file input element */ getInput: function(){ return this._input; }, /* cleans/recreates the file input */ reset: function(){ if (this._input.parentNode){ qq.remove(this._input); } qq.removeClass(this._element, this._options.focusClass); this._input = this._createInput(); }, _createInput: function(){ var input = document.createElement("input"); if (this._options.multiple){ input.setAttribute("multiple", "multiple"); } input.setAttribute("type", "file"); input.setAttribute("name", this._options.name); qq.css(input, { position: 'absolute', // in Opera only 'browse' button // is clickable and it is located at // the right side of the input right: 0, top: 0, fontFamily: 'Arial', // 4 persons reported this, the max values that worked for them were 243, 236, 236, 118 fontSize: '118px', margin: 0, padding: 0, cursor: 'pointer', opacity: 0 }); this._element.appendChild(input); var self = this; qq.attach(input, 'change', function(){ self._options.onChange(input); }); qq.attach(input, 'mouseover', function(){ qq.addClass(self._element, self._options.hoverClass); }); qq.attach(input, 'mouseout', function(){ qq.removeClass(self._element, self._options.hoverClass); }); qq.attach(input, 'focus', function(){ qq.addClass(self._element, self._options.focusClass); }); qq.attach(input, 'blur', function(){ qq.removeClass(self._element, self._options.focusClass); }); // IE and Opera, unfortunately have 2 tab stops on file input // which is unacceptable in our case, disable keyboard access if (window.attachEvent){ // it is IE or Opera input.setAttribute('tabIndex', "-1"); } return input; } }; /** * Class for uploading files, uploading itself is handled by child classes */ qq.UploadHandlerAbstract = function(o){ this._options = { debug: false, action: '/upload.php', // maximum number of concurrent uploads maxConnections: 999, onProgress: function(id, fileName, loaded, total){}, onComplete: function(id, fileName, response){}, onCancel: function(id, fileName){} }; qq.extend(this._options, o); this._queue = []; // params for files in queue this._params = []; }; qq.UploadHandlerAbstract.prototype = { log: function(str){ if (this._options.debug && window.console) console.log('[uploader] ' + str); }, /** * Adds file or file input to the queue * @returns id **/ add: function(file){}, /** * Sends the file identified by id and additional query params to the server */ upload: function(id, params){ var len = this._queue.push(id); var copy = {}; qq.extend(copy, params); this._params[id] = copy; // if too many active uploads, wait... if (len <= this._options.maxConnections){ this._upload(id, this._params[id]); } }, /** * Cancels file upload by id */ cancel: function(id){ this._cancel(id); this._dequeue(id); }, /** * Cancells all uploads */ cancelAll: function(){ for (var i=0; i<this._queue.length; i++){ this._cancel(this._queue[i]); } this._queue = []; }, /** * Returns name of the file identified by id */ getName: function(id){}, /** * Returns size of the file identified by id */ getSize: function(id){}, /** * Returns id of files being uploaded or * waiting for their turn */ getQueue: function(){ return this._queue; }, /** * Actual upload method */ _upload: function(id){}, /** * Actual cancel method */ _cancel: function(id){}, /** * Removes element from queue, starts upload of next */ _dequeue: function(id){ var i = qq.indexOf(this._queue, id); this._queue.splice(i, 1); var max = this._options.maxConnections; if (this._queue.length >= max && i < max){ var nextId = this._queue[max-1]; this._upload(nextId, this._params[nextId]); } } }; /** * Class for uploading files using form and iframe * @inherits qq.UploadHandlerAbstract */ qq.UploadHandlerForm = function(o){ qq.UploadHandlerAbstract.apply(this, arguments); this._inputs = {}; }; // @inherits qq.UploadHandlerAbstract qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype); qq.extend(qq.UploadHandlerForm.prototype, { add: function(fileInput){ fileInput.setAttribute('name', 'qqfile'); var id = 'qq-upload-handler-iframe' + qq.getUniqueId(); this._inputs[id] = fileInput; // remove file input from DOM if (fileInput.parentNode){ qq.remove(fileInput); } return id; }, getName: function(id){ // get input value and remove path to normalize return this._inputs[id].value.replace(/.*(\/|\\)/, ""); }, _cancel: function(id){ this._options.onCancel(id, this.getName(id)); delete this._inputs[id]; var iframe = document.getElementById(id); if (iframe){ // to cancel request set src to something else // we use src="javascript:false;" because it doesn't // trigger ie6 prompt on https iframe.setAttribute('src', 'javascript:false;'); qq.remove(iframe); } }, _upload: function(id, params){ var input = this._inputs[id]; if (!input){ throw new Error('file with passed id was not added, or already uploaded or cancelled'); } var fileName = this.getName(id); var iframe = this._createIframe(id); var form = this._createForm(iframe, params); form.appendChild(input); var self = this; this._attachLoadEvent(iframe, function(){ self.log('iframe loaded'); var response = self._getIframeContentJSON(iframe); self._options.onComplete(id, fileName, response); self._dequeue(id); delete self._inputs[id]; // timeout added to fix busy state in FF3.6 setTimeout(function(){ qq.remove(iframe); }, 1); }); form.submit(); qq.remove(form); return id; }, _attachLoadEvent: function(iframe, callback){ qq.attach(iframe, 'load', function(){ // when we remove iframe from dom // the request stops, but in IE load // event fires if (!iframe.parentNode){ return; } // fixing Opera 10.53 if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false"){ // In Opera event is fired second time // when body.innerHTML changed from false // to server response approx. after 1 sec // when we upload file with iframe return; } callback(); }); }, /** * Returns json object received by iframe from server. */ _getIframeContentJSON: function(iframe){ // iframe.contentWindow.document - for IE<7 var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document, response; this.log("converting iframe's innerHTML to JSON"); this.log("innerHTML = " + doc.body.innerHTML); try { response = eval("(" + doc.body.innerHTML + ")"); } catch(err){ response = {}; } return response; }, /** * Creates iframe with unique name */ _createIframe: function(id){ // We can't use following code as the name attribute // won't be properly registered in IE6, and new window // on form submit will open // var iframe = document.createElement('iframe'); // iframe.setAttribute('name', id); var iframe = qq.toElement('<iframe src="javascript:false;" name="' + id + '" />'); // src="javascript:false;" removes ie6 prompt on https iframe.setAttribute('id', id); iframe.style.display = 'none'; document.body.appendChild(iframe); return iframe; }, /** * Creates form, that will be submitted to iframe */ _createForm: function(iframe, params){ // We can't use the following code in IE6 // var form = document.createElement('form'); // form.setAttribute('method', 'post'); // form.setAttribute('enctype', 'multipart/form-data'); // Because in this case file won't be attached to request var form = qq.toElement('<form method="post" enctype="multipart/form-data"></form>'); var queryString = qq.obj2url(params, this._options.action); form.setAttribute('action', queryString); form.setAttribute('target', iframe.name); form.style.display = 'none'; document.body.appendChild(form); return form; } }); /** * Class for uploading files using xhr * @inherits qq.UploadHandlerAbstract */ qq.UploadHandlerXhr = function(o){ qq.UploadHandlerAbstract.apply(this, arguments); this._files = []; this._xhrs = []; // current loaded size in bytes for each file this._loaded = []; }; // static method qq.UploadHandlerXhr.isSupported = function(){ var input = document.createElement('input'); input.type = 'file'; return ( 'multiple' in input && typeof File != "undefined" && typeof (new XMLHttpRequest()).upload != "undefined" ); }; // @inherits qq.UploadHandlerAbstract qq.extend(qq.UploadHandlerXhr.prototype, qq.UploadHandlerAbstract.prototype); qq.extend(qq.UploadHandlerXhr.prototype, { /** * Adds file to the queue * Returns id to use with upload, cancel **/ add: function(file){ if (!(file instanceof File)){ throw new Error('Passed obj in not a File (in qq.UploadHandlerXhr)'); } return this._files.push(file) - 1; }, getName: function(id){ var file = this._files[id]; // fix missing name in Safari 4 return file.fileName != null ? file.fileName : file.name; }, getSize: function(id){ var file = this._files[id]; return file.fileSize != null ? file.fileSize : file.size; }, /** * Returns uploaded bytes for file identified by id */ getLoaded: function(id){ return this._loaded[id] || 0; }, /** * Sends the file identified by id and additional query params to the server * @param {Object} params name-value string pairs */ _upload: function(id, params){ var file = this._files[id], name = this.getName(id), size = this.getSize(id); this._loaded[id] = 0; var xhr = this._xhrs[id] = new XMLHttpRequest(); var self = this; xhr.upload.onprogress = function(e){ if (e.lengthComputable){ self._loaded[id] = e.loaded; self._options.onProgress(id, name, e.loaded, e.total); } }; xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ self._onComplete(id, xhr); } }; // build query string params = params || {}; params['qqfile'] = name; var queryString = qq.obj2url(params, this._options.action); xhr.open("POST", queryString, true); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.setRequestHeader("X-File-Name", encodeURIComponent(name)); xhr.setRequestHeader("Content-Type", "application/octet-stream"); xhr.send(file); }, _onComplete: function(id, xhr){ // the request was aborted/cancelled if (!this._files[id]) return; var name = this.getName(id); var size = this.getSize(id); this._options.onProgress(id, name, size, size); if (xhr.status == 200){ this.log("xhr - server response received"); this.log("responseText = " + xhr.responseText); var response; try { response = eval("(" + xhr.responseText + ")"); } catch(err){ response = {}; } this._options.onComplete(id, name, response); } else { this._options.onComplete(id, name, {}); } this._files[id] = null; this._xhrs[id] = null; this._dequeue(id); }, _cancel: function(id){ this._options.onCancel(id, this.getName(id)); this._files[id] = null; if (this._xhrs[id]){ this._xhrs[id].abort(); this._xhrs[id] = null; } } }); /* XXXXXXXXXX end of lib/scripts/fileuploader.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/fileuploaderextended.js XXXXXXXXXX */ qq.extend(qq.FileUploader.prototype, { _createUploadHandler: function(){ var self = this, handlerClass; if(qq.UploadHandlerXhr.isSupported()){ handlerClass = 'UploadHandlerXhr'; //handlerClass = 'UploadHandlerForm'; } else { handlerClass = 'UploadHandlerForm'; } var handler = new qq[handlerClass]({ debug: this._options.debug, action: this._options.action, maxConnections: this._options.maxConnections, onProgress: function(id, fileName, loaded, total){ self._onProgress(id, fileName, loaded, total); self._options.onProgress(id, fileName, loaded, total); }, onComplete: function(id, fileName, result){ self._onComplete(id, fileName, result); self._options.onComplete(id, fileName, result); }, onCancel: function(id, fileName){ self._onCancel(id, fileName); self._options.onCancel(id, fileName); }, onUpload: function(){ self._onUpload(); } }); return handler; }, _onUpload: function(){ this._handler.uploadAll(this._options.params); }, _uploadFile: function(fileContainer){ var id = this._handler.add(fileContainer); var fileName = this._handler.getName(id); if (this._options.onSubmit(id, fileName) !== false){ this._onSubmit(id, fileName); } }, _addToList: function(id, fileName){ var item = qq.toElement(this._options.fileTemplate); item.qqFileId = id; var fileElement = this._find(item, 'file'); qq.setText(fileElement, fileName); this._find(item, 'size').style.display = 'none'; // name suggestion (simplified cleanID) var nameElement = this._find(item, 'nameInput'); fileName = fileName.toLowerCase(); fileName = fileName.replace(/([ !"#$%&\'()+,\/;<=>?@[\]^`{|}~:]+)/g, '_'); fileName = fileName.replace(/^_+/,''); nameElement.value = fileName; nameElement.id = 'mediamanager__upload_item'+id; this._listElement.appendChild(item); } }); qq.FileUploaderExtended = function(o){ // call parent constructor qq.FileUploaderBasic.apply(this, arguments); qq.extend(this._options, { element: null, // if set, will be used instead of qq-upload-list in template listElement: null, template: '<div class="qq-uploader">' + '<div class="qq-upload-drop-area"><span>' + LANG.media_drop + '</span></div>' + '<div class="qq-upload-button">' + LANG.media_select + '</div>' + '<ul class="qq-upload-list"></ul>' + '<div class="qq-action-container">' + ' <button class="qq-upload-action" type="submit" id="mediamanager__upload_button">' + LANG.media_upload_btn + '</button>' + ' <label class="qq-overwrite-check"><input type="checkbox" value="1" name="ow" class="dw__ow"> <span>' + LANG.media_overwrt + '</span></label>' + '</div>' + '</div>', // template for one item in file list fileTemplate: '<li>' + '<span class="qq-upload-file hidden"></span>' + ' <input class="qq-upload-name-input edit" type="text" value="" />' + ' <span class="qq-upload-spinner hidden"></span>' + ' <span class="qq-upload-size"></span>' + ' <a class="qq-upload-cancel" href="#">' + LANG.media_cancel + '</a>' + ' <span class="qq-upload-failed-text error">Failed</span>' + '</li>', classes: { // used to get elements from templates button: 'qq-upload-button', drop: 'qq-upload-drop-area', dropActive: 'qq-upload-drop-area-active', list: 'qq-upload-list', nameInput: 'qq-upload-name-input', overwriteInput: 'qq-overwrite-check', uploadButton: 'qq-upload-action', file: 'qq-upload-file', spinner: 'qq-upload-spinner', size: 'qq-upload-size', cancel: 'qq-upload-cancel', // added to list item when upload completes // used in css to hide progress spinner success: 'qq-upload-success', fail: 'qq-upload-fail', failedText: 'qq-upload-failed-text' } }); qq.extend(this._options, o); this._element = this._options.element; this._element.innerHTML = this._options.template; this._listElement = this._options.listElement || this._find(this._element, 'list'); this._classes = this._options.classes; this._button = this._createUploadButton(this._find(this._element, 'button')); this._bindCancelEvent(); this._bindUploadEvent(); this._setupDragDrop(); }; qq.extend(qq.FileUploaderExtended.prototype, qq.FileUploader.prototype); qq.extend(qq.FileUploaderExtended.prototype, { _bindUploadEvent: function(){ var self = this, list = this._listElement; qq.attach(document.getElementById('mediamanager__upload_button'), 'click', function(e){ e = e || window.event; var target = e.target || e.srcElement; qq.preventDefault(e); self._handler._options.onUpload(); jQuery(".qq-upload-name-input").each(function (i) { jQuery(this).prop('disabled', true); }); }); }, _onComplete: function(id, fileName, result){ this._filesInProgress--; // mark completed var item = this._getItemByFileId(id); qq.remove(this._find(item, 'cancel')); qq.remove(this._find(item, 'spinner')); var nameInput = this._find(item, 'nameInput'); var fileElement = this._find(item, 'file'); qq.setText(fileElement, nameInput.value); qq.removeClass(fileElement, 'hidden'); qq.remove(nameInput); jQuery('.qq-upload-button, #mediamanager__upload_button').remove(); jQuery('.dw__ow').parent().hide(); jQuery('.qq-upload-drop-area').remove(); if (result.success){ qq.addClass(item, this._classes.success); $link = '<a href="' + result.link + '" id="h_:' + result.id + '" class="select">' + nameInput.value + '</a>'; jQuery(fileElement).html($link); } else { qq.addClass(item, this._classes.fail); var fail = this._find(item, 'failedText'); if (result.error) qq.setText(fail, result.error); } if (document.getElementById('media__content') && !document.getElementById('mediamanager__done_form')) { var action = document.location.href; var i = action.indexOf('?'); if (i) action = action.substr(0, i); var button = '<form method="post" action="' + action + '" id="mediamanager__done_form"><div>'; button += '<input type="hidden" value="' + result.ns + '" name="ns">'; button += '<input type="hidden" value="1" name="recent">'; button += '<button type="submit">' + LANG.media_done_btn + '</button></div></form>'; jQuery('#mediamanager__uploader').append(button); } } }); qq.extend(qq.UploadHandlerForm.prototype, { uploadAll: function(params){ this._uploadAll(params); }, getName: function(id){ var file = this._inputs[id]; var name = document.getElementById('mediamanager__upload_item'+id); if (name != null) { return name.value; } else { if (file != null) { // get input value and remove path to normalize return file.value.replace(/.*(\/|\\)/, ""); } else { return null; } } }, _uploadAll: function(params){ jQuery(".qq-upload-spinner").each(function (i) { jQuery(this).removeClass('hidden'); }); for (key in this._inputs) { this.upload(key, params); } }, _upload: function(id, params){ var input = this._inputs[id]; if (!input){ throw new Error('file with passed id was not added, or already uploaded or cancelled'); } var fileName = this.getName(id); var iframe = this._createIframe(id); var form = this._createForm(iframe, params); form.appendChild(input); var nameInput = qq.toElement('<input name="mediaid" value="' + fileName + '" type="text">'); form.appendChild(nameInput); var checked = jQuery('.dw__ow').is(':checked'); var owCheckbox = jQuery('.dw__ow').clone(); owCheckbox.attr('checked', checked); jQuery(form).append(owCheckbox); var self = this; this._attachLoadEvent(iframe, function(){ self.log('iframe loaded'); var response = self._getIframeContentJSON(iframe); self._options.onComplete(id, fileName, response); self._dequeue(id); delete self._inputs[id]; // timeout added to fix busy state in FF3.6 setTimeout(function(){ qq.remove(iframe); }, 1); }); form.submit(); qq.remove(form); return id; } }); qq.extend(qq.UploadHandlerXhr.prototype, { uploadAll: function(params){ this._uploadAll(params); }, getName: function(id){ var file = this._files[id]; var name = document.getElementById('mediamanager__upload_item'+id); if (name != null) { return name.value; } else { if (file != null) { // fix missing name in Safari 4 return file.fileName != null ? file.fileName : file.name; } else { return null; } } }, getSize: function(id){ var file = this._files[id]; if (file == null) return null; return file.fileSize != null ? file.fileSize : file.size; }, _upload: function(id, params){ var file = this._files[id], name = this.getName(id), size = this.getSize(id); if (name == null || size == null) return; this._loaded[id] = 0; var xhr = this._xhrs[id] = new XMLHttpRequest(); var self = this; xhr.upload.onprogress = function(e){ if (e.lengthComputable){ self._loaded[id] = e.loaded; self._options.onProgress(id, name, e.loaded, e.total); } }; xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ self._onComplete(id, xhr); } }; // build query string params = params || {}; params['qqfile'] = name; params['ow'] = jQuery('.dw__ow').is(':checked'); var queryString = qq.obj2url(params, this._options.action); xhr.open("POST", queryString, true); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.setRequestHeader("X-File-Name", encodeURIComponent(name)); xhr.setRequestHeader("Content-Type", "application/octet-stream"); xhr.send(file); }, _uploadAll: function(params){ jQuery(".qq-upload-spinner").each(function (i) { jQuery(this).removeClass('hidden'); }); for (key in this._files) { this.upload(key, params); } } }); /* XXXXXXXXXX end of lib/scripts/fileuploaderextended.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/helpers.js XXXXXXXXXX */ /** * Various helper functions */ /** * A PHP-style substr_replace * * Supports negative start and length and omitting length, but not * str and replace arrays. * See http://php.net/substr-replace for further documentation. */ function substr_replace(str, replace, start, length) { var a2, b1; a2 = (start < 0 ? str.length : 0) + start; if (typeof length === 'undefined') { length = str.length - a2; } else if (length < 0 && start < 0 && length <= start) { length = 0; } b1 = (length < 0 ? str.length : a2) + length; return str.substring(0, a2) + replace + str.substring(b1); } /** * Bind variables to a function call creating a closure * * Use this to circumvent variable scope problems when creating closures * inside a loop * * @author Adrian Lang <lang@cosmocode.de> * @link http://www.cosmocode.de/en/blog/gohr/2009-10/15-javascript-fixing-the-closure-scope-in-loops * @param functionref fnc - the function to be called * @param mixed - any arguments to be passed to the function * @returns functionref */ function bind(fnc/*, ... */) { var Aps = Array.prototype.slice, // Store passed arguments in this scope. // Since arguments is no Array nor has an own slice method, // we have to apply the slice method from the Array.prototype static_args = Aps.call(arguments, 1); // Return a function evaluating the passed function with the // given args and optional arguments passed on invocation. return function (/* ... */) { // Same here, but we use Array.prototype.slice solely for // converting arguments to an Array. return fnc.apply(this, static_args.concat(Aps.call(arguments, 0))); }; } /** * Report an error from a JS file to the console * * @param e The error object * @param file The file in which the error occurred */ function logError(e, file) { if (window.console && console.error) { console.error('The error "%s: %s" occurred in file "%s". ' + 'If this is in a plugin try updating or disabling the plugin, ' + 'if this is in a template try updating the template or switching to the "dokuwiki" template.', e.name, e.message, file); if(e.stack) { console.error(e.stack); } } } /* XXXXXXXXXX end of lib/scripts/helpers.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/delay.js XXXXXXXXXX */ /** * Manage delayed and timed actions * * @license GPL2 (http://www.gnu.org/licenses/gpl.html) * @author Adrian Lang <lang@cosmocode.de> */ /** * Provide a global callback for window.setTimeout * * To get a timeout for non-global functions, just call * delay.add(func, timeout). */ var timer = { _cur_id: 0, _handlers: {}, execDispatch: function (id) { timer._handlers[id](); }, add: function (func, timeout) { var id = ++timer._cur_id; timer._handlers[id] = func; return window.setTimeout('timer.execDispatch(' + id + ')', timeout); } }; /** * Provide a delayed start * * To call a function with a delay, just create a new Delay(func, timeout) and * call that object’s method “start”. */ function Delay (func, timeout) { this.func = func; if (timeout) { this.timeout = timeout; } } Delay.prototype = { func: null, timeout: 500, delTimer: function () { if (this.timer !== null) { window.clearTimeout(this.timer); this.timer = null; } }, start: function () { DEPRECATED('don\'t use the Delay object, use window.timeout with a callback instead'); this.delTimer(); var _this = this; this.timer = timer.add(function () { _this.exec.call(_this); }, this.timeout); this._data = { _this: arguments[0], _params: Array.prototype.slice.call(arguments, 2) }; }, exec: function () { this.delTimer(); this.func.call(this._data._this, this._data._params); } }; /* XXXXXXXXXX end of lib/scripts/delay.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/cookie.js XXXXXXXXXX */ /** * Handles the cookie used by several JavaScript functions * * Only a single cookie is written and read. You may only save * simple name-value pairs - no complex types! * * You should only use the getValue and setValue methods * * @author Andreas Gohr <andi@splitbrain.org> * @author Michal Rezler <m.rezler@centrum.cz> */ var DokuCookie = { data: {}, name: 'DOKU_PREFS', /** * Save a value to the cookie * * @author Andreas Gohr <andi@splitbrain.org> */ setValue: function(key,val){ var text = [], _this = this; this.init(); if (val === false){ delete this.data[key]; }else{ val = val + ""; this.data[key] = val; } //save the whole data array jQuery.each(_this.data, function (key, val) { if (_this.data.hasOwnProperty(key)) { text.push(encodeURIComponent(key)+'#'+encodeURIComponent(val)); } }); jQuery.cookie(this.name, text.join('#'), {expires: 365, path: DOKU_COOKIE_PARAM.path, secure: DOKU_COOKIE_PARAM.secure}); }, /** * Get a Value from the Cookie * * @author Andreas Gohr <andi@splitbrain.org> * @param def default value if key does not exist; if not set, returns undefined by default */ getValue: function(key, def){ this.init(); return this.data.hasOwnProperty(key) ? this.data[key] : def; }, /** * Loads the current set cookie * * @author Andreas Gohr <andi@splitbrain.org> */ init: function(){ var text, parts, i; if(!jQuery.isEmptyObject(this.data)) { return; } text = jQuery.cookie(this.name); if(text){ parts = text.split('#'); for(i = 0; i < parts.length; i += 2){ this.data[decodeURIComponent(parts[i])] = decodeURIComponent(parts[i+1]); } } } }; /* XXXXXXXXXX end of lib/scripts/cookie.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/script.js XXXXXXXXXX */ // if jQuery was loaded, let's make it noConflict here. if ('function' === typeof jQuery && 'function' === typeof jQuery.noConflict) { jQuery.noConflict(); } /** * Some browser detection */ var clientPC = navigator.userAgent.toLowerCase(); // Get client info var is_macos = navigator.appVersion.indexOf('Mac') != -1; var is_gecko = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1) && (clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1)); var is_safari = ((clientPC.indexOf('applewebkit')!=-1) && (clientPC.indexOf('spoofer')==-1)); var is_khtml = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled )); if (clientPC.indexOf('opera')!=-1) { var is_opera = true; var is_opera_preseven = (window.opera && !document.childNodes); var is_opera_seven = (window.opera && document.childNodes); } /** * Handler to close all open Popups */ function closePopups(){ jQuery('div.JSpopup').hide(); } jQuery(function () { jQuery(document).on('click', closePopups); }); /* XXXXXXXXXX end of lib/scripts/script.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/qsearch.js XXXXXXXXXX */ /** * AJAX functions for the pagename quicksearch * * @license GPL2 (http://www.gnu.org/licenses/gpl.html) * @author Andreas Gohr <andi@splitbrain.org> * @author Adrian Lang <lang@cosmocode.de> * @author Michal Rezler <m.rezler@centrum.cz> */ jQuery.fn.dw_qsearch = function (overrides) { var dw_qsearch = { output: '#qsearch__out', $inObj: this, $outObj: null, timer: null, curRequest: null, /** * initialize the quick search * * Attaches the event handlers * */ init: function () { var do_qsearch; dw_qsearch.$outObj = jQuery(dw_qsearch.output); // objects found? if (dw_qsearch.$inObj.length === 0 || dw_qsearch.$outObj.length === 0) { return; } // attach eventhandler to search field do_qsearch = function () { // abort any previous request if (dw_qsearch.curRequest != null) { dw_qsearch.curRequest.abort(); } var value = dw_qsearch.getSearchterm(); if (value === '') { dw_qsearch.clear_results(); return; } dw_qsearch.$inObj.parents('form').addClass('searching'); dw_qsearch.curRequest = jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', { call: 'qsearch', q: encodeURI(value) }, dw_qsearch.onCompletion, 'html' ); }; dw_qsearch.$inObj.on('keyup', function () { if (dw_qsearch.timer) { window.clearTimeout(dw_qsearch.timer); dw_qsearch.timer = null; } dw_qsearch.timer = window.setTimeout(do_qsearch, 500); } ); // attach eventhandler to output field dw_qsearch.$outObj.on('click', dw_qsearch.clear_results); }, /** * Read search term from input */ getSearchterm: function() { return dw_qsearch.$inObj.val(); }, /** * Empty and hide the output div */ clear_results: function () { dw_qsearch.$inObj.parents('form').removeClass('searching'); dw_qsearch.$outObj.hide(); dw_qsearch.$outObj.text(''); }, /** * Callback. Reformat and display the results. * * Namespaces are shortened here to keep the results from overflowing * or wrapping * * @param data The result HTML */ onCompletion: function (data) { var max, $links, too_big; dw_qsearch.$inObj.parents('form').removeClass('searching'); dw_qsearch.curRequest = null; if (data === '') { dw_qsearch.clear_results(); return; } dw_qsearch.$outObj .html(data) .show() .css('white-space', 'nowrap'); // disable overflow during shortening dw_qsearch.$outObj.find('li').css('overflow', 'visible'); $links = dw_qsearch.$outObj.find('a'); max = dw_qsearch.$outObj[0].clientWidth; // maximum width allowed (but take away paddings below) if (document.documentElement.dir === 'rtl') { max -= parseInt(dw_qsearch.$outObj.css('padding-left')); too_big = function (l) { return l.offsetLeft < 0; }; } else { max -= parseInt(dw_qsearch.$outObj.css('padding-right')); too_big = function (l) { return l.offsetWidth + l.offsetLeft > max; }; } $links.each(function () { var start, length, replace, nsL, nsR, eli, runaway; if (!too_big(this)) { return; } nsL = this.textContent.indexOf('('); nsR = this.textContent.indexOf(')'); eli = 0; runaway = 0; while ((nsR - nsL > 3) && too_big(this) && runaway++ < 500) { if (eli !== 0) { // elipsis already inserted if ((eli - nsL) > (nsR - eli)) { // cut left start = eli - 2; length = 2; } else { // cut right start = eli + 1; length = 1; } replace = ''; } else { // replace middle with ellipsis start = Math.floor(nsL + ((nsR - nsL) / 2)); length = 1; replace = '…'; } this.textContent = substr_replace(this.textContent, replace, start, length); eli = this.textContent.indexOf('…'); nsL = this.textContent.indexOf('('); nsR = this.textContent.indexOf(')'); } }); // reenable overflow dw_qsearch.$outObj.find('li').css('overflow', 'hidden').css('text-overflow', 'ellipsis'); } }; jQuery.extend(dw_qsearch, overrides); if (!overrides.deferInit) { dw_qsearch.init(); } return dw_qsearch; }; jQuery(function () { jQuery('#qsearch__in').dw_qsearch({ output: '#qsearch__out' }); }); /* XXXXXXXXXX end of lib/scripts/qsearch.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/search.js XXXXXXXXXX */ jQuery(function () { 'use strict'; var $searchForm = jQuery('.search-results-form'); if (!$searchForm.length) { return; } var $toggleAssistanceButton = jQuery('<button>') .addClass('toggleAssistant') .attr('type', 'button') .attr('aria-expanded', 'false') .text(LANG.search_toggle_tools) .prependTo($searchForm.find('fieldset')) ; $toggleAssistanceButton.on('click', function () { jQuery('.advancedOptions').toggle(0, function () { var $me = jQuery(this); if ($me.attr('aria-hidden')) { $me.removeAttr('aria-hidden'); $toggleAssistanceButton.attr('aria-expanded', 'true'); DokuCookie.setValue('sa', 'on'); } else { $me.attr('aria-hidden', 'true'); $toggleAssistanceButton.attr('aria-expanded', 'false'); DokuCookie.setValue('sa', 'off'); } }); }); if (DokuCookie.getValue('sa') === 'on') { $toggleAssistanceButton.trigger('click'); } $searchForm.find('.advancedOptions .toggle div.current').on('click', function () { var $me = jQuery(this); $me.parent().siblings().removeClass('open'); $me.parent().siblings().find('ul:first').attr('aria-expanded', 'false'); $me.parent().toggleClass('open'); if ($me.parent().hasClass('open')) { $me.parent().find('ul:first').attr('aria-expanded', 'true'); } else { $me.parent().find('ul:first').attr('aria-expanded', 'false'); } }); }); /* XXXXXXXXXX end of lib/scripts/search.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/tree.js XXXXXXXXXX */ jQuery.fn.dw_tree = function(overrides) { var dw_tree = { /** * Delay in ms before showing the throbber. * Used to skip the throbber for fast AJAX calls. */ throbber_delay: 500, $obj: this, toggle_selector: 'a.idx_dir', init: function () { this.$obj.on('click', this.toggle_selector, this, this.toggle); jQuery('ul:first', this.$obj).attr('role', 'tree'); jQuery('ul', this.$obj).not(':first').attr('role', 'group'); jQuery('li', this.$obj).attr('role', 'treeitem'); jQuery('li.open > ul', this.$obj).attr('aria-expanded', 'true'); jQuery('li.closed > ul', this.$obj).attr('aria-expanded', 'false'); jQuery('li.closed', this.$obj).attr('aria-live', 'assertive'); }, /** * Open or close a subtree using AJAX * The contents of subtrees are "cached" until the page is reloaded. * A "loading" indicator is shown only when the AJAX call is slow. * * @author Andreas Gohr <andi@splitbrain.org> * @author Ben Coburn <btcoburn@silicodon.net> * @author Pierre Spring <pierre.spring@caillou.ch> */ toggle: function (e) { var $listitem, $sublist, timeout, $clicky, show_sublist, dw_tree, opening; e.preventDefault(); dw_tree = e.data; $clicky = jQuery(this); $listitem = $clicky.closest('li'); $sublist = $listitem.find('ul').first(); opening = $listitem.hasClass('closed'); dw_tree.toggle_display($clicky, opening); if ($sublist.is(':visible')) { $listitem.removeClass('open').addClass('closed'); $sublist.attr('aria-expanded', 'false'); } else { $listitem.removeClass('closed').addClass('open'); $sublist.attr('aria-expanded', 'true'); } // if already open, close by hiding the sublist if (!opening) { $sublist.dw_hide(); return; } show_sublist = function (data) { $sublist.hide(); if (typeof data !== 'undefined') { $sublist.html(data); $sublist.parent().attr('aria-busy', 'false').removeAttr('aria-live'); jQuery('li.closed', $sublist).attr('aria-live', 'assertive'); } if ($listitem.hasClass('open')) { // Only show if user didn’t close the list since starting // to load the content $sublist.dw_show(); } }; // just show if already loaded if ($sublist.length > 0) { show_sublist(); return; } //prepare the new ul $sublist = jQuery('<ul class="idx" role="group"/>'); $listitem.append($sublist); timeout = window.setTimeout( bind(show_sublist, '<li aria-busy="true"><img src="' + DOKU_BASE + 'lib/images/throbber.gif" alt="loading..." title="loading..." /></li>'), dw_tree.throbber_delay); dw_tree.load_data(function (data) { window.clearTimeout(timeout); show_sublist(data); }, $clicky); }, toggle_display: function ($clicky, opening) { }, load_data: function (show_data, $clicky) { show_data(); } }; jQuery.extend(dw_tree, overrides); if (!overrides.deferInit) { dw_tree.init(); } return dw_tree; }; /* XXXXXXXXXX end of lib/scripts/tree.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/index.js XXXXXXXXXX */ var dw_index = jQuery('#index__tree').dw_tree({deferInit: true, load_data: function (show_sublist, $clicky) { jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', $clicky[0].search.substr(1) + '&call=index', show_sublist, 'html' ); } }); jQuery(function () { var $tree = jQuery('#index__tree'); dw_index.$obj = $tree; dw_index.init(); }); /* XXXXXXXXXX end of lib/scripts/index.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/textselection.js XXXXXXXXXX */ /** * Text selection related functions. */ /** * selection prototype * * Object that capsulates the selection in a textarea. Returned by DWgetSelection. * * @author Andreas Gohr <andi@splitbrain.org> */ function selection_class(){ this.start = 0; this.end = 0; this.obj = null; this.scroll = 0; this.fix = 0; this.getLength = function(){ return this.end - this.start; }; this.getText = function(){ return (!this.obj) ? '' : this.obj.value.substring(this.start,this.end); }; } /** * Get current selection/cursor position in a given textArea * * @link http://groups.drupal.org/node/1210 * @author Andreas Gohr <andi@splitbrain.org> * @link http://linebyline.blogspot.com/2006/11/textarea-cursor-position-in-internet.html * @returns object - a selection object */ function DWgetSelection(textArea) { var sel = new selection_class(); textArea.focus(); sel.obj = textArea; sel.start = textArea.selectionStart; sel.end = textArea.selectionEnd; sel.scroll = textArea.scrollTop; return sel; } /** * Set the selection * * You need to get a selection object via DWgetSelection() first, then modify the * start and end properties and pass it back to this function. * * @link http://groups.drupal.org/node/1210 * @author Andreas Gohr <andi@splitbrain.org> * @param {selection_class} selection a selection object as returned by DWgetSelection() */ function DWsetSelection(selection){ selection.obj.setSelectionRange(selection.start, selection.end); if(selection.scroll) selection.obj.scrollTop = selection.scroll; } /** * Inserts the given text at the current cursor position or replaces the current * selection * * @author Andreas Gohr <andi@splitbrain.org> * @param {string} text the new text to be pasted * @param {selection_class} selection selection object returned by DWgetSelection * @param {int} opts.startofs number of charcters at the start to skip from new selection * @param {int} opts.endofs number of characters at the end to skip from new selection * @param {boolean} opts.nosel set true if new text should not be selected */ function pasteText(selection,text,opts){ if(!opts) opts = {}; // replace the content selection.obj.value = selection.obj.value.substring(0, selection.start) + text + selection.obj.value.substring(selection.end, selection.obj.value.length); // set new selection if (is_opera) { // Opera replaces \n by \r\n when inserting text. selection.end = selection.start + text.replace(/\r?\n/g, '\r\n').length; } else { selection.end = selection.start + text.length; } // modify the new selection if wanted if(opts.startofs) selection.start += opts.startofs; if(opts.endofs) selection.end -= opts.endofs; // no selection wanted? set cursor to end position if(opts.nosel) selection.start = selection.end; DWsetSelection(selection); } /** * Format selection * * Apply tagOpen/tagClose to selection in textarea, use sampleText instead * of selection if there is none. * * @author Andreas Gohr <andi@splitbrain.org> */ function insertTags(textAreaID, tagOpen, tagClose, sampleText){ var txtarea = jQuery('#' + textAreaID)[0]; var selection = DWgetSelection(txtarea); var text = selection.getText(); var opts; // don't include trailing space in selection if(text.charAt(text.length - 1) == ' '){ selection.end--; text = selection.getText(); } if(!text){ // nothing selected, use the sample text and select it text = sampleText; opts = { startofs: tagOpen.length, endofs: tagClose.length }; }else{ // place cursor at the end opts = { nosel: true }; } // surround with tags text = tagOpen + text + tagClose; // do it pasteText(selection,text,opts); } /** * Wraps around pasteText() for backward compatibility * * @author Andreas Gohr <andi@splitbrain.org> */ function insertAtCarret(textAreaID, text){ var txtarea = jQuery('#' + textAreaID)[0]; var selection = DWgetSelection(txtarea); pasteText(selection,text,{nosel: true}); } /* XXXXXXXXXX end of lib/scripts/textselection.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/toolbar.js XXXXXXXXXX */ // used to identify pickers var pickercounter=0; /** * Create a toolbar * * @param string tbid ID of the element where to insert the toolbar * @param string edid ID of the editor textarea * @param array tb Associative array defining the buttons * @param bool allowblock Allow buttons creating multiline content * @author Andreas Gohr <andi@splitbrain.org> */ function initToolbar(tbid,edid,tb, allowblock){ var $toolbar, $edit; if (typeof tbid == 'string') { $toolbar = jQuery('#' + tbid); } else { $toolbar = jQuery(tbid); } $edit = jQuery('#' + edid); if ($toolbar.length == 0 || $edit.length == 0 || $edit.attr('readOnly')) { return; } if (typeof allowblock === 'undefined') { allowblock = true; } //empty the toolbar area: $toolbar.html(''); jQuery.each(tb, function (k, val) { if (!tb.hasOwnProperty(k) || (!allowblock && val.block === true)) { return; } var actionFunc, $btn; // create new button (jQuery object) $btn = jQuery(createToolButton(val.icon, val.title, val.key, val.id, val['class'])); // type is a tb function -> assign it as onclick actionFunc = 'tb_'+val.type; if( jQuery.isFunction(window[actionFunc]) ){ $btn.on('click', bind(window[actionFunc],$btn,val,edid) ); $toolbar.append($btn); return; } // type is a init function -> execute it actionFunc = 'addBtnAction'+val.type.charAt(0).toUpperCase()+val.type.substring(1); if( jQuery.isFunction(window[actionFunc]) ){ var pickerid = window[actionFunc]($btn, val, edid); if(pickerid !== ''){ $toolbar.append($btn); $btn.attr('aria-controls', pickerid); if (actionFunc === 'addBtnActionPicker') { $btn.attr('aria-haspopup', 'true'); } } return; } alert('unknown toolbar type: '+val.type+' '+actionFunc); }); } /** * Button action for format buttons * * @param DOMElement btn Button element to add the action to * @param array props Associative array of button properties * @param string edid ID of the editor textarea * @author Gabriel Birke <birke@d-scribe.de> * @author Andreas Gohr <andi@splitbrain.org> */ function tb_format(btn, props, edid) { var sample = props.sample || props.title; insertTags(edid, fixtxt(props.open), fixtxt(props.close), fixtxt(sample)); pickerClose(); return false; } /** * Button action for format buttons * * This works exactly as tb_format() except that, if multiple lines * are selected, each line will be formatted seperately * * @param DOMElement btn Button element to add the action to * @param array props Associative array of button properties * @param string edid ID of the editor textarea * @author Gabriel Birke <birke@d-scribe.de> * @author Andreas Gohr <andi@splitbrain.org> */ function tb_formatln(btn, props, edid) { var sample = props.sample || props.title, opts, selection = DWgetSelection(jQuery('#'+edid)[0]); sample = fixtxt(sample); props.open = fixtxt(props.open); props.close = fixtxt(props.close); // is something selected? if(selection.getLength()){ sample = selection.getText(); opts = {nosel: true}; }else{ opts = { startofs: props.open.length, endofs: props.close.length }; } sample = sample.split("\n").join(props.close+"\n"+props.open); sample = props.open+sample+props.close; pasteText(selection,sample,opts); pickerClose(); return false; } /** * Button action for insert buttons * * @param DOMElement btn Button element to add the action to * @param array props Associative array of button properties * @param string edid ID of the editor textarea * @author Gabriel Birke <birke@d-scribe.de> * @author Andreas Gohr <andi@splitbrain.org> */ function tb_insert(btn, props, edid) { insertAtCarret(edid,fixtxt(props.insert)); pickerClose(); return false; } /** * Button action for the media popup * * @param DOMElement btn Button element to add the action to * @param array props Associative array of button properties * @param string edid ID of the editor textarea * @author Andreas Gohr <andi@splitbrain.org> */ function tb_mediapopup(btn, props, edid) { window.open( DOKU_BASE+props.url+encodeURIComponent(NS)+'&edid='+encodeURIComponent(edid), props.name, props.options); return false; } /** * Button action for automatic headlines * * Insert a new headline based on the current section level * * @param DOMElement btn Button element to add the action to * @param array props Associative array of button properties * @param string edid ID of the editor textarea * @author Andreas Gohr <andi@splitbrain.org> */ function tb_autohead(btn, props, edid){ var lvl = currentHeadlineLevel(edid), tags; // determine new level lvl += props.mod; if(lvl < 1) lvl = 1; if(lvl > 5) lvl = 5; tags = (new Array(8 - lvl)).join('='); insertTags(edid, tags+' ', ' '+tags+"\n", props.text); pickerClose(); return false; } /** * Add button action for picker buttons and create picker element * * @param jQuery btn Button element to add the action to * @param array props Associative array of button properties * @param string edid ID of the editor textarea * @return boolean If button should be appended * @author Gabriel Birke <birke@d-scribe.de> */ function addBtnActionPicker($btn, props, edid) { var pickerid = 'picker'+(pickercounter++); var picker = createPicker(pickerid, props, edid); jQuery(picker).attr('aria-hidden', 'true'); $btn.click( function(e) { pickerToggle(pickerid,$btn); e.preventDefault(); return ''; } ); return pickerid; } /** * Add button action for the link wizard button * * @param DOMElement btn Button element to add the action to * @param array props Associative array of button properties * @param string edid ID of the editor textarea * @return boolean If button should be appended * @author Andreas Gohr <gohr@cosmocode.de> */ function addBtnActionLinkwiz($btn, props, edid) { dw_linkwiz.init(jQuery('#'+edid)); jQuery($btn).click(function(e){ dw_linkwiz.val = props; dw_linkwiz.toggle(); e.preventDefault(); return ''; }); return 'link__wiz'; } /** * Show/Hide a previously created picker window * * @author Andreas Gohr <andi@splitbrain.org> */ function pickerToggle(pickerid,$btn){ var $picker = jQuery('#' + pickerid), pos = $btn.offset(); if ($picker.hasClass('a11y')) { $picker.removeClass('a11y').attr('aria-hidden', 'false'); } else { $picker.addClass('a11y').attr('aria-hidden', 'true'); } var picker_left = pos.left + 3, picker_width = $picker.width(), window_width = jQuery(window).width(); if (picker_width > 300) { $picker.css("max-width", "300"); picker_width = 300; } if ((picker_left + picker_width + 40) > window_width) { picker_left = window_width - picker_width - 40; } if (picker_left < 0) { picker_left = 0; } $picker.offset({left: picker_left, top: pos.top+$btn[0].offsetHeight+3}); } /** * Close all open pickers * * @author Andreas Gohr <andi@splitbrain.org> */ function pickerClose(){ jQuery('.picker').addClass('a11y'); } /** * Replaces \n with linebreaks */ function fixtxt(str){ return str.replace(/\\n/g,"\n"); } jQuery(function () { initToolbar('tool__bar','wiki__text',toolbar); jQuery('#tool__bar').attr('role', 'toolbar'); }); /* XXXXXXXXXX end of lib/scripts/toolbar.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/edit.js XXXXXXXXXX */ /** * Functions for text editing (toolbar stuff) * * @todo most of the stuff in here should be revamped and then moved to toolbar.js * @author Andreas Gohr <andi@splitbrain.org> */ /** * Creates a toolbar button through the DOM * Called for each entry of toolbar definition array (built by inc/toolbar.php and extended via js) * * Style the buttons through the toolbutton class * * @param {string} icon image filename, relative to folder lib/images/toolbar/ * @param {string} label title of button, show on mouseover * @param {string} key hint in title of button for access key * @param {string} id id of button, and '<id>_ico' of icon * @param {string} classname for styling buttons * * @author Andreas Gohr <andi@splitbrain.org> * @author Michal Rezler <m.rezler@centrum.cz> */ function createToolButton(icon,label,key,id,classname){ var $btn = jQuery(document.createElement('button')), $ico = jQuery(document.createElement('img')); // prepare the basic button stuff $btn.addClass('toolbutton'); if(classname){ $btn.addClass(classname); } $btn.attr('title', label).attr('aria-controls', 'wiki__text'); if(key){ $btn.attr('title', label + ' ['+key.toUpperCase()+']') .attr('accessKey', key); } // set IDs if given if(id){ $btn.attr('id', id); $ico.attr('id', id+'_ico'); } // create the icon and add it to the button if(icon.substr(0,1) !== '/'){ icon = DOKU_BASE + 'lib/images/toolbar/' + icon; } $ico.attr('src', icon); $ico.attr('alt', ''); $ico.attr('width', 16); $ico.attr('height', 16); $btn.append($ico); // we have to return a DOM object (for compatibility reasons) return $btn[0]; } /** * Creates a picker window for inserting text * * The given list can be an associative array with text,icon pairs * or a simple list of text. Style the picker window through the picker * class or the picker buttons with the pickerbutton class. Picker * windows are appended to the body and created invisible. * * @param {string} id the ID to assign to the picker * @param {Array} props the properties for the picker * @param {string} edid the ID of the textarea * @return DOMobject the created picker * @author Andreas Gohr <andi@splitbrain.org> */ function createPicker(id,props,edid){ // create the wrapping div var $picker = jQuery(document.createElement('div')); $picker.addClass('picker a11y'); if(props['class']){ $picker.addClass(props['class']); } $picker.attr('id', id).css('position', 'absolute'); function $makebutton(title) { var $btn = jQuery(document.createElement('button')) .addClass('pickerbutton').attr('title', title) .attr('aria-controls', edid) .on('click', bind(pickerInsert, title, edid)) .appendTo($picker); return $btn; } jQuery.each(props.list, function (key, item) { if (!props.list.hasOwnProperty(key)) { return; } if(isNaN(key)){ // associative array -> treat as text => image pairs if (item.substr(0,1) !== '/') { item = DOKU_BASE+'lib/images/'+props.icobase+'/'+item; } jQuery(document.createElement('img')) .attr('src', item) .attr('alt', '') .appendTo($makebutton(key)); }else if (typeof item == 'string'){ // a list of text -> treat as text picker $makebutton(item).text(item); }else{ // a list of lists -> treat it as subtoolbar initToolbar($picker,edid,props.list); return false; // all buttons handled already } }); jQuery('body').append($picker); // we have to return a DOM object (for compatibility reasons) return $picker[0]; } /** * Called by picker buttons to insert Text and close the picker again * * @author Andreas Gohr <andi@splitbrain.org> */ function pickerInsert(text,edid){ insertAtCarret(edid,text); pickerClose(); } /** * Add button action for signature button * * @param {jQuery} $btn Button element to add the action to * @param {Array} props Associative array of button properties * @param {string} edid ID of the editor textarea * @return {string} picker id for aria-controls attribute * @author Gabriel Birke <birke@d-scribe.de> */ function addBtnActionSignature($btn, props, edid) { if(typeof SIG != 'undefined' && SIG != ''){ $btn.on('click', function (e) { insertAtCarret(edid,SIG); e.preventDefault(); }); return edid; } return ''; } /** * Determine the current section level while editing * * @param {string} textboxId ID of the text field * * @author Andreas Gohr <gohr@cosmocode.de> */ function currentHeadlineLevel(textboxId){ var field = jQuery('#' + textboxId)[0], s = false, opts = [field.value.substr(0,DWgetSelection(field).start)]; if (field.form && field.form.prefix) { // we need to look in prefix context opts.push(field.form.prefix.value); } jQuery.each(opts, function (_, opt) { // Check whether there is a headline in the given string var str = "\n" + opt, lasthl = str.lastIndexOf("\n=="); if (lasthl !== -1) { s = str.substr(lasthl+1,6); return false; } }); if (s === false) { return 0; } return 7 - s.match(/^={2,6}/)[0].length; } /** * global var used for not saved yet warning */ window.textChanged = false; /** * global var which stores original editor content */ window.doku_edit_text_content = ''; /** * Delete the draft before leaving the page */ function deleteDraft() { if (is_opera || window.keepDraft) { return; } var $dwform = jQuery('#dw__editform'); if($dwform.length === 0) { return; } // remove a possibly saved draft using ajax jQuery.post(DOKU_BASE + 'lib/exe/ajax.php', { call: 'draftdel', id: $dwform.find('input[name=id]').val() } ); } /** * Activate "not saved" dialog, add draft deletion to page unload, * add handlers to monitor changes * Note: textChanged could be set by e.g. html_edit() as well * * Sets focus to the editbox as well */ jQuery(function () { var $editform = jQuery('#dw__editform'); if ($editform.length == 0) { return; } var $edit_text = jQuery('#wiki__text'); if ($edit_text.length > 0) { if($edit_text.attr('readOnly')) { return; } // set focus and place cursor at the start var sel = DWgetSelection($edit_text[0]); sel.start = 0; sel.end = 0; DWsetSelection(sel); $edit_text.trigger('focus'); doku_edit_text_content = $edit_text.val(); } var changeHandler = function() { doku_hasTextBeenModified(); doku_summaryCheck(); }; $editform.change(changeHandler); $editform.keydown(changeHandler); window.onbeforeunload = function(){ if(window.textChanged) { return LANG.notsavedyet; } }; window.onunload = deleteDraft; // reset change memory var on submit jQuery('#edbtn__save').on('click', function() { window.onbeforeunload = ''; textChanged = false; } ); jQuery('#edbtn__preview').on('click', function() { window.onbeforeunload = ''; textChanged = false; window.keepDraft = true; // needed to keep draft on page unload } ); var $summary = jQuery('#edit__summary'); $summary.on('change keyup', doku_summaryCheck); if (textChanged) doku_summaryCheck(); }); /** * Updates textChanged variable if content of the editor has been modified */ function doku_hasTextBeenModified() { if (!textChanged) { var $edit_text = jQuery('#wiki__text'); if ($edit_text.length > 0) { textChanged = doku_edit_text_content != $edit_text.val(); } else { textChanged = true; } } } /** * Checks if a summary was entered - if not the style is changed * * @author Andreas Gohr <andi@splitbrain.org> */ function doku_summaryCheck(){ var $sum = jQuery('#edit__summary'), missing = $sum.val() === ''; $sum.toggleClass('missing', missing).toggleClass('edit', !missing); } /* XXXXXXXXXX end of lib/scripts/edit.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/editor.js XXXXXXXXXX */ /** * The DokuWiki editor features * * These are the advanced features of the editor. It does NOT contain any * code for the toolbar buttons and it functions. See toolbar.js for that. */ var dw_editor = { /** * initialize the default editor functionality * * All other functions can also be called separately for non-default * textareas */ init: function(){ var $editor = jQuery('#wiki__text'); if($editor.length === 0) { return; } dw_editor.initSizeCtl('#size__ctl',$editor); if($editor.attr('readOnly')) { return; } $editor.keydown(dw_editor.keyHandler); }, /** * Add the edit window size and wrap controls * * Initial values are read from cookie if it exists * * @param selector ctlarea the div to place the controls * @param selector editor the textarea to control */ initSizeCtl: function(ctlarea,editor){ var $ctl = jQuery(ctlarea), $textarea = jQuery(editor); if($ctl.length === 0 || $textarea.length === 0) { return; } $textarea.css('height', DokuCookie.getValue('sizeCtl') || '300px'); var wrp = DokuCookie.getValue('wrapCtl'); if(wrp){ dw_editor.setWrap($textarea[0], wrp); } // else use default value jQuery.each([ ['larger', function(){dw_editor.sizeCtl(editor,100);}], ['smaller', function(){dw_editor.sizeCtl(editor,-100);}], ['wrap', function(){dw_editor.toggleWrap(editor);}] ], function (_, img) { jQuery(document.createElement('img')) .attr('src', DOKU_BASE+'lib/images/' + img[0] + '.gif') .attr('alt', '') .on('click', img[1]) .appendTo($ctl); }); }, /** * This sets the vertical size of the editbox and adjusts the cookie * * @param selector editor the textarea to control * @param int val the relative value to resize in pixel */ sizeCtl: function(editor,val){ var $textarea = jQuery(editor), height = parseInt($textarea.css('height')) + val; $textarea.css('height', height+'px'); DokuCookie.setValue('sizeCtl',$textarea.css('height')); }, /** * Toggle the wrapping mode of the editor textarea and adjusts the * cookie * * @param selector editor the textarea to control */ toggleWrap: function(editor){ var $textarea = jQuery(editor), wrap = $textarea.attr('wrap'); dw_editor.setWrap($textarea[0], (wrap && wrap.toLowerCase() == 'off') ? 'soft' : 'off'); DokuCookie.setValue('wrapCtl',$textarea.attr('wrap')); }, /** * Set the wrapping mode of a textarea * * @author Fluffy Convict <fluffyconvict@hotmail.com> * @author <shutdown@flashmail.com> * @link http://news.hping.org/comp.lang.javascript.archive/12265.html * @link https://bugzilla.mozilla.org/show_bug.cgi?id=41464 * @param DomObject textarea * @param string wrapAttrValue */ setWrap: function(textarea, wrapAttrValue){ textarea.setAttribute('wrap', wrapAttrValue); // Fix display for mozilla var parNod = textarea.parentNode; var nxtSib = textarea.nextSibling; parNod.removeChild(textarea); parNod.insertBefore(textarea, nxtSib); }, /** * Make intended formattings easier to handle * * Listens to all key inputs and handle indentions * of lists and code blocks * * Currently handles space, backspace, enter and * ctrl-enter presses * * @author Andreas Gohr <andi@splitbrain.org> * @fixme handle tabs * @param event e - the key press event object */ keyHandler: function(e){ if(jQuery.inArray(e.keyCode,[8, 10, 13, 32]) === -1) { return; } var selection = DWgetSelection(this); if(selection.getLength() > 0) { return; //there was text selected, keep standard behavior } var search = "\n"+this.value.substr(0,selection.start); var linestart = Math.max(search.lastIndexOf("\n"), search.lastIndexOf("\r")); //IE workaround search = search.substr(linestart); if((e.keyCode == 13 || e.keyCode == 10) && e.ctrlKey) { // Ctrl-Enter (With Chrome workaround) // Submit current edit jQuery('#edbtn__save').trigger('click'); e.preventDefault(); // prevent enter key return false; }else if(e.keyCode == 13){ // Enter // keep current indention for lists and code var match = search.match(/(\n +([\*-] ?)?)/); if(match){ var scroll = this.scrollHeight; var match2 = search.match(/^\n +[\*-]\s*$/); // Cancel list if the last item is empty (i. e. two times enter) if (match2 && this.value.substr(selection.start).match(/^($|\r?\n)/)) { this.value = this.value.substr(0, linestart) + "\n" + this.value.substr(selection.start); selection.start = linestart + 1; selection.end = linestart + 1; DWsetSelection(selection); } else { insertAtCarret(this.id,match[1]); } this.scrollTop += (this.scrollHeight - scroll); e.preventDefault(); // prevent enter key return false; } }else if(e.keyCode == 8){ // Backspace // unindent lists var match = search.match(/(\n +)([*-] ?)$/); if(match){ var spaces = match[1].length-1; if(spaces > 3){ // unindent one level this.value = this.value.substr(0,linestart)+ this.value.substr(linestart+2); selection.start = selection.start - 2; selection.end = selection.start; }else{ // delete list point this.value = this.value.substr(0,linestart)+ this.value.substr(selection.start); selection.start = linestart; selection.end = linestart; } DWsetSelection(selection); e.preventDefault(); // prevent backspace return false; } }else if(e.keyCode == 32){ // Space // intend list item var match = search.match(/(\n +)([*-] )$/); if(match){ this.value = this.value.substr(0,linestart)+' '+ this.value.substr(linestart); selection.start = selection.start + 2; selection.end = selection.start; DWsetSelection(selection); e.preventDefault(); // prevent space return false; } } } }; jQuery(dw_editor.init); /* XXXXXXXXXX end of lib/scripts/editor.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/locktimer.js XXXXXXXXXX */ /** * Class managing the timer to display a warning on a expiring lock */ var dw_locktimer = { timeout: 0, draft: false, timerID: null, lasttime: null, msg: LANG.willexpire, pageid: '', fieldsToSaveAsDraft: [ 'input[name=prefix]', 'textarea[name=wikitext]', 'input[name=suffix]', 'input[name=date]', ], callbacks: [], /** * Initialize the lock timer * * @param {int} timeout Length of timeout in seconds * @param {bool} draft Whether to save drafts * @param {string} edid Optional; ID of an edit object which has to be present */ init: function(timeout,draft,edid){ var $edit; edid = edid || 'wiki__text'; $edit = jQuery('#' + edid); if($edit.length === 0 || $edit.attr('readonly')) { return; } // init values dw_locktimer.timeout = timeout*1000; dw_locktimer.draft = draft; dw_locktimer.lasttime = new Date(); dw_locktimer.pageid = jQuery('#dw__editform').find('input[name=id]').val(); if(!dw_locktimer.pageid) { return; } // register refresh event $edit.keypress(dw_locktimer.refresh); // start timer dw_locktimer.reset(); }, /** * Add another field of the editform to be posted to the server when a draft is saved */ addField: function(selector) { dw_locktimer.fieldsToSaveAsDraft.push(selector); }, /** * Add a callback that is executed when the post request to renew the lock and save the draft returns successfully * * If the user types into the edit-area, then dw_locktimer will regularly send a post request to the DokuWiki server * to extend the page's lock and update the draft. When this request returns successfully, then the draft__status * is updated. This method can be used to add further callbacks to be executed at that moment. * * @param {function} callback the only param is the data returned by the server */ addRefreshCallback: function(callback) { dw_locktimer.callbacks.push(callback); }, /** * (Re)start the warning timer */ reset: function(){ dw_locktimer.clear(); dw_locktimer.timerID = window.setTimeout(dw_locktimer.warning, dw_locktimer.timeout); }, /** * Display the warning about the expiring lock */ warning: function(){ dw_locktimer.clear(); alert(fixtxt(dw_locktimer.msg)); }, /** * Remove the current warning timer */ clear: function(){ if(dw_locktimer.timerID !== null){ window.clearTimeout(dw_locktimer.timerID); dw_locktimer.timerID = null; } }, /** * Refresh the lock via AJAX * * Called on keypresses in the edit area */ refresh: function(){ var now = new Date(), params = 'call=lock&id=' + dw_locktimer.pageid + '&'; // refresh every half minute only if(now.getTime() - dw_locktimer.lasttime.getTime() <= 30*1000) { return; } // POST everything necessary for draft saving if(dw_locktimer.draft && jQuery('#dw__editform').find('textarea[name=wikitext]').length > 0){ params += jQuery('#dw__editform').find(dw_locktimer.fieldsToSaveAsDraft.join(', ')).serialize(); } jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', params, null, 'json' ).done(function dwLocktimerRefreshDoneHandler(data) { dw_locktimer.callbacks.forEach( function (callback) { callback(data); } ); }); dw_locktimer.lasttime = now; }, /** * Callback. Resets the warning timer */ refreshed: function(data){ if (data.errors.length) { data.errors.forEach(function(error) { jQuery('#draft__status').after( jQuery('<div class="error"></div>').text(error) ); }) } jQuery('#draft__status').html(data.draft); if(data.lock !== '1') { return; // locking failed } dw_locktimer.reset(); } }; dw_locktimer.callbacks.push(dw_locktimer.refreshed); /* XXXXXXXXXX end of lib/scripts/locktimer.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/linkwiz.js XXXXXXXXXX */ /** * The Link Wizard * * @author Andreas Gohr <gohr@cosmocode.de> * @author Pierre Spring <pierre.spring@caillou.ch> */ var dw_linkwiz = { $wiz: null, $entry: null, result: null, timer: null, textArea: null, selected: null, selection: null, /** * Initialize the dw_linkwizard by creating the needed HTML * and attaching the eventhandlers */ init: function($editor){ // position relative to the text area var pos = $editor.position(); // create HTML Structure if(dw_linkwiz.$wiz) return; dw_linkwiz.$wiz = jQuery(document.createElement('div')) .dialog({ autoOpen: false, draggable: true, title: LANG.linkwiz, resizable: false }) .html( '<div>'+LANG.linkto+' <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+ '<div id="link__wiz_result"></div>' ) .parent() .attr('id','link__wiz') .css({ 'position': 'absolute', 'top': (pos.top+20)+'px', 'left': (pos.left+80)+'px' }) .hide() .appendTo('.dokuwiki:first'); dw_linkwiz.textArea = $editor[0]; dw_linkwiz.result = jQuery('#link__wiz_result')[0]; // scrollview correction on arrow up/down gets easier jQuery(dw_linkwiz.result).css('position', 'relative'); dw_linkwiz.$entry = jQuery('#link__wiz_entry'); if(JSINFO.namespace){ dw_linkwiz.$entry.val(JSINFO.namespace+':'); } // attach event handlers jQuery('#link__wiz .ui-dialog-titlebar-close').on('click', dw_linkwiz.hide); dw_linkwiz.$entry.keyup(dw_linkwiz.onEntry); jQuery(dw_linkwiz.result).on('click', 'a', dw_linkwiz.onResultClick); }, /** * handle all keyup events in the entry field */ onEntry: function(e){ if(e.keyCode == 37 || e.keyCode == 39){ //left/right return true; //ignore } if(e.keyCode == 27){ //Escape dw_linkwiz.hide(); e.preventDefault(); e.stopPropagation(); return false; } if(e.keyCode == 38){ //Up dw_linkwiz.select(dw_linkwiz.selected -1); e.preventDefault(); e.stopPropagation(); return false; } if(e.keyCode == 40){ //Down dw_linkwiz.select(dw_linkwiz.selected +1); e.preventDefault(); e.stopPropagation(); return false; } if(e.keyCode == 13){ //Enter if(dw_linkwiz.selected > -1){ var $obj = dw_linkwiz.$getResult(dw_linkwiz.selected); if($obj.length > 0){ dw_linkwiz.resultClick($obj.find('a')[0]); } }else if(dw_linkwiz.$entry.val()){ dw_linkwiz.insertLink(dw_linkwiz.$entry.val()); } e.preventDefault(); e.stopPropagation(); return false; } dw_linkwiz.autocomplete(); }, /** * Get one of the results by index * * @param num int result div to return * @returns DOMObject or null */ getResult: function(num){ DEPRECATED('use dw_linkwiz.$getResult()[0] instead'); return dw_linkwiz.$getResult()[0] || null; }, /** * Get one of the results by index * * @param num int result div to return * @returns jQuery object */ $getResult: function(num) { return jQuery(dw_linkwiz.result).find('div').eq(num); }, /** * Select the given result */ select: function(num){ if(num < 0){ dw_linkwiz.deselect(); return; } var $obj = dw_linkwiz.$getResult(num); if ($obj.length === 0) { return; } dw_linkwiz.deselect(); $obj.addClass('selected'); // make sure the item is viewable in the scroll view //getting child position within the parent var childPos = $obj.position().top; //getting difference between the childs top and parents viewable area var yDiff = childPos + $obj.outerHeight() - jQuery(dw_linkwiz.result).innerHeight(); if (childPos < 0) { //if childPos is above viewable area (that's why it goes negative) jQuery(dw_linkwiz.result)[0].scrollTop += childPos; } else if(yDiff > 0) { // if difference between childs top and parents viewable area is // greater than the height of a childDiv jQuery(dw_linkwiz.result)[0].scrollTop += yDiff; } dw_linkwiz.selected = num; }, /** * deselect a result if any is selected */ deselect: function(){ if(dw_linkwiz.selected > -1){ dw_linkwiz.$getResult(dw_linkwiz.selected).removeClass('selected'); } dw_linkwiz.selected = -1; }, /** * Handle clicks in the result set an dispatch them to * resultClick() */ onResultClick: function(e){ if(!jQuery(this).is('a')) { return; } e.stopPropagation(); e.preventDefault(); dw_linkwiz.resultClick(this); return false; }, /** * Handles the "click" on a given result anchor */ resultClick: function(a){ dw_linkwiz.$entry.val(a.title); if(a.title == '' || a.title.substr(a.title.length-1) == ':'){ dw_linkwiz.autocomplete_exec(); }else{ if (jQuery(a.nextSibling).is('span')) { dw_linkwiz.insertLink(a.nextSibling.innerHTML); }else{ dw_linkwiz.insertLink(''); } } }, /** * Insert the id currently in the entry box to the textarea, * replacing the current selection or at the cursor position. * When no selection is available the given title will be used * as link title instead */ insertLink: function(title){ var link = dw_linkwiz.$entry.val(), sel, stxt; if(!link) { return; } sel = DWgetSelection(dw_linkwiz.textArea); if(sel.start == 0 && sel.end == 0) { sel = dw_linkwiz.selection; } stxt = sel.getText(); // don't include trailing space in selection if(stxt.charAt(stxt.length - 1) == ' '){ sel.end--; stxt = sel.getText(); } if(!stxt && !DOKU_UHC) { stxt=title; } // prepend colon inside namespaces for non namespace pages if(dw_linkwiz.textArea.form.id.value.indexOf(':') != -1 && link.indexOf(':') == -1){ link = ':' + link; } var so = link.length; var eo = 0; if(dw_linkwiz.val){ if(dw_linkwiz.val.open) { so += dw_linkwiz.val.open.length; link = dw_linkwiz.val.open+link; } link += '|'; so += 1; if(stxt) { link += stxt; } if(dw_linkwiz.val.close) { link += dw_linkwiz.val.close; eo = dw_linkwiz.val.close.length; } } pasteText(sel,link,{startofs: so, endofs: eo}); dw_linkwiz.hide(); // reset the entry to the parent namespace var externallinkpattern = new RegExp('^((f|ht)tps?:)?//', 'i'), entry_value; if (externallinkpattern.test(dw_linkwiz.$entry.val())) { if (JSINFO.namespace) { entry_value = JSINFO.namespace + ':'; } else { entry_value = ''; //reset whole external links } } else { entry_value = dw_linkwiz.$entry.val().replace(/[^:]*$/, '') } dw_linkwiz.$entry.val(entry_value); }, /** * Start the page/namespace lookup timer * * Calls autocomplete_exec when the timer runs out */ autocomplete: function(){ if(dw_linkwiz.timer !== null){ window.clearTimeout(dw_linkwiz.timer); dw_linkwiz.timer = null; } dw_linkwiz.timer = window.setTimeout(dw_linkwiz.autocomplete_exec,350); }, /** * Executes the AJAX call for the page/namespace lookup */ autocomplete_exec: function(){ var $res = jQuery(dw_linkwiz.result); dw_linkwiz.deselect(); $res.html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />') .load( DOKU_BASE + 'lib/exe/ajax.php', { call: 'linkwiz', q: dw_linkwiz.$entry.val() } ); }, /** * Show the link wizard */ show: function(){ dw_linkwiz.selection = DWgetSelection(dw_linkwiz.textArea); dw_linkwiz.$wiz.show(); dw_linkwiz.$entry.focus(); dw_linkwiz.autocomplete(); // Move the cursor to the end of the input var temp = dw_linkwiz.$entry.val(); dw_linkwiz.$entry.val(''); dw_linkwiz.$entry.val(temp); }, /** * Hide the link wizard */ hide: function(){ dw_linkwiz.$wiz.hide(); dw_linkwiz.textArea.focus(); }, /** * Toggle the link wizard */ toggle: function(){ if(dw_linkwiz.$wiz.css('display') == 'none'){ dw_linkwiz.show(); }else{ dw_linkwiz.hide(); } } }; /* XXXXXXXXXX end of lib/scripts/linkwiz.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/media.js XXXXXXXXXX */ /** * JavaScript functionality for the media management popup * * @author Andreas Gohr <andi@splitbrain.org> * @author Pierre Spring <pierre.spring@caillou.ch> */ var dw_mediamanager = { keepopen: false, hide: false, popup: false, display: false, ext: false, $popup: null, // Image insertion opts align: false, link: false, size: false, forbidden_opts: {}, // File list options view_opts: {list: false, sort: false}, layout_width: 0, // The minimum height of the full-screen mediamanager in px minHeights: {thumbs: 200, rows: 100}, init: function () { var $content, $tree; $content = jQuery('#media__content'); $tree = jQuery('#media__tree'); if (!$tree.length) return; dw_mediamanager.prepare_content($content); dw_mediamanager.attachoptions(); dw_mediamanager.initpopup(); // add the action to autofill the "upload as" field $content .on('change', '#upload__file', dw_mediamanager.suggest) // Attach the image selector action to all links .on('click', 'a.select', dw_mediamanager.select) // Attach deletion confirmation dialog to the delete buttons .on('click', '#media__content a.btn_media_delete', dw_mediamanager.confirmattach) .on('submit', '#mediamanager__done_form', dw_mediamanager.list); $tree.dw_tree({ toggle_selector: 'img', load_data: function (show_sublist, $clicky) { // get the enclosed link (is always the first one) var $link = $clicky.parent().find('div.li a.idx_dir'); jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', $link[0].search.substr(1) + '&call=medians', show_sublist, 'html' ); }, toggle_display: function ($clicky, opening) { $clicky.attr('src', DOKU_BASE + 'lib/images/' + (opening ? 'minus' : 'plus') + '.gif'); } }); $tree.on('click', 'a', dw_mediamanager.list); // Init view property dw_mediamanager.set_fileview_list(); dw_mediamanager.init_options(); dw_mediamanager.image_diff(); dw_mediamanager.init_ajax_uploader(); // changing opened tab in the file list panel var $page = jQuery('#mediamanager__page'); $page.find('div.filelist') .on('click', 'ul.tabs a', dw_mediamanager.list) // loading file details .on('click', 'div.panelContent a', dw_mediamanager.details) // search form .on('submit', '#dw__mediasearch', dw_mediamanager.list) // "upload as" field autofill .on('change', '#upload__file', dw_mediamanager.suggest) // uploaded images .on('click', '.qq-upload-file a', dw_mediamanager.details); // changing opened tab in the file details panel $page.find('div.file') .on('click', 'ul.tabs a', dw_mediamanager.details) // "update new version" button .on('submit', '#mediamanager__btn_update', dw_mediamanager.list) // revisions form .on('submit', '#page__revisions', dw_mediamanager.details) .on('click', '#page__revisions a', dw_mediamanager.details) // meta edit form .on('submit', '#mediamanager__save_meta', dw_mediamanager.details) // delete button .on('submit', '#mediamanager__btn_delete', dw_mediamanager.details) // "restore this version" button .on('submit', '#mediamanager__btn_restore', dw_mediamanager.details) // less/more recent buttons in media revisions form .on('submit', '.btn_newer, .btn_older', dw_mediamanager.details); dw_mediamanager.update_resizable(); dw_mediamanager.layout_width = $page.width(); jQuery(window).on('resize', dw_mediamanager.window_resize); }, init_options: function () { var $options = jQuery('div.filelist div.panelHeader form.options'), $listType, $sortBy, $both; if ($options.length === 0) { return; } $listType = $options.find('li.listType'); $sortBy = $options.find('li.sortBy'); $both = $listType.add($sortBy); // Remove the submit button $options.find('button[type=submit]').parent().hide(); // Prepare HTML for jQuery UI buttonset $both.find('label').each(function () { var $this = jQuery(this); $this.children('input').appendTo($this.parent()); }); // Init buttonset $both.find("input[type='radio']").checkboxradio({icon: false}); $both.controlgroup(); // Change handlers $listType.children('input').change(function () { dw_mediamanager.set_fileview_list(); }); $sortBy.children('input').change(function (event) { dw_mediamanager.set_fileview_sort(); dw_mediamanager.list.call(jQuery('#dw__mediasearch')[0] || this, event); }); }, /** * build the popup window * * @author Dominik Eckelmann <eckelmann@cosmocode.de> */ initpopup: function () { var opts, $insp, $insbtn; dw_mediamanager.$popup = jQuery(document.createElement('div')) .attr('id', 'media__popup_content') .dialog({ autoOpen: false, width: 280, modal: true, draggable: true, title: LANG.mediatitle, resizable: false }); opts = [ { id: 'link', label: LANG.mediatarget, btns: ['lnk', 'direct', 'nolnk', 'displaylnk'] }, { id: 'align', label: LANG.mediaalign, btns: ['noalign', 'left', 'center', 'right'] }, { id: 'size', label: LANG.mediasize, btns: ['small', 'medium', 'large', 'original'] } ]; jQuery.each(opts, function (_, opt) { var $p, $l; $p = jQuery(document.createElement('p')) .attr('id', 'media__' + opt.id); if (dw_mediamanager.display === "2") { $p.hide(); } $l = jQuery(document.createElement('label')) .text(opt.label); $p.append($l); jQuery.each(opt.btns, function (i, text) { var $btn, $img; $btn = jQuery(document.createElement('button')) .addClass('button') .attr('id', "media__" + opt.id + "btn" + (i + 1)) .attr('title', LANG['media' + text]) .on('click', bind(dw_mediamanager.setOpt, opt.id)); $img = jQuery(document.createElement('img')) .attr('src', DOKU_BASE + 'lib/images/media_' + opt.id + '_' + text + '.png'); $btn.append($img); $p.append($btn); }); dw_mediamanager.$popup.append($p); }); // insert button $insp = jQuery(document.createElement('p')); dw_mediamanager.$popup.append($insp); $insbtn = jQuery(document.createElement('input')) .attr('id', 'media__sendbtn') .attr('type', 'button') .addClass('button') .val(LANG.mediainsert); $insp.append($insbtn); }, /** * Insert the clicked image into the opener's textarea * * @author Andreas Gohr <andi@splitbrain.org> * @author Dominik Eckelmann <eckelmann@cosmocode.de> * @author Pierre Spring <pierre.spring@caillou.ch> */ insert: function (id) { var opts, cb, edid, s; // set syntax options dw_mediamanager.$popup.dialog('close'); opts = ''; if ({img: 1, swf: 1}[dw_mediamanager.ext] === 1) { if (dw_mediamanager.link === '4') { opts = '?linkonly'; } else { if (dw_mediamanager.link === "3" && dw_mediamanager.ext === 'img') { opts = '?nolink'; } else if (dw_mediamanager.link === "2" && dw_mediamanager.ext === 'img') { opts = '?direct'; } s = parseInt(dw_mediamanager.size, 10); var size = s * 200; if (s && s >= 1 && s < 4) { opts += (opts.length) ? '&' : '?'; opts += size; if (dw_mediamanager.ext === 'swf') { switch (s) { case 1: opts += 'x62'; break; case 2: opts += 'x123'; break; case 3: opts += 'x185'; break; } } } } } edid = String.prototype.match.call(document.location, /&edid=([^&]+)/); edid = edid ? edid[1] : 'wiki__text'; cb = String.prototype.match.call(document.location, /&onselect=([^&]+)/); cb = cb ? cb[1].replace(/[^\w]+/, '') : 'dw_mediamanager_item_select'; // arguments here only match the dw_mediamanager_item_select function, these will need to change if you override cb with onselect GET param opener[cb](edid, id, opts, dw_mediamanager.align, dw_mediamanager.keepopen); if (!dw_mediamanager.keepopen) { window.close(); } opener.focus(); return false; }, /** * Prefills the wikiname. * * @author Andreas Gohr <andi@splitbrain.org> */ suggest: function () { var $file, $name, text; $file = jQuery(this); $name = jQuery('#upload__name'); if ($name.val() != '') return; if (!$file.length || !$name.length) { return; } text = $file.val(); text = text.substr(text.lastIndexOf('/') + 1); text = text.substr(text.lastIndexOf('\\') + 1); $name.val(text); }, /** * list the content of a namespace using AJAX * * @author Andreas Gohr <andi@splitbrain.org> * @author Pierre Spring <pierre.spring@caillou.ch> */ list: function (event) { var $link, $content, params; if (event) { event.preventDefault(); } jQuery('div.success, div.info, div.error, div.notify').remove(); $link = jQuery(this); //popup $content = jQuery('#media__content'); if ($content.length === 0) { //fullscreen media manager $content = jQuery('div.filelist'); if ($link.hasClass('idx_dir')) { //changing namespace jQuery('div.file').empty(); jQuery('div.namespaces .selected').removeClass('selected'); $link.addClass('selected'); } } params = 'call=medialist&'; if ($link[0].search) { params += $link[0].search.substr(1); } else if ($link.is('form')) { params += dw_mediamanager.form_params($link); } else if ($link.closest('form').length > 0) { params += dw_mediamanager.form_params($link.closest('form')); } // fetch the subtree dw_mediamanager.update_content($content, params); }, /** * Returns form parameters * * @author Kate Arzamastseva <pshns@ukr.net> */ form_params: function ($form) { if (!$form.length) return; var action = ''; var i = $form[0].action.indexOf('?'); if (i >= 0) { action = $form[0].action.substr(i + 1); } return action + '&' + $form.serialize(); }, set_fileview_list: function (new_type) { dw_mediamanager.set_fileview_opt(['list', 'listType', function (new_type) { jQuery('div.filelist div.panelContent ul') .toggleClass('rows', new_type === 'rows') .toggleClass('thumbs', new_type === 'thumbs'); }], new_type); // FIXME: Move to onchange handler (opt[2])? dw_mediamanager.resize(); }, set_fileview_sort: function (new_sort) { dw_mediamanager.set_fileview_opt(['sort', 'sortBy', function (new_sort) { // FIXME }], new_sort); }, set_fileview_opt: function (opt, new_val) { if (typeof new_val === 'undefined') { new_val = jQuery('form.options li.' + opt[1] + ' input') .filter(':checked').val(); // if new_val is still undefined (because form.options is not in active tab), set to most spacious option if (typeof new_val === 'undefined') { new_val = 'thumbs'; } } if (new_val !== dw_mediamanager.view_opts[opt[0]]) { opt[2](new_val); DokuCookie.setValue(opt[0], new_val); dw_mediamanager.view_opts[opt[0]] = new_val; } }, /** * Lists the content of the right column (image details) using AJAX * * @author Kate Arzamastseva <pshns@ukr.net> */ details: function (event) { var $link, $content, params, update_list; $link = jQuery(this); event.preventDefault(); jQuery('div.success, div.info, div.error, div.notify').remove(); if ($link[0].id == 'mediamanager__btn_delete' && !confirm(LANG.del_confirm)) { return false; } if ($link[0].id == 'mediamanager__btn_restore' && !confirm(LANG.restore_confirm)) { return false; } $content = jQuery('div.file'); params = 'call=mediadetails&'; if ($link[0].search) { params += $link[0].search.substr(1); } else if ($link.is('form')) { params += dw_mediamanager.form_params($link); } else if ($link.closest('form').length > 0) { params += dw_mediamanager.form_params($link.closest('form')); } update_list = ($link[0].id == 'mediamanager__btn_delete' || $link[0].id == 'mediamanager__btn_restore'); dw_mediamanager.update_content($content, params, update_list); }, update_content: function ($content, params, update_list) { var $container; jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', params, function (data) { dw_mediamanager.$resizables().resizable('destroy'); if (update_list) { dw_mediamanager.list.call(jQuery('#mediamanager__page').find('form.options button[type="submit"]')[0]); } $content.html(data); dw_mediamanager.prepare_content($content); dw_mediamanager.updatehide(); dw_mediamanager.update_resizable(); dw_behaviour.revisionBoxHandler(); // Make sure that the list view style stays the same dw_mediamanager.set_fileview_list(dw_mediamanager.view_opts.list); dw_mediamanager.image_diff(); dw_mediamanager.init_ajax_uploader(); dw_mediamanager.init_options(); }, 'html' ); $container = $content.find('div.panelContent'); if ($container.length === 0) { $container = $content; } $container.html('<img src="' + DOKU_BASE + 'lib/images/throbber.gif" alt="..." class="load" />'); }, window_resize: function () { dw_mediamanager.resize(); dw_mediamanager.opacity_slider(); dw_mediamanager.portions_slider(); }, $resizables: function () { return jQuery('#mediamanager__page').find('div.namespaces, div.filelist'); }, /** * Updates mediamanager layout * * @author Kate Arzamastseva <pshns@ukr.net> */ update_resizable: function () { var $resizables = dw_mediamanager.$resizables(); $resizables.resizable({ handles: (jQuery('html[dir=rtl]').length ? 'w' : 'e'), resize: function (event, ui) { var $page = jQuery('#mediamanager__page'); var widthFull = $page.width(); var widthResizables = 0; $resizables.each(function () { widthResizables += jQuery(this).width(); }); var $filePanel = $page.find('div.panel.file'); // set max width of resizable column var widthOtherResizable = widthResizables - jQuery(this).width(); var minWidthNonResizable = parseFloat($filePanel.css("min-width")); var maxWidth = widthFull - (widthOtherResizable + minWidthNonResizable) - 1; $resizables.resizable("option", "maxWidth", maxWidth); // width of file panel in % = 100% - width of resizables in % // this calculates with 99.9 and not 100 to overcome rounding errors var relWidthNonResizable = 99.9 - (100 * widthResizables / widthFull); // set width of file panel $filePanel.width(relWidthNonResizable + '%'); dw_mediamanager.resize(); dw_mediamanager.opacity_slider(); dw_mediamanager.portions_slider(); } }); dw_mediamanager.resize(); }, resize: function () { var $contents = jQuery('#mediamanager__page').find('div.panelContent'), height = jQuery(window).height() - jQuery(document.body).height() + Math.max.apply(null, jQuery.map($contents, function (v) { return jQuery(v).height(); })); // If the screen is too small, don’t try to resize if (height < dw_mediamanager.minHeights[dw_mediamanager.view_opts.list]) { $contents.add(dw_mediamanager.$resizables()).height('auto'); } else { $contents.height(height); dw_mediamanager.$resizables().each(function () { var $this = jQuery(this); $this.height(height + $this.find('div.panelContent').offset().top - $this.offset().top); }); } }, /** * Prints 'select' for image difference representation type * * @author Kate Arzamastseva <pshns@ukr.net> */ image_diff: function () { if (jQuery('#mediamanager__difftype').length) return; var $form = jQuery('#mediamanager__form_diffview'); if (!$form.length) return; var $label = jQuery(document.createElement('label')); $label.append('<span>' + LANG.media_diff + '</span> '); var $select = jQuery(document.createElement('select')) .attr('id', 'mediamanager__difftype') .attr('name', 'difftype') .change(dw_mediamanager.change_diff_type); $select.append(new Option(LANG.media_diff_both, "both")); $select.append(new Option(LANG.media_diff_opacity, "opacity")); $select.append(new Option(LANG.media_diff_portions, "portions")); $label.append($select); $form.append($label); // for IE var select = document.getElementById('mediamanager__difftype'); select.options[0].text = LANG.media_diff_both; select.options[1].text = LANG.media_diff_opacity; select.options[2].text = LANG.media_diff_portions; }, /** * Handles selection of image difference representation type * * @author Kate Arzamastseva <pshns@ukr.net> */ change_diff_type: function () { var $select = jQuery('#mediamanager__difftype'); var $content = jQuery('#mediamanager__diff'); var params = dw_mediamanager.form_params($select.closest('form')) + '&call=mediadiff'; jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', params, function (data) { $content.html(data); dw_mediamanager.portions_slider(); dw_mediamanager.opacity_slider(); }, 'html' ); }, /** * Sets options for opacity diff slider * * @author Kate Arzamastseva <pshns@ukr.net> */ opacity_slider: function () { var $diff = jQuery("#mediamanager__diff"); var $slider = $diff.find("div.slider"); if (!$slider.length) return; var $image = $diff.find('div.imageDiff.opacity div.image1 img'); if (!$image.length) return; $slider.width($image.width() - 20); $slider.slider(); $slider.slider("option", "min", 0); $slider.slider("option", "max", 0.999); $slider.slider("option", "step", 0.001); $slider.slider("option", "value", 0.5); $slider.on("slide", function (event, ui) { jQuery('#mediamanager__diff').find('div.imageDiff.opacity div.image2 img').css({opacity: $slider.slider("option", "value")}); }); }, /** * Sets options for red line diff slider * * @author Kate Arzamastseva <pshns@ukr.net> */ portions_slider: function () { var $diff = jQuery("#mediamanager__diff"); if (!$diff.length) return; var $image1 = $diff.find('div.imageDiff.portions div.image1 img'); var $image2 = $diff.find('div.imageDiff.portions div.image2 img'); if (!$image1.length || !$image2.length) return; $diff.width('100%'); $image2.parent().width('97%'); $image1.width('100%'); $image2.width('100%'); if ($image1.width() < $diff.width()) { $diff.width($image1.width()); } $image2.parent().width('50%'); $image2.width($image1.width()); $image1.width($image1.width()); var $slider = $diff.find("div.slider"); if (!$slider.length) return; $slider.width($image1.width() - 20); $slider.slider(); $slider.slider("option", "min", 0); $slider.slider("option", "max", 97); $slider.slider("option", "step", 1); $slider.slider("option", "value", 50); $slider.on("slide", function (event, ui) { jQuery('#mediamanager__diff').find('div.imageDiff.portions div.image2').css({width: $slider.slider("option", "value") + '%'}); }); }, /** * Parse a URI query string to an associative array * * @author Kate Arzamastseva <pshns@ukr.net> */ params_toarray: function (str) { var vars = [], hash; var hashes = str.split('&'); for (var i = 0; i < hashes.length; i++) { hash = hashes[i].split('='); vars[decodeURIComponent(hash[0])] = decodeURIComponent(hash[1]); } return vars; }, init_ajax_uploader: function () { if (!jQuery('#mediamanager__uploader').length) return; if (jQuery('.qq-upload-list').length) return; var params = dw_mediamanager.form_params(jQuery('#dw__upload')) + '&call=mediaupload'; params = dw_mediamanager.params_toarray(params); var uploader = new qq.FileUploaderExtended({ element: document.getElementById('mediamanager__uploader'), action: DOKU_BASE + 'lib/exe/ajax.php', params: params }); }, prepare_content: function ($content) { // hide syntax example $content.find('div.example:visible').hide(); // toggle list of allowed mime types $content.find('a.allowedmime').on('click', function (event) { event.preventDefault(); $toggle = jQuery(this); $list = $toggle.next('span'); $list.toggle(); }).next('span').hide(); }, /** * shows the popup for a image link */ select: function (event) { var $link, id, dot, ext; event.preventDefault(); $link = jQuery(this); id = $link.attr('id').substr(2); if (!opener) { // if we don't run in popup display example // the id's are a bit wierd and jQuery('#ex_wiki_dokuwiki-128.png') // will not be found by Sizzle (the CSS Selector Engine // used by jQuery), hence the document.getElementById() call jQuery(document.getElementById('ex_' + id.replace(/:/g, '_').replace(/^_/, ''))).dw_toggle(); return; } dw_mediamanager.ext = false; dot = id.lastIndexOf("."); if (-1 === dot) { dw_mediamanager.insert(id); return; } ext = id.substr(dot); if ({'.jpg': 1, '.jpeg': 1, '.png': 1, '.gif': 1, '.swf': 1}[ext] !== 1) { dw_mediamanager.insert(id); return; } // remove old callback from the insert button and set the new one. var $sendbtn = jQuery('#media__sendbtn'); $sendbtn.off().on('click', bind(dw_mediamanager.insert, id)); dw_mediamanager.unforbid('ext'); if (ext === '.swf') { dw_mediamanager.ext = 'swf'; dw_mediamanager.forbid('ext', { link: ['1', '2'], size: ['4'] }); } else { dw_mediamanager.ext = 'img'; } // Set to defaults dw_mediamanager.setOpt('link'); dw_mediamanager.setOpt('align'); dw_mediamanager.setOpt('size'); // toggle buttons for detail and linked image, original size jQuery('#media__linkbtn1, #media__linkbtn2, #media__sizebtn4') .toggle(dw_mediamanager.ext === 'img'); dw_mediamanager.$popup.dialog('open'); $sendbtn.focus(); }, /** * Deletion confirmation dialog to the delete buttons. * * @author Michael Klier <chi@chimeric.de> * @author Pierre Spring <pierre.spring@caillou.ch> */ confirmattach: function (e) { if (!confirm(LANG.del_confirm + "\n" + jQuery(this).attr('title'))) { e.preventDefault(); } }, /** * Creates checkboxes for additional options * * @author Andreas Gohr <andi@splitbrain.org> * @author Pierre Spring <pierre.spring@caillou.ch> */ attachoptions: function () { var $obj, opts; $obj = jQuery('#media__opts'); if ($obj.length === 0) { return; } opts = []; // keep open if (opener) { opts.push(['keepopen', 'keepopen']); } opts.push(['hide', 'hidedetails']); jQuery.each(opts, function (_, opt) { var $box, $lbl; $box = jQuery(document.createElement('input')) .attr('type', 'checkbox') .attr('id', 'media__' + opt[0]) .on('click', bind(dw_mediamanager.toggleOption, opt[0])); if (DokuCookie.getValue(opt[0])) { $box.prop('checked', true); dw_mediamanager[opt[0]] = true; } $lbl = jQuery(document.createElement('label')) .attr('for', 'media__' + opt[0]) .text(LANG[opt[1]]); $obj.append($box, $lbl, document.createElement('br')); }); dw_mediamanager.updatehide(); }, /** * Generalized toggler * * @author Pierre Spring <pierre.spring@caillou.ch> */ toggleOption: function (variable) { if (jQuery(this).prop('checked')) { DokuCookie.setValue(variable, 1); dw_mediamanager[variable] = true; } else { DokuCookie.setValue(variable, ''); dw_mediamanager[variable] = false; } if (variable === 'hide') { dw_mediamanager.updatehide(); } }, /** * Sets the visibility of the image details accordingly to the * chosen hide state * * @author Andreas Gohr <andi@splitbrain.org> */ updatehide: function () { jQuery('#media__content').find('div.detail').dw_toggle(!dw_mediamanager.hide); }, /** * set media insertion option * * @author Dominik Eckelmann <eckelmann@cosmocode.de> */ setOpt: function (opt, e) { var val, i; if (typeof e !== 'undefined') { val = this.id.substring(this.id.length - 1); } else { val = dw_mediamanager.getOpt(opt); } if (val === false) { DokuCookie.setValue(opt, ''); dw_mediamanager[opt] = false; return; } if (opt === 'link') { if (val !== '4' && dw_mediamanager.link === '4') { dw_mediamanager.unforbid('linkonly'); dw_mediamanager.setOpt('align'); dw_mediamanager.setOpt('size'); } else if (val === '4') { dw_mediamanager.forbid('linkonly', {align: false, size: false}); } jQuery("#media__size, #media__align").dw_toggle(val !== '4'); } DokuCookie.setValue(opt, val); dw_mediamanager[opt] = val; for (i = 1; i <= 4; i++) { jQuery("#media__" + opt + "btn" + i).removeClass('selected'); } jQuery('#media__' + opt + 'btn' + val).addClass('selected'); }, unforbid: function (group) { delete dw_mediamanager.forbidden_opts[group]; }, forbid: function (group, forbids) { dw_mediamanager.forbidden_opts[group] = forbids; }, allowedOpt: function (opt, val) { var ret = true; jQuery.each(dw_mediamanager.forbidden_opts, function (_, forbids) { ret = forbids[opt] !== false && jQuery.inArray(val, forbids[opt]) === -1; return ret; }); return ret; }, getOpt: function (opt) { var allowed = bind(dw_mediamanager.allowedOpt, opt); // Current value if (dw_mediamanager[opt] !== false && allowed(dw_mediamanager[opt])) { return dw_mediamanager[opt]; } // From cookie if (DokuCookie.getValue(opt) && allowed(DokuCookie.getValue(opt))) { return DokuCookie.getValue(opt); } // size default if (opt === 'size' && allowed('2')) { return '2'; } // Whatever is allowed, and be it false return jQuery.grep(['1', '2', '3', '4'], allowed)[0] || false; } }; /** * Default implementation for the media manager's select action * * Can be overriden with the onselect URL parameter. Is called on the opener context * * @param {string} edid * @param {string} mediaid * @param {string} opts * @param {string} align [none, left, center, right] */ function dw_mediamanager_item_select(edid, mediaid, opts, align, keepopen) { var alignleft = ''; var alignright = ''; // Get the 2 characters after the cursor to check if we're currently inside an image tag var cursorInImageTag = false; var textArea = jQuery('#' + edid)[0]; var selection = DWgetSelection(textArea); selection.end = selection.end + 2; var charsAfterCursor = selection.getText(); if (charsAfterCursor === '}}') { cursorInImageTag = true; } if (align !== '1') { alignleft = align === '2' ? '' : ' '; alignright = align === '4' ? '' : ' '; } if (keepopen && cursorInImageTag) { selection.start = selection.start + 2; DWsetSelection(selection); } insertTags(edid, '{{' + alignleft + mediaid + opts + alignright + '|', '}}', ''); } jQuery(dw_mediamanager.init); /* XXXXXXXXXX end of lib/scripts/media.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/compatibility.js XXXXXXXXXX */ /** * Mark a JavaScript function as deprecated * * This will print a warning to the JavaScript console (if available) in * Firebug and Chrome and a stack trace (if available) to easily locate the * problematic function call. * * @param msg optional message to print */ function DEPRECATED(msg){ if(!window.console) return; if(!msg) msg = ''; var func; if(arguments.callee) func = arguments.callee.caller.name; if(func) func = ' '+func+'()'; var line = 'DEPRECATED function call'+func+'. '+msg; if(console.warn){ console.warn(line); }else{ console.log(line); } if(console.trace) console.trace(); } /** * Construct a wrapper function for deprecated function names * * This function returns a wrapper function which just calls DEPRECATED * and the new function. * * @param func The new function * @param context Optional; The context (`this`) of the call */ function DEPRECATED_WRAP(func, context) { return function () { DEPRECATED(); return func.apply(context || this, arguments); }; } /* XXXXXXXXXX end of lib/scripts/compatibility.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/behaviour.js XXXXXXXXXX */ /** * Hides elements with a slide animation * * @param {function} fn optional callback to run after hiding * @param {bool} noaria supress aria-expanded state setting * @author Adrian Lang <mail@adrianlang.de> */ jQuery.fn.dw_hide = function(fn, noaria) { if(!noaria) this.attr('aria-expanded', 'false'); return this.slideUp('fast', fn); }; /** * Unhides elements with a slide animation * * @param {function} fn optional callback to run after hiding * @param {bool} noaria supress aria-expanded state setting * @author Adrian Lang <mail@adrianlang.de> */ jQuery.fn.dw_show = function(fn, noaria) { if(!noaria) this.attr('aria-expanded', 'true'); return this.slideDown('fast', fn); }; /** * Toggles visibility of an element using a slide element * * @param {bool} state the current state of the element (optional) * @param {function} fn callback after the state has been toggled * @param {bool} noaria supress aria-expanded state setting */ jQuery.fn.dw_toggle = function(state, fn, noaria) { return this.each(function() { var $this = jQuery(this); if (typeof state === 'undefined') { state = $this.is(':hidden'); } $this[state ? "dw_show" : "dw_hide" ](fn, noaria); }); }; /** * Automatic behaviours * * This class wraps various JavaScript functionalities that are triggered * automatically whenever a certain object is in the DOM or a certain CSS * class was found */ var dw_behaviour = { init: function(){ dw_behaviour.focusMarker(); dw_behaviour.scrollToMarker(); dw_behaviour.removeHighlightOnClick(); dw_behaviour.quickSelect(); dw_behaviour.checkWindowsShares(); dw_behaviour.subscription(); dw_behaviour.revisionBoxHandler(); jQuery(document).on('click','#page__revisions input[type=checkbox]', dw_behaviour.revisionBoxHandler ); jQuery('.bounce').effect('bounce', {times:10}, 2000 ); }, /** * Looks for an element with the ID scroll__here at scrolls to it */ scrollToMarker: function(){ var $obj = jQuery('#scroll__here'); if($obj.length) { if($obj.offset().top != 0) { jQuery('html, body').animate({ scrollTop: $obj.offset().top - 100 }, 500); } else { // hidden object have no offset but can still be scrolled into view $obj[0].scrollIntoView(); } } }, /** * Looks for an element with the ID focus__this at sets focus to it */ focusMarker: function(){ jQuery('#focus__this').trigger('focus'); }, /** * Remove all search highlighting when clicking on a highlighted term */ removeHighlightOnClick: function(){ jQuery('span.search_hit').on('click', function(e){ jQuery(e.target).removeClass('search_hit', 1000); } ); }, /** * Autosubmit quick select forms * * When a <select> tag has the class "quickselect", this script will * automatically submit its parent form when the select value changes. * It also hides the submit button of the form. * * @author Andreas Gohr <andi@splitbrain.org> */ quickSelect: function(){ jQuery('select.quickselect') .on('change', function(e){ e.target.form.submit(); }) .closest('form').find(':button').not('.show').hide(); }, /** * Display error for Windows Shares on browsers other than IE * * @author Michael Klier <chi@chimeric.de> */ checkWindowsShares: function() { if(!LANG.nosmblinks || navigator.userAgent.match(/(Trident|MSIE|Edge)/)) { // No warning requested or none necessary return; } jQuery('a.windows').on('click', function(){ alert(LANG.nosmblinks.replace(/\\n/,"\n")); }); }, /** * Hide list subscription style if target is a page * * @author Adrian Lang <lang@cosmocode.de> * @author Pierre Spring <pierre.spring@caillou.ch> */ subscription: function(){ var $form, $list, $digest; $form = jQuery('#subscribe__form'); if (0 === $form.length) return; $list = $form.find("input[name='sub_style'][value='list']"); $digest = $form.find("input[name='sub_style'][value='digest']"); $form.find("input[name='sub_target']") .on('click', function () { var $this = jQuery(this), show_list; if (!$this.prop('checked')) { return; } show_list = $this.val().match(/:$/); $list.parent().dw_toggle(show_list); if (!show_list && $list.prop('checked')) { $digest.prop('checked', 'checked'); } } ) .filter(':checked') .trigger('click'); }, /** * disable multiple revisions checkboxes if two are checked * * @author Andreas Gohr <andi@splitbrain.org> * @author Anika Henke <anika@selfthinker.org> */ revisionBoxHandler: function() { var $revisions = jQuery('#page__revisions'); var $all = jQuery('input[type=checkbox]', $revisions); var $checked = $all.filter(':checked'); var $button = jQuery('button', $revisions); if($checked.length < 2) { $all.prop('disabled', false); $button.prop('disabled', true); } else { $all.prop('disabled', true); $button.prop('disabled', false); $checked.each(function(i) { jQuery(this).prop('disabled', false); if(i>1) { jQuery(this).prop('checked', false); } }); } } }; jQuery(dw_behaviour.init); /* XXXXXXXXXX end of lib/scripts/behaviour.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/scripts/page.js XXXXXXXXXX */ /** * Page behaviours * * This class adds various behaviours to the rendered page */ dw_page = { /** * initialize page behaviours */ init: function(){ dw_page.sectionHighlight(); dw_page.currentIDHighlight(); jQuery('a.fn_top').on('mouseover', dw_page.footnoteDisplay); dw_page.makeToggle('#dw__toc h3','#dw__toc > div'); }, /** * Highlight the section when hovering over the appropriate section edit button * * @author Andreas Gohr <andi@splitbrain.org> */ sectionHighlight: function() { jQuery('form.btn_secedit') .on('mouseover', function(){ var $tgt = jQuery(this).parent(), nr = $tgt.attr('class').match(/(\s+|^)editbutton_(\d+)(\s+|$)/)[2], $highlight = jQuery(), // holder for elements in the section to be highlighted $highlightWrap = jQuery('<div class="section_highlight"></div>'); // section highlight wrapper // Walk the dom tree in reverse to find the sibling which is or contains the section edit marker while($tgt.length > 0 && !($tgt.hasClass('sectionedit' + nr) || $tgt.find('.sectionedit' + nr).length)) { $tgt = $tgt.prev(); $highlight = $highlight.add($tgt); } // insert the section highlight wrapper before the last element added to $highlight $highlight.filter(':last').before($highlightWrap); // and move the elements to be highlighted inside the section highlight wrapper $highlight.detach().appendTo($highlightWrap); }) .on('mouseout', function(){ // find the section highlight wrapper... var $highlightWrap = jQuery('.section_highlight'); // ...move its children in front of it (as siblings)... $highlightWrap.before($highlightWrap.children().detach()); // ...and remove the section highlight wrapper $highlightWrap.detach(); }); }, /** * Highlight internal link pointing to current page * * @author Henry Pan <dokuwiki@phy25.com> */ currentIDHighlight: function(){ jQuery('a.wikilink1, a.wikilink2').filter('[data-wiki-id="'+JSINFO.id+'"]').wrap('<span class="curid"></div>'); }, /** * Create/get a insitu popup used by the footnotes * * @param target - the DOM element at which the popup should be aligned at * @param popup_id - the ID of the (new) DOM popup * @return the Popup jQuery object */ insituPopup: function(target, popup_id) { // get or create the popup div var $fndiv = jQuery('#' + popup_id); // popup doesn't exist, yet -> create it if($fndiv.length === 0){ $fndiv = jQuery(document.createElement('div')) .attr('id', popup_id) .addClass('insitu-footnote JSpopup') .attr('aria-hidden', 'true') .on('mouseleave', function () {jQuery(this).hide().attr('aria-hidden', 'true');}) .attr('role', 'tooltip'); jQuery('.dokuwiki:first').append($fndiv); } // position() does not support hidden elements $fndiv.show().position({ my: 'left top', at: 'left center', of: target }).hide(); return $fndiv; }, /** * Display an insitu footnote popup * * @author Andreas Gohr <andi@splitbrain.org> * @author Chris Smith <chris@jalakai.co.uk> * @author Anika Henke <anika@selfthinker.org> */ footnoteDisplay: function () { var $content = jQuery(jQuery(this).attr('href')) // Footnote text anchor .parent().siblings('.content').clone(); if (!$content.length) { return; } // prefix ids on any elements with "insitu__" to ensure they remain unique jQuery('[id]', $content).each(function(){ var id = jQuery(this).attr('id'); jQuery(this).attr('id', 'insitu__' + id); }); var content = $content.html().trim(); // now put the content into the wrapper dw_page.insituPopup(this, 'insitu__fn').html(content) .show().attr('aria-hidden', 'false'); }, /** * Makes an element foldable by clicking its handle * * This is used for the TOC toggling, but can be used for other elements * as well. A state indicator is inserted into the handle and can be styled * by CSS. * * To properly reserve space for the expanded element, the sliding animation is * done on the children of the content. To make that look good and to make sure aria * attributes are assigned correctly, it's recommended to make sure that the content * element contains a single child element only. * * @param {selector} handle What should be clicked to toggle * @param {selector} content This element will be toggled * @param {int} state initial state (-1 = open, 1 = closed) */ makeToggle: function(handle, content, state){ var $handle, $content, $clicky, $child, setClicky; $handle = jQuery(handle); if(!$handle.length) return; $content = jQuery(content); if(!$content.length) return; // we animate the children $child = $content.children(); // class/display toggling setClicky = function(hiding){ if(hiding){ $clicky.html('<span>+</span>'); $handle.addClass('closed'); $handle.removeClass('open'); }else{ $clicky.html('<span>−</span>'); $handle.addClass('open'); $handle.removeClass('closed'); } }; $handle[0].setState = function(state){ var hidden; if(!state) state = 1; // Assert that content instantly takes the whole space $content.css('min-height', $content.height()).show(); // stop any running animation $child.stop(true, true); // was a state given or do we toggle? if(state === -1) { hidden = false; } else if(state === 1) { hidden = true; } else { hidden = $child.is(':hidden'); } // update the state setClicky(!hidden); // Start animation and assure that $toc is hidden/visible $child.dw_toggle(hidden, function () { $content.toggle(hidden); $content.attr('aria-expanded', hidden); $content.css('min-height',''); // remove min-height again }, true); }; // the state indicator $clicky = jQuery(document.createElement('strong')); // click function $handle.css('cursor','pointer') .on('click', $handle[0].setState) .prepend($clicky); // initial state $handle[0].setState(state); } }; jQuery(dw_page.init); /* XXXXXXXXXX end of lib/scripts/page.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/tpl/dokuwiki/script.js XXXXXXXXXX */ /** * We handle several device classes based on browser width. * * - desktop: > __tablet_width__ (as set in style.ini) * - mobile: * - tablet <= __tablet_width__ * - phone <= __phone_width__ */ var device_class = ''; // not yet known var device_classes = 'desktop mobile tablet phone'; function tpl_dokuwiki_mobile(){ // the z-index in mobile.css is (mis-)used purely for detecting the screen mode here var screen_mode = jQuery('#screen__mode').css('z-index') + ''; // determine our device pattern // TODO: consider moving into dokuwiki core switch (screen_mode) { case '1': if (device_class.match(/tablet/)) return; device_class = 'mobile tablet'; break; case '2': if (device_class.match(/phone/)) return; device_class = 'mobile phone'; break; default: if (device_class == 'desktop') return; device_class = 'desktop'; } jQuery('html').removeClass(device_classes).addClass(device_class); // handle some layout changes based on change in device var $handle = jQuery('#dokuwiki__aside h3.toggle'); var $toc = jQuery('#dw__toc h3'); if (device_class == 'desktop') { // reset for desktop mode if($handle.length) { $handle[0].setState(1); $handle.hide(); } if($toc.length) { $toc[0].setState(1); } } if (device_class.match(/mobile/)){ // toc and sidebar hiding if($handle.length) { $handle.show(); $handle[0].setState(-1); } if($toc.length) { $toc[0].setState(-1); } } } jQuery(function(){ var resizeTimer; dw_page.makeToggle('#dokuwiki__aside h3.toggle','#dokuwiki__aside div.content'); tpl_dokuwiki_mobile(); jQuery(window).on('resize', function(){ if (resizeTimer) clearTimeout(resizeTimer); resizeTimer = setTimeout(tpl_dokuwiki_mobile,200); } ); // increase sidebar length to match content (desktop mode only) var sidebar_height = jQuery('.desktop #dokuwiki__aside').height(); var pagetool_height = jQuery('.desktop #dokuwiki__pagetools ul:first').height(); // pagetools div has no height; ul has a height var content_min = Math.max(sidebar_height || 0, pagetool_height || 0); var content_height = jQuery('#dokuwiki__content div.page').height(); if(content_min && content_min > content_height) { var $content = jQuery('#dokuwiki__content div.page'); $content.css('min-height', content_min); } // blur when clicked jQuery('#dokuwiki__pagetools div.tools>ul>li>a').on('click', function(){ this.blur(); }); }); /* XXXXXXXXXX end of lib/tpl/dokuwiki/script.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/plugins/acl/script.js XXXXXXXXXX */ /** * ACL Manager AJAX enhancements * * @author Andreas Gohr <andi@splitbrain.org> */ var dw_acl = { /** * Initialize the object and attach the event handlers */ init: function () { var $tree; //FIXME only one underscore!! if (jQuery('#acl_manager').length === 0) { return; } jQuery('#acl__user select').on('change', dw_acl.userselhandler); jQuery('#acl__user button').on('click', dw_acl.loadinfo); $tree = jQuery('#acl__tree'); $tree.dw_tree({toggle_selector: 'img', load_data: function (show_sublist, $clicky) { // get the enclosed link and the edit form var $frm = jQuery('#acl__detail form'); jQuery.post( DOKU_BASE + 'lib/exe/ajax.php', jQuery.extend(dw_acl.parseatt($clicky.parent().find('a')[0].search), {call: 'plugin_acl', ajax: 'tree', current_ns: $frm.find('input[name=ns]').val(), current_id: $frm.find('input[name=id]').val()}), show_sublist, 'html' ); }, toggle_display: function ($clicky, opening) { $clicky.attr('src', DOKU_BASE + 'lib/images/' + (opening ? 'minus' : 'plus') + '.gif'); }}); $tree.delegate('a', 'click', dw_acl.treehandler); }, /** * Handle user dropdown * * Hides or shows the user/group entry box depending on what was selected in the * dropdown element */ userselhandler: function () { // make entry field visible/invisible jQuery('#acl__user input').toggle(this.value === '__g__' || this.value === '__u__'); dw_acl.loadinfo(); }, /** * Load the current permission info and edit form */ loadinfo: function () { jQuery('#acl__info') .attr('role', 'alert') .html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="..." />') .load( DOKU_BASE + 'lib/exe/ajax.php', jQuery('#acl__detail form').serialize() + '&call=plugin_acl&ajax=info' ); return false; }, /** * parse URL attributes into a associative array * * @todo put into global script lib? */ parseatt: function (str) { if (str[0] === '?') { str = str.substr(1); } var attributes = {}; var all = str.split('&'); for (var i = 0; i < all.length; i++) { var att = all[i].split('='); attributes[att[0]] = decodeURIComponent(att[1]); } return attributes; }, /** * Handles clicks to the tree nodes */ treehandler: function () { var $link, $frm; $link = jQuery(this); // remove highlighting jQuery('#acl__tree a.cur').removeClass('cur'); // add new highlighting $link.addClass('cur'); // set new page to detail form $frm = jQuery('#acl__detail form'); if ($link.hasClass('wikilink1')) { $frm.find('input[name=ns]').val(''); $frm.find('input[name=id]').val(dw_acl.parseatt($link[0].search).id); } else if ($link.hasClass('idx_dir')) { $frm.find('input[name=ns]').val(dw_acl.parseatt($link[0].search).ns); $frm.find('input[name=id]').val(''); } dw_acl.loadinfo(); return false; } }; jQuery(dw_acl.init); /* XXXXXXXXXX end of lib/plugins/acl/script.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/plugins/extension/script.js XXXXXXXXXX */ jQuery(function(){ var $extmgr = jQuery('#extension__manager'); /** * Confirm uninstalling */ $extmgr.find('button.uninstall').on('click', function(e){ if(!window.confirm(LANG.plugins.extension.reallydel)){ e.preventDefault(); return false; } return true; }); /** * very simple lightbox * @link http://webdesign.tutsplus.com/tutorials/htmlcss-tutorials/super-simple-lightbox-with-css-and-jquery/ */ $extmgr.find('a.extension_screenshot').on('click', function(e) { e.preventDefault(); //Get clicked link href var image_href = jQuery(this).attr("href"); // create lightbox if needed var $lightbox = jQuery('#plugin__extensionlightbox'); if(!$lightbox.length){ $lightbox = jQuery('<div id="plugin__extensionlightbox"><p>Click to close</p><div></div></div>') .appendTo(jQuery('body')) .hide() .on('click', function(){ $lightbox.hide(); }); } // fill and show it $lightbox .show() .find('div').html('<img src="' + image_href + '" />'); return false; }); /** * Enable/Disable extension via AJAX */ $extmgr.find('button.disable, button.enable').on('click', function (e) { e.preventDefault(); var $btn = jQuery(this); // get current state var extension = $btn.attr('name').split('[')[2]; extension = extension.substr(0, extension.length - 1); var act = ($btn.hasClass('disable')) ? 'disable' : 'enable'; // disable while we wait $btn.attr('disabled', 'disabled'); $btn.css('cursor', 'wait'); // execute jQuery.get( DOKU_BASE + 'lib/exe/ajax.php', { call: 'plugin_extension', ext: extension, act: act }, function (data) { $btn.css('cursor', '') .removeAttr('disabled') .removeClass('disable') .removeClass('enable') .text(data.label) .addClass(data.reverse) .parents('li') .removeClass('disabled') .removeClass('enabled') .addClass(data.state); } ); }); /** * AJAX detail infos */ $extmgr.find('a.info').on('click', function(e){ e.preventDefault(); var $link = jQuery(this); var $details = $link.parent().find('dl.details'); if($details.length){ $link.toggleClass('close'); $details.toggle(); return; } $link.addClass('close'); jQuery.get( DOKU_BASE + 'lib/exe/ajax.php', { call: 'plugin_extension', ext: $link.data('extid'), act: 'info' }, function(data){ $link.parent().append(data); } ); }); /** Create section for enabling/disabling viewing options */ if ( $extmgr.find('.plugins, .templates').hasClass('active') ) { var $extlist = jQuery('#extension__list'); $extlist.addClass('hasDisplayOptions'); var $displayOpts = jQuery('<p>', { id: 'extension__viewoptions'} ).appendTo($extmgr.find( '.panelHeader' )); $displayOpts.append(LANG.plugins.extension.display_viewoptions); var displayOptionsHandler = function(){ $extlist.toggleClass( this.name ); DokuCookie.setValue('ext_'+this.name, $extlist.hasClass(this.name) ? '1' : '0'); }; jQuery(['enabled', 'disabled', 'updatable']).each(function(index, chkName){ var $label = jQuery( '<label></label>' ) .appendTo($displayOpts); var $input = jQuery( '<input />', { type: 'checkbox', name: chkName }) .on('change', displayOptionsHandler) .appendTo($label); var previous = DokuCookie.getValue('ext_'+chkName); if(typeof previous === "undefined" || previous == '1') { $input.trigger('click'); } jQuery( '<span/>' ) .append(' '+LANG.plugins.extension['display_'+chkName]) .appendTo($label); }); } }); /* XXXXXXXXXX end of lib/plugins/extension/script.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/plugins/styling/script.js XXXXXXXXXX */ jQuery(function () { /** * Function to reload the preview styles in the main window * * @param {Window} target the main window */ function applyPreview(target) { // remove style var $style = target.jQuery('link[rel=stylesheet][href*="lib/exe/css.php"]'); $style.attr('href', ''); // append the loader screen var $loader = target.jQuery('#plugin__styling_loader'); if (!$loader.length) { $loader = target.jQuery('<div id="plugin__styling_loader">' + LANG.plugins.styling.loader + '</div>'); $loader.css({ 'position': 'absolute', 'width': '100%', 'height': '100%', 'top': 0, 'left': 0, 'z-index': 5000, 'background-color': '#fff', 'opacity': '0.7', 'color': '#000', 'font-size': '2.5em', 'text-align': 'center', 'line-height': 1.5, 'padding-top': '2em' }); target.jQuery('body').append($loader); } // load preview in main window (timeout works around chrome updating CSS weirdness) setTimeout(function () { var now = new Date().getTime(); $style.attr('href', DOKU_BASE + 'lib/exe/css.php?preview=1&tseed=' + now); }, 500); } var doreload = 1; var $styling_plugin = jQuery('#plugin__styling'); // if we are not on the plugin page (either main or popup) if (!$styling_plugin.length) { // handle the preview cookie if(DokuCookie.getValue('styling_plugin') == 1) { applyPreview(window); } return; // nothing more to do here } /* ---- from here on we're in the popup or admin page ---- */ // add button on main page if (!$styling_plugin.hasClass('ispopup')) { var $form = $styling_plugin.find('form.styling').first(); var $btn = jQuery('<button>' + LANG.plugins.styling.popup + '</button>'); $form.prepend($btn); $btn.on('click', function (e) { var windowFeatures = "menubar=no,location=no,resizable=yes,scrollbars=yes,status=false,width=500,height=500"; window.open(DOKU_BASE + 'lib/plugins/styling/popup.php', 'styling_popup', windowFeatures); e.preventDefault(); e.stopPropagation(); }).wrap('<p></p>'); return; // we exit here if this is not the popup } /* ---- from here on we're in the popup only ---- */ // reload the main page on close window.onunload = function(e) { if(doreload) { DokuCookie.setValue('styling_plugin', 0); if(window.opener) window.opener.document.location.reload(); } return null; }; // don't reload on our own buttons jQuery(':button').click(function(e){ doreload = false; }); // on first load apply preview if(window.opener) applyPreview(window.opener); // enable the preview cookie DokuCookie.setValue('styling_plugin', 1); }); /* XXXXXXXXXX end of lib/plugins/styling/script.js XXXXXXXXXX */ /* XXXXXXXXXX begin of lib/plugins/usermanager/script.js XXXXXXXXXX */ /** * Add JavaScript confirmation to the User Delete button */ jQuery(function(){ jQuery('#usrmgr__del').on('click', function(){ return confirm(LANG.del_confirm); }); }); /* XXXXXXXXXX end of lib/plugins/usermanager/script.js XXXXXXXXXX */ jQuery(function(){ dw_locktimer.init(840,1); });