1/**
2 * The Link Wizard
3 *
4 * @author Andreas Gohr <gohr@cosmocode.de>
5 * @author Pierre Spring <pierre.spring@caillou.ch>
6 */
7var dw_linkwiz = {
8    $wiz: null,
9    $entry: null,
10    result: null,
11    timer: null,
12    textArea: null,
13    selected: null,
14    selection: null,
15
16    /**
17     * Initialize the dw_linkwizard by creating the needed HTML
18     * and attaching the eventhandlers
19     */
20    init: function($editor){
21        // position relative to the text area
22        var pos = $editor.position();
23
24        // create HTML Structure
25        if(dw_linkwiz.$wiz)
26            return;
27        dw_linkwiz.$wiz = jQuery(document.createElement('div'))
28               .dialog({
29                   autoOpen: false,
30                   draggable: true,
31                   title: LANG.linkwiz,
32                   resizable: false
33               })
34               .html(
35                    '<div>'+LANG.linkto+' <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+
36                    '<div id="link__wiz_result"></div>'
37                    )
38               .parent()
39               .attr('id','link__wiz')
40               .css({
41                    'position':    'absolute',
42                    'top':         (pos.top+20)+'px',
43                    'left':        (pos.left+80)+'px'
44                   })
45               .hide()
46               .appendTo('.dokuwiki:first');
47
48        dw_linkwiz.textArea = $editor[0];
49        dw_linkwiz.result = jQuery('#link__wiz_result')[0];
50
51        // scrollview correction on arrow up/down gets easier
52        jQuery(dw_linkwiz.result).css('position', 'relative');
53
54        dw_linkwiz.$entry = jQuery('#link__wiz_entry');
55        if(JSINFO.namespace){
56            dw_linkwiz.$entry.val(JSINFO.namespace+':');
57        }
58
59        // attach event handlers
60        jQuery('#link__wiz .ui-dialog-titlebar-close').click(dw_linkwiz.hide);
61        dw_linkwiz.$entry.keyup(dw_linkwiz.onEntry);
62        jQuery(dw_linkwiz.result).delegate('a', 'click', dw_linkwiz.onResultClick);
63    },
64
65    /**
66     * handle all keyup events in the entry field
67     */
68    onEntry: function(e){
69        if(e.keyCode == 37 || e.keyCode == 39){ //left/right
70            return true; //ignore
71        }
72        if(e.keyCode == 27){ //Escape
73            dw_linkwiz.hide();
74            e.preventDefault();
75            e.stopPropagation();
76            return false;
77        }
78        if(e.keyCode == 38){ //Up
79            dw_linkwiz.select(dw_linkwiz.selected -1);
80            e.preventDefault();
81            e.stopPropagation();
82            return false;
83        }
84        if(e.keyCode == 40){ //Down
85            dw_linkwiz.select(dw_linkwiz.selected +1);
86            e.preventDefault();
87            e.stopPropagation();
88            return false;
89        }
90        if(e.keyCode == 13){ //Enter
91            if(dw_linkwiz.selected > -1){
92                var $obj = dw_linkwiz.$getResult(dw_linkwiz.selected);
93                if($obj.length > 0){
94                    dw_linkwiz.resultClick($obj.find('a')[0]);
95                }
96            }else if(dw_linkwiz.$entry.val()){
97                dw_linkwiz.insertLink(dw_linkwiz.$entry.val());
98            }
99
100            e.preventDefault();
101            e.stopPropagation();
102            return false;
103        }
104        dw_linkwiz.autocomplete();
105    },
106
107    /**
108     * Get one of the results by index
109     *
110     * @param   num int result div to return
111     * @returns DOMObject or null
112     */
113    getResult: function(num){
114        DEPRECATED('use dw_linkwiz.$getResult()[0] instead');
115        return dw_linkwiz.$getResult()[0] || null;
116    },
117
118    /**
119     * Get one of the results by index
120     *
121     * @param   num int result div to return
122     * @returns jQuery object
123     */
124    $getResult: function(num) {
125        return jQuery(dw_linkwiz.result).find('div').eq(num);
126    },
127
128    /**
129     * Select the given result
130     */
131    select: function(num){
132        if(num < 0){
133            dw_linkwiz.deselect();
134            return;
135        }
136
137        var $obj = dw_linkwiz.$getResult(num);
138        if ($obj.length === 0) {
139            return;
140        }
141
142        dw_linkwiz.deselect();
143        $obj.addClass('selected');
144
145        // make sure the item is viewable in the scroll view
146
147        //getting child position within the parent
148        var childPos = $obj.position().top;
149        //getting difference between the childs top and parents viewable area
150        var yDiff = childPos + $obj.outerHeight() - jQuery(dw_linkwiz.result).innerHeight();
151
152        if (childPos < 0) {
153            //if childPos is above viewable area (that's why it goes negative)
154            jQuery(dw_linkwiz.result)[0].scrollTop += childPos;
155        } else if(yDiff > 0) {
156            // if difference between childs top and parents viewable area is
157            // greater than the height of a childDiv
158            jQuery(dw_linkwiz.result)[0].scrollTop += yDiff;
159        }
160
161        dw_linkwiz.selected = num;
162    },
163
164    /**
165     * deselect a result if any is selected
166     */
167    deselect: function(){
168        if(dw_linkwiz.selected > -1){
169            dw_linkwiz.$getResult(dw_linkwiz.selected).removeClass('selected');
170        }
171        dw_linkwiz.selected = -1;
172    },
173
174    /**
175     * Handle clicks in the result set an dispatch them to
176     * resultClick()
177     */
178    onResultClick: function(e){
179        if(!jQuery(this).is('a')) {
180            return;
181        }
182        e.stopPropagation();
183        e.preventDefault();
184        dw_linkwiz.resultClick(this);
185        return false;
186    },
187
188    /**
189     * Handles the "click" on a given result anchor
190     */
191    resultClick: function(a){
192        dw_linkwiz.$entry.val(a.title);
193        if(a.title == '' || a.title.substr(a.title.length-1) == ':'){
194            dw_linkwiz.autocomplete_exec();
195        }else{
196            if (jQuery(a.nextSibling).is('span')) {
197                dw_linkwiz.insertLink(a.nextSibling.innerHTML);
198            }else{
199                dw_linkwiz.insertLink('');
200            }
201        }
202    },
203
204    /**
205     * Insert the id currently in the entry box to the textarea,
206     * replacing the current selection or at the cursor position.
207     * When no selection is available the given title will be used
208     * as link title instead
209     */
210    insertLink: function(title){
211        var link = dw_linkwiz.$entry.val(),
212            sel, stxt;
213        if(!link) {
214            return;
215        }
216
217        sel = DWgetSelection(dw_linkwiz.textArea);
218        if(sel.start == 0 && sel.end == 0) {
219            sel = dw_linkwiz.selection;
220        }
221
222        stxt = sel.getText();
223
224        // don't include trailing space in selection
225        if(stxt.charAt(stxt.length - 1) == ' '){
226            sel.end--;
227            stxt = sel.getText();
228        }
229
230        if(!stxt && !DOKU_UHC) {
231            stxt=title;
232        }
233
234        // prepend colon inside namespaces for non namespace pages
235        if(dw_linkwiz.textArea.form.id.value.indexOf(':') != -1 &&
236           link.indexOf(':') == -1){
237           link = ':' + link;
238        }
239
240        var so = link.length;
241        var eo = 0;
242        if(dw_linkwiz.val){
243            if(stxt) {
244                //link += '|'+stxt;
245                link = dw_linkwiz.val.open+stxt+' | '+link+dw_linkwiz.val.close;
246                so = stxt.length-2;
247                eo = stxt.length+2;
248            }
249            else {
250				link = dw_linkwiz.val.open+link+dw_linkwiz.val.close;
251                so = link.length-4;
252                eo = 2;
253			}
254
255        }
256
257        pasteText(sel,link,{startofs: so, endofs: eo});
258        dw_linkwiz.hide();
259
260        // reset the entry to the parent namespace
261        dw_linkwiz.$entry.val(dw_linkwiz.$entry.val().replace(/[^:]*$/, ''));
262    },
263
264    /**
265     * Start the page/namespace lookup timer
266     *
267     * Calls autocomplete_exec when the timer runs out
268     */
269    autocomplete: function(){
270        if(dw_linkwiz.timer !== null){
271            window.clearTimeout(dw_linkwiz.timer);
272            dw_linkwiz.timer = null;
273        }
274
275        dw_linkwiz.timer = window.setTimeout(dw_linkwiz.autocomplete_exec,350);
276    },
277
278    /**
279     * Executes the AJAX call for the page/namespace lookup
280     */
281    autocomplete_exec: function(){
282        var $res = jQuery(dw_linkwiz.result);
283        dw_linkwiz.deselect();
284        $res.html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />')
285            .load(
286            DOKU_BASE + 'lib/exe/ajax.php',
287            {
288                call: 'linkwiz',
289                q: dw_linkwiz.$entry.val()
290            }
291        );
292    },
293
294    /**
295     * Show the link wizard
296     */
297    show: function(){
298        dw_linkwiz.selection  = DWgetSelection(dw_linkwiz.textArea);
299        dw_linkwiz.$wiz.show();
300        dw_linkwiz.$entry.focus();
301        dw_linkwiz.autocomplete();
302    },
303
304    /**
305     * Hide the link wizard
306     */
307    hide: function(){
308        dw_linkwiz.$wiz.hide();
309        dw_linkwiz.textArea.focus();
310    },
311
312    /**
313     * Toggle the link wizard
314     */
315    toggle: function(){
316        if(dw_linkwiz.$wiz.css('display') == 'none'){
317            dw_linkwiz.show();
318        }else{
319            dw_linkwiz.hide();
320        }
321    }
322};
323