%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /data/www_bck/varak.net_bck/recepty.varak.net/data/cache/0/
Upload File :
Create Path :
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); });


Zerion Mini Shell 1.0