diff options
| author | sembrestels <sembrestels@riseup.net> | 2011-10-13 15:23:11 +0200 | 
|---|---|---|
| committer | sembrestels <sembrestels@riseup.net> | 2011-10-13 15:23:11 +0200 | 
| commit | 74bd6999c5e5c23ebbf90dbb6bdaabbddd7594cf (patch) | |
| tree | 834c120d692be288f261bcae169eedd3d6b31d74 /vendors/dokuwiki/lib/scripts | |
| parent | f8be8643f0faadb2c0ce87d553b7b9d569af5afd (diff) | |
| download | elgg-74bd6999c5e5c23ebbf90dbb6bdaabbddd7594cf.tar.gz elgg-74bd6999c5e5c23ebbf90dbb6bdaabbddd7594cf.tar.bz2 | |
Rename lib/dokuwiki to vendors/dokuwiki
Diffstat (limited to 'vendors/dokuwiki/lib/scripts')
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/ajax.js | 68 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/cookie.js | 112 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/drag.js | 99 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/edit.js | 442 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/events.js | 176 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/helpers.js | 146 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/index.html | 12 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/index.js | 116 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/linkwiz.js | 282 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/media.js | 351 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/pngbehavior.htc | 53 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/script.js | 561 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/textselection.js | 226 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/toolbar.js | 252 | ||||
| -rw-r--r-- | vendors/dokuwiki/lib/scripts/tw-sack.js | 136 | 
15 files changed, 3032 insertions, 0 deletions
| diff --git a/vendors/dokuwiki/lib/scripts/ajax.js b/vendors/dokuwiki/lib/scripts/ajax.js new file mode 100644 index 000000000..a2a48a996 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/ajax.js @@ -0,0 +1,68 @@ +/** + * AJAX functions for the pagename quicksearch + * + * We're using a global object with self referencing methods + * here to make callbacks work + * + * @license  GPL2 (http://www.gnu.org/licenses/gpl.html) + * @author   Andreas Gohr <andi@splitbrain.org> + */ + +//prepare class +function ajax_qsearch_class(){ +  this.sack = null; +  this.inObj = null; +  this.outObj = null; +  this.timer = null; +} + +//create global object and add functions +var ajax_qsearch = new ajax_qsearch_class(); +ajax_qsearch.sack = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +ajax_qsearch.sack.AjaxFailedAlert = ''; +ajax_qsearch.sack.encodeURIString = false; + +ajax_qsearch.init = function(inID,outID){ +  ajax_qsearch.inObj  = document.getElementById(inID); +  ajax_qsearch.outObj = document.getElementById(outID); + +  // objects found? +  if(ajax_qsearch.inObj === null){ return; } +  if(ajax_qsearch.outObj === null){ return; } + +  // attach eventhandler to search field +  addEvent(ajax_qsearch.inObj,'keyup',ajax_qsearch.call); + +  // attach eventhandler to output field +  addEvent(ajax_qsearch.outObj,'click',function(){ ajax_qsearch.outObj.style.display='none'; }); +}; + +ajax_qsearch.clear = function(){ +  ajax_qsearch.outObj.style.display = 'none'; +  ajax_qsearch.outObj.innerHTML = ''; +  if(ajax_qsearch.timer !== null){ +    window.clearTimeout(ajax_qsearch.timer); +    ajax_qsearch.timer = null; +  } +}; + +ajax_qsearch.exec = function(){ +  ajax_qsearch.clear(); +  var value = ajax_qsearch.inObj.value; +  if(value === ''){ return; } +  ajax_qsearch.sack.runAJAX('call=qsearch&q='+encodeURI(value)); +}; + +ajax_qsearch.sack.onCompletion = function(){ +  var data = ajax_qsearch.sack.response; +  if(data === ''){ return; } + +  ajax_qsearch.outObj.innerHTML = data; +  ajax_qsearch.outObj.style.display = 'block'; +}; + +ajax_qsearch.call = function(){ +  ajax_qsearch.clear(); +  ajax_qsearch.timer = window.setTimeout("ajax_qsearch.exec()",500); +}; + diff --git a/vendors/dokuwiki/lib/scripts/cookie.js b/vendors/dokuwiki/lib/scripts/cookie.js new file mode 100644 index 000000000..d7e6b3550 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/cookie.js @@ -0,0 +1,112 @@ +/** + * Handles the cookie used by several JavaScript functions + * + * Only a single cookie is written and read. You may only save + * sime name-value pairs - no complex types! + * + * You should only use the getValue and setValue methods + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +DokuCookie = { +    data: Array(), +    name: 'DOKU_PREFS', + +    /** +     * Save a value to the cookie +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    setValue: function(key,val){ +        DokuCookie.init(); +        DokuCookie.data[key] = val; + +        // prepare expire date +        var now = new Date(); +        DokuCookie.fixDate(now); +        now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000); //expire in a year + +        //save the whole data array +        var text = ''; +        for(var key in DokuCookie.data){ +            if (!DokuCookie.data.hasOwnProperty(key)) continue; +            text += '#'+escape(key)+'#'+DokuCookie.data[key]; +        } +        DokuCookie.setCookie(DokuCookie.name,text.substr(1),now,DOKU_BASE); +    }, + +    /** +     * Get a Value from the Cookie +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    getValue: function(key){ +        DokuCookie.init(); +        return DokuCookie.data[key]; +    }, + +    /** +     * Loads the current set cookie +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    init: function(){ +        if(DokuCookie.data.length) return; +        var text  = DokuCookie.getCookie(DokuCookie.name); +        if(text){ +            var parts = text.split('#'); +            for(var i=0; i<parts.length; i+=2){ +                DokuCookie.data[unescape(parts[i])] = unescape(parts[i+1]); +            } +        } +    }, + +    /** +     * This sets a cookie by JavaScript +     * +     * @link http://www.webreference.com/js/column8/functions.html +     */ +    setCookie: function(name, value, expires, path, domain, secure) { +        var curCookie = name + "=" + escape(value) + +            ((expires) ? "; expires=" + expires.toGMTString() : "") + +            ((path) ? "; path=" + path : "") + +            ((domain) ? "; domain=" + domain : "") + +            ((secure) ? "; secure" : ""); +        document.cookie = curCookie; +    }, + +    /** +     * This reads a cookie by JavaScript +     * +     * @link http://www.webreference.com/js/column8/functions.html +     */ +    getCookie: function(name) { +        var dc = document.cookie; +        var prefix = name + "="; +        var begin = dc.indexOf("; " + prefix); +        if (begin == -1) { +            begin = dc.indexOf(prefix); +            if (begin !== 0){ return null; } +        } else { +            begin += 2; +        } +        var end = document.cookie.indexOf(";", begin); +        if (end == -1){ +            end = dc.length; +        } +        return unescape(dc.substring(begin + prefix.length, end)); +    }, + +    /** +     * This is needed for the cookie functions +     * +     * @link http://www.webreference.com/js/column8/functions.html +     */ +    fixDate: function(date) { +        var base = new Date(0); +        var skew = base.getTime(); +        if (skew > 0){ +            date.setTime(date.getTime() - skew); +        } +    } +}; diff --git a/vendors/dokuwiki/lib/scripts/drag.js b/vendors/dokuwiki/lib/scripts/drag.js new file mode 100644 index 000000000..908ab670c --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/drag.js @@ -0,0 +1,99 @@ +/** + * Makes a DOM object draggable + * + * This is currently for movable DOM dialogs only. If needed it could be + * extended to execute callbacks on special events... + * + * @link http://nofunc.org/Drag_Drop/ + */ +var drag = { +    obj: null, +    handle: null, +    oX: 0,  // object X position +    oY: 0,  // object Y position +    eX: 0,  // event X delta +    eY: 0,  // event Y delta + +    /** +     * Attaches the needed handlers to the given object +     * +     * This can be called for multiple objects, the right one is later +     * determined from the event itself. The handle is optional +     * +     * @param DOMObject obj    The object that should be draggable +     * @param DOMObject handle A handle on which the obj can be dragged +     */ +    attach: function (obj,handle) { +        if(handle){ +            handle.dragobject = obj; +            addEvent(DOKUid(handle),'mousedown',drag.start); +        }else{ +            addEvent(DOKUid(obj),'mousedown',drag.start); +        } +    }, + +    /** +     * Starts the dragging operation +     */ +    start: function (e){ +        drag.handle = e.target; +        if(drag.handle.dragobject){ +            drag.obj = drag.handle.dragobject; +        }else{ +            drag.obj = drag.handle; +        } + +        drag.handle.className += ' ondrag'; +        drag.obj.className    += ' ondrag'; + +        drag.oX = parseInt(drag.obj.style.left); +        drag.oY = parseInt(drag.obj.style.top); +        drag.eX = drag.evX(e); +        drag.eY = drag.evY(e); + +        addEvent(document,'mousemove',drag.drag); +        addEvent(document,'mouseup',drag.stop); + +        e.preventDefault(); +        e.stopPropagation(); +        return false; +    }, + +    /** +     * Ends the dragging operation +     */ +    stop: function(){ +        drag.handle.className = drag.handle.className.replace(/ ?ondrag/,''); +        drag.obj.className    = drag.obj.className.replace(/ ?ondrag/,''); +        removeEvent(document,'mousemove',drag.drag); +        removeEvent(document,'mouseup',drag.stop); +        drag.obj = null; +        drag.handle = null; +    }, + +    /** +     * Moves the object during the dragging operation +     */ +    drag: function(e) { +        if(drag.obj) { +            drag.obj.style.top  = (drag.evY(e)+drag.oY-drag.eY+'px'); +            drag.obj.style.left = (drag.evX(e)+drag.oX-drag.eX+'px'); +        } +    }, + +    /** +     * Returns the X position of the given event. +     */ +    evX: function(e){ +        return (e.pageX) ? e.pageX : e.clientX + document.body.scrollTop; //fixme shouldn't this be scrollLeft? +    }, + +    /** +     * Returns the Y position of the given event. +     */ +    evY: function(e){ +        return (e.pageY) ? e.pageY : e.clientY + document.body.scrollTop; +    } + +}; + diff --git a/vendors/dokuwiki/lib/scripts/edit.js b/vendors/dokuwiki/lib/scripts/edit.js new file mode 100644 index 000000000..6494a925f --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/edit.js @@ -0,0 +1,442 @@ +/** + * 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 + * + * Style the buttons through the toolbutton class + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function createToolButton(icon,label,key,id){ +    var btn = document.createElement('button'); +    var ico = document.createElement('img'); + +    // preapare the basic button stuff +    btn.className = 'toolbutton'; +    btn.title = label; +    if(key){ +        btn.title += ' ['+key.toUpperCase()+']'; +        btn.accessKey = key; +    } + +    // set IDs if given +    if(id){ +        btn.id = id; +        ico.id = id+'_ico'; +    } + +    // create the icon and add it to the button +    if(icon.substr(0,1) == '/'){ +        ico.src = icon; +    }else{ +        ico.src = DOKU_MEDIA+'lib/images/toolbar/'+icon; +    } +    btn.appendChild(ico); + +    return btn; +} + +/** + * 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 + * @rteurn DOMobject    the created picker + * @author Andreas Gohr <andi@splitbrain.org> + */ +function createPicker(id,props,edid){ +    var icobase = props['icobase']; +    var list    = props['list']; + +    // create the wrapping div +    var picker            = document.createElement('div'); +    picker.className      = 'picker'; +    if(props['class']){ +        picker.className += ' '+props['class']; +    } +    picker.id               = id; +    picker.style.position   = 'absolute'; +    picker.style.marginLeft = '-10000px'; // no display:none, to keep access keys working + +    for(var key in list){ +        if (!list.hasOwnProperty(key)) continue; + +        if(isNaN(key)){ +            // associative array -> treat as image/value pairs +            var btn = document.createElement('button'); +            btn.className = 'pickerbutton'; +            var ico = document.createElement('img'); +            if(list[key].substr(0,1) == '/'){ +                ico.src = list[key]; +            }else{ +                ico.src = DOKU_MEDIA+'lib/images/'+icobase+'/'+list[key]; +            } +            btn.title     = key; +            btn.appendChild(ico); +            addEvent(btn,'click',bind(pickerInsert,key,edid)); +            picker.appendChild(btn); +        }else if(isString(list[key])){ +            // a list of text -> treat as text picker +            var btn = document.createElement('button'); +            btn.className = 'pickerbutton'; +            var txt = document.createTextNode(list[key]); +            btn.title     = list[key]; +            btn.appendChild(txt); +            addEvent(btn,'click',bind(pickerInsert,list[key],edid)); +            picker.appendChild(btn); +        }else{ +            // a list of lists -> treat it as subtoolbar +            initToolbar(picker,edid,list); +            break; // all buttons handled already +        } + +    } +    var body = document.getElementsByTagName('body')[0]; +    body.appendChild(picker); +    return picker; +} + +/** + * 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  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 Gabriel Birke <birke@d-scribe.de> + */ +function addBtnActionSignature(btn, props, edid) { +    if(typeof(SIG) != 'undefined' && SIG != ''){ +        addEvent(btn,'click',bind(insertAtCarret,edid,SIG)); +        return true; +    } +    return false; +} + +/** + * Make intended formattings easier to handle + * + * Listens to all key inputs and handle indentions + * of lists and code blocks + * + * Currently handles space, backspce and enter presses + * + * @author Andreas Gohr <andi@splitbrain.org> + * @fixme handle tabs + */ +function keyHandler(e){ +    if(e.keyCode != 13 && +       e.keyCode != 8  && +       e.keyCode != 32) return; +    var field     = e.target; +    var selection = getSelection(field); +    var search    = "\n"+field.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){ // Enter +        // keep current indention for lists and code +        var match = search.match(/(\n  +([\*-] ?)?)/); +        if(match){ +            var scroll = field.scrollHeight; +            insertAtCarret(field.id,match[1]); +            field.scrollTop += (field.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 +                field.value = field.value.substr(0,linestart)+ +                              field.value.substr(linestart+2); +                selection.start = selection.start - 2; +                selection.end   = selection.start; +            }else{ // delete list point +                field.value = field.value.substr(0,linestart)+ +                              field.value.substr(selection.start); +                selection.start = linestart; +                selection.end   = linestart; +            } +            setSelection(selection); +            e.preventDefault(); // prevent backspace +            return false; +        } +    }else if(e.keyCode == 32){ // Space +        // intend list item +        var match = search.match(/(\n  +)([*-] )$/); +        if(match){ +            field.value = field.value.substr(0,linestart)+'  '+ +                          field.value.substr(linestart); +            selection.start = selection.start + 2; +            selection.end   = selection.start; +            setSelection(selection); +            e.preventDefault(); // prevent space +            return false; +        } +    } +} + +//FIXME consolidate somewhere else +addInitEvent(function(){ +    var field = DOKUid('wiki__text'); +    if(!field) return; +    addEvent(field,'keydown',keyHandler); +}); + +/** + * Determine the current section level while editing + * + * @author Andreas Gohr <gohr@cosmocode.de> + */ +function currentHeadlineLevel(textboxId){ +    var field     = DOKUid(textboxId); +    var selection = getSelection(field); +    var search    = "\n"+field.value.substr(0,selection.start); +    var lasthl    = search.lastIndexOf("\n=="); +    if(lasthl == -1 && field.form.prefix){ +        // we need to look in prefix context +        search = field.form.prefix.value; +        lasthl    = search.lastIndexOf("\n=="); +    } +    search    = search.substr(lasthl+1,6); + +    if(search == '======') return 1; +    if(search.substr(0,5) == '=====') return 2; +    if(search.substr(0,4) == '====') return 3; +    if(search.substr(0,3) == '===') return 4; +    if(search.substr(0,2) == '==') return 5; + +    return 0; +} + + +/** + * global var used for not saved yet warning + */ +var textChanged = false; + +/** + * Check for changes before leaving the page + */ +function changeCheck(msg){ +  if(textChanged){ +    var ok = confirm(msg); +    if(ok){ +        // remove a possibly saved draft using ajax +        var dwform = DOKUid('dw__editform'); +        if(dwform){ +            var params = 'call=draftdel'; +            params += '&id='+encodeURIComponent(dwform.elements.id.value); + +            var sackobj = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +            sackobj.AjaxFailedAlert = ''; +            sackobj.encodeURIString = false; +            sackobj.runAJAX(params); +            // we send this request blind without waiting for +            // and handling the returned data +        } +    } +    return ok; +  }else{ +    return true; +  } +} + +/** + * Add changeCheck to all Links and Forms (except those with a + * JSnocheck class), add handlers to monitor changes + * + * Sets focus to the editbox as well + * + * @fixme this is old and crappy code. needs to be redone + */ +function initChangeCheck(msg){ +    var edit_text   = document.getElementById('wiki__text'); +    if(!edit_text) return; +    if(edit_text.readOnly) return; +    if(!DOKUid('dw__editform')) return; + +    // add change check for links +    var links = document.getElementsByTagName('a'); +    for(var i=0; i < links.length; i++){ +        if(links[i].className.indexOf('JSnocheck') == -1){ +            links[i].onclick = function(){ +                                    var rc = changeCheck(msg); +                                    if(window.event) window.event.returnValue = rc; +                                    return rc; +                               }; +        } +    } +    // add change check for forms +    var forms = document.forms; +    for(i=0; i < forms.length; i++){ +        if(forms[i].className.indexOf('JSnocheck') == -1){ +            forms[i].onsubmit = function(){ +                                    var rc = changeCheck(msg); +                                    if(window.event) window.event.returnValue = rc; +                                    return rc; +                               }; +        } +    } + +    // reset change memory var on submit +    var btn_save        = document.getElementById('edbtn__save'); +    btn_save.onclick    = function(){ textChanged = false; }; +    var btn_prev        = document.getElementById('edbtn__preview'); +    btn_prev.onclick    = function(){ textChanged = false; }; + +    // add change memory setter +    edit_text.onchange = function(){ +        textChanged = true; //global var +        summaryCheck(); +    }; +    var summary = document.getElementById('edit__summary'); +    addEvent(summary, 'change', summaryCheck); +    addEvent(summary, 'keyup', summaryCheck); +    if (textChanged) summaryCheck(); + +    // set focus +    edit_text.focus(); +} + +/** + * Checks if a summary was entered - if not the style is changed + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function summaryCheck(){ +    var sum = document.getElementById('edit__summary'); +    if(sum.value === ''){ +        sum.className='missing'; +    }else{ +        sum.className='edit'; +    } +} + + +/** + * Class managing the timer to display a warning on a expiring lock + */ +function locktimer_class(){ +        this.sack     = null; +        this.timeout  = 0; +        this.timerID  = null; +        this.lasttime = null; +        this.msg      = ''; +        this.pageid   = ''; +}; +var locktimer = new locktimer_class(); +    locktimer.init = function(timeout,msg,draft){ +        // init values +        locktimer.timeout  = timeout*1000; +        locktimer.msg      = msg; +        locktimer.draft    = draft; +        locktimer.lasttime = new Date(); + +        if(!DOKUid('dw__editform')) return; +        locktimer.pageid = DOKUid('dw__editform').elements.id.value; +        if(!locktimer.pageid) return; + +        // init ajax component +        locktimer.sack = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +        locktimer.sack.AjaxFailedAlert = ''; +        locktimer.sack.encodeURIString = false; +        locktimer.sack.onCompletion = locktimer.refreshed; + +        // register refresh event +        addEvent(DOKUid('dw__editform').elements.wikitext,'keypress',function(){locktimer.refresh();}); + +        // start timer +        locktimer.reset(); +    }; + +    /** +     * (Re)start the warning timer +     */ +    locktimer.reset = function(){ +        locktimer.clear(); +        locktimer.timerID = window.setTimeout("locktimer.warning()", locktimer.timeout); +    }; + +    /** +     * Display the warning about the expiring lock +     */ +    locktimer.warning = function(){ +        locktimer.clear(); +        alert(locktimer.msg); +    }; + +    /** +     * Remove the current warning timer +     */ +    locktimer.clear = function(){ +        if(locktimer.timerID !== null){ +            window.clearTimeout(locktimer.timerID); +            locktimer.timerID = null; +        } +    }; + +    /** +     * Refresh the lock via AJAX +     * +     * Called on keypresses in the edit area +     */ +    locktimer.refresh = function(){ +        var now = new Date(); +        // refresh every minute only +        if(now.getTime() - locktimer.lasttime.getTime() > 30*1000){ //FIXME decide on time +            var params = 'call=lock&id='+encodeURIComponent(locktimer.pageid); +            if(locktimer.draft){ +                var dwform = DOKUid('dw__editform'); +                params += '&prefix='+encodeURIComponent(dwform.elements.prefix.value); +                params += '&wikitext='+encodeURIComponent(dwform.elements.wikitext.value); +                params += '&suffix='+encodeURIComponent(dwform.elements.suffix.value); +                params += '&date='+encodeURIComponent(dwform.elements.date.value); +            } +            locktimer.sack.runAJAX(params); +            locktimer.lasttime = now; +        } +    }; + + +    /** +     * Callback. Resets the warning timer +     */ +    locktimer.refreshed = function(){ +        var data  = this.response; +        var error = data.charAt(0); +            data  = data.substring(1); + +        DOKUid('draft__status').innerHTML=data; +        if(error != '1') return; // locking failed +        locktimer.reset(); +    }; +// end of locktimer class functions + diff --git a/vendors/dokuwiki/lib/scripts/events.js b/vendors/dokuwiki/lib/scripts/events.js new file mode 100644 index 000000000..e7526ced7 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/events.js @@ -0,0 +1,176 @@ +// written by Dean Edwards, 2005 +// with input from Tino Zijdel + +// http://dean.edwards.name/weblog/2005/10/add-event/ + +function addEvent(element, type, handler) { +    // assign each event handler a unique ID +    if (!handler.$$guid) handler.$$guid = addEvent.guid++; +    // create a hash table of event types for the element +    if (!element.events) element.events = {}; +    // create a hash table of event handlers for each element/event pair +    var handlers = element.events[type]; +    if (!handlers) { +        handlers = element.events[type] = {}; +        // store the existing event handler (if there is one) +        if (element["on" + type]) { +            handlers[0] = element["on" + type]; +        } +    } +    // store the event handler in the hash table +    handlers[handler.$$guid] = handler; +    // assign a global event handler to do all the work +    element["on" + type] = handleEvent; +}; +// a counter used to create unique IDs +addEvent.guid = 1; + +function removeEvent(element, type, handler) { +    // delete the event handler from the hash table +    if (element.events && element.events[type]) { +        delete element.events[type][handler.$$guid]; +    } +}; + +function handleEvent(event) { +    var returnValue = true; +    // grab the event object (IE uses a global event object) +    event = event || fixEvent(window.event); +    // get a reference to the hash table of event handlers +    var handlers = this.events[event.type]; +    // execute each event handler +    for (var i in handlers) { +        if (!handlers.hasOwnProperty(i)) continue; +        this.$$handleEvent = handlers[i]; +        if (this.$$handleEvent(event) === false) { +            returnValue = false; +        } +    } +    return returnValue; +}; + +function fixEvent(event) { +    // add W3C standard event methods +    event.preventDefault = fixEvent.preventDefault; +    event.stopPropagation = fixEvent.stopPropagation; +    // fix target +    event.target = event.srcElement; +    return event; +}; +fixEvent.preventDefault = function() { +    this.returnValue = false; +}; +fixEvent.stopPropagation = function() { +    this.cancelBubble = true; +}; + + +/** + * Pseudo event handler to be fired after the DOM was parsed or + * on window load at last. + * + * @author based upon some code by Dean Edwards + * @author Dean Edwards + * @link   http://dean.edwards.name/weblog/2006/06/again/ + */ +window.fireoninit = function() { +  // quit if this function has already been called +  if (arguments.callee.done) return; +  // flag this function so we don't do the same thing twice +  arguments.callee.done = true; +  // kill the timer +  if (_timer) { +     clearInterval(_timer); +     _timer = null; +  } + +  if (typeof window.oninit == 'function') { +        window.oninit(); +  } +}; + +/** + * Run the fireoninit function as soon as possible after + * the DOM was loaded, using different methods for different + * Browsers + * + * @author Dean Edwards + * @link   http://dean.edwards.name/weblog/2006/06/again/ + */ +  // for Mozilla +  if (document.addEventListener) { +    document.addEventListener("DOMContentLoaded", window.fireoninit, null); +  } + +  // for Internet Explorer (using conditional comments) +  /*@cc_on @*/ +  /*@if (@_win32) +    document.write("<scr" + "ipt id=\"__ie_init\" defer=\"true\" src=\"//:\"><\/script>"); +    var script = document.getElementById("__ie_init"); +    script.onreadystatechange = function() { +        if (this.readyState == "complete") { +            window.fireoninit(); // call the onload handler +        } +    }; +  /*@end @*/ + +  // for Safari +  if (/WebKit/i.test(navigator.userAgent)) { // sniff +    var _timer = setInterval(function() { +        if (/loaded|complete/.test(document.readyState)) { +            window.fireoninit(); // call the onload handler +        } +    }, 10); +  } + +  // for other browsers +  window.onload = window.fireoninit; + + +/** + * This is a pseudo Event that will be fired by the fireoninit + * function above. + * + * Use addInitEvent to bind to this event! + * + * @author Andreas Gohr <andi@splitbrain.org> + * @see fireoninit() + */ +window.oninit = function(){}; + +/** + * Bind a function to the window.init pseudo event + * + * @author Simon Willison + * @see http://simon.incutio.com/archive/2004/05/26/addLoadEvent + */ +function addInitEvent(func) { +  var oldoninit = window.oninit; +  if (typeof window.oninit != 'function') { +    window.oninit = func; +  } else { +    window.oninit = function() { +      oldoninit(); +      func(); +    }; +  } +} + +/** + * 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 args = Array.prototype.slice.call(arguments, 1); +    return function() { +        return fnc.apply(this, args); +    } +} diff --git a/vendors/dokuwiki/lib/scripts/helpers.js b/vendors/dokuwiki/lib/scripts/helpers.js new file mode 100644 index 000000000..8d4f3ea78 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/helpers.js @@ -0,0 +1,146 @@ +/** + * Differrent helper functions + * + * @author Ilya Lebedev <ilya@lebedev.net> + * @license LGPL + */ +//----------------------------------------------------------------------------- +//  Variable/property checks +//----------------------------------------------------------------------------- +/** + *  Checks if property is undefined + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isUndefined (prop /* :Object */) /* :Boolean */ { +  return (typeof prop == 'undefined'); +} +/** + *  Checks if property is function + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isFunction (prop /* :Object */) /* :Boolean */ { +  return (typeof prop == 'function'); +} +/** + *  Checks if property is string + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isString (prop /* :Object */) /* :Boolean */ { +  return (typeof prop == 'string'); +} +/** + *  Checks if property is number + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isNumber (prop /* :Object */) /* :Boolean */ { +  return (typeof prop == 'number'); +} +/** + *  Checks if property is the calculable number + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isNumeric (prop /* :Object */) /* :Boolean */ { +  return isNumber(prop)&&!isNaN(prop)&&isFinite(prop); +} +/** + *  Checks if property is array + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isArray (prop /* :Object */) /* :Boolean */ { +  return (prop instanceof Array); +} +/** + *  Checks if property is regexp + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isRegExp (prop /* :Object */) /* :Boolean */ { +  return (prop instanceof RegExp); +} +/** + *  Checks if property is a boolean value + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isBoolean (prop /* :Object */) /* :Boolean */ { +  return ('boolean' == typeof prop); +} +/** + *  Checks if property is a scalar value (value that could be used as the hash key) + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isScalar (prop /* :Object */) /* :Boolean */ { +  return isNumeric(prop)||isString(prop); +} +/** + *  Checks if property is empty + * + *  @param {Object} prop value to check + *  @return {Boolean} true if matched + *  @scope public + */ +function isEmpty (prop /* :Object */) /* :Boolean */ { +  if (isBoolean(prop)) return false; +  if (isRegExp(prop) && new RegExp("").toString() == prop.toString()) return true; +  if (isString(prop) || isNumber(prop)) return !prop; +  if (Boolean(prop)&&false != prop) { +    for (var i in prop) if(prop.hasOwnProperty(i)) return false +  } +  return true; +} + +/** + *  Checks if property is derived from prototype, applies method if it is not exists + * + *  @param string property name + *  @return bool true if prototyped + *  @access public + */ +if ('undefined' == typeof Object.hasOwnProperty) { +  Object.prototype.hasOwnProperty = function (prop) { +    return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]); +  } +} + +/** + * Very simplistic Flash plugin check, probably works for Flash 8 and higher only + */ +function hasFlash(version){ +    var ver = 0; +    try{ +        if(navigator.plugins != null && navigator.plugins.length > 0){ +           ver = navigator.plugins["Shockwave Flash"].description.split(' ')[2].split('.')[0]; +        }else{ +           var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); +           ver = axo.GetVariable("$version").split(' ')[1].split(',')[0]; +        } +    }catch(e){ } + +    if(ver >= version) return true; +    return false; +} diff --git a/vendors/dokuwiki/lib/scripts/index.html b/vendors/dokuwiki/lib/scripts/index.html new file mode 100644 index 000000000..d614603ac --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" +    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<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> diff --git a/vendors/dokuwiki/lib/scripts/index.js b/vendors/dokuwiki/lib/scripts/index.js new file mode 100644 index 000000000..16b00c0ab --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/index.js @@ -0,0 +1,116 @@ +/** + * Javascript for index view + * + * @author Andreas Gohr <andi@splitbrain.org> + */ + +var index = { + +     /** +     * Delay in ms before showing the throbber. +     * Used to skip the throbber for fast AJAX calls. +     */ +    throbber_delay: 500, + +    /** +     * Attach event handlers to all "folders" below the given element +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    treeattach: function(obj){ +        if(!obj) return; + +        var items = getElementsByClass('idx_dir',obj,'a'); +        for(var i=0; i<items.length; i++){ +            var elem = items[i]; + +            // attach action to make the link clickable by AJAX +            addEvent(elem,'click',function(e){ return index.toggle(e,this); }); + +            // get the listitem the elem belongs to +            var listitem = elem.parentNode; +            while (listitem.tagName != 'LI') { +              listitem = listitem.parentNode; +            } +            //when there are uls under this listitem mark this listitem as opened +            if (listitem.getElementsByTagName('ul').length) { +              listitem.open = true; +            } +        } +    }, + +    /** +     * Open or close a subtree using AJAX +     * The contents of subtrees are "cached" untill 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> +     */ +    toggle: function(e,clicky){ +        var listitem = clicky.parentNode.parentNode; + +        listitem.open = !listitem.open; +        // listitem.open represents now the action to be done + +        // if already open, close by removing the sublist +        var sublists = listitem.getElementsByTagName('ul'); +        if(!listitem.open){ +            if (sublists.length) { +              sublists[0].style.display='none'; +            } +            listitem.className='closed'; +            e.preventDefault(); +            return false; +        } + +        // just show if already loaded +        if(sublists.length && listitem.open){ +            sublists[0].style.display=''; +            listitem.className='open'; +            e.preventDefault(); +            return false; +        } + +        // prepare an AJAX call to fetch the subtree +        var ajax = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +        ajax.AjaxFailedAlert = ''; +        ajax.encodeURIString = false; +        if(ajax.failed) return true; + +        //prepare the new ul +        var ul = document.createElement('ul'); +        ul.className = 'idx'; +        timeout = window.setTimeout(function(){ +            // show the throbber as needed +            if (listitem.open) { +              ul.innerHTML = '<li><img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="loading..." title="loading..." /></li>'; +              listitem.appendChild(ul); +              listitem.className='open'; +            } +        }, this.throbber_delay); +        ajax.elementObj = ul; +        ajax.afterCompletion = function(){ +            window.clearTimeout(timeout); +            index.treeattach(ul); +            if (listitem.className!='open') { +              if (!listitem.open) { +                ul.style.display='none'; +              } +              listitem.appendChild(ul); +              if (listitem.open) { +                listitem.className='open'; +              } +            } +        }; +        ajax.runAJAX(clicky.search.substr(1)+'&call=index'); +        e.preventDefault(); +        return false; +    } +}; + + +addInitEvent(function(){ +    if (DOKUid('index__tree')) + 	   index.treeattach(DOKUid('index__tree')); +}); diff --git a/vendors/dokuwiki/lib/scripts/linkwiz.js b/vendors/dokuwiki/lib/scripts/linkwiz.js new file mode 100644 index 000000000..55469c158 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/linkwiz.js @@ -0,0 +1,282 @@ +/** + * The Link Wizard + * + * @author Andreas Gohr <gohr@cosmocode.de> + */ +var linkwiz = { +    wiz:    null, +    entry:  null, +    result: null, +    timer:  null, +    sack:   null, +    textArea: null, +    selected: -1, +    selection: null, + +    /** +     * Initialize the linkwizard by creating the needed HTML +     * and attaching the eventhandlers +     */ +    init: function(textArea){ +        // prepare AJAX object +        linkwiz.sack = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +        linkwiz.sack.AjaxFailedAlert = ''; +        linkwiz.sack.encodeURIString = false; + +        // create HTML Structure +        linkwiz.wiz = document.createElement('div'); +        linkwiz.wiz.id = 'link__wiz'; +        linkwiz.wiz.className     = 'picker'; +        linkwiz.wiz.style.top  = (findPosY(textArea)+20)+'px'; +        linkwiz.wiz.style.left = (findPosX(textArea)+80)+'px'; +        linkwiz.wiz.style.marginLeft = '-10000px'; + +        linkwiz.wiz.innerHTML = +             '<div id="link__wiz_header">'+ +             '<img src="'+DOKU_BASE+'lib/images/close.png" width="16" height="16" align="right" alt="" id="link__wiz_close" />'+ +             LANG['linkwiz']+'</div>'+ +             '<div>'+LANG['linkto']+' <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+ +             '<div id="link__wiz_result"></div>'; +        textArea.form.parentNode.appendChild(linkwiz.wiz); +        linkwiz.textArea = textArea; +        linkwiz.result = DOKUid('link__wiz_result'); +        linkwiz.entry = DOKUid('link__wiz_entry'); + +        // attach event handlers +        var obj; +        obj = DOKUid('link__wiz_close'); +        obj.onclick = linkwiz.hide; + +        linkwiz.sack.elementObj = linkwiz.result; +        addEvent(linkwiz.entry,'keyup',linkwiz.onEntry); +        addEvent(linkwiz.result,'click',linkwiz.onResultClick); +        drag.attach(linkwiz.wiz,DOKUid('link__wiz_header')); +    }, + +    /** +     * 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){ +            linkwiz.hide(); +            e.preventDefault(); +            e.stopPropagation(); +            return false; +        } +        if(e.keyCode == 38){ //Up +            linkwiz.select(linkwiz.selected -1); +            e.preventDefault(); +            e.stopPropagation(); +            return false; +        } +        if(e.keyCode == 40){ //Down +            linkwiz.select(linkwiz.selected +1); +            e.preventDefault(); +            e.stopPropagation(); +            return false; +        } +        if(e.keyCode == 13){ //Enter +            if(linkwiz.selected > -1){ +                var obj = linkwiz.getResult(linkwiz.selected); +                if(obj){ +                    var a = obj.getElementsByTagName('A')[0]; +                    linkwiz.resultClick(a); +                } +            }else if(linkwiz.entry.value){ +                linkwiz.insertLink(linkwiz.entry.value); +            } + +            e.preventDefault(); +            e.stopPropagation(); +            return false; +        } +        linkwiz.autocomplete(); +    }, + +    /** +     * Get one of the result by index +     * +     * @param int result div to return +     * @returns DOMObject or null +     */ +    getResult: function(num){ +        var obj; +        var childs = linkwiz.result.getElementsByTagName('DIV'); +        obj = childs[num]; +        if(obj){ +            return obj; +        }else{ +            return null; +        } +    }, + +    /** +     * Select the given result +     */ +    select: function(num){ +        if(num < 0){ +            linkwiz.deselect(); +            return; +        } + +        var obj = linkwiz.getResult(num); +        if(obj){ +            linkwiz.deselect(); +            obj.className += ' selected'; + +            // make sure the item is viewable in the scroll view +            // FIXME check IE compatibility +            if(obj.offsetTop > linkwiz.result.scrollTop + linkwiz.result.clientHeight){ +                linkwiz.result.scrollTop += obj.clientHeight; +            }else if(obj.offsetTop - linkwiz.result.clientHeight < linkwiz.result.scrollTop){ // this works but isn't quite right, fixes welcome +                linkwiz.result.scrollTop -= obj.clientHeight; +            } +            // now recheck - if still not in view, the user used the mouse to scroll +            if( (obj.offsetTop > linkwiz.result.scrollTop + linkwiz.result.clientHeight) || +                (obj.offsetTop < linkwiz.result.scrollTop) ){ +                obj.scrollIntoView(); +            } + +            linkwiz.selected = num; +        } +    }, + +    /** +     * deselect a result if any is selected +     */ +    deselect: function(){ +        if(linkwiz.selected > -1){ +            var obj = linkwiz.getResult(linkwiz.selected); +            if(obj){ +                obj.className = obj.className.replace(/ ?selected/,''); +            } +        } +        linkwiz.selected = -1; +    }, + +    /** +     * Handle clicks in the result set an dispatch them to +     * resultClick() +     */ +    onResultClick: function(e){ +        if(e.target.tagName != 'A') return; +        e.stopPropagation(); +        e.preventDefault(); +        linkwiz.resultClick(e.target); +        return false; +    }, + +    /** +     * Handles the "click" on a given result anchor +     */ +    resultClick: function(a){ +        var id = a.title; +        if(id == '' || id.substr(id.length-1) == ':'){ +            linkwiz.entry.value = id; +            linkwiz.autocomplete_exec(); +        }else{ +            linkwiz.entry.value = id; +            if(a.nextSibling && a.nextSibling.tagName == 'SPAN'){ +                linkwiz.insertLink(a.nextSibling.innerHTML); +            }else{ +                linkwiz.insertLink(''); +            } +        } +    }, + +    /** +     * Insert the id currently in the entry box to the textarea, +     * replacing the current selection or at the curso postion. +     * When no selection is available the given title will be used +     * as link title instead +     */ +    insertLink: function(title){ +        if(!linkwiz.entry.value) return; + +        var sel = getSelection(linkwiz.textArea); +        if(sel.start == 0 && sel.end == 0) sel = linkwiz.selection; + +        var stxt = sel.getText(); +        if(!stxt && !DOKU_UHC) stxt=title; + +        // prepend colon inside namespaces for non namespace pages +        if(linkwiz.textArea.form['id'].value.indexOf(':') != -1 && +           linkwiz.entry.value.indexOf(':') == -1){ +            linkwiz.entry.value = ':'+linkwiz.entry.value; +        } + +        var link = '[['+linkwiz.entry.value+'|'; +        if(stxt) link += stxt; +        link += ']]'; + +        var so = linkwiz.entry.value.length+3; +        var eo = 2; + +        pasteText(sel,link,{startofs: so, endofs: eo}); +        linkwiz.hide(); +    }, + +    /** +     * Start the page/namespace lookup timer +     * +     * Calls autocomplete_exec when the timer runs out +     */ +    autocomplete: function(){ +        if(linkwiz.timer !== null){ +            window.clearTimeout(linkwiz.timer); +            linkwiz.timer = null; +        } + +        linkwiz.timer = window.setTimeout(linkwiz.autocomplete_exec,350); +    }, + +    /** +     * Executes the AJAX call for the page/namespace lookup +     */ +    autocomplete_exec: function(){ +        linkwiz.deselect(); +        linkwiz.result.innerHTML = '<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />'; +        linkwiz.sack.runAJAX('call=linkwiz&q='+encodeURI(linkwiz.entry.value)); +    }, + +    /** +     * Clears the result area +     */ +    clear: function(){ +        linkwiz.result.innerHTML = 'Search for a matching page name above, or browse through the pages on the right'; +        linkwiz.entry.value = ''; +    }, + +    /** +     * Show the linkwizard +     */ +    show: function(){ +        linkwiz.selection  = getSelection(linkwiz.textArea); +        linkwiz.wiz.style.marginLeft = '0px'; +        linkwiz.entry.focus(); +        linkwiz.autocomplete(); +    }, + +    /** +     * Hide the link wizard +     */ +    hide: function(){ +        linkwiz.wiz.style.marginLeft = '-10000px'; +        linkwiz.textArea.focus(); +    }, + +    /** +     * Toggle the link wizard +     */ +    toggle: function(){ +        if(linkwiz.wiz.style.marginLeft == '-10000px'){ +            linkwiz.show(); +        }else{ +            linkwiz.hide(); +        } +    } +}; + diff --git a/vendors/dokuwiki/lib/scripts/media.js b/vendors/dokuwiki/lib/scripts/media.js new file mode 100644 index 000000000..598fb61f4 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/media.js @@ -0,0 +1,351 @@ +/** + * JavaScript functionalitiy for the media management popup + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +var media_manager = { +    keepopen: false, +    hide: false, + +    /** +     * Attach event handlers to all "folders" below the given element +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    treeattach: function(obj){ +        if(!obj) return; +        var items = obj.getElementsByTagName('li'); +        for(var i=0; i<items.length; i++){ +            var elem = items[i]; + +            // attach action to make the +/- clickable +            var clicky = elem.getElementsByTagName('img')[0]; +            clicky.style.cursor = 'pointer'; +            addEvent(clicky,'click',function(event){ return media_manager.toggle(event,this); }); + +            // attach action load folder list via AJAX +            var link = elem.getElementsByTagName('a')[0]; +            link.style.cursor = 'pointer'; +            addEvent(link,'click',function(event){ return media_manager.list(event,this); }); +        } +    }, + +    /** +     * Attach the image selector action to all links below the given element +     * also add the action to autofill the "upload as" field +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    selectorattach: function(obj){ +        if(!obj) return; + +        var items = getElementsByClass('select',obj,'a'); +        for(var i=0; i<items.length; i++){ +            var elem = items[i]; +            elem.style.cursor = 'pointer'; +            addEvent(elem,'click',function(event){ return media_manager.select(event,this); }); +        } + +        // hide syntax example +        items = getElementsByClass('example',obj,'div'); +        for(var i=0; i<items.length; i++){ +            elem = items[i]; +            elem.style.display = 'none'; +        } + +        var file = DOKUid('upload__file'); +        if(!file) return; +        addEvent(file,'change',media_manager.suggest); +    }, + +    /** +     * Attach deletion confirmation dialog to the delete buttons. +     * +     * Michael Klier <chi@chimeric.de> +     */ +    confirmattach: function(obj){ +        if(!obj) return; + +        items = getElementsByClass('btn_media_delete',obj,'a'); +        for(var i=0; i<items.length; i++){ +            var elem = items[i]; +            addEvent(elem,'click',function(e){ +                if(e.target.tagName == 'IMG'){ +                    var name = e.target.parentNode.title; +                }else{ +                    var name = e.target.title; +                } +                if(!confirm(LANG['del_confirm'] + "\n" + name)) { +                    e.preventDefault(); +                    return false; +                } else { +                    return true; +                } +            }); +        } +    }, + +    /** +     * Creates checkboxes for additional options +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    attachoptions: function(obj){ +        if(!obj) return; + +        // keep open +        if(opener){ +            var kobox  = document.createElement('input'); +            kobox.type = 'checkbox'; +            kobox.id   = 'media__keepopen'; +            if(DokuCookie.getValue('keepopen')){ +                kobox.checked  = true; +                kobox.defaultChecked = true; //IE wants this +                media_manager.keepopen = true; +            } +            addEvent(kobox,'click',function(event){ return media_manager.togglekeepopen(event,this); }); + +            var kolbl  = document.createElement('label'); +            kolbl.htmlFor   = 'media__keepopen'; +            kolbl.innerHTML = LANG['keepopen']; + +            var kobr = document.createElement('br'); + +            obj.appendChild(kobox); +            obj.appendChild(kolbl); +            obj.appendChild(kobr); +        } + +        // hide details +        var hdbox  = document.createElement('input'); +        hdbox.type = 'checkbox'; +        hdbox.id   = 'media__hide'; +        if(DokuCookie.getValue('hide')){ +            hdbox.checked = true; +            hdbox.defaultChecked = true; //IE wants this +            media_manager.hide    = true; +        } +        addEvent(hdbox,'click',function(event){ return media_manager.togglehide(event,this); }); + +        var hdlbl  = document.createElement('label'); +        hdlbl.htmlFor   = 'media__hide'; +        hdlbl.innerHTML = LANG['hidedetails']; + +        var hdbr = document.createElement('br'); + +        obj.appendChild(hdbox); +        obj.appendChild(hdlbl); +        obj.appendChild(hdbr); +        media_manager.updatehide(); +    }, + +    /** +     * Opens the searchfield +     * +     * @author Tobias Sarnowski <sarnowski@cosmocode.de> +     */ +    showsearchfield: function(event,link){ +        // prepare an AJAX call to fetch the search +        var ajax = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +        ajax.AjaxFailedAlert = ''; +        ajax.encodeURIString = false; +        if(ajax.failed) return true; + +        cleanMsgArea(); + +        var content = DOKUid('media__content'); +        content.innerHTML = '<img src="'+DOKU_MEDIA+'lib/images/loading.gif" alt="..." class="load" />'; + +        ajax.elementObj = content; +        ajax.afterCompletion = function(){ +            media_manager.selectorattach(content); +            media_manager.confirmattach(content); +            media_manager.updatehide(); +        }; +        ajax.runAJAX(link.search.substr(1)+'&call=mediasearchlist'); +        return false; +    }, + +    /** +     * Toggles the keep open state +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    togglekeepopen: function(event,cb){ +        if(cb.checked){ +            DokuCookie.setValue('keepopen',1); +            media_manager.keepopen = true; +        }else{ +            DokuCookie.setValue('keepopen',''); +            media_manager.keepopen = false; +        } +    }, + +    /** +     * Toggles the hide details state +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    togglehide: function(event,cb){ +        if(cb.checked){ +            DokuCookie.setValue('hide',1); +            media_manager.hide = true; +        }else{ +            DokuCookie.setValue('hide',''); +            media_manager.hide = false; +        } +        media_manager.updatehide(); +    }, + +    /** +     * Sets the visibility of the image details accordingly to the +     * chosen hide state +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    updatehide: function(){ +        var obj = DOKUid('media__content'); +        if(!obj) return; +        var details = getElementsByClass('detail',obj,'div'); +        for(var i=0; i<details.length; i++){ +            if(media_manager.hide){ +                details[i].style.display = 'none'; +            }else{ +                details[i].style.display = ''; +            } +        } +    }, + +    /** +     * Insert the clicked image into the opener's textarea +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    select: function(event,link){ +        var id = link.name.substr(2); + +        if(!opener){ +            // if we don't run in popup display example +            var ex = DOKUid('ex_'+id.replace(/:/g,'_')); +            if(ex.style.display == ''){ +                ex.style.display = 'none'; +            }else{ +                ex.style.display = ''; +            } +            return false; +        } +        opener.insertTags('wiki__text','{{'+id+'|','}}',''); + +        if(!media_manager.keepopen) window.close(); +        opener.focus(); +        return false; +    }, + +    /** +     * list the content of a namespace using AJAX +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    list: function(event,link){ +        // prepare an AJAX call to fetch the subtree +        var ajax = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +        ajax.AjaxFailedAlert = ''; +        ajax.encodeURIString = false; +        if(ajax.failed) return true; + +        cleanMsgArea(); + +        var content = DOKUid('media__content'); +        content.innerHTML = '<img src="'+DOKU_MEDIA+'lib/images/loading.gif" alt="..." class="load" />'; + +        ajax.elementObj = content; +        ajax.afterCompletion = function(){ +            media_manager.selectorattach(content); +            media_manager.confirmattach(content); +            media_manager.updatehide(); +            media_manager.initFlashUpload(); +        }; +        ajax.runAJAX(link.search.substr(1)+'&call=medialist'); +        return false; +    }, + + +    /** +     * Open or close a subtree using AJAX +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    toggle: function(event,clicky){ +        var listitem = clicky.parentNode; + +        // if already open, close by removing the sublist +        var sublists = listitem.getElementsByTagName('ul'); +        if(sublists.length){ +            listitem.removeChild(sublists[0]); +            clicky.src = DOKU_MEDIA+'lib/images/plus.gif'; +            return false; +        } + +        // get the enclosed link (is always the first one) +        var link = listitem.getElementsByTagName('a')[0]; + +        // prepare an AJAX call to fetch the subtree +        var ajax = new sack(DOKU_BASE + 'lib/exe/ajax.php'); +        ajax.AjaxFailedAlert = ''; +        ajax.encodeURIString = false; +        if(ajax.failed) return true; + +        //prepare the new ul +        var ul = document.createElement('ul'); +        //fixme add classname here +        listitem.appendChild(ul); +        ajax.elementObj = ul; +        ajax.afterCompletion = function(){ media_manager.treeattach(ul); }; +        ajax.runAJAX(link.search.substr(1)+'&call=medians'); +        clicky.src = DOKU_MEDIA+'lib/images/minus.gif'; +        return false; +    }, + +    /** +     * Prefills the wikiname. +     * +     * @author Andreas Gohr <andi@splitbrain.org> +     */ +    suggest: function(){ +        var file = DOKUid('upload__file'); +        var name = DOKUid('upload__name'); +        if(!file || !name) return; + +        var text = file.value; +        text = text.substr(text.lastIndexOf('/')+1); +        text = text.substr(text.lastIndexOf('\\')+1); +        name.value = text; +    }, + + +    initFlashUpload: function(){ +        if(!hasFlash(8)) return; +        var oform  = DOKUid('dw__upload'); +        var oflash = DOKUid('dw__flashupload'); +        if(!oform || !oflash) return; + +        var clicky = document.createElement('img'); +        clicky.src     = DOKU_MEDIA+'lib/images/multiupload.png'; +        clicky.title   = LANG['mu_btn']; +        clicky.alt     = LANG['mu_btn']; +        clicky.style.cursor = 'pointer'; +        clicky.onclick = function(){ +                            oform.style.display  = 'none'; +                            oflash.style.display = ''; +                         }; +        oform.appendChild(clicky); +    } +}; + +addInitEvent(function(){ +    media_manager.treeattach(DOKUid('media__tree')); +    media_manager.selectorattach(DOKUid('media__content')); +    media_manager.confirmattach(DOKUid('media__content')); +    media_manager.attachoptions(DOKUid('media__opts')); +    media_manager.initFlashUpload(); +}); diff --git a/vendors/dokuwiki/lib/scripts/pngbehavior.htc b/vendors/dokuwiki/lib/scripts/pngbehavior.htc new file mode 100644 index 000000000..d1db8e765 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/pngbehavior.htc @@ -0,0 +1,53 @@ +// this is an ugly fix to make Internet Explorer work with transparent +// PNG images - do your self a favour and use a real browser! + +<public:component> +<public:attach event="onpropertychange" onevent="propertyChanged()" /> +<script> + +var supported = /MSIE (5\.5)|[6789]/.test(navigator.userAgent) && navigator.platform == "Win32"; +var realSrc; +var blankSrc = DOKU_BASE+"lib/images/blank.gif"; + +if (supported) fixImage(); + +function propertyChanged() { +   if (!supported) return; + +   var pName = event.propertyName; +   if (pName != "src") return; +   // if not set to blank +   if ( ! new RegExp(blankSrc).test(src)) +      fixImage(); +}; + +function fixImage() { +   // get src +   var src = element.src; + +   // check for real change +   if (src == realSrc) { +      element.src = blankSrc; +      return; +   } + +   if ( ! new RegExp(blankSrc).test(src)) { +      // backup old src +      realSrc = src; +   } + +   // test for png +   if ( /\.png$/.test( realSrc.toLowerCase() ) ) { +      // set blank image +      element.src = blankSrc; +      // set filter +      element.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "',sizingMethod='scale')"; +   } +   else { +      // remove filter +      element.runtimeStyle.filter = ""; +   } +} + +</script> +</public:component> diff --git a/vendors/dokuwiki/lib/scripts/script.js b/vendors/dokuwiki/lib/scripts/script.js new file mode 100644 index 000000000..491794f13 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/script.js @@ -0,0 +1,561 @@ +/** + * Some of these scripts were taken from wikipedia.org and were modified for DokuWiki + */ + +/** + * 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); +} + +/** + * Handy shortcut to document.getElementById + * + * This function was taken from the prototype library + * + * @link http://prototype.conio.net/ + */ +function DOKUid() { +  var elements = new Array(); + +  for (var i = 0; i < arguments.length; i++) { +    var element = arguments[i]; +    if (typeof element == 'string') +      element = document.getElementById(element); + +    if (arguments.length == 1) +      return element; + +    elements.push(element); +  } + +  return elements; +} + +/** + * Simple function to check if a global var is defined + * + * @author Kae Verens + * @link http://verens.com/archives/2005/07/25/isset-for-javascript/#comment-2835 + */ +function isset(varname){ +  return(typeof(window[varname])!='undefined'); +} + +/** + * Select elements by their class name + * + * @author Dustin Diaz <dustin [at] dustindiaz [dot] com> + * @link   http://www.dustindiaz.com/getelementsbyclass/ + */ +function getElementsByClass(searchClass,node,tag) { +    var classElements = new Array(); +    if ( node == null ) +        node = document; +    if ( tag == null ) +        tag = '*'; +    var els = node.getElementsByTagName(tag); +    var elsLen = els.length; +    var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)"); +    for (var i = 0, j = 0; i < elsLen; i++) { +        if ( pattern.test(els[i].className) ) { +            classElements[j] = els[i]; +            j++; +        } +    } +    return classElements; +} + +/** + * Get the X offset of the top left corner of the given object + * + * @link http://www.quirksmode.org/index.html?/js/findpos.html + */ +function findPosX(object){ +  var curleft = 0; +  var obj = DOKUid(object); +  if (obj.offsetParent){ +    while (obj.offsetParent){ +      curleft += obj.offsetLeft; +      obj = obj.offsetParent; +    } +  } +  else if (obj.x){ +    curleft += obj.x; +  } +  return curleft; +} //end findPosX function + +/** + * Get the Y offset of the top left corner of the given object + * + * @link http://www.quirksmode.org/index.html?/js/findpos.html + */ +function findPosY(object){ +  var curtop = 0; +  var obj = DOKUid(object); +  if (obj.offsetParent){ +    while (obj.offsetParent){ +      curtop += obj.offsetTop; +      obj = obj.offsetParent; +    } +  } +  else if (obj.y){ +    curtop += obj.y; +  } +  return curtop; +} //end findPosY function + +/** + * Escape special chars in JavaScript + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function jsEscape(text){ +    var re=new RegExp("\\\\","g"); +    text=text.replace(re,"\\\\"); +    re=new RegExp("'","g"); +    text=text.replace(re,"\\'"); +    re=new RegExp('"',"g"); +    text=text.replace(re,'"'); +    re=new RegExp("\\\\\\\\n","g"); +    text=text.replace(re,"\\n"); +    return text; +} + +/** + * This function escapes some special chars + * @deprecated by above function + */ +function escapeQuotes(text) { +  var re=new RegExp("'","g"); +  text=text.replace(re,"\\'"); +  re=new RegExp('"',"g"); +  text=text.replace(re,'"'); +  re=new RegExp("\\n","g"); +  text=text.replace(re,"\\n"); +  return text; +} + +/** + * Adds a node as the first childenode to the given parent + * + * @see appendChild() + */ +function prependChild(parent,element) { +    if(!parent.firstChild){ +        parent.appendChild(element); +    }else{ +        parent.insertBefore(element,parent.firstChild); +    } +} + +/** + * Prints a animated gif to show the search is performed + * + * Because we need to modify the DOM here before the document is loaded + * and parsed completely we have to rely on document.write() + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function showLoadBar(){ + +  document.write('<img src="'+DOKU_MEDIA+'lib/images/loading.gif" '+ +                 'width="150" height="12" alt="..." />'); + +  /* this does not work reliable in IE +  obj = DOKUid(id); + +  if(obj){ +    obj.innerHTML = '<img src="'+DOKU_BASE+'lib/images/loading.gif" '+ +                    'width="150" height="12" alt="..." />'; +    obj.style.display="block"; +  } +  */ +} + +/** + * Disables the animated gif to show the search is done + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function hideLoadBar(id){ +  obj = DOKUid(id); +  if(obj) obj.style.display="none"; +} + +/** + * Adds the toggle switch to the TOC + */ +function addTocToggle() { +    if(!document.getElementById) return; +    var header = DOKUid('toc__header'); +    if(!header) return; +    var toc = DOKUid('toc__inside'); + +    var obj          = document.createElement('span'); +    obj.id           = 'toc__toggle'; +    obj.style.cursor = 'pointer'; +    if (toc && toc.style.display == 'none') { +        obj.innerHTML    = '<span>+</span>'; +        obj.className    = 'toc_open'; +    } else { +        obj.innerHTML    = '<span>−</span>'; +        obj.className    = 'toc_close'; +    } + +    prependChild(header,obj); +    obj.parentNode.onclick = toggleToc; +    try { +       obj.parentNode.style.cursor = 'pointer'; +       obj.parentNode.style.cursor = 'hand'; +    }catch(e){} +} + +/** + * This toggles the visibility of the Table of Contents + */ +function toggleToc() { +  var toc = DOKUid('toc__inside'); +  var obj = DOKUid('toc__toggle'); +  if(toc.style.display == 'none') { +    toc.style.display   = ''; +    obj.innerHTML       = '<span>−</span>'; +    obj.className       = 'toc_close'; +  } else { +    toc.style.display   = 'none'; +    obj.innerHTML       = '<span>+</span>'; +    obj.className       = 'toc_open'; +  } +} + +/** + * Display an insitu footnote popup + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Chris Smith <chris@jalakai.co.uk> + */ +function footnote(e){ +    var obj = e.target; +    var id = obj.id.substr(5); + +    // get or create the footnote popup div +    var fndiv = DOKUid('insitu__fn'); +    if(!fndiv){ +        fndiv = document.createElement('div'); +        fndiv.id        = 'insitu__fn'; +        fndiv.className = 'insitu-footnote JSpopup dokuwiki'; + +        // autoclose on mouseout - ignoring bubbled up events +        addEvent(fndiv,'mouseout',function(e){ +            if(e.target != fndiv){ +                e.stopPropagation(); +                return; +            } +            // check if the element was really left +            if(e.pageX){        // Mozilla +                var bx1 = findPosX(fndiv); +                var bx2 = bx1 + fndiv.offsetWidth; +                var by1 = findPosY(fndiv); +                var by2 = by1 + fndiv.offsetHeight; +                var x = e.pageX; +                var y = e.pageY; +                if(x > bx1 && x < bx2 && y > by1 && y < by2){ +                    // we're still inside boundaries +                    e.stopPropagation(); +                    return; +                } +            }else{              // IE +                if(e.offsetX > 0 && e.offsetX < fndiv.offsetWidth-1 && +                   e.offsetY > 0 && e.offsetY < fndiv.offsetHeight-1){ +                    // we're still inside boundaries +                    e.stopPropagation(); +                    return; +                } +            } +            // okay, hide it +            fndiv.style.display='none'; +        }); +        document.body.appendChild(fndiv); +    } + +    // locate the footnote anchor element +    var a = DOKUid( "fn__"+id ); +    if (!a){ return; } + +    // anchor parent is the footnote container, get its innerHTML +    var content = new String (a.parentNode.parentNode.innerHTML); + +    // strip the leading content anchors and their comma separators +    content = content.replace(/<sup>.*<\/sup>/gi, ''); +    content = content.replace(/^\s+(,\s+)+/,''); + +    // prefix ids on any elements with "insitu__" to ensure they remain unique +    content = content.replace(/\bid=\"(.*?)\"/gi,'id="insitu__$1'); + +    // now put the content into the wrapper +    fndiv.innerHTML = content; + +    // position the div and make it visible +    var x; var y; +    if(e.pageX){        // Mozilla +        x = e.pageX; +        y = e.pageY; +    }else{              // IE +        x = e.offsetX; +        y = e.offsetY; +    } +    fndiv.style.position = 'absolute'; +    fndiv.style.left = (x+2)+'px'; +    fndiv.style.top  = (y+2)+'px'; +    fndiv.style.display = ''; +} + +/** + * Add the event handlers to footnotes + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +addInitEvent(function(){ +    var elems = getElementsByClass('fn_top',null,'a'); +    for(var i=0; i<elems.length; i++){ +        addEvent(elems[i],'mouseover',function(e){footnote(e);}); +    } +}); + +/** + * Add the edit window size controls + */ +function initSizeCtl(ctlid,edid){ +    if(!document.getElementById){ return; } + +    var ctl      = DOKUid(ctlid); +    var textarea = DOKUid(edid); +    if(!ctl || !textarea) return; + +    var hgt = DokuCookie.getValue('sizeCtl'); +    if(hgt){ +      textarea.style.height = hgt; +    }else{ +      textarea.style.height = '300px'; +    } + +    var wrp = DokuCookie.getValue('wrapCtl'); +    if(wrp){ +      setWrap(textarea, wrp); +    } // else use default value + +    var l = document.createElement('img'); +    var s = document.createElement('img'); +    var w = document.createElement('img'); +    l.src = DOKU_MEDIA+'lib/images/larger.gif'; +    s.src = DOKU_MEDIA+'lib/images/smaller.gif'; +    w.src = DOKU_MEDIA+'lib/images/wrap.gif'; +    addEvent(l,'click',function(){sizeCtl(edid,100);}); +    addEvent(s,'click',function(){sizeCtl(edid,-100);}); +    addEvent(w,'click',function(){toggleWrap(edid);}); +    ctl.appendChild(l); +    ctl.appendChild(s); +    ctl.appendChild(w); +} + +/** + * This sets the vertical size of the editbox + */ +function sizeCtl(edid,val){ +  var textarea = DOKUid(edid); +  var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2)); +  height += val; +  textarea.style.height = height+'px'; + +  DokuCookie.setValue('sizeCtl',textarea.style.height); +} + +/** + * Toggle the wrapping mode of a textarea + */ +function toggleWrap(edid){ +    var textarea = DOKUid(edid); +    var wrap = textarea.getAttribute('wrap'); +    if(wrap && wrap.toLowerCase() == 'off'){ +        setWrap(textarea, 'soft'); +    }else{ +        setWrap(textarea, 'off'); +    } + +    DokuCookie.setValue('wrapCtl',textarea.getAttribute('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 + */ +function setWrap(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); +} + +/** + * Handler to close all open Popups + */ +function closePopups(){ +  if(!document.getElementById){ return; } + +  var divs = document.getElementsByTagName('div'); +  for(var i=0; i < divs.length; i++){ +    if(divs[i].className.indexOf('JSpopup') != -1){ +            divs[i].style.display = 'none'; +    } +  } +} + +/** + * Looks for an element with the ID scroll__here at scrolls to it + */ +function scrollToMarker(){ +    var obj = DOKUid('scroll__here'); +    if(obj) obj.scrollIntoView(); +} + +/** + * Looks for an element with the ID focus__this at sets focus to it + */ +function focusMarker(){ +    var obj = DOKUid('focus__this'); +    if(obj) obj.focus(); +} + +/** + * Remove messages + */ +function cleanMsgArea(){ +    var elems = getElementsByClass('(success|info|error)',document,'div'); +    if(elems){ +        for(var i=0; i<elems.length; i++){ +            elems[i].style.display = 'none'; +        } +    } +} + +/** + * disable multiple revisions checkboxes if two are checked + * + * @author Anika Henke <anika@selfthinker.org> + */ +addInitEvent(function(){ +    var revForm = DOKUid('page__revisions'); +    if (!revForm) return; +    var elems = revForm.elements; +    var countTicks = 0; +    for (var i=0; i<elems.length; i++) { +        var input1 = elems[i]; +        if (input1.type=='checkbox') { +            addEvent(input1,'click',function(e){ +                if (this.checked) countTicks++; +                else countTicks--; +                for (var j=0; j<elems.length; j++) { +                    var input2 = elems[j]; +                    if (countTicks >= 2) input2.disabled = (input2.type=='checkbox' && !input2.checked); +                    else input2.disabled = (input2.type!='checkbox'); +                } +            }); +            input1.checked = false; // chrome reselects on back button which messes up the logic +        } else if(input1.type=='submit'){ +            input1.disabled = true; +        } +    } +}); + +/** + * Add the event handler to the actiondropdown + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +addInitEvent(function(){ +    var selector = DOKUid('action__selector'); +    if(!selector) return; + +    addEvent(selector,'change',function(e){ +        this.form.submit(); +    }); + +    DOKUid('action__selectorbtn').style.display = 'none'; +}); + +/** + * Display error for Windows Shares on browsers other than IE + * + * @author Michael Klier <chi@chimeric.de> + */ +function checkWindowsShares() { +    if(!LANG['nosmblinks']) return true; +    var elems = getElementsByClass('windows',document,'a'); +    if(elems){ +        for(var i=0; i<elems.length; i++){ +            var share = elems[i]; +            addEvent(share,'click',function(){ +                if(document.all == null) { +                    alert(LANG['nosmblinks']); +                } +            }); +        } +    } +} + +/** + * Add the event handler for the Windows Shares check + * + * @author Michael Klier <chi@chimeric.de> + */ +addInitEvent(function(){ +    checkWindowsShares(); +}); + +/** + * Highlight the section when hovering over the appropriate section edit button + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +addInitEvent(function(){ +    var break_classes = new RegExp('secedit|toc|page'); +    var btns = getElementsByClass('btn_secedit',document,'form'); +    for(var i=0; i<btns.length; i++){ +        addEvent(btns[i],'mouseover',function(e){ +            var tgt = e.target; +            if(tgt.form) tgt = tgt.form; +            tgt = tgt.parentNode.previousSibling; +            if(tgt.nodeName != "DIV") tgt = tgt.previousSibling; +            while(!break_classes.test(tgt.className)) { +                tgt.className += ' section_highlight'; +                if (tgt.tagName == 'H1') break; +                tgt = (tgt.previousSibling != null) ? tgt.previousSibling : tgt.parentNode; +            } +        }); + +        addEvent(btns[i],'mouseout',function(e){ +            var secs = getElementsByClass('section_highlight'); +            for(var j=0; j<secs.length; j++){ +                secs[j].className = secs[j].className.replace(/section_highlight/,''); +            } +            var secs = getElementsByClass('section_highlight'); +        }); +    } +}); diff --git a/vendors/dokuwiki/lib/scripts/textselection.js b/vendors/dokuwiki/lib/scripts/textselection.js new file mode 100644 index 000000000..39dd4cc41 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/textselection.js @@ -0,0 +1,226 @@ +/** + * Text selection related functions. + */ + +/** + * selection prototype + * + * Object that capsulates the selection in a textarea. Returned by getSelection. + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function selection_class(){ +    this.start     = 0; +    this.end       = 0; +    this.obj       = null; +    this.rangeCopy = null; +    this.scroll    = 0; +    this.fix       = 0; + +    this.getLength = function(){ +        return this.end - this.start; +    }; + +    this.getText = function(){ +        if(!this.obj) return ''; +        return 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 getSelection(textArea) { +    var sel = new selection_class(); + +    sel.obj   = textArea; +    sel.start = textArea.value.length; +    sel.end   = textArea.value.length; + +    textArea.focus(); +    if(document.getSelection) {          // Mozilla et al. +        sel.start  = textArea.selectionStart; +        sel.end    = textArea.selectionEnd; +        sel.scroll = textArea.scrollTop; +    } else if(document.selection) {      // MSIE +        /* +         * This huge lump of code is neccessary to work around two MSIE bugs: +         * +         * 1. Selections trim newlines at the end of the code +         * 2. Selections count newlines as two characters +         */ + +        // The current selection +        sel.rangeCopy = document.selection.createRange().duplicate(); + +        var before_range = document.body.createTextRange(); +        before_range.moveToElementText(textArea);                    // Selects all the text +        before_range.setEndPoint("EndToStart", sel.rangeCopy);     // Moves the end where we need it + +        var before_finished = false, selection_finished = false; +        var before_text, selection_text; +        // Load the text values we need to compare +        before_text  = before_range.text; +        selection_text = sel.rangeCopy.text; + +        sel.start = before_text.length; +        sel.end   = sel.start + selection_text.length; + +        // Check each range for trimmed newlines by shrinking the range by 1 character and seeing +        // if the text property has changed.  If it has not changed then we know that IE has trimmed +        // a \r\n from the end. +        do { +            if (!before_finished) { +                if (before_range.compareEndPoints("StartToEnd", before_range) == 0) { +                    before_finished = true; +                } else { +                    before_range.moveEnd("character", -1); +                    if (before_range.text == before_text) { +                        sel.start += 2; +                        sel.end += 2; +                    } else { +                        before_finished = true; +                    } +                } +            } +            if (!selection_finished) { +                if (sel.rangeCopy.compareEndPoints("StartToEnd", sel.rangeCopy) == 0) { +                    selection_finished = true; +                } else { +                    sel.rangeCopy.moveEnd("character", -1); +                    if (sel.rangeCopy.text == selection_text) { +                        sel.end += 2; +                    } else { +                        selection_finished = true; +                    } +                } +            } +        } while ((!before_finished || !selection_finished)); + + +        // count number of newlines in str to work around stupid IE selection bug +        var countNL = function(str) { +            var m = str.split("\r\n"); +            if (!m || !m.length) return 0; +            return m.length-1; +        }; +        sel.fix = countNL(sel.obj.value.substring(0,sel.start)); + +    } +    return sel; +} + +/** + * Set the selection + * + * You need to get a selection object via getSelection() 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 object selection - a selection object as returned by getSelection() + */ +function setSelection(selection){ +    if(document.getSelection){ // FF +        // what a pleasure in FF ;) +        selection.obj.setSelectionRange(selection.start,selection.end); +        if(selection.scroll) selection.obj.scrollTop = selection.scroll; +    } else if(document.selection) { // IE +        selection.rangeCopy.collapse(true); +        selection.rangeCopy.moveStart('character',selection.start - selection.fix); +        selection.rangeCopy.moveEnd('character',selection.end - selection.start); +        selection.rangeCopy.select(); +    } +} + +/** + * 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 objct  selecttion    - selection object returned by getSelection + * @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 bool   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 +    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; + +    setSelection(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 = DOKUid(textAreaID); + +    var selection = getSelection(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 = DOKUid(textAreaID); +    var selection = getSelection(txtarea); +    pasteText(selection,text,{nosel: true}); +} + diff --git a/vendors/dokuwiki/lib/scripts/toolbar.js b/vendors/dokuwiki/lib/scripts/toolbar.js new file mode 100644 index 000000000..d9633ef2d --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/toolbar.js @@ -0,0 +1,252 @@ + +// 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 + * @author Andreas Gohr <andi@splitbrain.org> + */ +function initToolbar(tbid,edid,tb){ +    var toolbar = DOKUid(tbid); +    if(!toolbar) return; +    var edit = DOKUid(edid); +    if(!edit) return; +    if(edit.readOnly) return; + +    //empty the toolbar area: +    toolbar.innerHTML=''; + +    var cnt = tb.length; +    for(var i=0; i<cnt; i++){ +        var actionFunc; + +        // create new button +        var btn = createToolButton(tb[i]['icon'], +                                   tb[i]['title'], +                                   tb[i]['key']); + + +        // type is a tb function -> assign it as onclick +        actionFunc = 'tb_'+tb[i]['type']; +        if( isFunction(window[actionFunc]) ){ +            addEvent(btn,'click', bind(window[actionFunc],btn,tb[i],edid)); +            toolbar.appendChild(btn); +            continue; +        } + +        // type is a init function -> execute it +        actionFunc = 'addBtnAction'+tb[i]['type'].charAt(0).toUpperCase()+tb[i]['type'].substring(1); +        if( isFunction(window[actionFunc]) ){ +            if(window[actionFunc](btn, tb[i], edid)){ +                toolbar.appendChild(btn); +            } +            continue; +        } + +        alert('unknown toolbar type: '+tb[i]['type']+'  '+actionFunc); +    } // end for + +} + +/** + * 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['title']; +    if(props['sample']){ +        sample = props['sample']; +    } +    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['title']; +    if(props['sample']){ +        sample = props['sample']; +    } +    sample = fixtxt(sample); + +    props['open']  = fixtxt(props['open']); +    props['close'] = fixtxt(props['close']); + +    // is something selected? +    var opts; +    var selection = getSelection(DOKUid(edid)); +    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), +        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); + +    // determine new level +    lvl += props['mod']; +    if(lvl < 1) lvl = 1; +    if(lvl > 5) lvl = 5; + +    var tags = '='; +    for(var i=0; i<=5-lvl; i++) tags += '='; +    insertTags(edid, tags+' ', ' '+tags+"\n", props['text']); +    pickerClose(); +    return false; +} + + +/** + * Add button action for picker buttons and create picker element + * + * @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 Gabriel Birke <birke@d-scribe.de> + */ +function addBtnActionPicker(btn, props, edid) { +    var pickerid = 'picker'+(pickercounter++); +    createPicker(pickerid, props, edid); +    addEvent(btn,'click',function(){ +        pickerToggle(pickerid,btn); +        return false; +    }); +    return true; +} + +/** + * 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) { +    linkwiz.init(DOKUid(edid)); +    addEvent(btn,'click',function(){ +        linkwiz.toggle(); +        return false; +    }); +    return true; +} + +/** + * Show/Hide a previosly created picker window + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function pickerToggle(pickerid,btn){ +    var picker = DOKUid(pickerid); +    if(picker.style.marginLeft == '-10000px'){ +        var x = findPosX(btn); +        var y = findPosY(btn); +        picker.style.left = (x+3)+'px'; +        picker.style.top = (y+btn.offsetHeight+3)+'px'; +        picker.style.marginLeft = '0px'; +    }else{ +        picker.style.marginLeft = '-10000px'; +    } +} + +/** + * Close all open pickers + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function pickerClose(){ +    var pobjs = getElementsByClass('picker'); +    for(var i=0; i<pobjs.length; i++){ +        pobjs[i].style.marginLeft = '-10000px'; +    } +} + + +/** + * Replaces \n with linebreaks + */ +function fixtxt(str){ +    return str.replace(/\\n/g,"\n"); +} + diff --git a/vendors/dokuwiki/lib/scripts/tw-sack.js b/vendors/dokuwiki/lib/scripts/tw-sack.js new file mode 100644 index 000000000..cfcbe0ea9 --- /dev/null +++ b/vendors/dokuwiki/lib/scripts/tw-sack.js @@ -0,0 +1,136 @@ +/* Simple AJAX Code-Kit (SACK) */ +/* ©2005 Gregory Wild-Smith */ +/* www.twilightuniverse.com */ +/* Software licenced under a modified X11 licence, see documentation or authors website for more details */ + +function sack(file){ +  this.AjaxFailedAlert = "Your browser does not support the enhanced functionality of this website, and therefore you will have an experience that differs from the intended one.\n"; +  this.requestFile = file; +  this.method = "POST"; +  this.URLString = ""; +  this.encodeURIString = true; +  this.execute = false; + +  this.onLoading = function() { }; +  this.onLoaded = function() { }; +  this.onInteractive = function() { }; +  this.onCompletion = function() { }; +  this.afterCompletion = function() { }; + +  this.createAJAX = function() { +    try { +      this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); +    } catch (e) { +      try { +        this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); +      } catch (err) { +        this.xmlhttp = null; +      } +    } +    if(!this.xmlhttp && typeof XMLHttpRequest != "undefined"){ +      this.xmlhttp = new XMLHttpRequest(); +    } +    if (!this.xmlhttp){ +      this.failed = true; +    } +  }; + +  this.setVar = function(name, value){ +    if (this.URLString.length < 3){ +      this.URLString = name + "=" + value; +    } else { +      this.URLString += "&" + name + "=" + value; +    } +  }; + +  this.encVar = function(name, value){ +    var varString = encodeURIComponent(name) + "=" + encodeURIComponent(value); +  return varString; +  }; + +  this.encodeURLString = function(string){ +    varArray = string.split('&'); +    for (i = 0; i < varArray.length; i++){ +      urlVars = varArray[i].split('='); +      if (urlVars[0].indexOf('amp;') != -1){ +        urlVars[0] = urlVars[0].substring(4); +      } +      varArray[i] = this.encVar(urlVars[0],urlVars[1]); +    } +  return varArray.join('&'); +  }; + +  this.runResponse = function(){ +    eval(this.response); +  }; + +  this.runAJAX = function(urlstring){ +    this.responseStatus = new Array(2); +    if(this.failed && this.AjaxFailedAlert){ +      alert(this.AjaxFailedAlert); +    } else { +      if (urlstring){ +        if (this.URLString.length){ +          this.URLString = this.URLString + "&" + urlstring; +        } else { +          this.URLString = urlstring; +        } +      } +      if (this.encodeURIString){ +        var timeval = new Date().getTime(); +        this.URLString = this.encodeURLString(this.URLString); +        this.setVar("rndval", timeval); +      } +      if (this.element) { this.elementObj = document.getElementById(this.element); } +      if (this.xmlhttp) { +        var self = this; +        if (this.method == "GET") { +          var totalurlstring = this.requestFile + "?" + this.URLString; +          this.xmlhttp.open(this.method, totalurlstring, true); +        } else { +          this.xmlhttp.open(this.method, this.requestFile, true); +        } +        if (this.method == "POST"){ +          try { +             this.xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8'); +          } catch (e) {} +        } + +        this.xmlhttp.onreadystatechange = function() { +          switch (self.xmlhttp.readyState){ +            case 1: +              self.onLoading(); +            break; +            case 2: +              self.onLoaded(); +            break; +            case 3: +              self.onInteractive(); +            break; +            case 4: +              self.response = self.xmlhttp.responseText; +              self.responseXML = self.xmlhttp.responseXML; +              self.responseStatus[0] = self.xmlhttp.status; +              self.responseStatus[1] = self.xmlhttp.statusText; +              self.onCompletion(); +              if(self.execute){ self.runResponse(); } +              if (self.elementObj) { +                var elemNodeName = self.elementObj.nodeName; +                elemNodeName.toLowerCase(); +                if (elemNodeName == "input" || elemNodeName == "select" || elemNodeName == "option" || elemNodeName == "textarea"){ +                  self.elementObj.value = self.response; +                } else { +                  self.elementObj.innerHTML = self.response; +                } +              } +              self.afterCompletion(); +              self.URLString = ""; +            break; +          } +        }; +        this.xmlhttp.send(this.URLString); +      } +    } +  }; +this.createAJAX(); +} | 
