xref: /dokuwiki/lib/scripts/linkwiz.js (revision 0071aa2162e87ac729531c1c625d9bfb31f2adec)
1/**
2 * The Link Wizard
3 *
4 * @author Andreas Gohr <gohr@cosmocode.de>
5 */
6linkwiz = {
7    wiz:    null,
8    entry:  null,
9    result: null,
10    timer:  null,
11    sack:   null,
12    textArea: null,
13    selected: -1,
14
15    /**
16     * Initialize the linkwizard by creating the needed HTML
17     * and attaching the eventhandlers
18     */
19    init: function(textArea){
20        // prepare AJAX object
21        linkwiz.sack = new sack(DOKU_BASE + 'lib/exe/ajax.php');
22        linkwiz.sack.AjaxFailedAlert = '';
23        linkwiz.sack.encodeURIString = false;
24
25        // create HTML Structure
26        linkwiz.wiz = document.createElement('div');
27        linkwiz.wiz.id = 'link__wiz';
28        linkwiz.wiz.className     = 'picker';
29        linkwiz.wiz.style.top  = (findPosY(textArea)+20)+'px';
30        linkwiz.wiz.style.left = (findPosX(textArea)+80)+'px';
31        linkwiz.wiz.style.display = 'none';
32
33        linkwiz.wiz.innerHTML =
34             '<div id="link__wiz_header">'+
35             '<img src="'+DOKU_BASE+'lib/images/close.png" width="16" height="16" align="right" alt="" id="link__wiz_close" />'+
36             'Link Wizard</div>'+
37             '<div>Link: <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+
38             '<div id="link__wiz_result"></div>';
39        textArea.form.parentNode.appendChild(linkwiz.wiz);
40        linkwiz.textArea = textArea;
41        linkwiz.result = $('link__wiz_result');
42        linkwiz.entry = $('link__wiz_entry');
43
44        // attach event handlers
45        var obj;
46        obj = $('link__wiz_close');
47        obj.onclick = linkwiz.hide;
48
49        linkwiz.sack.elementObj = linkwiz.result;
50        addEvent(linkwiz.entry,'keyup',linkwiz.onEntry);
51        addEvent(linkwiz.result,'click',linkwiz.onResultClick);
52        drag.attach(linkwiz.wiz,$('link__wiz_header'));
53    },
54
55    /**
56     * handle all keyup events in the entry field
57     */
58    onEntry: function(e){
59        if(e.keyCode == 37 || e.keyCode == 39){ //left/right
60            return true; //ignore
61        }
62        if(e.keyCode == 38){ //Up
63            linkwiz.select(linkwiz.selected -1);
64            e.preventDefault();
65            e.stopPropagation();
66            return false;
67        }
68        if(e.keyCode == 40){ //Down
69            linkwiz.select(linkwiz.selected +1);
70            e.preventDefault();
71            e.stopPropagation();
72            return false;
73        }
74        if(e.keyCode == 13){ //Enter
75            if(linkwiz.selected > -1){
76                var obj = linkwiz.getResult(linkwiz.selected);
77                if(obj){
78                    var a = obj.getElementsByTagName('A')[0];
79                    linkwiz.resultClick(a);
80                }
81            }else if(linkwiz.entry.value){
82                linkwiz.insertLink(linkwiz.entry.value);
83            }
84
85            e.preventDefault();
86            e.stopPropagation();
87            return false;
88        }
89        linkwiz.autocomplete();
90    },
91
92    /**
93     * Get one of the result by index
94     *
95     * @param int result div to return
96     * @returns DOMObject or null
97     */
98    getResult: function(num){
99        var obj;
100        var childs = linkwiz.result.getElementsByTagName('DIV');
101        obj = childs[num];
102        if(obj){
103            return obj;
104        }else{
105            return null;
106        }
107    },
108
109    /**
110     * Select the given result
111     */
112    select: function(num){
113        if(num < 0){
114            linkwiz.deselect();
115            return;
116        }
117
118        var obj = linkwiz.getResult(num);
119        if(obj){
120            linkwiz.deselect();
121            obj.className += ' selected';
122            linkwiz.selected = num;
123        }
124    },
125
126    /**
127     * deselect a result if any is selected
128     */
129    deselect: function(){
130        if(linkwiz.selected > -1){
131            var obj = linkwiz.getResult(linkwiz.selected);
132            if(obj){
133                obj.className = obj.className.replace(/ ?selected/,'');
134            }
135        }
136        linkwiz.selected = -1;
137    },
138
139    /**
140     * Handle clicks in the result set an dispatch them to
141     * resultClick()
142     */
143    onResultClick: function(e){
144        if(e.target.tagName != 'A') return;
145        e.stopPropagation();
146        e.preventDefault();
147        linkwiz.resultClick(e.target);
148        return false;
149    },
150
151    /**
152     * Handles the "click" on a given result anchor
153     */
154    resultClick: function(a){
155        var id = a.title;
156        if(id == '' || id.substr(id.length-1) == ':'){
157            linkwiz.entry.value = id;
158            linkwiz.autocomplete_exec();
159        }else{
160            linkwiz.entry.value = id;
161            if(a.nextSibling && a.nextSibling.tagName == 'SPAN'){
162                linkwiz.insertLink(a.nextSibling.innerHTML);
163            }else{
164                linkwiz.insertLink('');
165            }
166        }
167    },
168
169    /**
170     * Insert the id currently in the entry box to the textarea,
171     * replacing the current selection or at the curso postion.
172     * When no selection is available the given title will be used
173     * as link title instead
174     */
175    insertLink: function(title){
176        if(!linkwiz.entry.value) return;
177        var sel  = getSelection(linkwiz.textArea);
178        var stxt = sel.getText();
179        if(!stxt) stxt=title;
180
181        var link = '[['+linkwiz.entry.value;
182        if(stxt) link += '|'+stxt;
183        link += ']]';
184
185        var so = linkwiz.entry.value.length+3;
186        var eo = 2;
187
188        pasteText(sel,link,{startofs: so, endofs: eo});
189        linkwiz.hide();
190    },
191
192    /**
193     * Start the page/namespace lookup timer
194     *
195     * Calls autocomplete_exec when the timer runs out
196     */
197    autocomplete: function(){
198        if(linkwiz.timer !== null){
199            window.clearTimeout(linkwiz.timer);
200            linkwiz.timer = null;
201        }
202
203        linkwiz.timer = window.setTimeout(linkwiz.autocomplete_exec,350);
204    },
205
206    /**
207     * Executes the AJAX call for the page/namespace lookup
208     */
209    autocomplete_exec: function(){
210        linkwiz.deselect();
211        linkwiz.result.innerHTML = '<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />';
212        linkwiz.sack.runAJAX('call=linkwiz&q='+encodeURI(linkwiz.entry.value));
213    },
214
215    /**
216     * Clears the result area
217     */
218    clear: function(){
219        linkwiz.result.innerHTML = 'Search for a matching page name above, or browse through the pages on the right';
220        linkwiz.entry.value = '';
221    },
222
223    /**
224     * Show the linkwizard
225     */
226    show: function(){
227        linkwiz.wiz.style['display'] = '';
228        linkwiz.entry.focus();
229        linkwiz.autocomplete();
230    },
231
232    /**
233     * Hide the link wizard
234     */
235    hide: function(){
236        linkwiz.wiz.style['display'] = 'none';
237    },
238
239    /**
240     * Toggle the link wizard
241     */
242    toggle: function(){
243        if(linkwiz.wiz.style['display'] == 'none'){
244            linkwiz.show();
245        }else{
246            linkwiz.hide();
247        }
248    },
249};
250
251