diff options
Diffstat (limited to 'wiki/lib/scripts/linkwiz.js')
-rw-r--r-- | wiki/lib/scripts/linkwiz.js | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/wiki/lib/scripts/linkwiz.js b/wiki/lib/scripts/linkwiz.js new file mode 100644 index 0000000..da1e072 --- /dev/null +++ b/wiki/lib/scripts/linkwiz.js @@ -0,0 +1,339 @@ +/** + * The Link Wizard + * + * @author Andreas Gohr <gohr@cosmocode.de> + * @author Pierre Spring <pierre.spring@caillou.ch> + */ +var dw_linkwiz = { + $wiz: null, + $entry: null, + result: null, + timer: null, + textArea: null, + selected: null, + selection: null, + + /** + * Initialize the dw_linkwizard by creating the needed HTML + * and attaching the eventhandlers + */ + init: function($editor){ + // position relative to the text area + var pos = $editor.position(); + + // create HTML Structure + if(dw_linkwiz.$wiz) + return; + dw_linkwiz.$wiz = jQuery(document.createElement('div')) + .dialog({ + autoOpen: false, + draggable: true, + title: LANG.linkwiz, + resizable: false + }) + .html( + '<div>'+LANG.linkto+' <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+ + '<div id="link__wiz_result"></div>' + ) + .parent() + .attr('id','link__wiz') + .css({ + 'position': 'absolute', + 'top': (pos.top+20)+'px', + 'left': (pos.left+80)+'px' + }) + .hide() + .appendTo('.dokuwiki:first'); + + dw_linkwiz.textArea = $editor[0]; + dw_linkwiz.result = jQuery('#link__wiz_result')[0]; + + // scrollview correction on arrow up/down gets easier + jQuery(dw_linkwiz.result).css('position', 'relative'); + + dw_linkwiz.$entry = jQuery('#link__wiz_entry'); + if(JSINFO.namespace){ + dw_linkwiz.$entry.val(JSINFO.namespace+':'); + } + + // attach event handlers + jQuery('#link__wiz .ui-dialog-titlebar-close').click(dw_linkwiz.hide); + dw_linkwiz.$entry.keyup(dw_linkwiz.onEntry); + jQuery(dw_linkwiz.result).on('click', 'a', dw_linkwiz.onResultClick); + }, + + /** + * handle all keyup events in the entry field + */ + onEntry: function(e){ + if(e.keyCode == 37 || e.keyCode == 39){ //left/right + return true; //ignore + } + if(e.keyCode == 27){ //Escape + dw_linkwiz.hide(); + e.preventDefault(); + e.stopPropagation(); + return false; + } + if(e.keyCode == 38){ //Up + dw_linkwiz.select(dw_linkwiz.selected -1); + e.preventDefault(); + e.stopPropagation(); + return false; + } + if(e.keyCode == 40){ //Down + dw_linkwiz.select(dw_linkwiz.selected +1); + e.preventDefault(); + e.stopPropagation(); + return false; + } + if(e.keyCode == 13){ //Enter + if(dw_linkwiz.selected > -1){ + var $obj = dw_linkwiz.$getResult(dw_linkwiz.selected); + if($obj.length > 0){ + dw_linkwiz.resultClick($obj.find('a')[0]); + } + }else if(dw_linkwiz.$entry.val()){ + dw_linkwiz.insertLink(dw_linkwiz.$entry.val()); + } + + e.preventDefault(); + e.stopPropagation(); + return false; + } + dw_linkwiz.autocomplete(); + }, + + /** + * Get one of the results by index + * + * @param num int result div to return + * @returns DOMObject or null + */ + getResult: function(num){ + DEPRECATED('use dw_linkwiz.$getResult()[0] instead'); + return dw_linkwiz.$getResult()[0] || null; + }, + + /** + * Get one of the results by index + * + * @param num int result div to return + * @returns jQuery object + */ + $getResult: function(num) { + return jQuery(dw_linkwiz.result).find('div').eq(num); + }, + + /** + * Select the given result + */ + select: function(num){ + if(num < 0){ + dw_linkwiz.deselect(); + return; + } + + var $obj = dw_linkwiz.$getResult(num); + if ($obj.length === 0) { + return; + } + + dw_linkwiz.deselect(); + $obj.addClass('selected'); + + // make sure the item is viewable in the scroll view + + //getting child position within the parent + var childPos = $obj.position().top; + //getting difference between the childs top and parents viewable area + var yDiff = childPos + $obj.outerHeight() - jQuery(dw_linkwiz.result).innerHeight(); + + if (childPos < 0) { + //if childPos is above viewable area (that's why it goes negative) + jQuery(dw_linkwiz.result)[0].scrollTop += childPos; + } else if(yDiff > 0) { + // if difference between childs top and parents viewable area is + // greater than the height of a childDiv + jQuery(dw_linkwiz.result)[0].scrollTop += yDiff; + } + + dw_linkwiz.selected = num; + }, + + /** + * deselect a result if any is selected + */ + deselect: function(){ + if(dw_linkwiz.selected > -1){ + dw_linkwiz.$getResult(dw_linkwiz.selected).removeClass('selected'); + } + dw_linkwiz.selected = -1; + }, + + /** + * Handle clicks in the result set an dispatch them to + * resultClick() + */ + onResultClick: function(e){ + if(!jQuery(this).is('a')) { + return; + } + e.stopPropagation(); + e.preventDefault(); + dw_linkwiz.resultClick(this); + return false; + }, + + /** + * Handles the "click" on a given result anchor + */ + resultClick: function(a){ + dw_linkwiz.$entry.val(a.title); + if(a.title == '' || a.title.substr(a.title.length-1) == ':'){ + dw_linkwiz.autocomplete_exec(); + }else{ + if (jQuery(a.nextSibling).is('span')) { + dw_linkwiz.insertLink(a.nextSibling.innerHTML); + }else{ + dw_linkwiz.insertLink(''); + } + } + }, + + /** + * Insert the id currently in the entry box to the textarea, + * replacing the current selection or at the cursor position. + * When no selection is available the given title will be used + * as link title instead + */ + insertLink: function(title){ + var link = dw_linkwiz.$entry.val(), + sel, stxt; + if(!link) { + return; + } + + sel = DWgetSelection(dw_linkwiz.textArea); + if(sel.start == 0 && sel.end == 0) { + sel = dw_linkwiz.selection; + } + + stxt = sel.getText(); + + // don't include trailing space in selection + if(stxt.charAt(stxt.length - 1) == ' '){ + sel.end--; + stxt = sel.getText(); + } + + if(!stxt && !DOKU_UHC) { + stxt=title; + } + + // prepend colon inside namespaces for non namespace pages + if(dw_linkwiz.textArea.form.id.value.indexOf(':') != -1 && + link.indexOf(':') == -1){ + link = ':' + link; + } + + var so = link.length; + var eo = 0; + if(dw_linkwiz.val){ + if(dw_linkwiz.val.open) { + so += dw_linkwiz.val.open.length; + link = dw_linkwiz.val.open+link; + } + link += '|'; + so += 1; + if(stxt) { + link += stxt; + } + if(dw_linkwiz.val.close) { + link += dw_linkwiz.val.close; + eo = dw_linkwiz.val.close.length; + } + } + + pasteText(sel,link,{startofs: so, endofs: eo}); + dw_linkwiz.hide(); + + // reset the entry to the parent namespace + var externallinkpattern = new RegExp('^((f|ht)tps?:)?//', 'i'), + entry_value; + if (externallinkpattern.test(dw_linkwiz.$entry.val())) { + if (JSINFO.namespace) { + entry_value = JSINFO.namespace + ':'; + } else { + entry_value = ''; //reset whole external links + } + } else { + entry_value = dw_linkwiz.$entry.val().replace(/[^:]*$/, '') + } + dw_linkwiz.$entry.val(entry_value); + }, + + /** + * Start the page/namespace lookup timer + * + * Calls autocomplete_exec when the timer runs out + */ + autocomplete: function(){ + if(dw_linkwiz.timer !== null){ + window.clearTimeout(dw_linkwiz.timer); + dw_linkwiz.timer = null; + } + + dw_linkwiz.timer = window.setTimeout(dw_linkwiz.autocomplete_exec,350); + }, + + /** + * Executes the AJAX call for the page/namespace lookup + */ + autocomplete_exec: function(){ + var $res = jQuery(dw_linkwiz.result); + dw_linkwiz.deselect(); + $res.html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />') + .load( + DOKU_BASE + 'lib/exe/ajax.php', + { + call: 'linkwiz', + q: dw_linkwiz.$entry.val() + } + ); + }, + + /** + * Show the link wizard + */ + show: function(){ + dw_linkwiz.selection = DWgetSelection(dw_linkwiz.textArea); + dw_linkwiz.$wiz.show(); + dw_linkwiz.$entry.focus(); + dw_linkwiz.autocomplete(); + + // Move the cursor to the end of the input + var temp = dw_linkwiz.$entry.val(); + dw_linkwiz.$entry.val(''); + dw_linkwiz.$entry.val(temp); + }, + + /** + * Hide the link wizard + */ + hide: function(){ + dw_linkwiz.$wiz.hide(); + dw_linkwiz.textArea.focus(); + }, + + /** + * Toggle the link wizard + */ + toggle: function(){ + if(dw_linkwiz.$wiz.css('display') == 'none'){ + dw_linkwiz.show(); + }else{ + dw_linkwiz.hide(); + } + } +}; |