1/**
2 * The Indexmenu Wizard
3 *
4 * @author Gerrit Uitslag
5 * based on Linkwiz by
6 * @author Andreas Gohr <gohr@cosmocode.de>
7 * @author Pierre Spring <pierre.spring@caillou.ch>
8 * and the concepts of the old indexmenu wizard
9 */
10var indexmenu_wiz = {
11    $wiz: null,
12    timer: null,
13    textArea: null,
14
15    defaulttheme: 'default',
16    fields: {
17        div1: {
18            elems: {
19                js: {}
20            }
21        },
22        div2: {
23            tlbclass: 'js theme',
24            elems: {
25                el1: {headerid: 'theme'}
26            }
27        },
28        div3: {
29            elems: {
30                el2: {headerid: 'navigation'},
31                navbar: {},
32                context: {},
33                nocookie: {tlbclass: 'js'},
34                noscroll: {tlbclass: 'js'},
35                notoc: {tlbclass: 'js'}
36            }
37        },
38        div4: {
39            elems: {
40                el3: {headerid: 'sort'},
41                tsort: {},
42                dsort: {},
43                msort: {},
44                hsort: {},
45                rsort: {},
46                nsort: {}
47            }
48        },
49        div5: {
50            elems: {
51                el4: {headerid: 'filter'},
52                nons: {},
53                nopg: {}
54            }
55        },
56        div6: {
57            tlbclass: 'js',
58            elems: {
59                el5: {headerid: 'performance'},
60                max: {tlbclass: 'js', number: ['maxn', 'maxm']},
61                maxjs: {tlbclass: 'js', number: ['maxjsn']},
62                id: {tlbclass: 'js', number: ['idn']}
63            }
64        }
65    },
66
67    /**
68     * Initialize the indexmenu_wiz by creating the needed HTML
69     * and attaching the eventhandlers
70     */
71    init: function($editor){
72        // position relative to the text area
73        var pos = $editor.position();
74
75        // create HTML Structure
76        indexmenu_wiz.$wiz = jQuery(document.createElement('div'))
77            .dialog({
78                autoOpen: false,
79                draggable: true,
80                title: LANG.plugins.indexmenu.indexmenuwizard,
81                resizable: false
82            })
83            .html(
84                '<fieldset class="index"><legend>'+LANG.plugins.indexmenu.index+'</legend>' +
85                    '<div><label>'+LANG.plugins.indexmenu.namespace+'<input id="namespace" type="text"></label></div>' +
86                    '<div><label class="number">'+LANG.plugins.indexmenu.nsdepth+' #<input id="nsdepth" type="text" value=1></label></div>' +
87                '</fieldset>' +
88
89                '<fieldset class="options"><legend>'+LANG.plugins.indexmenu.options+'</legend>' +
90                '</fieldset>' +
91                '<input type="submit" value="'+LANG.plugins.indexmenu.insert+'" class="button" id="indexmenu__insert">'+
92
93                '<fieldset class="metanumber">' +
94                    '<label class="number">'+LANG.plugins.indexmenu.metanum+'<input type="text" id="metanumber"></label>' +
95                    '<input type="submit" value="'+LANG.plugins.indexmenu.insertmetanum+'" class="button" id="indexmenu__insertmetanum">' +
96                '</fieldset>'
97            )
98            .parent()
99            .attr('id','indexmenu__wiz')
100            .css({
101                'position':    'absolute',
102                'top':         (pos.top+20)+'px',
103                'left':        (pos.left+80)+'px'
104            })
105            .hide()
106            .appendTo('.dokuwiki:first');
107
108        indexmenu_wiz.textArea = $editor[0];
109        var $opt_fieldset = jQuery('#indexmenu__wiz fieldset.options');
110
111        jQuery.each(indexmenu_wiz.fields, function(i,section) {
112            var div = jQuery('<div>').addClass(section.tlbclass);
113
114            jQuery.each(section.elems, function(elid,props){
115                if(props.headerid) {
116                    div.append('<strong>'+LANG.plugins.indexmenu[props.headerid]+'</strong><br />');
117                } else {
118                    //checkbox
119                    jQuery("<label>")
120                        .addClass(props.tlbclass).addClass(props.number ? ' num':'')
121                        .html('<input id="'+elid+'" type="checkbox">'+elid)
122                        .attr({title: LANG.plugins.indexmenu[elid]})
123                        .appendTo(div);
124
125                    //number inputs
126                    if(props.number) {
127                        jQuery.each(props.number, function(j,numid){
128                             jQuery("<label>")
129                                .attr({title: LANG.plugins.indexmenu[elid]})
130                                .addClass("number "+props.tlbclass )
131                                .html('#<input type="text" id="'+numid+'">')
132                                .appendTo(div);
133                        });
134                    }
135                }
136            });
137            $opt_fieldset.append(div);
138        });
139
140        indexmenu_wiz.includeThemes();
141
142        if(JSINFO && JSINFO.namespace){
143            jQuery('#namespace').val(':'+JSINFO.namespace);
144        }
145
146        // attach event handlers
147
148        //toggle js fields
149        jQuery('#js')
150            .change(function(){
151                jQuery('#indexmenu__wiz .js').toggle(this.checked);
152            }).change()
153            .parent().css({display: 'inline-block', width: '40px'}); //enlarge clickable area of label
154
155        //interactive number fields
156        jQuery('label.number input').bind('keydown keyup', function(){
157            //allow only numbers
158            indexmenu_wiz.filterNumberinput(this);
159            //checked the option if a number in input
160            indexmenu_wiz.autoCheckboxForNumbers(this);
161        });
162
163        jQuery('#indexmenu__insert').click(indexmenu_wiz.insertIndexmenu);
164        jQuery('#indexmenu__insertmetanum').click(indexmenu_wiz.insertMetaNumber);
165
166        jQuery('#indexmenu__wiz').find('.ui-dialog-titlebar-close').click(indexmenu_wiz.hide);
167    },
168
169    /**
170     * Request and include themes in wizard
171     */
172    includeThemes: function() {
173
174        var addButtons = function(data) {
175            var $themebar = jQuery('<div>')
176                .attr('id','themebar')
177                .addClass('toolbar')
178                .appendTo('div.theme');
179
180            jQuery.each(data.themes, function(i, theme){
181                var themeName =theme.split('.');
182
183                var $ico = jQuery('<div>')
184                    .css({ background: 'url('+ DOKU_BASE + data.themebase + '/' + theme + '/base.' + IndexmenuUtils.determineExtension(theme)+') no-repeat center' });
185                var $btn = jQuery('<button>')
186                    .addClass('themebutton toolbutton')
187                    .attr('id', theme)
188                    .attr('title', themeName[0])
189                    .append($ico)
190                    .click(indexmenu_wiz.selectTheme)
191                    .appendTo('div#themebar');
192            });
193
194            //select default theme
195            jQuery('#themebar button#'+indexmenu_wiz.defaulttheme).click();
196        };
197
198        jQuery.post(
199            DOKU_BASE + 'lib/exe/ajax.php',
200            {call: 'indexmenu', req: 'local'},
201            addButtons,
202            'json'
203        );
204    },
205
206    /**
207     * set class 'selected' to clicked theme, remove from other
208     */
209    selectTheme: function(){
210        jQuery('.themebutton').toggleClass('selected', false);
211        jQuery(this).toggleClass('selected', true);
212    },
213
214    /**
215     * Allow only number, by direct removing other characters from input
216     */
217    filterNumberinput: function(elem){
218        if(elem.value.match(/\D/)) {
219            elem.value=this.value.replace(/\D/g,'');
220        }
221    },
222
223    /**
224     * When a number larger than zero is inputted, check the checkbox
225     */
226    autoCheckboxForNumbers: function(elem){
227        var checkboxid = elem.id.substr(0,elem.id.length-1);
228        var value = elem.value;
229        //exception for second number field of max: only uncheck when first field is also empty
230        if(elem.id=='maxm' && !(elem.value>0)) {
231            value = parseInt(jQuery('input#maxn').val());
232        }
233        jQuery('input#'+checkboxid).prop('checked', value>0 );
234    },
235
236    /**
237     * Insert the indexmenu with options to the textarea,
238     * replacing the current selection or at the cursor position.
239     */
240    insertIndexmenu: function(){
241        var options = '';
242        jQuery('fieldset.options input').each(function(i, input){
243            var $label = jQuery(this).parent();
244
245            if(input.checked && ( !$label.hasClass('js')||jQuery('input#js').is(':checked') )){
246                //add option
247                options += ' '+input.id;
248
249                //add numbers
250                if($label.hasClass('num')){
251                    jQuery.each(indexmenu_wiz.fields.div6.elems[input.id].number, function(j,numid){
252                        var num = parseInt(jQuery('input#'+numid).val());
253                        options +=  num ? '#'+num : '';
254                    });
255                }
256                //add theme
257                if(input.id == 'js') {
258                    var themename = jQuery('#themebar button.selected').attr('id');
259                    if(indexmenu_wiz.defaulttheme !== themename) { //skip default theme
260                        options += '#'+jQuery('#themebar button.selected').attr('id');
261                    }
262
263                }
264            }
265
266        });
267        options = options ? '|'+jQuery.trim(options) : '';
268
269        var sel, ns, depth, syntax, eo;
270
271        // XXX: Compatibility Fix for 2014-05-05 "Ponder Stibbons", splitbrain/dokuwiki#505
272        if(DWgetSelection) {
273            sel = DWgetSelection(indexmenu_wiz.textArea);
274        } else {
275            sel = getSelection(indexmenu_wiz.textArea);
276        }
277
278
279        ns = jQuery('#namespace').val();
280        depth = parseInt(jQuery('#nsdepth').val());
281        depth = depth ? '#'+depth : '';
282
283        syntax = '{{indexmenu>'+ns+depth+options+'}}';
284        eo = depth.length + options.length + 2;
285
286        pasteText(sel, syntax,{startofs: 12, endofs: eo});
287        indexmenu_wiz.hide();
288    },
289
290    /**
291     * Insert meta number for sorting in textarea
292     * Takes number from input, otherwise tries the selection in textarea
293     */
294    insertMetaNumber: function(){
295        var sel, selnum, syntax, number;
296
297        // XXX: Compatibility Fix for 2014-05-05 "Ponder Stibbons", splitbrain/dokuwiki#505
298        if(DWgetSelection) {
299            sel = DWgetSelection(indexmenu_wiz.textArea);
300        } else {
301            sel = getSelection(indexmenu_wiz.textArea);
302        }
303
304        selnum = parseInt(sel.getText());
305        number = parseInt(jQuery('input#metanumber').val());
306        number = number || selnum || 1;
307        syntax = '{{indexmenu_n>'+number+'}}';
308
309        pasteText(sel, syntax,{startofs: 14, endofs: 2});
310        indexmenu_wiz.hide();
311    },
312
313    /**
314     * Show the indexmenu wizard
315     */
316    show: function(){
317        // XXX: Compatibility Fix for 2014-05-05 "Ponder Stibbons", splitbrain/dokuwiki#505
318        if(DWgetSelection) {
319            indexmenu_wiz.selection = DWgetSelection(indexmenu_wiz.textArea);
320        } else {
321            indexmenu_wiz.selection = getSelection(indexmenu_wiz.textArea);
322        }
323
324        indexmenu_wiz.$wiz.show();
325        jQuery('#namespace').focus();
326    },
327
328    /**
329     * Hide the indexmenu wizard
330     */
331    hide: function(){
332        indexmenu_wiz.$wiz.hide();
333        indexmenu_wiz.textArea.focus();
334    },
335
336    /**
337     * Toggle the indexmenu wizard
338     */
339    toggle: function(){
340        if(indexmenu_wiz.$wiz.css('display') == 'none'){
341            indexmenu_wiz.show();
342        }else{
343            indexmenu_wiz.hide();
344        }
345    }
346};
347