xref: /dokuwiki/lib/scripts/media.js (revision b5941dfab8516bd445afebc91d6a4942cab4d5f0)
1/*jslint white: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: false, strict: true, newcap: true, immed: true, sloppy: true, browser: true */
2/*global jQuery, DOKU_BASE, LANG, bind, DokuCookie, opener, confirm*/
3
4/**
5 * JavaScript functionality for the media management popup
6 *
7 * @author Andreas Gohr <andi@splitbrain.org>
8 * @author Pierre Spring <pierre.spring@caillou.ch>
9 */
10
11var dw_mediamanager = {
12    keepopen: false,
13    hide: false,
14    popup: false,
15    display: false,
16    ext: false,
17    $popup: null,
18
19    // Image insertion opts
20    align: false,
21    link: false,
22    size: false,
23    forbidden_opts: {},
24
25    init: function () {
26        var $content, $tree;
27        $content = jQuery('#media__content');
28        $tree    = jQuery('#media__tree');
29
30        dw_mediamanager.prepare_content($content);
31
32        dw_mediamanager.attachoptions();
33        dw_mediamanager.initpopup();
34
35        // add the action to autofill the "upload as" field
36        $content.delegate('#upload__file', 'change', dw_mediamanager.suggest)
37                // Attach the image selector action to all links
38                .delegate('a.select', 'click', dw_mediamanager.select)
39                // Attach deletion confirmation dialog to the delete buttons
40                .delegate('#media__content a.btn_media_delete', 'click',
41                          dw_mediamanager.confirmattach);
42
43        $tree.dw_tree({toggle_selector: 'img',
44                       load_data: function (show_sublist, $clicky) {
45                           // get the enclosed link (is always the first one)
46                           var $link = $clicky.parent().find('div.li a.idx_dir');
47
48                           jQuery.post(
49                               DOKU_BASE + 'lib/exe/ajax.php',
50                               $link[0].search.substr(1) + '&call=medians',
51                               show_sublist,
52                               'html'
53                           );
54                       },
55
56                       toggle_display: function ($clicky, opening) {
57                           $clicky.attr('src',
58                                        DOKU_BASE + 'lib/images/' +
59                                        (opening ? 'minus' : 'plus') + '.gif');
60                       }});
61        $tree.delegate('a', 'click', dw_mediamanager.list);
62
63        jQuery('#mediamanager__layout_list').delegate('#mediamanager__tabs_files a', 'click', dw_mediamanager.list)
64            .delegate('#mediamanager__tabs_list a', 'click', dw_mediamanager.list_view)
65            .delegate('#mediamanager__file_list a', 'click', dw_mediamanager.details)
66            .delegate('#dw__mediasearch', 'submit', dw_mediamanager.list)
67            .delegate('#upload__file', 'change', dw_mediamanager.suggest);
68
69        jQuery('#mediamanager__layout_detail').delegate('#mediamanager__tabs_details a', 'click', dw_mediamanager.details)
70            .delegate('#mediamanager__btn_update', 'submit', dw_mediamanager.list)
71            .delegate('#page__revisions', 'submit', dw_mediamanager.details)
72            .delegate('#page__revisions a', 'click', dw_mediamanager.details)
73            .delegate('#mediamanager__save_meta', 'submit', dw_mediamanager.details)
74            .delegate('#mediamanager__btn_delete', 'submit', dw_mediamanager.details)
75            .delegate('#mediamanager__btn_restore', 'submit', dw_mediamanager.details);
76
77    },
78
79    /**
80     * build the popup window
81     *
82     * @author Dominik Eckelmann <eckelmann@cosmocode.de>
83     */
84    initpopup: function () {
85        var opts, $insp, $insbtn;
86
87        dw_mediamanager.$popup = jQuery(document.createElement('div'))
88                 .attr('id', 'media__popup_content')
89                 .dialog({autoOpen: false, width: 280, modal: true,
90                          draggable: true, title: LANG.mediatitle,
91                          resizable: false});
92
93        opts = [{id: 'link', label: LANG.mediatarget,
94                 btns: ['lnk', 'direct', 'nolnk', 'displaylnk']},
95                {id: 'align', label: LANG.mediaalign,
96                 btns: ['noalign', 'left', 'center', 'right']},
97                {id: 'size', label: LANG.mediasize,
98                 btns: ['small', 'medium', 'large', 'original']}
99               ];
100
101        jQuery.each(opts, function (_, opt) {
102            var $p, $l;
103            $p = jQuery(document.createElement('p'))
104                 .attr('id', 'media__' + opt.id);
105
106            if (dw_mediamanager.display === "2") {
107                $p.hide();
108            }
109
110            $l = jQuery(document.createElement('label'))
111                 .text(opt.label);
112            $p.append($l);
113
114            jQuery.each(opt.btns, function (i, text) {
115                var $btn, $img;
116                $btn = jQuery(document.createElement('button'))
117                       .addClass('button')
118                       .attr('id', "media__" + opt.id + "btn" + (i + 1))
119                       .attr('title', LANG['media' + text])
120                       .click(bind(dw_mediamanager.setOpt, opt.id));
121
122                $img = jQuery(document.createElement('img'))
123                       .attr('src', DOKU_BASE + 'lib/images/media_' +
124                                    opt.id + '_' + text + '.png');
125
126                $btn.append($img);
127                $p.append($btn);
128            });
129
130            dw_mediamanager.$popup.append($p);
131        });
132
133        // insert button
134        $insp = jQuery(document.createElement('p'))
135                .addClass('btnlbl');
136        dw_mediamanager.$popup.append($insp);
137
138        $insbtn = jQuery(document.createElement('input'))
139                  .attr('id', 'media__sendbtn')
140                  .attr('type', 'button')
141                  .addClass('button')
142                  .val(LANG.mediainsert);
143        $insp.append($insbtn);
144    },
145
146    /**
147     * Insert the clicked image into the opener's textarea
148     *
149     * @author Andreas Gohr <andi@splitbrain.org>
150     * @author Dominik Eckelmann <eckelmann@cosmocode.de>
151     * @author Pierre Spring <pierre.spring@caillou.ch>
152     */
153    insert: function () {
154        var opts, alignleft, alignright, edid, s;
155
156        // set syntax options
157        dw_mediamanager.$popup.dialog('close');
158
159        opts = '';
160        alignleft = '';
161        alignright = '';
162
163        if ({img: 1, swf: 1}[dw_mediamanager.ext] === 1) {
164
165            if (dw_mediamanager.link === '4') {
166                    opts = '?linkonly';
167            } else {
168
169                if (dw_mediamanager.link === "3" && dw_mediamanager.ext === 'img') {
170                    opts = '?nolink';
171                } else if (dw_mediamanager.link === "2" && dw_mediamanager.ext === 'img') {
172                    opts = '?direct';
173                }
174
175                s = parseInt(dw_mediamanager.size, 10);
176
177                if (s && s >= 1 && s < 4) {
178                    opts += (opts.length)?'&':'?';
179                    opts += dw_mediamanager.size + '00';
180                    if (dw_mediamanager.ext === 'swf') {
181                        switch (s) {
182                        case 1:
183                            opts += 'x62';
184                            break;
185                        case 2:
186                            opts += 'x123';
187                            break;
188                        case 3:
189                            opts += 'x185';
190                            break;
191                        }
192                    }
193                }
194                alignleft = dw_mediamanager.align === '2' ? '' : ' ';
195                alignright = dw_mediamanager.align === '4' ? '' : ' ';
196            }
197        }
198        edid = String.prototype.match.call(document.location, /&edid=([^&]+)/);
199        opener.insertTags(edid ? edid[1] : 'wiki__text',
200                          '{{'+alignleft+id+opts+alignright+'|','}}','');
201
202        if(!dw_mediamanager.keepopen) {
203            window.close();
204        }
205        opener.focus();
206        return false;
207    },
208
209    /**
210     * Prefills the wikiname.
211     *
212     * @author Andreas Gohr <andi@splitbrain.org>
213     */
214    suggest: function(){
215        var $file, $name, text;
216
217        $file = jQuery(this);
218        $name = jQuery('#upload__name');
219
220        if ($name.val() != '') return;
221
222        if(!$file.length || !$name.length) {
223            return;
224        }
225
226        text = $file.val();
227        text = text.substr(text.lastIndexOf('/')+1);
228        text = text.substr(text.lastIndexOf('\\')+1);
229        $name.val(text);
230    },
231
232    /**
233     * list the content of a namespace using AJAX
234     *
235     * @author Andreas Gohr <andi@splitbrain.org>
236     * @author Pierre Spring <pierre.spring@caillou.ch>
237     */
238    list: function (event) {
239        var $link, $content, params;
240        $link = jQuery(this);
241
242        event.preventDefault();
243
244        jQuery('div.success, div.info, div.error, div.notify').remove();
245
246        if (document.getElementById('media__content')) {
247            //popup
248            $content = jQuery('#media__content');
249            $content.html('<img src="' + DOKU_BASE + 'lib/images/loading.gif" alt="..." class="load" />');
250
251        } else {
252            //fullscreen media manager
253            $content = jQuery('#mediamanager__layout_list');
254
255            if ($link.hasClass('idx_dir')) {
256                //changing namespace
257                jQuery('#mediamanager__layout_detail').empty();
258                jQuery('#media__tree .selected').each(function(){
259                    jQuery(this).removeClass('selected');
260                });
261                $link.addClass('selected');
262            }
263
264            jQuery('.scroll-container', $content).html('<img src="' + DOKU_BASE + 'lib/images/loading.gif" alt="..." class="load" />');
265        }
266
267        params = '';
268
269        if ($link[0].search) {
270            params = $link[0].search.substr(1)+'&call=medialist';
271        } else if ($link[0].action) {
272            params = dw_mediamanager.form_params($link)+'&call=medialist';
273        }
274
275        // fetch the subtree
276        dw_mediamanager.update_content($content, params);
277
278    },
279
280     /**
281     * Returns form parameters
282     *
283     * @author Kate Arzamastseva <pshns@ukr.net>
284     */
285    form_params: function ($form) {
286        var elements = $form.serialize();
287        var action = '';
288        var i = $form[0].action.indexOf('?');
289        if (i >= 0) action = $form[0].action.substr(i+1);
290        return elements+'&'+action;
291    },
292
293     /**
294     * Changes view of media files list
295     *
296     * @author Kate Arzamastseva <pshns@ukr.net>
297     */
298    list_view: function (event) {
299        var $link, $content;
300        $link = jQuery(this);
301
302        event.preventDefault();
303
304        $content = jQuery('#mediamanager__file_list');
305
306        if ($link[0].id == 'mediamanager__link_thumbs') {
307            $content.removeClass('mediamanager-list');
308            $content.addClass('mediamanager-thumbs');
309
310        } else if ($link[0].id == 'mediamanager__link_list') {
311            $content.removeClass('mediamanager-thumbs');
312            $content.addClass('mediamanager-list');
313        }
314    },
315
316     /**
317     * Lists the content of the right column (image details) using AJAX
318     *
319     * @author Kate Arzamastseva <pshns@ukr.net>
320     */
321    details: function (event) {
322        var $link, $content, params, update_list;
323        $link = jQuery(this);
324
325        event.preventDefault();
326
327        jQuery('div.success, div.info, div.error, div.notify').remove();
328
329        if ($link[0].id == 'mediamanager__btn_delete' && !confirm(LANG['del_confirm'])) return false;
330        if ($link[0].id == 'mediamanager__btn_restore' && !confirm(LANG['restore_confirm'])) return false;
331
332        $content = jQuery('#mediamanager__layout_detail');
333        if (jQuery('.scroll-container', $content).length) {
334            jQuery('.scroll-container', $content).html('<img src="' + DOKU_BASE + 'lib/images/loading.gif" alt="..." class="load" />');
335        } else {
336            jQuery($content).html('<img src="' + DOKU_BASE + 'lib/images/loading.gif" alt="..." class="load" />');
337        }
338
339        params = '';
340
341        if ($link[0].search) {
342            params = $link[0].search.substr(1)+'&call=mediadetails';
343        } else {
344            params = dw_mediamanager.form_params($link)+'&call=mediadetails';
345        }
346
347        dw_mediamanager.update_content($content, params);
348
349        update_list = ($link[0].id == 'mediamanager__btn_delete' || $link[0].id == 'mediamanager__btn_restore');
350        if (update_list) {
351            var $link1, $content1, params1;
352            $link1 = jQuery('a.files');
353            params1 = $link1[0].search.substr(1)+'&call=medialist';
354            $content1 = jQuery('#mediamanager__layout_list');
355            jQuery('.scroll-container', $content1).html('<img src="' + DOKU_BASE + 'lib/images/loading.gif" alt="..." class="load" />');
356
357            dw_mediamanager.update_content($content1, params1);
358        }
359    },
360
361    update_content: function ($content, params) {
362        jQuery.post(
363            DOKU_BASE + 'lib/exe/ajax.php',
364            params,
365            function (data) {
366                jQuery('.ui-resizable').each(function(){
367                    jQuery(this).resizable('destroy');
368                });
369
370                $content.html(data);
371                dw_mediamanager.prepare_content($content);
372                dw_mediamanager.updatehide();
373                dw_mediamanager.update_resizable(0);
374                dw_mediamanager.opacity_slider();
375                dw_mediamanager.portions_slider();
376                addInitEvent(revisionsForm);
377            },
378            'html'
379        );
380    },
381
382    update_resizable: function (count_width) {
383        $resizable = jQuery("#mediamanager__layout .layout-resizable");
384
385        $resizable.resizable({ handles: 'e' ,
386            resize: function(event, ui){
387                var w = 0;
388                $resizable.each(function() {
389                    w += jQuery(this).width();
390                });
391                wSum = w + parseFloat(jQuery('#mediamanager__layout_detail').css("min-width"));
392
393                // max width of resizable column
394                var maxWidth = 0.95 * jQuery('#mediamanager__layout').width() - wSum + jQuery(this).width() - 30;
395                $resizable.resizable( "option", "maxWidth", maxWidth );
396
397                // percentage width of the first two columns
398                var wLeft = ( 100*(w+30) / jQuery('#mediamanager__layout').width() );
399
400                // width of the third column
401                var wRight = 95-wLeft;
402                wRight += "%";
403                jQuery('#mediamanager__layout_detail').width(wRight);
404            }
405        });
406
407        var windowHeight = jQuery(window).height();
408        var height = windowHeight - 300;
409        jQuery('#mediamanager__layout .scroll-container').each(function (i) {
410            jQuery(this).height(height);
411        });
412        $resizable.each(function() {
413            jQuery(this).height(height+100);
414        });
415    },
416
417    opacity_slider: function () {
418        var $slider = jQuery( "#mediamanager__opacity_slider" );
419        $slider.slider();
420        $slider.slider("option", "min", 0);
421        $slider.slider("option", "max", 0.999);
422        $slider.slider("option", "step", 0.001);
423        $slider.slider("option", "value", 0.5);
424        $slider.bind("slide", function(event, ui) {
425            jQuery('#mediamanager__diff_opacity_image2').css({ opacity: $slider.slider("option", "value")});
426        });
427    },
428
429    portions_slider: function () {
430        var $slider = jQuery( "#mediamanager__portions_slider" );
431        $slider.slider();
432        $slider.slider("option", "min", 0);
433        $slider.slider("option", "max", 100);
434        $slider.slider("option", "step", 1);
435        $slider.slider("option", "value", 50);
436        $slider.bind("slide", function(event, ui) {
437            jQuery('#mediamanager__diff_portions_image2').css({ width: $slider.slider("option", "value")+'%'});
438        });
439    },
440
441    prepare_content: function ($content) {
442        // hide syntax example
443        $content.find('div.example:visible').hide();
444        dw_mediamanager.initFlashUpload();
445    },
446
447    /**
448     * shows the popup for a image link
449     */
450    select: function(event){
451        var $link, id, dot, ext;
452
453        event.preventDefault();
454
455        $link = jQuery(this);
456        id = $link.attr('name').substr(2);
457
458        if(!opener){
459            // if we don't run in popup display example
460            // the id's are a bit wierd and jQuery('#ex_wiki_dokuwiki-128.png')
461            // will not be found by Sizzle (the CSS Selector Engine
462            // used by jQuery), hence the document.getElementById() call
463            jQuery(document.getElementById('ex_'+id.replace(/:/g,'_').replace(/^_/,''))).dw_toggle();
464            return;
465        }
466
467        dw_mediamanager.ext = false;
468        dot = id.lastIndexOf(".");
469
470        if (-1 === dot) {
471            dw_mediamanager.insert(id);
472            return;
473        }
474
475        ext = id.substr(dot);
476
477        if ({'.jpg':1, '.jpeg':1, '.png':1, '.gif':1, '.swf':1}[ext] !== 1) {
478            dw_mediamanager.insert(id);
479            return;
480        }
481
482        // remove old callback from the insert button and set the new one.
483        jQuery('#media__sendbtn').unbind().click(bind(dw_mediamanager.insert, id));
484
485        dw_mediamanager.unforbid('ext');
486        if (ext === '.swf') {
487            dw_mediamanager.ext = 'swf';
488            dw_mediamanager.forbid('ext', {link: ['1', '2'],
489                                           size: ['4']});
490        } else {
491            dw_mediamanager.ext = 'img';
492        }
493
494        // Set to defaults
495        dw_mediamanager.setOpt('link');
496        dw_mediamanager.setOpt('align');
497        dw_mediamanager.setOpt('size');
498
499        // toggle buttons for detail and linked image, original size
500        jQuery('#media__linkbtn1, #media__linkbtn2, #media__sizebtn4')
501            .toggle(dw_mediamanager.ext === 'img');
502
503        dw_mediamanager.$popup.dialog('open');
504
505        jQuery('#media__sendbtn').focus();
506    },
507
508    /**
509     * Deletion confirmation dialog to the delete buttons.
510     *
511     * @author Michael Klier <chi@chimeric.de>
512     * @author Pierre Spring <pierre.spring@caillou.ch>
513     */
514    confirmattach: function(e){
515        if(!confirm(LANG.del_confirm + "\n" + jQuery(this).attr('title'))) {
516            e.preventDefault();
517        }
518    },
519
520    /**
521     * Creates checkboxes for additional options
522     *
523     * @author Andreas Gohr <andi@splitbrain.org>
524     * @author Pierre Spring <pierre.spring@caillou.ch>
525     */
526    attachoptions: function(){
527        var $obj, opts;
528
529        $obj = jQuery('#media__opts');
530        if($obj.length === 0) {
531            return;
532        }
533
534        opts = [];
535        // keep open
536        if(opener){
537            opts.push(['keepopen', 'keepopen']);
538        }
539        opts.push(['hide', 'hidedetails']);
540
541        jQuery.each(opts,
542                    function(_, opt) {
543                        var $box, $lbl;
544                        $box = jQuery(document.createElement('input'))
545                                 .attr('type', 'checkbox')
546                                 .attr('id', 'media__' + opt[0])
547                                 .click(bind(dw_mediamanager.toggleOption,
548                                             opt[0]));
549
550                        if(DokuCookie.getValue(opt[0])){
551                            $box.prop('checked', true);
552                            dw_mediamanager[opt[0]] = true;
553                        }
554
555                        $lbl = jQuery(document.createElement('label'))
556                                 .attr('for', 'media__' + opt[0])
557                                 .text(LANG[opt[1]]);
558
559                        $obj.append($box, $lbl, document.createElement('br'));
560                    });
561
562        dw_mediamanager.updatehide();
563    },
564
565    /**
566     * Generalized toggler
567     *
568     * @author Pierre Spring <pierre.spring@caillou.ch>
569     */
570    toggleOption: function (variable) {
571        if (jQuery(this).prop('checked')) {
572            DokuCookie.setValue(variable, 1);
573            dw_mediamanager[variable] = true;
574        } else {
575            DokuCookie.setValue(variable, '');
576            dw_mediamanager[variable] = false;
577        }
578        if (variable === 'hide') {
579            dw_mediamanager.updatehide();
580        }
581    },
582
583    initFlashUpload: function () {
584        var $oform, $oflash;
585        if(!hasFlash(8)) {
586            return;
587        }
588
589        $oform  = jQuery('#dw__upload');
590        $oflash = jQuery('#dw__flashupload');
591
592        if(!$oform.length || !$oflash.length) {
593            return;
594        }
595
596        jQuery(document.createElement('img'))
597            .attr('src', DOKU_BASE+'lib/images/multiupload.png')
598            .attr('title', LANG.mu_btn)
599            .attr('alt', LANG.mu_btn)
600            .css('cursor', 'pointer')
601            .click(
602                function () {
603                    $oform.hide();
604                    $oflash.show();
605                }
606            )
607            .appendTo($oform);
608    },
609
610    /**
611     * Sets the visibility of the image details accordingly to the
612     * chosen hide state
613     *
614     * @author Andreas Gohr <andi@splitbrain.org>
615     */
616    updatehide: function(){
617        jQuery('#media__content div.detail').dw_toggle(!dw_mediamanager.hide);
618    },
619
620    /**
621     * set media insertion option
622     *
623     * @author Dominik Eckelmann <eckelmann@cosmocode.de>
624     */
625    setOpt: function(opt, e){
626        var val, i;
627        if (typeof e !== 'undefined') {
628            val = this.id.substring(this.id.length - 1);
629        } else {
630            val = dw_mediamanager.getOpt(opt);
631        }
632
633        if (val === false) {
634            DokuCookie.setValue(opt,'');
635            dw_mediamanager[opt] = false;
636            return;
637        }
638
639        if (opt === 'link') {
640            if (val !== '4' && dw_mediamanager.link === '4') {
641                dw_mediamanager.unforbid('linkonly');
642                dw_mediamanager.setOpt('align');
643                dw_mediamanager.setOpt('size');
644            } else if (val === '4') {
645                dw_mediamanager.forbid('linkonly', {align: false, size: false});
646            }
647
648            jQuery("#media__size, #media__align").dw_toggle(val !== '4');
649        }
650
651        DokuCookie.setValue(opt, val);
652        dw_mediamanager[opt] = val;
653
654        for (i = 1; i <= 4; i++) {
655            jQuery("#media__" + opt + "btn" + i).removeClass('selected');
656        }
657        jQuery('#media__' + opt + 'btn' + val).addClass('selected');
658    },
659
660    unforbid: function (group) {
661        delete dw_mediamanager.forbidden_opts[group];
662    },
663
664    forbid: function (group, forbids) {
665        dw_mediamanager.forbidden_opts[group] = forbids;
666    },
667
668    allowedOpt: function (opt, val) {
669        var ret = true;
670        jQuery.each(dw_mediamanager.forbidden_opts,
671                    function (_, forbids) {
672                        ret = forbids[opt] !== false &&
673                              jQuery.inArray(val, forbids[opt]) === -1;
674                        return ret;
675                    });
676        return ret;
677    },
678
679    getOpt: function (opt) {
680        var allowed = bind(dw_mediamanager.allowedOpt, opt);
681
682        // Current value
683        if (dw_mediamanager[opt] !== false && allowed(dw_mediamanager[opt])) {
684            return dw_mediamanager[opt];
685        }
686
687        // From cookie
688        if (DokuCookie.getValue(opt) && allowed(DokuCookie.getValue(opt))) {
689            return DokuCookie.getValue(opt);
690        }
691
692        // size default
693        if (opt === 'size' && allowed('2')) {
694            return '2';
695        }
696
697        // Whatever is allowed, and be it false
698        return jQuery.grep(['1', '2', '3', '4'], allowed)[0] || false;
699    }
700};
701
702// moved from helpers.js temporarily here
703/**
704 * Very simplistic Flash plugin check, probably works for Flash 8 and higher only
705 *
706 */
707function hasFlash(version){
708    var ver = 0, axo;
709    try{
710        if(navigator.plugins !== null && navigator.plugins.length > 0){
711           ver = navigator.plugins["Shockwave Flash"].description.split(' ')[2].split('.')[0];
712        }else{
713           axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
714           ver = axo.GetVariable("$version").split(' ')[1].split(',')[0];
715        }
716    }catch(e){ }
717
718    return ver >= version;
719}
720
721jQuery(document).ready(function() {
722    dw_mediamanager.update_resizable(1);
723    dw_mediamanager.opacity_slider();
724    dw_mediamanager.portions_slider();
725    jQuery(window).resize(dw_mediamanager.update_resizable);
726});
727
728jQuery(dw_mediamanager.init);
729