From 2bcca88a344ad5112322fb2533dceefb8757619a Mon Sep 17 00:00:00 2001
From: Andreas Gohr <andi@splitbrain.org>
Date: Fri, 8 Jul 2011 00:22:27 +0200
Subject: [PATCH] some initial refactoring of the linkwizard

---
 lib/scripts/linkwiz.js | 601 ++++++++++++++++++++---------------------
 lib/scripts/toolbar.js |   7 +-
 2 files changed, 303 insertions(+), 305 deletions(-)

diff --git a/lib/scripts/linkwiz.js b/lib/scripts/linkwiz.js
index e9a1d71b3..9ad72626d 100644
--- a/lib/scripts/linkwiz.js
+++ b/lib/scripts/linkwiz.js
@@ -1,319 +1,312 @@
+/*jslint sloppy: true, indent: 4, white: true, browser: true, eqeq: true */
+/*global jQuery, DOKU_BASE, LANG, DOKU_UHC, getSelection, pasteText */
+
+
 /**
  * The Link Wizard
  *
  * @author Andreas Gohr <gohr@cosmocode.de>
  * @author Pierre Spring <pierre.spring@caillou.ch>
  */
-(function($){
-    $.fn.extend({
-        linkwiz: function(editor) {
-
-            var wiz;
-            var entry;
-            var result;
-            var timer;
-            var textArea;
-            var selected;
-            var selection;
-
-            /**
-             * Initialize the linkwizard by creating the needed HTML
-             * and attaching the eventhandlers
-             */
-            var init = function(textAreaElement){
-
-
-                // create HTML Structure
-                wiz = document.createElement('div');
-                wiz.style.position = 'absolute';
-                wiz.id = 'link__wiz';
-                wiz.className     = 'picker';
-                wiz.style.top  = (findPosY(textAreaElement)+20)+'px';
-                wiz.style.left = (findPosX(textAreaElement)+80)+'px';
-                wiz.style.marginLeft = '-10000px';
-                wiz.style.marginTop  = '-10000px';
-
-                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')[0].parentNode.appendChild(wiz);
-                textArea = textAreaElement;
-                result = $('#link__wiz_result')[0];
-                entry = $('#link__wiz_entry')[0];
-
-                // attach event handlers
-                var obj;
-                var obj = $('#link__wiz_close')[0];
-                obj.onclick = hide;
-
-                addEvent(entry,'keyup',onEntry);
-                addEvent(result,'click',onResultClick);
-
-                $(wiz).draggable({handle: '#link__wiz_header'});
-
-            };
-
-            /**
-             * handle all keyup events in the entry field
-             */
-            var onEntry = function(e){
-                if(e.keyCode == 37 || e.keyCode == 39){ //left/right
-                    return true; //ignore
-                }
-                if(e.keyCode == 27){
-                    hide();
-                    e.preventDefault();
-                    e.stopPropagation();
-                    return false;
-                }
-                if(e.keyCode == 38){ //Up
-                    select(selected -1);
-                    e.preventDefault();
-                    e.stopPropagation();
-                    return false;
-                }
-                if(e.keyCode == 40){ //Down
-                    select(selected +1);
-                    e.preventDefault();
-                    e.stopPropagation();
-                    return false;
-                }
-                if(e.keyCode == 13){ //Enter
-                    if(selected > -1){
-                        var obj = getResult(selected);
-                        if(obj){
-                            var a = $(obj).find('a')[0];
-                            resultClick(a);
-                        }
-                    }else if(entry.value){
-                        insertLink(entry.value);
-                    }
-
-                    e.preventDefault();
-                    e.stopPropagation();
-                    return false;
-                }
-                autocomplete();
-            };
-
-            /**
-             * Get one of the result by index
-             *
-             * @param int result div to return
-             * @returns DOMObject or null
-             */
-            var getResult = function(num){
-                var obj;
-                var childs = $(result).find('div');
-                var obj = childs[num];
+var linkwiz = {
+    $wiz: null,
+    entry: null,
+    result: null,
+    timer: null,
+    textArea: null,
+    selected: null,
+    selection: null,
+
+    /**
+     * Initialize the linkwizard by creating the needed HTML
+     * and attaching the eventhandlers
+     */
+    init: function($editor){
+        // position relative to the text area
+        var pos = $editor.position();
+        pos.left += 20;
+        pos.right += 80;
+
+        // create HTML Structure
+        linkwiz.$wiz = jQuery(document.createElement('div'))
+               .attr('id','link__wiz')
+               .css({
+                    'position':    'absolute',
+                    'top':         pos.left+'px',
+                    'left':        pos.top+'px',
+                    'margin-left': '-10000px',
+                    'margin-top':  '-10000px'
+                   })
+               .html(
+                    '<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>'
+                    )
+               .addClass('picker');
+
+        $editor[0].form.parentNode.appendChild(linkwiz.$wiz[0]);
+        linkwiz.textArea = $editor[0];
+        linkwiz.result = jQuery('#link__wiz_result')[0];
+        linkwiz.entry = jQuery('#link__wiz_entry')[0];
+
+        // attach event handlers
+        jQuery('#link__wiz_close').click(linkwiz.hide);
+        jQuery(linkwiz.entry).keyup(linkwiz.onEntry);
+        jQuery(linkwiz.result).click(linkwiz.onResultClick);
+
+        linkwiz.$wiz.draggable({handle: '#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){
-                    return obj;
-                }else{
-                    return null;
-                }
-            };
-
-            /**
-             * Select the given result
-             */
-            var select = function(num){
-                if(num < 0){
-                    deselect();
-                    return;
+                    var a = jQuery(obj).find('a')[0];
+                    linkwiz.resultClick(a);
                 }
+            }else if(linkwiz.entry.value){
+                linkwiz.insertLink(linkwiz.entry.value);
+            }
 
-                var obj = getResult(num);
-                if(obj){
-                    deselect();
-                    obj.className += ' selected';
-
-                    // make sure the item is viewable in the scroll view
-                    // FIXME check IE compatibility
-                    if(obj.offsetTop > result.scrollTop + result.clientHeight){
-                        result.scrollTop += obj.clientHeight;
-                    }else if(obj.offsetTop - result.clientHeight < result.scrollTop){ // this works but isn't quite right, fixes welcome
-                        result.scrollTop -= obj.clientHeight;
-                    }
-                    // now recheck - if still not in view, the user used the mouse to scroll
-                    if( (obj.offsetTop > result.scrollTop + result.clientHeight) ||
-                        (obj.offsetTop < result.scrollTop) ){
-                        obj.scrollIntoView();
-                    }
-
-                    selected = num;
-                }
-            };
-
-            /**
-             * deselect a result if any is selected
-             */
-            var deselect = function(){
-                if(selected > -1){
-                    var obj = getResult(selected);
-                    if(obj){
-                        obj.className = obj.className.replace(/ ?selected/,'');
-                    }
-                }
-                selected = -1;
-            };
-
-            /**
-             * Handle clicks in the result set an dispatch them to
-             * resultClick()
-             */
-            var onResultClick = function(e){
-                if(e.target.tagName != 'A') return;
-                e.stopPropagation();
-                e.preventDefault();
-                resultClick(e.target);
-                return false;
-            };
-
-            /**
-             * Handles the "click" on a given result anchor
-             */
-            var resultClick = function(a){
-                var id = a.title;
-                if(id == '' || id.substr(id.length-1) == ':'){
-                    entry.value = id;
-                    autocomplete_exec();
-                }else{
-                    entry.value = id;
-                    if(a.nextSibling && a.nextSibling.tagName == 'SPAN'){
-                        insertLink(a.nextSibling.innerHTML);
-                    }else{
-                        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
-             */
-            var insertLink = function(title){
-                if(!entry.value) return;
-
-                var sel = getSelection(textArea);
-                if(sel.start == 0 && sel.end == 0) sel = selection;
-
-                var stxt = sel.getText();
-
-                // don't include trailing space in selection
-                if(stxt.charAt(stxt.length - 1) == ' '){
-                    sel.end--;
-                    var stxt = sel.getText();
-                }
-
-                if(!stxt && !DOKU_UHC) stxt=title;
+            e.preventDefault();
+            e.stopPropagation();
+            return false;
+        }
+        linkwiz.autocomplete();
+    },
+
+    /**
+     * Get one of the results by index
+     *
+     * @param int result div to return
+     * @returns DOMObject or null
+     */
+    getResult: function(num){
+        var childs = jQuery(linkwiz.result).find('div');
+        var obj = childs[num];
+        if(obj){
+            return obj;
+        }else{
+            return null;
+        }
+    },
+
+    /**
+     * Select the given result
+     */
+    select: function(num){
+        if(num < 0){
+            linkwiz.deselect();
+            return;
+        }
 
-                // prepend colon inside namespaces for non namespace pages
-                if(textArea.form['id'].value.indexOf(':') != -1 &&
-                   entry.value.indexOf(':') == -1){
-                    entry.value = ':'+entry.value;
-                }
+        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 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 sel = getSelection(linkwiz.textArea);
+        if(sel.start == 0 && sel.end == 0) sel = linkwiz.selection;
+
+        var stxt = sel.getText();
+
+        // don't include trailing space in selection
+        if(stxt.charAt(stxt.length - 1) == ' '){
+            sel.end--;
+            stxt = sel.getText();
+        }
 
-                var link = '[['+entry.value+'|';
-                if(stxt) link += stxt;
-                link += ']]';
-
-                var so = entry.value.length+3;
-                var eo = 2;
-
-                pasteText(sel,link,{startofs: so, endofs: eo});
-                hide();
-                // reset the entry to the parent namespace and remove : at the beginning
-                entry.value = entry.value.replace(/(^:)?[^:]*$/, '');
-            };
-
-            /**
-             * Start the page/namespace lookup timer
-             *
-             * Calls autocomplete_exec when the timer runs out
-             */
-            var autocomplete = function(){
-                if(timer !== null){
-                    window.clearTimeout(timer);
-                    timer = null;
-                }
+        if(!stxt && !DOKU_UHC) stxt=title;
 
-                timer = window.setTimeout(autocomplete_exec,350);
-            };
-
-            /**
-             * Executes the AJAX call for the page/namespace lookup
-             */
-            var autocomplete_exec = function(){
-                deselect();
-                result.innerHTML = '<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />';
-
-                // because we need to use POST, we
-                // can not use the .load() function.
-                $.post(
-                    DOKU_BASE + 'lib/exe/ajax.php',
-                    {
-                        call: 'linkwiz',
-                        q: entry.value
-                    },
-                    function (data) {
-                        result.innerHTML = data;
-                    },
-                    'html'
-                );
-            };
-
-            /**
-             * Clears the result area
-             */
-            var clear = function(){
-                result.innerHTML = 'Search for a matching page name above, or browse through the pages on the right';
-                entry.value = '';
-            };
-
-            /**
-             * Show the linkwizard
-             */
-            var show = function(){
-                selection  = getSelection(textArea);
-                wiz.style.marginLeft = '0px';
-                wiz.style.marginTop = '0px';
-                entry.focus();
-                autocomplete();
-            };
-
-            /**
-             * Hide the link wizard
-             */
-            var hide = function(){
-                wiz.style.marginLeft = '-10000px';
-                wiz.style.marginTop  = '-10000px';
-                textArea.focus();
-            };
-
-            /**
-             * Toggle the link wizard
-             */
-            var toggle = function(){
-                if(wiz.style.marginLeft == '-10000px'){
-                    show();
-                }else{
-                    hide();
-                }
-            };
+        // 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;
+        }
 
-            init($(editor)[0]);
+        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();
+        // reset the entry to the parent namespace and remove : at the beginning
+        linkwiz.entry.value = linkwiz.entry.value.replace(/(^:)?[^:]*$/, '');
+    },
+
+    /**
+     * 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;
+        }
 
-            return this.each(function() {
-                $(this).click(function (e) {
-                    e.preventDefault();
-                    toggle();
-                });
-            });
+        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" />';
+
+        // because we need to use POST, we
+        // can not use the .load() function.
+        jQuery.post(
+            DOKU_BASE + 'lib/exe/ajax.php',
+            {
+                call: 'linkwiz',
+                q: linkwiz.entry.value
+            },
+            function (data) {
+                linkwiz.result.innerHTML = data;
+            },
+            'html'
+        );
+    },
+
+    /**
+     * Clears the result area
+     * @fixme localize
+     */
+    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.css('marginLeft', '0');
+        linkwiz.$wiz.css('marginTop', '0');
+        linkwiz.entry.focus();
+        linkwiz.autocomplete();
+    },
+
+    /**
+     * Hide the link wizard
+     */
+    hide: function(){
+        linkwiz.$wiz.css('marginLeft', '-10000px');
+        linkwiz.$wiz.css('marginTop', '-10000px');
+        linkwiz.textArea.focus();
+    },
+
+    /**
+     * Toggle the link wizard
+     */
+    toggle: function(){
+        if(linkwiz.$wiz.css('marginLeft') == '-10000px'){
+            linkwiz.show();
+        }else{
+            linkwiz.hide();
         }
-    });
-})(jQuery);
+    }
+
+};
diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js
index c8dfe394d..fc95340f5 100644
--- a/lib/scripts/toolbar.js
+++ b/lib/scripts/toolbar.js
@@ -226,10 +226,15 @@ function addBtnActionPicker(btn, props, edid) {
  * @author Andreas Gohr <gohr@cosmocode.de>
  */
 function addBtnActionLinkwiz(btn, props, edid) {
-    jQuery(btn).linkwiz(jQuery('#' + edid));
+    linkwiz.init(jQuery('#'+edid));
+    jQuery(btn).click(function(){
+        linkwiz.toggle();
+        return false;
+    });
     return true;
 }
 
+
 /**
  * Show/Hide a previosly created picker window
  *
-- 
GitLab