about summary refs log tree commit diff stats
path: root/wiki/lib/scripts/linkwiz.js
diff options
context:
space:
mode:
Diffstat (limited to 'wiki/lib/scripts/linkwiz.js')
-rw-r--r--wiki/lib/scripts/linkwiz.js339
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();
+        }
+    }
+};