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