diff options
Diffstat (limited to 'lib/scripts/linkwiz.js')
-rw-r--r-- | lib/scripts/linkwiz.js | 292 |
1 files changed, 153 insertions, 139 deletions
diff --git a/lib/scripts/linkwiz.js b/lib/scripts/linkwiz.js index fec43ad5e..cc4c19e0d 100644 --- a/lib/scripts/linkwiz.js +++ b/lib/scripts/linkwiz.js @@ -2,57 +2,60 @@ * The Link Wizard * * @author Andreas Gohr <gohr@cosmocode.de> + * @author Pierre Spring <pierre.spring@caillou.ch> */ -var linkwiz = { - wiz: null, - entry: null, +var dw_linkwiz = { + $wiz: null, + $entry: null, result: null, - timer: null, - sack: null, + timer: null, textArea: null, - selected: -1, + selected: null, selection: null, /** - * Initialize the linkwizard by creating the needed HTML + * Initialize the dw_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; + init: function($editor){ + // position relative to the text area + var pos = $editor.position(); // 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.style.marginTop = '-10000px'; - linkwiz.wiz.style.position = 'absolute'; - - 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>'; - $('dw__editform').parentNode.appendChild(linkwiz.wiz); - linkwiz.textArea = textArea; - linkwiz.result = $('link__wiz_result'); - linkwiz.entry = $('link__wiz_entry'); + dw_linkwiz.$wiz = jQuery(document.createElement('div')) + .dialog({ + autoOpen: false, + draggable: true, + title: LANG.linkwiz, + resizable: false + }) + .html( + '<div>'+LANG.linkto+' <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+ + '<div id="link__wiz_result"></div>' + ) + .parent() + .attr('id','link__wiz') + .addClass('a11y') + .css({ + 'position': 'absolute', + 'top': (pos.top+20)+'px', + 'left': (pos.left+80)+'px' + }) + .show() + .appendTo('div.dokuwiki'); + + dw_linkwiz.textArea = $editor[0]; + dw_linkwiz.result = jQuery('#link__wiz_result')[0]; + + // scrollview correction on arrow up/down gets easier + jQuery(dw_linkwiz.result).css('position', 'relative'); + + dw_linkwiz.$entry = jQuery('#link__wiz_entry'); // attach event handlers - var obj; - obj = $('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,$('link__wiz_header')); + jQuery('#link__wiz_close').click(dw_linkwiz.hide); + dw_linkwiz.$entry.keyup(dw_linkwiz.onEntry); + jQuery(dw_linkwiz.result).delegate('a', 'click', dw_linkwiz.onResultClick); }, /** @@ -63,56 +66,59 @@ var linkwiz = { return true; //ignore } if(e.keyCode == 27){ - linkwiz.hide(); + dw_linkwiz.hide(); e.preventDefault(); e.stopPropagation(); return false; } if(e.keyCode == 38){ //Up - linkwiz.select(linkwiz.selected -1); + dw_linkwiz.select(dw_linkwiz.selected -1); e.preventDefault(); e.stopPropagation(); return false; } if(e.keyCode == 40){ //Down - linkwiz.select(linkwiz.selected +1); + dw_linkwiz.select(dw_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); + if(dw_linkwiz.selected > -1){ + var $obj = dw_linkwiz.$getResult(dw_linkwiz.selected); + if($obj.length > 0){ + dw_linkwiz.resultClick($obj.find('a')[0]); } - }else if(linkwiz.entry.value){ - linkwiz.insertLink(linkwiz.entry.value); + }else if(dw_linkwiz.$entry.val()){ + dw_linkwiz.insertLink(dw_linkwiz.$entry.val()); } e.preventDefault(); e.stopPropagation(); return false; } - linkwiz.autocomplete(); + dw_linkwiz.autocomplete(); }, /** - * Get one of the result by index + * Get one of the results 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; - } + DEPRECATED('use dw_linkwiz.$getResult()[0] instead'); + return dw_linkwiz.$getResult()[0] || null; + }, + + /** + * Get one of the results by index + * + * @param int result div to return + * @returns jQuery object + */ + $getResult: function(num) { + return jQuery(dw_linkwiz.result).find('div').eq(num); }, /** @@ -120,43 +126,45 @@ var linkwiz = { */ select: function(num){ if(num < 0){ - linkwiz.deselect(); + dw_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(); - } + var $obj = dw_linkwiz.$getResult(num); + if ($obj.length === 0) { + return; + } - linkwiz.selected = num; + dw_linkwiz.deselect(); + $obj.addClass('selected'); + + // make sure the item is viewable in the scroll view + + //getting child position within the parent + var childPos = $obj.position().top; + //getting difference between the childs top and parents viewable area + var yDiff = childPos + $obj.outerHeight() - jQuery(dw_linkwiz.result).innerHeight(); + + if (childPos < 0) { + //if childPos is above viewable area (that's why it goes negative) + jQuery(dw_linkwiz.result)[0].scrollTop += childPos; + } else if(yDiff > 0) { + // if difference between childs top and parents viewable area is + // greater than the height of a childDiv + jQuery(dw_linkwiz.result)[0].scrollTop += yDiff; } + + dw_linkwiz.selected = num; }, /** * deselect a result if any is selected */ deselect: function(){ - if(linkwiz.selected > -1){ - var obj = linkwiz.getResult(linkwiz.selected); - if(obj){ - obj.className = obj.className.replace(/ ?selected/,''); - } + if(dw_linkwiz.selected > -1){ + dw_linkwiz.$getResult(dw_linkwiz.selected).removeClass('selected'); } - linkwiz.selected = -1; + dw_linkwiz.selected = -1; }, /** @@ -164,10 +172,12 @@ var linkwiz = { * resultClick() */ onResultClick: function(e){ - if(e.target.tagName != 'A') return; + if(!jQuery(this).is('a')) { + return; + } e.stopPropagation(); e.preventDefault(); - linkwiz.resultClick(e.target); + dw_linkwiz.resultClick(this); return false; }, @@ -175,33 +185,37 @@ var linkwiz = { * 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(); + dw_linkwiz.$entry.val(a.title); + if(a.title == '' || a.title.substr(-1) == ':'){ + dw_linkwiz.autocomplete_exec(); }else{ - linkwiz.entry.value = id; - if(a.nextSibling && a.nextSibling.tagName == 'SPAN'){ - linkwiz.insertLink(a.nextSibling.innerHTML); + if (jQuery(a.nextSibling).is('span')) { + dw_linkwiz.insertLink(a.nextSibling.innerHTML); }else{ - linkwiz.insertLink(''); + dw_linkwiz.insertLink(''); } } }, /** * Insert the id currently in the entry box to the textarea, - * replacing the current selection or at the curso postion. + * replacing the current selection or at the cursor position. * When no selection is available the given title will be used * as link title instead */ insertLink: function(title){ - if(!linkwiz.entry.value) return; + var link = dw_linkwiz.$entry.val(), + sel, stxt; + if(!link) { + return; + } - var sel = getSelection(linkwiz.textArea); - if(sel.start == 0 && sel.end == 0) sel = linkwiz.selection; + sel = getSelection(dw_linkwiz.textArea); + if(sel.start == 0 && sel.end == 0) { + sel = dw_linkwiz.selection; + } - var stxt = sel.getText(); + stxt = sel.getText(); // don't include trailing space in selection if(stxt.charAt(stxt.length - 1) == ' '){ @@ -209,25 +223,29 @@ var linkwiz = { stxt = sel.getText(); } - if(!stxt && !DOKU_UHC) stxt=title; + 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; + if(dw_linkwiz.textArea.form.id.value.indexOf(':') != -1 && + link.indexOf(':') == -1){ + link = ':' + link; } - var link = '[['+linkwiz.entry.value+'|'; - if(stxt) link += stxt; + var so = link.length+3; + + link = '[['+link+'|'; + if(stxt) { + link += stxt; + } link += ']]'; - var so = linkwiz.entry.value.length+3; - var eo = 2; + pasteText(sel,link,{startofs: so, endofs: 2}); + dw_linkwiz.hide(); - pasteText(sel,link,{startofs: so, endofs: eo}); - linkwiz.hide(); - // reset the entry to the parent namespace and remove : at the beginning - linkwiz.entry.value = linkwiz.entry.value.replace(/(^:)?[^:]*$/, ''); + // reset the entry to the parent namespace + dw_linkwiz.$entry.val(dw_linkwiz.$entry.val().replace(/[^:]*$/, '')); }, /** @@ -236,60 +254,56 @@ var linkwiz = { * Calls autocomplete_exec when the timer runs out */ autocomplete: function(){ - if(linkwiz.timer !== null){ - window.clearTimeout(linkwiz.timer); - linkwiz.timer = null; + if(dw_linkwiz.timer !== null){ + window.clearTimeout(dw_linkwiz.timer); + dw_linkwiz.timer = null; } - linkwiz.timer = window.setTimeout(linkwiz.autocomplete_exec,350); + dw_linkwiz.timer = window.setTimeout(dw_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 = ''; + var $res = jQuery(dw_linkwiz.result); + dw_linkwiz.deselect(); + $res.html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />') + .load( + DOKU_BASE + 'lib/exe/ajax.php', + { + call: 'linkwiz', + q: dw_linkwiz.$entry.val() + } + ); }, /** - * Show the linkwizard + * Show the link wizard */ show: function(){ - linkwiz.selection = getSelection(linkwiz.textArea); - linkwiz.wiz.style.marginLeft = '0px'; - linkwiz.wiz.style.marginTop = '0px'; - linkwiz.entry.focus(); - linkwiz.autocomplete(); + dw_linkwiz.selection = getSelection(dw_linkwiz.textArea); + dw_linkwiz.$wiz.removeClass('a11y'); + dw_linkwiz.$entry.focus(); + dw_linkwiz.autocomplete(); }, /** * Hide the link wizard */ hide: function(){ - linkwiz.wiz.style.marginLeft = '-10000px'; - linkwiz.wiz.style.marginTop = '-10000px'; - linkwiz.textArea.focus(); + dw_linkwiz.$wiz.addClass('a11y'); + dw_linkwiz.textArea.focus(); }, /** * Toggle the link wizard */ toggle: function(){ - if(linkwiz.wiz.style.marginLeft == '-10000px'){ - linkwiz.show(); + if(dw_linkwiz.$wiz.hasClass('a11y')){ + dw_linkwiz.show(); }else{ - linkwiz.hide(); + dw_linkwiz.hide(); } } }; - |