diff options
Diffstat (limited to 'lib/scripts')
-rw-r--r-- | lib/scripts/ajax.js | 104 | ||||
-rw-r--r-- | lib/scripts/delay.js | 69 | ||||
-rw-r--r-- | lib/scripts/drag.js | 72 | ||||
-rw-r--r-- | lib/scripts/edit.js | 150 | ||||
-rw-r--r-- | lib/scripts/events.js | 21 | ||||
-rw-r--r-- | lib/scripts/helpers.js | 4 | ||||
-rw-r--r-- | lib/scripts/hotkeys.js | 304 | ||||
-rw-r--r-- | lib/scripts/linkwiz.js | 5 | ||||
-rw-r--r-- | lib/scripts/media.js | 490 | ||||
-rw-r--r-- | lib/scripts/pngbehavior.htc | 53 | ||||
-rw-r--r-- | lib/scripts/script.js | 134 | ||||
-rw-r--r-- | lib/scripts/subscriptions.js | 46 | ||||
-rw-r--r-- | lib/scripts/textselection.js | 20 | ||||
-rw-r--r-- | lib/scripts/toolbar.js | 23 | ||||
-rw-r--r-- | lib/scripts/tw-sack.js | 5 |
15 files changed, 1134 insertions, 366 deletions
diff --git a/lib/scripts/ajax.js b/lib/scripts/ajax.js index a2a48a996..de009d448 100644 --- a/lib/scripts/ajax.js +++ b/lib/scripts/ajax.js @@ -1,68 +1,48 @@ /** * 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> + * @author Adrian Lang <lang@cosmocode.de> */ - -//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); -}; - +addInitEvent(function () { + + var inID = 'qsearch__in'; + var outID = 'qsearch__out'; + + var inObj = document.getElementById(inID); + var outObj = document.getElementById(outID); + + // objects found? + if (inObj === null){ return; } + if (outObj === null){ return; } + + function clear_results(){ + outObj.style.display = 'none'; + outObj.innerHTML = ''; + } + + var sack_obj = new sack(DOKU_BASE + 'lib/exe/ajax.php'); + sack_obj.AjaxFailedAlert = ''; + sack_obj.encodeURIString = false; + sack_obj.onCompletion = function () { + var data = sack_obj.response; + if (data === '') { return; } + + outObj.innerHTML = data; + outObj.style.display = 'block'; + }; + + // attach eventhandler to search field + var delay = new Delay(function () { + clear_results(); + var value = inObj.value; + if(value === ''){ return; } + sack_obj.runAJAX('call=qsearch&q=' + encodeURI(value)); + }); + + addEvent(inObj, 'keyup', function () {clear_results(); delay.start(); }); + + // attach eventhandler to output field + addEvent(outObj, 'click', function () {outObj.style.display = 'none'; }); +}); diff --git a/lib/scripts/delay.js b/lib/scripts/delay.js new file mode 100644 index 000000000..2ef9f8846 --- /dev/null +++ b/lib/scripts/delay.js @@ -0,0 +1,69 @@ +/** + * Manage delayed and timed actions + * + * @license GPL2 (http://www.gnu.org/licenses/gpl.html) + * @author Adrian Lang <lang@cosmocode.de> + */ + +/** + * Provide a global callback for window.setTimeout + * + * To get a timeout for non-global functions, just call + * delay.add(func, timeout). + */ +var timer = { + _cur_id: 0, + _handlers: {}, + + execDispatch: function (id) { + timer._handlers[id](); + }, + + add: function (func, timeout) { + var id = ++timer._cur_id; + timer._handlers[id] = func; + return window.setTimeout('timer.execDispatch(' + id + ')', timeout); + } +}; + +/** + * Provide a delayed start + * + * To call a function with a delay, just create a new Delay(func, timeout) and + * call that object’s method “start”. + */ +function Delay (func, timeout) { + this.func = func; + if (timeout) { + this.timeout = timeout; + } +} + +Delay.prototype = { + func: null, + timeout: 500, + + delTimer: function () { + if (this.timer !== null) { + window.clearTimeout(this.timer); + this.timer = null; + } + }, + + start: function () { + this.delTimer(); + var _this = this; + this.timer = timer.add(function () { _this.exec.call(_this); }, + this.timeout); + + this._data = { + _this: arguments[0], + _params: Array.prototype.slice.call(arguments, 2) + }; + }, + + exec: function () { + this.delTimer(); + this.func.call(this._data._this, this._data._params); + } +}; diff --git a/lib/scripts/drag.js b/lib/scripts/drag.js index 4726b77de..2212fb6c1 100644 --- a/lib/scripts/drag.js +++ b/lib/scripts/drag.js @@ -1,8 +1,9 @@ /** * 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... + * If you just want to move objects around, use drag.attach. For full + * customization, drag can be used as a javascript prototype, it is + * inheritance-aware. * * @link http://nofunc.org/Drag_Drop/ */ @@ -26,36 +27,37 @@ var drag = { attach: function (obj,handle) { if(handle){ handle.dragobject = obj; - addEvent($(handle),'mousedown',drag.start); }else{ - addEvent($(obj),'mousedown',drag.start); + handle = obj; } + var _this = this; + addEvent($(handle),'mousedown',function (e) {return _this.start(e); }); }, /** * Starts the dragging operation */ start: function (e){ - drag.handle = e.target; - if(drag.handle.dragobject){ - drag.obj = drag.handle.dragobject; + this.handle = e.target; + if(this.handle.dragobject){ + this.obj = this.handle.dragobject; }else{ - drag.obj = drag.handle; + this.obj = this.handle; } - drag.handle.className += ' ondrag'; - drag.obj.className += ' ondrag'; + this.handle.className += ' ondrag'; + this.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); + this.oX = parseInt(this.obj.style.left); + this.oY = parseInt(this.obj.style.top); + this.eX = e.pageX; + this.eY = e.pageY; - addEvent(document,'mousemove',drag.drag); - addEvent(document,'mouseup',drag.stop); + var _this = this; + this.mousehandlers = [function (e) {return _this.drag(e);}, function (e) {return _this.stop(e);}]; + addEvent(document,'mousemove', this.mousehandlers[0]); + addEvent(document,'mouseup', this.mousehandlers[1]); - e.preventDefault(); - e.stopPropagation(); return false; }, @@ -63,37 +65,21 @@ var drag = { * 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; + this.handle.className = this.handle.className.replace(/ ?ondrag/,''); + this.obj.className = this.obj.className.replace(/ ?ondrag/,''); + removeEvent(document,'mousemove', this.mousehandlers[0]); + removeEvent(document,'mouseup', this.mousehandlers[1]); + this.obj = null; + this.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'); + if(this.obj) { + this.obj.style.top = (e.pageY+this.oY-this.eY+'px'); + this.obj.style.left = (e.pageX+this.oX-this.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/lib/scripts/edit.js b/lib/scripts/edit.js index ef0a9a106..01262bcef 100644 --- a/lib/scripts/edit.js +++ b/lib/scripts/edit.js @@ -12,12 +12,15 @@ * * @author Andreas Gohr <andi@splitbrain.org> */ -function createToolButton(icon,label,key,id){ +function createToolButton(icon,label,key,id,classname){ var btn = document.createElement('button'); var ico = document.createElement('img'); // preapare the basic button stuff btn.className = 'toolbutton'; + if(classname){ + btn.className += ' '+classname; + } btn.title = label; if(key){ btn.title += ' ['+key.toUpperCase()+']'; @@ -68,6 +71,7 @@ function createPicker(id,props,edid){ picker.id = id; picker.style.position = 'absolute'; picker.style.marginLeft = '-10000px'; // no display:none, to keep access keys working + picker.style.marginTop = '-10000px'; for(var key in list){ if (!list.hasOwnProperty(key)) continue; @@ -151,6 +155,7 @@ function keyHandler(e){ e.keyCode != 32) return; var field = e.target; var selection = getSelection(field); + if(selection.getLength()) return; //there was text selected, keep standard behavior var search = "\n"+field.value.substr(0,selection.start); var linestart = Math.max(search.lastIndexOf("\n"), search.lastIndexOf("\r")); //IE workaround @@ -162,7 +167,17 @@ function keyHandler(e){ var match = search.match(/(\n +([\*-] ?)?)/); if(match){ var scroll = field.scrollHeight; - insertAtCarret(field.id,match[1]); + var match2 = search.match(/^\n +[\*-]\s*$/); + // Cancel list if the last item is empty (i. e. two times enter) + if (match2 && field.value.substr(selection.start).match(/^($|\r?\n)/)) { + field.value = field.value.substr(0, linestart) + "\n" + + field.value.substr(selection.start); + selection.start = linestart + 1; + selection.end = linestart + 1; + setSelection(selection); + } else { + insertAtCarret(field.id,match[1]); + } field.scrollTop += (field.scrollHeight - scroll); e.preventDefault(); // prevent enter key return false; @@ -207,7 +222,13 @@ function keyHandler(e){ addInitEvent(function(){ var field = $('wiki__text'); if(!field) return; - addEvent(field,'keydown',keyHandler); + // in Firefox, keypress doesn't send the correct keycodes, + // in Opera, the default of keydown can't be prevented + if (is_opera) { + addEvent(field,'keypress',keyHandler); + } else { + addEvent(field,'keydown',keyHandler); + } }); /** @@ -243,88 +264,68 @@ function currentHeadlineLevel(textboxId){ var textChanged = false; /** - * Check for changes before leaving the page + * Delete the draft before leaving the page */ -function changeCheck(msg){ - if(textChanged){ - var ok = confirm(msg); - if(ok){ - // remove a possibly saved draft using ajax - var dwform = $('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 - } +function deleteDraft() { + if (is_opera) return; + + // remove a possibly saved draft using ajax + var dwform = $('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'); + // this needs to be synchronous and GET to not be aborted upon page unload + sackobj.asynchronous = false; + sackobj.method = 'GET'; + sackobj.AjaxFailedAlert = ''; + sackobj.encodeURIString = false; + sackobj.runAJAX(params); } - return ok; - }else{ - return true; - } } /** - * Add changeCheck to all Links and Forms (except those with a - * JSnocheck class), add handlers to monitor changes + * Activate "not saved" dialog, add draft deletion to page unload, + * 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(!$('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; - }; - } - } +addInitEvent(function (){ + var editform = $('dw__editform'); + if (!editform) return; - // 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; }; + var edit_text = $('wiki__text'); + if(edit_text) { + if(edit_text.readOnly) return; - // add change memory setter - edit_text.onchange = function(){ + // set focus + edit_text.focus(); + } + + var checkfunc = function(){ textChanged = true; //global var summaryCheck(); }; - var summary = document.getElementById('edit__summary'); + addEvent(editform, 'change', checkfunc); + addEvent(editform, 'keydown', checkfunc); + + window.onbeforeunload = function(){ + if(textChanged) { + return LANG.notsavedyet; + } + }; + window.onunload = deleteDraft; + + // reset change memory var on submit + addEvent($('edbtn__save'), 'click', function(){ textChanged = false; }); + addEvent($('edbtn__preview'), 'click', function(){ textChanged = false; }); + + var summary = $('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 @@ -371,8 +372,7 @@ var locktimer = new locktimer_class(); locktimer.sack.onCompletion = locktimer.refreshed; // register refresh event - addEvent($('dw__editform').elements.wikitext,'keypress',function(){locktimer.refresh();}); - + addEvent($('dw__editform'),'keypress',function(){locktimer.refresh();}); // start timer locktimer.reset(); }; @@ -413,12 +413,14 @@ var locktimer = new locktimer_class(); // 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 = $('dw__editform'); + var dwform = $('dw__editform'); + if(locktimer.draft && dwform.elements.wikitext){ 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); + if(dwform.elements.date){ + params += '&date='+encodeURIComponent(dwform.elements.date.value); + } } locktimer.sack.runAJAX(params); locktimer.lasttime = now; diff --git a/lib/scripts/events.js b/lib/scripts/events.js index e7526ced7..a1fcac718 100644 --- a/lib/scripts/events.js +++ b/lib/scripts/events.js @@ -35,26 +35,31 @@ function removeEvent(element, type, handler) { function handleEvent(event) { var returnValue = true; // grab the event object (IE uses a global event object) - event = event || fixEvent(window.event); + event = event || fixEvent(window.event, this); // 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) { + if (handlers[i].call(this, event) === false) { returnValue = false; } } return returnValue; }; -function fixEvent(event) { +function fixEvent(event, _this) { // add W3C standard event methods event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; // fix target event.target = event.srcElement; + event.currentTarget = _this; + // fix coords + var base = (document.documentElement.scrollTop?document.documentElement:document.body); + event.pageX = (typeof event.pageX !== 'undefined') ? event.pageX : event.clientX + base.scrollLeft; + event.pageY = (typeof event.pageY !== 'undefined') ? event.pageY : event.clientY + base.scrollTop; + return event; }; fixEvent.preventDefault = function() { @@ -103,8 +108,8 @@ window.fireoninit = function() { } // for Internet Explorer (using conditional comments) - /*@cc_on @*/ - /*@if (@_win32) + /*@cc_on + @if (@_win32) document.write("<scr" + "ipt id=\"__ie_init\" defer=\"true\" src=\"//:\"><\/script>"); var script = document.getElementById("__ie_init"); script.onreadystatechange = function() { @@ -112,7 +117,7 @@ window.fireoninit = function() { window.fireoninit(); // call the onload handler } }; - /*@end @*/ + @end @*/ // for Safari if (/WebKit/i.test(navigator.userAgent)) { // sniff @@ -172,5 +177,5 @@ function bind (fnc) { var args = Array.prototype.slice.call(arguments, 1); return function() { return fnc.apply(this, args); - } + }; } diff --git a/lib/scripts/helpers.js b/lib/scripts/helpers.js index 8d4f3ea78..129964d29 100644 --- a/lib/scripts/helpers.js +++ b/lib/scripts/helpers.js @@ -109,7 +109,7 @@ function isEmpty (prop /* :Object */) /* :Boolean */ { 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 + for (var i in prop) if(prop.hasOwnProperty(i)) return false; } return true; } @@ -124,7 +124,7 @@ function isEmpty (prop /* :Object */) /* :Boolean */ { 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]); - } + }; } /** diff --git a/lib/scripts/hotkeys.js b/lib/scripts/hotkeys.js new file mode 100644 index 000000000..356b691ea --- /dev/null +++ b/lib/scripts/hotkeys.js @@ -0,0 +1,304 @@ +/** + * Some of these scripts were taken from TinyMCE (http://tinymce.moxiecode.com/) and were modified for DokuWiki + * + * Class handles accesskeys using javascript and also provides ability + * to register and use other hotkeys as well. + * + * @author Marek Sacha <sachamar@fel.cvut.cz> + */ +function Hotkeys() { + + this.shortcuts = new Array(); + + /** + * Set modifier keys, for instance: + * this.modifier = 'ctrl'; + * this.modifier = 'ctrl+shift'; + * this.modifier = 'ctrl+alt+shift'; + * this.modifier = 'alt'; + * this.modifier = 'alt+shift'; + * + * overwritten in intitialize (see below) + */ + this.modifier = 'ctrl+alt'; + + /** + * Initialization + * + * This function looks up all the accesskeys used in the current page + * (at anchor elements and input elements [type="submit"]) and registers + * appropriate shortcuts. + * + * Secondly, initialization registers listeners on document to catch all + * keyboard events. + * + * @author Marek Sacha <sachamar@fel.cvut.cz> + */ + this.initialize = function() { + var t = this; + + //switch modifier key based on OS FS#1958 + if(is_macos){ + t.modifier = 'ctrl+alt'; + }else{ + t.modifier = 'alt'; + } + + /** + * Lookup all anchors with accesskey and register event - go to anchor + * target. + */ + var anchors = document.getElementsByTagName("a"); + t.each(anchors, function(a) { + if (a.accessKey != "") { + t.addShortcut(t.modifier + '+' + a.accessKey, function() { + a.click(); + }); + a.accessKey = ''; + } + }); + + /** + * Lookup all input [type="submit"] with accesskey and register event - + * perform "click" on a button. + */ + var inputs = document.getElementsByTagName("input"); + t.each(inputs, function(i) { + if (i.type == "submit" && i.accessKey != "") { + t.addShortcut(t.modifier + '+' + i.accessKey, function() { + i.click(); + }); + i.accessKey = ''; + } + }); + + /** + * Lookup all buttons with accesskey and register event - + * perform "click" on a button. + */ + var buttons = document.getElementsByTagName("button"); + t.each(buttons, function(b) { + if (b.accessKey != "") { + t.addShortcut(t.modifier + '+' + b.accessKey, function() { + b.click(); + }); + b.accessKey = ''; + } + }); + + /** + * Register listeners on document to catch keyboard events. + */ + + addEvent(document,'keyup',function (e) { + return t.onkeyup.call(t,e); + }); + + addEvent(document,'keypress',function (e) { + return t.onkeypress.call(t,e); + }); + + addEvent(document,'keydown',function (e) { + return t.onkeydown.call(t,e); + }); + }; + + /** + * Keyup processing function + * Function returns true if keyboard event has registered handler, and + * executes the handler function. + * + * @param e KeyboardEvent + * @author Marek Sacha <sachamar@fel.cvut.cz> + * @return b boolean + */ + this.onkeyup = function(e) { + var t = this; + var v = t.findShortcut(e); + if (v != null && v != false) { + v.func.call(t); + return false; + } + return true; + }; + + /** + * Keydown processing function + * Function returns true if keyboard event has registered handler + * + * @param e KeyboardEvent + * @author Marek Sacha <sachamar@fel.cvut.cz> + * @return b boolean + */ + this.onkeydown = function(e) { + var t = this; + var v = t.findShortcut(e); + if (v != null && v != false) { + return false; + } + return true; + }; + + /** + * Keypress processing function + * Function returns true if keyboard event has registered handler + * + * @param e KeyboardEvent + * @author Marek Sacha <sachamar@fel.cvut.cz> + * @return b + */ + this.onkeypress = function(e) { + var t = this; + var v = t.findShortcut(e); + if (v != null && v != false) { + return false; + } + return true; + }; + + /** + * Register new shortcut + * + * This function registers new shortcuts, each shortcut is defined by its + * modifier keys and a key (with + as delimiter). If shortcut is pressed + * cmd_function is performed. + * + * For example: + * pa = "ctrl+alt+p"; + * pa = "shift+alt+s"; + * + * Full example of method usage: + * hotkeys.addShortcut('ctrl+s',function() { + * document.getElementByID('form_1').submit(); + * }); + * + * @param pa String description of the shortcut (ctrl+a, ctrl+shift+p, .. ) + * @param cmd_func Function to be called if shortcut is pressed + * @author Marek Sacha <sachamar@fel.cvut.cz> + */ + this.addShortcut = function(pa, cmd_func) { + var t = this; + + var o = { + func : cmd_func, + alt : false, + ctrl : false, + shift : false + }; + + t.each(t.explode(pa, '+'), function(v) { + switch (v) { + case 'alt': + case 'ctrl': + case 'shift': + o[v] = true; + break; + + default: + o.charCode = v.charCodeAt(0); + o.keyCode = v.toUpperCase().charCodeAt(0); + } + }); + + t.shortcuts.push((o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode, o); + + return true; + }; + + /** + * @property isMac + */ + this.isMac = (navigator.userAgent.indexOf('Mac') != -1); + + /** + * Apply function cb on each element of o in the namespace of s + * @param o Array of objects + * @param cb Function to be called on each object + * @param s Namespace to be used during call of cb (default namespace is o) + * @author Marek Sacha <sachamar@fel.cvut.cz> + */ + this.each = function(o, cb, s) { + var n, l; + + if (!o) + return 0; + + s = s || o; + + if (o.length !== undefined) { + // Indexed arrays, needed for Safari + for (n=0, l = o.length; n < l; n++) { + if (cb.call(s, o[n], n, o) === false) + return 0; + } + } else { + // Hashtables + for (n in o) { + if (o.hasOwnProperty(n)) { + if (cb.call(s, o[n], n, o) === false) + return 0; + } + } + } + + return 1; + }; + + /** + * Explode string according to delimiter + * @param s String + * @param d Delimiter (default ',') + * @author Marek Sacha <sachamar@fel.cvut.cz> + * @return a Array of tokens + */ + this.explode = function(s, d) { + return s.split(d || ','); + }; + + /** + * Find if the shortcut was registered + * + * @param e KeyboardEvent + * @author Marek Sacha <sachamar@fel.cvut.cz> + * @return v Shortcut structure or null if not found + */ + this.findShortcut = function (e) { + var t = this; + var v = null; + + /* No modifier key used - shortcut does not exist */ + if (!e.altKey && !e.ctrlKey && !e.metaKey) { + return v; + } + + t.each(t.shortcuts, function(o) { + if (t.isMac && o.ctrl != e.metaKey) + return; + else if (!t.isMac && o.ctrl != e.ctrlKey) + return; + + if (o.alt != e.altKey) + return; + + if (o.shift != e.shiftKey) + return; + + if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) { + v = o; + return; + } + }); + return v; + }; +} + +/** + * Init function for hotkeys. Called from js.php, to ensure hotkyes are initialized after toolbar. + * Call of addInitEvent(initializeHotkeys) is unnecessary now. + * + * @author Marek Sacha <sachamar@fel.cvut.cz> + */ +function initializeHotkeys() { + var hotkeys = new Hotkeys(); + hotkeys.initialize(); +} diff --git a/lib/scripts/linkwiz.js b/lib/scripts/linkwiz.js index d687ebbeb..225868592 100644 --- a/lib/scripts/linkwiz.js +++ b/lib/scripts/linkwiz.js @@ -30,6 +30,7 @@ var linkwiz = { linkwiz.wiz.style.top = (findPosY(textArea)+20)+'px'; linkwiz.wiz.style.left = (findPosX(textArea)+80)+'px'; linkwiz.wiz.style.marginLeft = '-10000px'; + linkwiz.wiz.style.marginTop = '-10000px'; linkwiz.wiz.innerHTML = '<div id="link__wiz_header">'+ @@ -37,7 +38,7 @@ var linkwiz = { 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); + $('dw__editform').parentNode.appendChild(linkwiz.wiz); linkwiz.textArea = textArea; linkwiz.result = $('link__wiz_result'); linkwiz.entry = $('link__wiz_entry'); @@ -256,6 +257,7 @@ var linkwiz = { show: function(){ linkwiz.selection = getSelection(linkwiz.textArea); linkwiz.wiz.style.marginLeft = '0px'; + linkwiz.wiz.style.marginTop = '0px'; linkwiz.entry.focus(); linkwiz.autocomplete(); }, @@ -265,6 +267,7 @@ var linkwiz = { */ hide: function(){ linkwiz.wiz.style.marginLeft = '-10000px'; + linkwiz.wiz.style.marginTop = '-10000px'; linkwiz.textArea.focus(); }, diff --git a/lib/scripts/media.js b/lib/scripts/media.js index 3e4213f19..95b1ab69e 100644 --- a/lib/scripts/media.js +++ b/lib/scripts/media.js @@ -6,6 +6,13 @@ var media_manager = { keepopen: false, hide: false, + align: false, + popup: false, + id: false, + display: false, + link: false, + size: false, + ext: false, /** * Attach event handlers to all "folders" below the given element @@ -141,33 +148,6 @@ var media_manager = { }, /** - * 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 = $('media__content'); - content.innerHTML = '<img src="'+DOKU_BASE+'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> @@ -218,24 +198,359 @@ var media_manager = { }, /** - * Insert the clicked image into the opener's textarea - * - * @author Andreas Gohr <andi@splitbrain.org> + * shows the popup for a image link */ select: function(event,link){ var id = link.name.substr(2); + media_manager.id = id; if(!opener){ // if we don't run in popup display example var ex = $('ex_'+id.replace(/:/g,'_')); if(ex.style.display == ''){ ex.style.display = 'none'; - }else{ + } else { ex.style.display = ''; } return false; } - opener.insertTags('wiki__text','{{'+id+'|','}}',''); + + media_manager.ext = false; + var dot = id.lastIndexOf("."); + if (dot != -1) { + var ext = id.substr(dot,id.length); + + if (ext != '.jpg' && ext != '.jpeg' && ext != '.png' && ext != '.gif' && ext != '.swf') { + media_manager.insert(null); + return false; + } + } else { + media_manager.insert(null); + return false; + } + + media_manager.popup.style.display = 'inline'; + media_manager.popup.style.left = event.pageX + 'px'; + media_manager.popup.style.top = event.pageY + 'px'; + + // set all buttons to outset + media_manager.outSet('media__linkbtn1'); + media_manager.outSet('media__linkbtn2'); + media_manager.outSet('media__linkbtn3'); + media_manager.outSet('media__linkbtn4'); + + media_manager.outSet('media__alignbtn0'); + media_manager.outSet('media__alignbtn1'); + media_manager.outSet('media__alignbtn2'); + media_manager.outSet('media__alignbtn3'); + + media_manager.outSet('media__sizebtn1'); + media_manager.outSet('media__sizebtn2'); + media_manager.outSet('media__sizebtn3'); + media_manager.outSet('media__sizebtn4'); + + + if (ext == '.swf') { + media_manager.ext = 'swf'; + + // disable display buttons for detail and linked image + $('media__linkbtn1').style.display = 'none'; + $('media__linkbtn2').style.display = 'none'; + + // set the link button to default + if (media_manager.link != false) { + if ( media_manager.link == '2' || media_manager.link == '1') { + media_manager.inSet('media__linkbtn3'); + media_manager.link = '3'; + DokuCookie.setValue('link','3'); + } else { + media_manager.inSet('media__linkbtn'+media_manager.link); + } + } else if (DokuCookie.getValue('link')) { + if ( DokuCookie.getValue('link') == '2' || DokuCookie.getValue('link') == '1') { + // this options are not availible + media_manager.inSet('media__linkbtn3'); + media_manager.link = '3'; + DokuCookie.setValue('link','3'); + } else { + media_manager.inSet('media__linkbtn'+DokuCookie.getValue('link')); + media_manager.link = DokuCookie.getValue('link'); + } + } else { + // default case + media_manager.link = '3'; + media_manager.inSet('media__linkbtn3'); + DokuCookie.setValue('link','3'); + } + + // disable button for original size + $('media__sizebtn4').style.display = 'none'; + + } else { + media_manager.ext = 'img'; + + // ensure that the display buttons are there + $('media__linkbtn1').style.display = 'inline'; + $('media__linkbtn2').style.display = 'inline'; + $('media__sizebtn4').style.display = 'inline'; + + // set the link button to default + if (DokuCookie.getValue('link')) { + media_manager.link = DokuCookie.getValue('link'); + } + if (media_manager.link == false) { + // default case + media_manager.link = '1'; + DokuCookie.setValue('link','1'); + } + media_manager.inSet('media__linkbtn'+media_manager.link); + } + + if (media_manager.link == '4') { + media_manager.align = false; + media_manager.size = false; + $('media__align').style.display = 'none'; + $('media__size').style.display = 'none'; + } else { + $('media__align').style.display = 'block'; + $('media__size').style.display = 'block'; + + // set the align button to default + if (media_manager.align != false) { + media_manager.inSet('media__alignbtn'+media_manager.align); + } else if (DokuCookie.getValue('align')) { + media_manager.inSet('media__alignbtn'+DokuCookie.getValue('align')); + media_manager.align = DokuCookie.getValue('align'); + } else { + // default case + media_manager.align = '0'; + media_manager.inSet('media__alignbtn0'); + DokuCookie.setValue('align','0'); + } + + // set the size button to default + if (DokuCookie.getValue('size')) { + media_manager.size = DokuCookie.getValue('size'); + } + if (media_manager.size == false || (media_manager.size === '4' && ext === '.swf')) { + // default case + media_manager.size = '2'; + DokuCookie.setValue('size','2'); + } + media_manager.inSet('media__sizebtn'+media_manager.size); + + $('media__sendbtn').focus(); + } + + return false; + }, + + /** + * build the popup window + * + * @author Dominik Eckelmann <eckelmann@cosmocode.de> + */ + initpopup: function() { + + media_manager.popup = document.createElement('div'); + media_manager.popup.setAttribute('id','media__popup'); + + var root = document.getElementById('media__manager'); + if (root == null) return; + root.appendChild(media_manager.popup); + + var headline = document.createElement('h1'); + headline.innerHTML = LANG.mediatitle; + var headlineimg = document.createElement('img'); + headlineimg.src = DOKU_BASE + 'lib/images/close.png'; + headlineimg.id = 'media__closeimg'; + addEvent(headlineimg,'click',function(event){ return media_manager.closePopup(event,this); }); + headline.insertBefore(headlineimg, headline.firstChild); + media_manager.popup.appendChild(headline); + drag.attach(media_manager.popup,headline); + + // link + + var linkp = document.createElement('p'); + + linkp.id = "media__linkstyle"; + if (media_manager.display == "2") { + linkp.style.display = "none"; + } + + var linkl = document.createElement('label'); + linkl.innerHTML = LANG.mediatarget; + linkp.appendChild(linkl); + + var linkbtns = ['lnk', 'direct', 'nolnk', 'displaylnk']; + for (var i = 0 ; i < linkbtns.length ; ++i) { + var linkbtn = document.createElement('button'); + linkbtn.className = 'button'; + linkbtn.value = i + 1; + linkbtn.id = "media__linkbtn" + (i + 1); + linkbtn.title = LANG['media' + linkbtns[i]]; + linkbtn.style.borderStyle = 'outset'; + addEvent(linkbtn,'click',function(event){ return media_manager.setlink(event,this); }); + + var linkimg = document.createElement('img'); + linkimg.src = DOKU_BASE + 'lib/images/media_link_' + linkbtns[i] + '.png'; + + linkbtn.appendChild(linkimg); + linkp.appendChild(linkbtn); + } + + media_manager.popup.appendChild(linkp); + + // align + + var alignp = document.createElement('p'); + var alignl = document.createElement('label'); + + alignp.appendChild(alignl); + alignp.id = 'media__align'; + if (media_manager.display == "2") { + alignp.style.display = "none"; + } + alignl.innerHTML = LANG['mediaalign']; + + var alignbtns = ['noalign', 'left', 'center', 'right']; + for (var n = 0 ; n < alignbtns.length ; ++n) { + var alignbtn = document.createElement('button'); + var alignimg = document.createElement('img'); + alignimg.src = DOKU_BASE + 'lib/images/media_align_' + alignbtns[n] + '.png'; + + alignbtn.id = "media__alignbtn" + n; + alignbtn.value = n; + alignbtn.title = LANG['media' + alignbtns[n]]; + alignbtn.className = 'button'; + alignbtn.appendChild(alignimg); + alignbtn.style.borderStyle = 'outset'; + addEvent(alignbtn,'click',function(event){ return media_manager.setalign(event,this); }); + + alignp.appendChild(alignbtn); + } + + media_manager.popup.appendChild(alignp); + + // size + + var sizep = document.createElement('p'); + var sizel = document.createElement('label'); + + sizep.id = 'media__size'; + if (media_manager.display == "2") { + sizep.style.display = "none"; + } + sizep.appendChild(sizel); + sizel.innerHTML = LANG['mediasize']; + + var sizebtns = ['small', 'medium', 'large', 'original']; + for (var size = 0 ; size < sizebtns.length ; ++size) { + var sizebtn = document.createElement('button'); + var sizeimg = document.createElement('img'); + + sizep.appendChild(sizebtn); + sizeimg.src = DOKU_BASE + 'lib/images/media_size_' + sizebtns[size] + '.png'; + + sizebtn.className = 'button'; + sizebtn.appendChild(sizeimg); + sizebtn.value = size + 1; + sizebtn.id = 'media__sizebtn' + (size + 1); + sizebtn.title = LANG['media' + sizebtns[size]]; + sizebtn.style.borderStyle = 'outset'; + addEvent(sizebtn,'click',function(event){ return media_manager.setsize(event,this); }); + } + + media_manager.popup.appendChild(sizep); + + // send and close button + + var btnp = document.createElement('p'); + media_manager.popup.appendChild(btnp); + btnp.setAttribute('class','btnlbl'); + + var cls = document.createElement('input'); + cls.type = 'button'; + cls.setAttribute('class','button'); + cls.value = LANG['mediaclose']; + btnp.appendChild(cls); + addEvent(cls,'click',function(event){ return media_manager.closePopup(event,this); }); + + var btn = document.createElement('input'); + btn.type = 'button'; + btn.id = 'media__sendbtn'; + btn.setAttribute('class','button'); + btn.value = LANG['mediainsert']; + btnp.appendChild(btn); + addEvent(btn,'click',function(event){ return media_manager.insert(event); }); + }, + + /** + * Insert the clicked image into the opener's textarea + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Dominik Eckelmann <eckelmann@cosmocode.de> + */ + insert: function(event){ + var id = media_manager.id; + // set syntax options + $('media__popup').style.display = 'none'; + + var opts = ''; + var optsstart = ''; + var alignleft = ''; + var alignright = ''; + + if (media_manager.ext == 'img' || media_manager.ext == 'swf') { + + if (media_manager.link == '4') { + opts = '?linkonly'; + } else { + + if (media_manager.link == "3" && media_manager.ext == 'img') { + opts = '?nolink'; + optsstart = true; + } else if (media_manager.link == "2" && media_manager.ext == 'img') { + opts = '?direct'; + optsstart = true; + } + + var s = parseInt(media_manager.size); + + if (s && s >= 1) { + opts += (optsstart)?'&':'?'; + if (s=="1") { + opts += '100'; + if (media_manager.ext == 'swf') { + opts += 'x62'; + } + } else if (s=="2") { + opts += '200'; + if (media_manager.ext == 'swf') { + opts += 'x123'; + } + } else if (s=="3"){ + opts += '300'; + if (media_manager.ext == 'swf') { + opts += 'x185'; + } + } + } + if (media_manager.align == '1') { + alignleft = ''; + alignright = ' '; + } + if (media_manager.align == '2') { + alignleft = ' '; + alignright = ' '; + } + if (media_manager.align == '3') { + alignleft = ' '; + alignright = ''; + } + } + } + opener.insertTags('wiki__text','{{'+alignleft+id+opts+alignright+'|','}}',''); if(!media_manager.keepopen) window.close(); opener.focus(); @@ -340,6 +655,116 @@ var media_manager = { oflash.style.display = ''; }; oform.appendChild(clicky); + }, + + /** + * closes the link type popup + */ + closePopup: function(event) { + $('media__popup').style.display = 'none'; + }, + + /** + * set the align + * + * @author Dominik Eckelmann <eckelmann@cosmocode.de> + */ + setalign: function(event,cb){ + if(cb.value){ + DokuCookie.setValue('align',cb.value); + media_manager.align = cb.value; + media_manager.outSet("media__alignbtn0"); + media_manager.outSet("media__alignbtn1"); + media_manager.outSet("media__alignbtn2"); + media_manager.outSet("media__alignbtn3"); + media_manager.inSet("media__alignbtn"+cb.value); + }else{ + DokuCookie.setValue('align',''); + media_manager.align = false; + } + }, + /** + * set the link type + * + * @author Dominik Eckelmann <eckelmann@cosmocode.de> + */ + setlink: function(event,cb){ + if(cb.value){ + DokuCookie.setValue('link',cb.value); + media_manager.link = cb.value; + media_manager.outSet("media__linkbtn1"); + media_manager.outSet("media__linkbtn2"); + media_manager.outSet("media__linkbtn3"); + media_manager.outSet("media__linkbtn4"); + media_manager.inSet("media__linkbtn"+cb.value); + var size = document.getElementById("media__size"); + var align = document.getElementById("media__align"); + if (cb.value != '4') { + size.style.display = "block"; + align.style.display = "block"; + } else { + size.style.display = "none"; + align.style.display = "none"; + } + }else{ + DokuCookie.setValue('link',''); + media_manager.link = false; + } + }, + + /** + * set the display type + * + * @author Dominik Eckelmann <eckelmann@cosmocode.de> + */ + setdisplay: function(event,cb){ + if(cb.value){ + DokuCookie.setValue('display',cb.value); + media_manager.display = cb.value; + media_manager.outSet("media__displaybtn1"); + media_manager.outSet("media__displaybtn2"); + media_manager.inSet("media__displaybtn"+cb.value); + + }else{ + DokuCookie.setValue('display',''); + media_manager.align = false; + } + }, + + /** + * sets the border to outset + */ + outSet: function(id) { + var ele = document.getElementById(id); + if (ele == null) return; + ele.style.borderStyle = "outset"; + }, + /** + * sets the border to inset + */ + inSet: function(id) { + var ele = document.getElementById(id); + if (ele == null) return; + ele.style.borderStyle = "inset"; + }, + + /** + * set the image size + * + * @author Dominik Eckelmann <eckelmann@cosmocode.de> + */ + setsize: function(event,cb){ + if (cb.value) { + DokuCookie.setValue('size',cb.value); + media_manager.size = cb.value; + for (var i = 1 ; i <= 4 ; ++i) { + media_manager.outSet("media__sizebtn" + i); + } + media_manager.inSet("media__sizebtn"+cb.value); + } else { + DokuCookie.setValue('size',''); + media_manager.width = false; + } } }; @@ -348,5 +773,6 @@ addInitEvent(function(){ media_manager.selectorattach($('media__content')); media_manager.confirmattach($('media__content')); media_manager.attachoptions($('media__opts')); + media_manager.initpopup(); media_manager.initFlashUpload(); }); diff --git a/lib/scripts/pngbehavior.htc b/lib/scripts/pngbehavior.htc deleted file mode 100644 index d1db8e765..000000000 --- a/lib/scripts/pngbehavior.htc +++ /dev/null @@ -1,53 +0,0 @@ -// 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/lib/scripts/script.js b/lib/scripts/script.js index ccba82144..57917aeb5 100644 --- a/lib/scripts/script.js +++ b/lib/scripts/script.js @@ -9,7 +9,7 @@ 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_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; @@ -78,16 +78,15 @@ function getElementsByClass(searchClass,node,tag) { /** * Get the X offset of the top left corner of the given object * - * @link http://www.quirksmode.org/index.html?/js/findpos.html + * @link http://www.quirksmode.org/js/findpos.html */ function findPosX(object){ var curleft = 0; var obj = $(object); if (obj.offsetParent){ - while (obj.offsetParent){ + do { curleft += obj.offsetLeft; - obj = obj.offsetParent; - } + } while (obj = obj.offsetParent); } else if (obj.x){ curleft += obj.x; @@ -98,16 +97,15 @@ function findPosX(object){ /** * Get the Y offset of the top left corner of the given object * - * @link http://www.quirksmode.org/index.html?/js/findpos.html + * @link http://www.quirksmode.org/js/findpos.html */ function findPosY(object){ var curtop = 0; var obj = $(object); if (obj.offsetParent){ - while (obj.offsetParent){ + do { curtop += obj.offsetTop; - obj = obj.offsetParent; - } + } while (obj = obj.offsetParent); } else if (obj.y){ curtop += obj.y; @@ -215,10 +213,7 @@ function addTocToggle() { prependChild(header,obj); obj.parentNode.onclick = toggleToc; - try { - obj.parentNode.style.cursor = 'pointer'; - obj.parentNode.style.cursor = 'hand'; - }catch(e){} + obj.parentNode.style.cursor = 'pointer'; } /** @@ -239,57 +234,51 @@ function toggleToc() { } /** - * Display an insitu footnote popup - * - * @author Andreas Gohr <andi@splitbrain.org> - * @author Chris Smith <chris@jalakai.co.uk> + * Create JavaScript mouseover popup */ -function footnote(e){ - var obj = e.target; - var id = obj.id.substr(5); +function insitu_popup(target, popup_id) { - // get or create the footnote popup div - var fndiv = $('insitu__fn'); + // get or create the popup div + var fndiv = $(popup_id); if(!fndiv){ fndiv = document.createElement('div'); - fndiv.id = 'insitu__fn'; + fndiv.id = popup_id; 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; + var p = e.relatedTarget || e.toElement; + while (p && p !== this) { + p = p.parentNode; } - // 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; - } + if (p === this) { + return; } // okay, hide it - fndiv.style.display='none'; + this.style.display='none'; }); - document.body.appendChild(fndiv); + getElementsByClass('dokuwiki', document.body, 'div')[0].appendChild(fndiv); } + // position the div and make it visible + fndiv.style.position = 'absolute'; + fndiv.style.left = findPosX(target)+'px'; + fndiv.style.top = (findPosY(target)+target.offsetHeight * 1.5) + 'px'; + fndiv.style.display = ''; + return fndiv; +} + +/** + * Display an insitu footnote popup + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Chris Smith <chris@jalakai.co.uk> + */ +function footnote(e){ + var fndiv = insitu_popup(e.target, 'insitu__fn'); + // locate the footnote anchor element - var a = $( "fn__"+id ); + var a = $("fn__" + e.target.id.substr(5)); if (!a){ return; } // anchor parent is the footnote container, get its innerHTML @@ -300,24 +289,10 @@ function footnote(e){ 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'); + content = content.replace(/\bid=(['"])([^"']+)\1/gi,'id="insitu__$2'); // 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 = ''; } /** @@ -507,14 +482,14 @@ addInitEvent(function(){ */ function checkWindowsShares() { if(!LANG['nosmblinks']) return true; + if(document.all != null) 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']); - } + alert(LANG['nosmblinks']); }); } } @@ -535,27 +510,30 @@ addInitEvent(function(){ * @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; + var tgt = this.parentNode; + var nr = tgt.className.match(/(\s+|^)editbutton_(\d+)(\s+|$)/)[2]; + do { + tgt = tgt.previousSibling; + } while (tgt !== null && typeof tgt.tagName === 'undefined'); + if (tgt === null) return; + while(typeof tgt.className === 'undefined' || + tgt.className.match('(\\s+|^)sectionedit' + nr + '(\\s+|$)') === null) { + if (typeof tgt.className !== 'undefined') { + tgt.className += ' section_highlight'; + } + tgt = (tgt.previousSibling !== null) ? tgt.previousSibling : tgt.parentNode; } + if (typeof tgt.className !== 'undefined') tgt.className += ' section_highlight'; }); 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/,''); + secs[j].className = secs[j].className.replace(/section_highlight/g,''); } - var secs = getElementsByClass('section_highlight'); }); } }); diff --git a/lib/scripts/subscriptions.js b/lib/scripts/subscriptions.js new file mode 100644 index 000000000..d701f258f --- /dev/null +++ b/lib/scripts/subscriptions.js @@ -0,0 +1,46 @@ +/** + * Hide list subscription style if target is a page + * + * @author Adrian Lang <lang@cosmocode.de> + */ + +addInitEvent(function () { + var form = $('subscribe__form'); + if (!form) { + return; + } + + var styleradios = {}; + + function update_state() { + if (!this.checked) { + return; + } + if (this.value.match(/:$/)) { + styleradios.list.parentNode.style.display = ''; + } else { + styleradios.list.parentNode.style.display = 'none'; + if (styleradios.list.checked) { + styleradios.digest.checked = 'checked'; + } + } + } + + var cur_sel = null; + + var inputs = form.getElementsByTagName('input'); + for (var i = 0; i < inputs.length ; ++i) { + switch (inputs[i].name) { + case 'sub_target': + addEvent(inputs[i], 'click', update_state); + if (inputs[i].checked) { + cur_sel = inputs[i]; + } + break; + case 'sub_style': + styleradios[inputs[i].value] = inputs[i]; + break; + } + } + update_state.call(cur_sel); +}); diff --git a/lib/scripts/textselection.js b/lib/scripts/textselection.js index 76cc6bcbb..742338785 100644 --- a/lib/scripts/textselection.js +++ b/lib/scripts/textselection.js @@ -24,7 +24,7 @@ function selection_class(){ this.getText = function(){ if(!this.obj) return ''; return this.obj.value.substring(this.start,this.end); - } + }; } /** @@ -41,7 +41,6 @@ function getSelection(textArea) { 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; @@ -57,9 +56,13 @@ function getSelection(textArea) { // The current selection sel.rangeCopy = document.selection.createRange().duplicate(); - - var before_range = document.body.createTextRange(); - before_range.moveToElementText(textArea); // Selects all the text + if (textArea.tagName === 'INPUT') { + var before_range = textArea.createTextRange(); + before_range.expand('textedit'); // Selects all the text + } else { + 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; @@ -158,7 +161,12 @@ function pasteText(selection,text,opts){ selection.obj.value.substring(selection.end, selection.obj.value.length); // set new selection - selection.end = selection.start + text.length; + if (is_opera) { + // Opera replaces \n by \r\n when inserting text. + selection.end = selection.start + text.replace(/\r?\n/g, '\r\n').length; + } else { + selection.end = selection.start + text.length; + } // modify the new selection if wanted if(opts.startofs) selection.start += opts.startofs; diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js index eacfc7cad..3f967448c 100644 --- a/lib/scripts/toolbar.js +++ b/lib/scripts/toolbar.js @@ -5,29 +5,39 @@ var pickercounter=0; /** * Create a toolbar * - * @param string tbid ID of the element where to insert the toolbar - * @param string edid ID of the editor textarea - * @param array tb Associative array defining the buttons + * @param string tbid ID of the element where to insert the toolbar + * @param string edid ID of the editor textarea + * @param array tb Associative array defining the buttons + * @param bool allowblock Allow buttons creating multiline content * @author Andreas Gohr <andi@splitbrain.org> */ -function initToolbar(tbid,edid,tb){ +function initToolbar(tbid,edid,tb, allowblock){ var toolbar = $(tbid); if(!toolbar) return; var edit = $(edid); if(!edit) return; if(edit.readOnly) return; + if (typeof allowblock === 'undefined') { + allowblock = true; + } + //empty the toolbar area: toolbar.innerHTML=''; var cnt = tb.length; for(var i=0; i<cnt; i++){ + if (!allowblock && tb[i].block === true) { + continue; + } var actionFunc; // create new button var btn = createToolButton(tb[i]['icon'], tb[i]['title'], - tb[i]['key']); + tb[i]['key'], + tb[i]['id'], + tb[i]['class']); // type is a tb function -> assign it as onclick @@ -225,8 +235,10 @@ function pickerToggle(pickerid,btn){ picker.style.left = (x+3)+'px'; picker.style.top = (y+btn.offsetHeight+3)+'px'; picker.style.marginLeft = '0px'; + picker.style.marginTop = '0px'; }else{ picker.style.marginLeft = '-10000px'; + picker.style.marginTop = '-10000px'; } } @@ -239,6 +251,7 @@ function pickerClose(){ var pobjs = getElementsByClass('picker'); for(var i=0; i<pobjs.length; i++){ pobjs[i].style.marginLeft = '-10000px'; + pobjs[i].style.marginTop = '-10000px'; } } diff --git a/lib/scripts/tw-sack.js b/lib/scripts/tw-sack.js index cfcbe0ea9..b5a5c8861 100644 --- a/lib/scripts/tw-sack.js +++ b/lib/scripts/tw-sack.js @@ -10,6 +10,7 @@ function sack(file){ this.URLString = ""; this.encodeURIString = true; this.execute = false; + this.asynchronous = true; this.onLoading = function() { }; this.onLoaded = function() { }; @@ -86,9 +87,9 @@ function sack(file){ var self = this; if (this.method == "GET") { var totalurlstring = this.requestFile + "?" + this.URLString; - this.xmlhttp.open(this.method, totalurlstring, true); + this.xmlhttp.open(this.method, totalurlstring, this.asynchronous); } else { - this.xmlhttp.open(this.method, this.requestFile, true); + this.xmlhttp.open(this.method, this.requestFile, this.asynchronous); } if (this.method == "POST"){ try { |