Initial commit
							
								
								
									
										195
									
								
								content/lib/scripts/behaviour.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,195 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
							
								
								
									
										42
									
								
								content/lib/scripts/compatibility.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,42 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								content/lib/scripts/cookie.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,71 @@
 | 
			
		||||
/**
 | 
			
		||||
* 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]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										70
									
								
								content/lib/scripts/delay.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,70 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										307
									
								
								content/lib/scripts/edit.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,307 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										205
									
								
								content/lib/scripts/editor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,205 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
							
								
								
									
										1249
									
								
								content/lib/scripts/fileuploader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										345
									
								
								content/lib/scripts/fileuploaderextended.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,345 @@
 | 
			
		||||
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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										69
									
								
								content/lib/scripts/helpers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,69 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										302
									
								
								content/lib/scripts/hotkeys.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,302 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Some of these scripts were taken from TinyMCE (http://tinymce.moxiecode.com/) and were modified for DokuWiki
 | 
			
		||||
 *
 | 
			
		||||
 * Class handles accesskeys using javascript and also provides ability
 | 
			
		||||
 * to register and use other hotkeys as well.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
 */
 | 
			
		||||
function Hotkeys() {
 | 
			
		||||
 | 
			
		||||
    this.shortcuts = new Array();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set modifier keys, for instance:
 | 
			
		||||
     *  this.modifier = 'ctrl';
 | 
			
		||||
     *  this.modifier = 'ctrl+shift';
 | 
			
		||||
     *  this.modifier = 'ctrl+alt+shift';
 | 
			
		||||
     *  this.modifier = 'alt';
 | 
			
		||||
     *  this.modifier = 'alt+shift';
 | 
			
		||||
     *
 | 
			
		||||
     *  overwritten in intitialize (see below)
 | 
			
		||||
     */
 | 
			
		||||
    this.modifier = 'ctrl+alt';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialization
 | 
			
		||||
     *
 | 
			
		||||
     * This function looks up all the accesskeys used in the current page
 | 
			
		||||
     * (at anchor elements and button elements [type="submit"]) and registers
 | 
			
		||||
     * appropriate shortcuts.
 | 
			
		||||
     *
 | 
			
		||||
     * Secondly, initialization registers listeners on document to catch all
 | 
			
		||||
     * keyboard events.
 | 
			
		||||
     *
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     */
 | 
			
		||||
    this.initialize = function() {
 | 
			
		||||
        var t = this;
 | 
			
		||||
 | 
			
		||||
        //switch modifier key based on OS FS#1958
 | 
			
		||||
        if(is_macos){
 | 
			
		||||
            t.modifier = 'ctrl+alt';
 | 
			
		||||
        }else{
 | 
			
		||||
            t.modifier = 'alt';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Lookup all anchors with accesskey and register event - go to anchor
 | 
			
		||||
         * target.
 | 
			
		||||
         */
 | 
			
		||||
        var anchors = document.getElementsByTagName("a");
 | 
			
		||||
        t.each(anchors, function(a) {
 | 
			
		||||
            if (a.accessKey != "") {
 | 
			
		||||
                t.addShortcut(t.modifier + '+' + a.accessKey, function() {
 | 
			
		||||
                    location.href = a.href;
 | 
			
		||||
                });
 | 
			
		||||
                a.accessKey = '';
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Lookup all button [type="submit"] with accesskey and register event -
 | 
			
		||||
         * perform "click" on a button.
 | 
			
		||||
         */
 | 
			
		||||
        var inputs = document.getElementsByTagName("button");
 | 
			
		||||
        t.each(inputs, function(i) {
 | 
			
		||||
            if (i.type == "submit" && i.accessKey != "") {
 | 
			
		||||
                t.addShortcut(t.modifier + '+' + i.accessKey, function() {
 | 
			
		||||
                    i.click();
 | 
			
		||||
                });
 | 
			
		||||
                i.accessKey = '';
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Lookup all buttons with accesskey and register event -
 | 
			
		||||
         * perform "click" on a button.
 | 
			
		||||
         */
 | 
			
		||||
        var buttons = document.getElementsByTagName("button");
 | 
			
		||||
        t.each(buttons, function(b) {
 | 
			
		||||
            if (b.accessKey != "") {
 | 
			
		||||
                t.addShortcut(t.modifier + '+' + b.accessKey, function() {
 | 
			
		||||
                    b.click();
 | 
			
		||||
                });
 | 
			
		||||
                b.accessKey = '';
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Register listeners on document to catch keyboard events.
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        addEvent(document,'keyup',function (e) {
 | 
			
		||||
            return t.onkeyup.call(t,e);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        addEvent(document,'keypress',function (e) {
 | 
			
		||||
            return t.onkeypress.call(t,e);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        addEvent(document,'keydown',function (e) {
 | 
			
		||||
            return t.onkeydown.call(t,e);
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Keyup processing function
 | 
			
		||||
     * Function returns true if keyboard event has registered handler, and
 | 
			
		||||
     * executes the handler function.
 | 
			
		||||
     *
 | 
			
		||||
     * @param e KeyboardEvent
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     * @return b boolean
 | 
			
		||||
     */
 | 
			
		||||
    this.onkeyup = function(e) {
 | 
			
		||||
        var t = this;
 | 
			
		||||
        var v = t.findShortcut(e);
 | 
			
		||||
        if (v != null && v != false) {
 | 
			
		||||
            v.func.call(t);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Keydown processing function
 | 
			
		||||
     * Function returns true if keyboard event has registered handler
 | 
			
		||||
     *
 | 
			
		||||
     * @param e KeyboardEvent
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     * @return b boolean
 | 
			
		||||
     */
 | 
			
		||||
    this.onkeydown = function(e) {
 | 
			
		||||
        var t = this;
 | 
			
		||||
        var v = t.findShortcut(e);
 | 
			
		||||
        if (v != null && v != false) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Keypress processing function
 | 
			
		||||
     * Function returns true if keyboard event has registered handler
 | 
			
		||||
     *
 | 
			
		||||
     * @param e KeyboardEvent
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     * @return b
 | 
			
		||||
     */
 | 
			
		||||
    this.onkeypress = function(e) {
 | 
			
		||||
        var t = this;
 | 
			
		||||
        var v = t.findShortcut(e);
 | 
			
		||||
        if (v != null && v != false) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register new shortcut
 | 
			
		||||
     *
 | 
			
		||||
     * This function registers new shortcuts, each shortcut is defined by its
 | 
			
		||||
     * modifier keys and a key (with + as delimiter). If shortcut is pressed
 | 
			
		||||
     * cmd_function is performed.
 | 
			
		||||
     *
 | 
			
		||||
     * For example:
 | 
			
		||||
     *  pa = "ctrl+alt+p";
 | 
			
		||||
     *  pa = "shift+alt+s";
 | 
			
		||||
     *
 | 
			
		||||
     * Full example of method usage:
 | 
			
		||||
     *  hotkeys.addShortcut('ctrl+s',function() {
 | 
			
		||||
     *      document.getElementByID('form_1').submit();
 | 
			
		||||
     *  });
 | 
			
		||||
     *
 | 
			
		||||
     * @param pa String description of the shortcut (ctrl+a, ctrl+shift+p, .. )
 | 
			
		||||
     * @param cmd_func Function to be called if shortcut is pressed
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     */
 | 
			
		||||
    this.addShortcut = function(pa, cmd_func) {
 | 
			
		||||
        var t = this;
 | 
			
		||||
 | 
			
		||||
        var o = {
 | 
			
		||||
            func : cmd_func,
 | 
			
		||||
            alt : false,
 | 
			
		||||
            ctrl : false,
 | 
			
		||||
            shift : false
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        t.each(t.explode(pa, '+'), function(v) {
 | 
			
		||||
            switch (v) {
 | 
			
		||||
                case 'alt':
 | 
			
		||||
                case 'ctrl':
 | 
			
		||||
                case 'shift':
 | 
			
		||||
                    o[v] = true;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                    o.charCode = v.charCodeAt(0);
 | 
			
		||||
                    o.keyCode = v.toUpperCase().charCodeAt(0);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        t.shortcuts.push((o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode,  o);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @property isMac
 | 
			
		||||
     */
 | 
			
		||||
    this.isMac = is_macos;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Apply function cb on each element of o in the namespace of s
 | 
			
		||||
     * @param o Array of objects
 | 
			
		||||
     * @param cb Function to be called on each object
 | 
			
		||||
     * @param s Namespace to be used during call of cb (default namespace is o)
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     */
 | 
			
		||||
    this.each = function(o, cb, s) {
 | 
			
		||||
        var n, l;
 | 
			
		||||
 | 
			
		||||
        if (!o)
 | 
			
		||||
            return 0;
 | 
			
		||||
 | 
			
		||||
        s = s || o;
 | 
			
		||||
 | 
			
		||||
        if (o.length !== undefined) {
 | 
			
		||||
            // Indexed arrays, needed for Safari
 | 
			
		||||
            for (n=0, l = o.length; n < l; n++) {
 | 
			
		||||
                if (cb.call(s, o[n], n, o) === false)
 | 
			
		||||
                    return 0;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Hashtables
 | 
			
		||||
            for (n in o) {
 | 
			
		||||
                if (o.hasOwnProperty(n)) {
 | 
			
		||||
                    if (cb.call(s, o[n], n, o) === false)
 | 
			
		||||
                        return 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 1;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Explode string according to delimiter
 | 
			
		||||
     * @param s String
 | 
			
		||||
     * @param d Delimiter (default ',')
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     * @return a Array of tokens
 | 
			
		||||
     */
 | 
			
		||||
    this.explode = function(s, d) {
 | 
			
		||||
        return  s.split(d || ',');
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Find if the shortcut was registered
 | 
			
		||||
     *
 | 
			
		||||
     * @param e KeyboardEvent
 | 
			
		||||
     * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
     * @return v Shortcut structure or null if not found
 | 
			
		||||
     */
 | 
			
		||||
    this.findShortcut = function (e) {
 | 
			
		||||
        var t = this;
 | 
			
		||||
        var v = null;
 | 
			
		||||
 | 
			
		||||
        /* No modifier key used - shortcut does not exist */
 | 
			
		||||
        if (!e.altKey && !e.ctrlKey && !e.metaKey) {
 | 
			
		||||
            return v;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        t.each(t.shortcuts, function(o) {
 | 
			
		||||
            if (o.ctrl != e.ctrlKey)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (o.alt != e.altKey)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (o.shift != e.shiftKey)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) {
 | 
			
		||||
                v = o;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return v;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Init function for hotkeys. Called from js.php, to ensure hotkyes are initialized after toolbar.
 | 
			
		||||
 * Call of addInitEvent(initializeHotkeys) is unnecessary now.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Marek Sacha <sachamar@fel.cvut.cz>
 | 
			
		||||
 */
 | 
			
		||||
function initializeHotkeys() {
 | 
			
		||||
    var hotkeys = new Hotkeys();
 | 
			
		||||
    hotkeys.initialize();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								content/lib/scripts/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="refresh" content="0; URL=../../" />
 | 
			
		||||
<meta name="robots" content="noindex" />
 | 
			
		||||
<title>nothing here...</title>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<!-- this is just here to prevent directory browsing -->
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										16
									
								
								content/lib/scripts/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,16 @@
 | 
			
		||||
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();
 | 
			
		||||
});
 | 
			
		||||
| 
		 After Width: | Height: | Size: 393 B  | 
| 
		 After Width: | Height: | Size: 265 B  | 
| 
		 After Width: | Height: | Size: 323 B  | 
| 
		 After Width: | Height: | Size: 324 B  | 
| 
		 After Width: | Height: | Size: 390 B  | 
| 
		 After Width: | Height: | Size: 325 B  | 
| 
		 After Width: | Height: | Size: 6.9 KiB  | 
| 
		 After Width: | Height: | Size: 4.6 KiB  | 
| 
		 After Width: | Height: | Size: 6.9 KiB  | 
| 
		 After Width: | Height: | Size: 6.9 KiB  | 
| 
		 After Width: | Height: | Size: 4.6 KiB  | 
							
								
								
									
										1311
									
								
								content/lib/scripts/jquery/jquery-ui-theme/smoothness.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										13
									
								
								content/lib/scripts/jquery/jquery-ui.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										117
									
								
								content/lib/scripts/jquery/jquery.cookie.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,117 @@
 | 
			
		||||
/*!
 | 
			
		||||
 * 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);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}));
 | 
			
		||||
							
								
								
									
										2
									
								
								content/lib/scripts/jquery/jquery.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										48
									
								
								content/lib/scripts/jquery/update.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@@ -0,0 +1,48 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#
 | 
			
		||||
# This script loads the latest jQuery and jQuery-UI 1.* versions from jQuery's CDN
 | 
			
		||||
#
 | 
			
		||||
# It also loads the 'smoothness' jQuery-UI theme and all referenced images.
 | 
			
		||||
#
 | 
			
		||||
# @author Andreas Gohr <andi@splitbrain.org>
 | 
			
		||||
# @author Stefan Grönke <stefan@gronke.net>
 | 
			
		||||
# @link   http://code.jquery.com/
 | 
			
		||||
 | 
			
		||||
# load version infor from external file
 | 
			
		||||
source ./versions
 | 
			
		||||
JQUI_HOST="https://code.jquery.com/ui/$JQUI_VERSION"
 | 
			
		||||
JQUI_GIT="https://raw.githubusercontent.com/jquery/jquery-ui/$JQUI_VERSION/ui"
 | 
			
		||||
 | 
			
		||||
# load jQuery
 | 
			
		||||
wget -nv https://code.jquery.com/jquery-${JQ_VERSION}.min.js      -O jquery.min.js
 | 
			
		||||
# load jQuery-UI
 | 
			
		||||
wget -nv "$JQUI_HOST/jquery-ui.min.js" -O jquery-ui.min.js
 | 
			
		||||
 | 
			
		||||
# load the smoothness theme
 | 
			
		||||
mkdir -p jquery-ui-theme/images
 | 
			
		||||
wget -nv -qO- "$JQUI_HOST/themes/smoothness/jquery-ui.css" | sed "s/font-family:[^;]*;//" > jquery-ui-theme/smoothness.css
 | 
			
		||||
images=`gawk 'match($0, /url\("?(images\/[^\)"]+)"?\)/, m) { print m[1] }' jquery-ui-theme/smoothness.css`
 | 
			
		||||
for img in $images
 | 
			
		||||
do
 | 
			
		||||
    wget -nv "$JQUI_HOST/themes/smoothness/$img" -O jquery-ui-theme/$img
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# load the localization data for jquery ui
 | 
			
		||||
for LNG in ../../../inc/lang/*
 | 
			
		||||
do
 | 
			
		||||
    CODE=`basename $LNG`
 | 
			
		||||
    wget -nv "$JQUI_GIT/i18n/datepicker-$CODE.js" -O $LNG/jquery.ui.datepicker.js
 | 
			
		||||
    if [ ! -s "$LNG/jquery.ui.datepicker.js" ]; then
 | 
			
		||||
        rm -f $LNG/jquery.ui.datepicker.js
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# some custom language codes
 | 
			
		||||
wget -nv "$JQUI_GIT/i18n/datepicker-de.js" -O ../../../inc/lang/de-informal/jquery.ui.datepicker.js
 | 
			
		||||
wget -nv "$JQUI_GIT/i18n/datepicker-pt-BR.js" -O ../../../inc/lang/pt-br/jquery.ui.datepicker.js
 | 
			
		||||
wget -nv "$JQUI_GIT/i18n/datepicker-zh-CN.js" -O ../../../inc/lang/zh/jquery.ui.datepicker.js
 | 
			
		||||
wget -nv "$JQUI_GIT/i18n/datepicker-zh-TW.js" -O ../../../inc/lang/zh-tw/jquery.ui.datepicker.js
 | 
			
		||||
wget -nv "$JQUI_GIT/i18n/datepicker-cy-GB.js" -O ../../../inc/lang/cy/jquery.ui.datepicker.js
 | 
			
		||||
 | 
			
		||||
# strip source maps
 | 
			
		||||
sed -i '/sourceMappingURL/d' *.min.js
 | 
			
		||||
							
								
								
									
										3
									
								
								content/lib/scripts/jquery/versions
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,3 @@
 | 
			
		||||
# this is loaded from the update.sh script and our PHP code
 | 
			
		||||
JQ_VERSION=3.5.1
 | 
			
		||||
JQUI_VERSION=1.12.1
 | 
			
		||||
							
								
								
									
										339
									
								
								content/lib/scripts/linkwiz.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,339 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										151
									
								
								content/lib/scripts/locktimer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,151 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
							
								
								
									
										974
									
								
								content/lib/scripts/media.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,974 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
							
								
								
									
										201
									
								
								content/lib/scripts/page.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,201 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
							
								
								
									
										191
									
								
								content/lib/scripts/qsearch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,191 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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'
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										30
									
								
								content/lib/scripts/script.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,30 @@
 | 
			
		||||
// 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);
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										48
									
								
								content/lib/scripts/search.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,48 @@
 | 
			
		||||
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');
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										152
									
								
								content/lib/scripts/textselection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,152 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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});
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										282
									
								
								content/lib/scripts/toolbar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,282 @@
 | 
			
		||||
// 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');
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										107
									
								
								content/lib/scripts/tree.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,107 @@
 | 
			
		||||
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;
 | 
			
		||||
};
 | 
			
		||||