1/**
2 * Script for the Gallery Plugin to add nifty inline image viewing.
3 *
4 * It's based upon lightbox plus by Takuya Otani which is based upon
5 * lightbox by Lokesh Dhakar.
6 *
7 * For the DokuWiki plugin the following modifications were made:
8 *
9 * - addEvent removed (is shipped with DokuWiki)
10 * - IDs were changed to avoid clashs
11 * - previous and next buttons added
12 * - keyboard support added
13 * - neighbor preloading (not sure if it works)
14 *
15 * @license Creative Commons Attribution 2.5 License
16 * @author  Takuya Otani <takuya.otani@gmail.com>
17 * @link    http://serennz.cool.ne.jp/sb/sp/lightbox/
18 * @author  Lokesh Dhakar <lokesh@huddletogether.com>
19 * @link    http://www.huddletogether.com/projects/lightbox/
20 * @author  Andreas Gohr <andi@splitbrain.org>
21 */
22
23/* Original copyright notices follow:
24
25  lightbox_plus.js
26  == written by Takuya Otani <takuya.otani@gmail.com> ===
27  == Copyright (C) 2006 SimpleBoxes/SerendipityNZ Ltd. ==
28
29    Copyright (C) 2006 Takuya Otani/SimpleBoxes - http://serennz.cool.ne.jp/sb/
30    Copyright (C) 2006 SerendipityNZ - http://serennz.cool.ne.jp/snz/
31
32    This script is licensed under the Creative Commons Attribution 2.5 License
33    http://creativecommons.org/licenses/by/2.5/
34
35    basically, do anything you want, just leave my name and link.
36
37    Original script : Lightbox JS : Fullsize Image Overlays
38    Copyright (C) 2005 Lokesh Dhakar - http://www.huddletogether.com
39    For more information on this script, visit:
40    http://huddletogether.com/projects/lightbox/
41*/
42
43function WindowSize()
44{ // window size object
45    this.w = 0;
46    this.h = 0;
47    return this.update();
48}
49WindowSize.prototype.update = function()
50{
51    var d = document;
52    this.w =
53      (window.innerWidth) ? window.innerWidth
54    : (d.documentElement && d.documentElement.clientWidth) ? d.documentElement.clientWidth
55    : d.body.clientWidth;
56    this.h =
57      (window.innerHeight) ? window.innerHeight
58    : (d.documentElement && d.documentElement.clientHeight) ? d.documentElement.clientHeight
59    : d.body.clientHeight;
60    return this;
61};
62function PageSize()
63{ // page size object
64    this.win = new WindowSize();
65    this.w = 0;
66    this.h = 0;
67    return this.update();
68}
69PageSize.prototype.update = function()
70{
71    var d = document;
72    this.w =
73      (window.innerWidth && window.scrollMaxX) ? window.innerWidth + window.scrollMaxX
74    : (d.body.scrollWidth > d.body.offsetWidth) ? d.body.scrollWidth
75    : d.body.offsetWidt;
76    this.h =
77      (window.innerHeight && window.scrollMaxY) ? window.innerHeight + window.scrollMaxY
78    : (d.body.scrollHeight > d.body.offsetHeight) ? d.body.scrollHeight
79    : d.body.offsetHeight;
80    this.win.update();
81    if (this.w < this.win.w) this.w = this.win.w;
82    if (this.h < this.win.h) this.h = this.win.h;
83    return this;
84};
85function PagePos()
86{ // page position object
87    this.x = 0;
88    this.y = 0;
89    return this.update();
90}
91PagePos.prototype.update = function()
92{
93    var d = document;
94    this.x =
95      (window.pageXOffset) ? window.pageXOffset
96    : (d.documentElement && d.documentElement.scrollLeft) ? d.documentElement.scrollLeft
97    : (d.body) ? d.body.scrollLeft
98    : 0;
99    this.y =
100      (window.pageYOffset) ? window.pageYOffset
101    : (d.documentElement && d.documentElement.scrollTop) ? d.documentElement.scrollTop
102    : (d.body) ? d.body.scrollTop
103    : 0;
104    return this;
105};
106function UserAgent()
107{ // user agent information
108    var ua = navigator.userAgent;
109    this.isWinIE = this.isMacIE = false;
110    this.isGecko  = ua.match(/Gecko\//);
111    this.isSafari = ua.match(/AppleWebKit/);
112    this.isOpera  = window.opera;
113    if (document.all && !this.isGecko && !this.isSafari && !this.isOpera) {
114        this.isWinIE = ua.match(/Win/);
115        this.isMacIE = ua.match(/Mac/);
116        this.isNewIE = (ua.match(/MSIE 5\.5/) || ua.match(/MSIE 6\.0/));
117    }
118    return this;
119}
120// === lightbox ===
121function LightBox(option)
122{
123    var self = this;
124    self._imgs = new Array();
125    self._wrap = null;
126    self._box  = null;
127    self._open = -1;
128    self._page = new PageSize();
129    self._pos  = new PagePos();
130    self._ua   = new UserAgent();
131    self._expandable = false;
132    self._expanded = false;
133    self._expand = option.expandimg;
134    self._shrink = option.shrinkimg;
135    return self._init(option);
136}
137LightBox.prototype = {
138    _init : function(option)
139    {
140        var self = this;
141        var d = document;
142        if (!d.getElementsByTagName) return;
143        var links = d.getElementsByTagName("a");
144        for (var i=0;i<links.length;i++) {
145            var anchor = links[i];
146            var num = self._imgs.length;
147            if (!anchor.getAttribute("href")
148              || anchor.getAttribute("rel") != "lightbox") continue;
149            // initialize item
150            self._imgs[num] = {src:anchor.getAttribute("href"),w:-1,h:-1,title:'',cls:anchor.className};
151            if (anchor.getAttribute("title"))
152                self._imgs[num].title = anchor.getAttribute("title");
153            else if (anchor.firstChild && anchor.firstChild.getAttribute && anchor.firstChild.getAttribute("title"))
154                self._imgs[num].title = anchor.firstChild.getAttribute("title");
155            anchor.onclick = self._genOpener(num); // set closure to onclick event
156        }
157        var body = d.getElementsByTagName("body")[0];
158        self._wrap = self._createWrapOn(body,option.loadingimg);
159        self._box  = self._createBoxOn(body,option);
160        return self;
161    },
162    _genOpener : function(num)
163    {
164        var self = this;
165        return function() {
166            self._show(num);
167            if(window.event) window.event.returnValue = false;
168            return false;
169        }
170    },
171    _createWrapOn : function(obj,imagePath)
172    {
173        var self = this;
174        if (!obj) return null;
175        // create wrapper object, translucent background
176        var wrap = document.createElement('div');
177        wrap.id = 'gallery__overlay';
178        with (wrap.style) {
179            display = 'none';
180            position = 'fixed';
181            top = '0px';
182            left = '0px';
183            zIndex = '50';
184            width = '100%';
185            height = '100%';
186        }
187        if (self._ua.isWinIE) wrap.style.position = 'absolute';
188        addEvent(wrap,"click",function() { self._close(); });
189        obj.appendChild(wrap);
190        // create loading image, animated image
191        var imag = new Image;
192        imag.onload = function() {
193            var spin = document.createElement('img');
194            spin.id = 'gallery__loadingImage';
195            spin.src = imag.src;
196            spin.style.position = 'relative';
197            self._set_cursor(spin);
198            addEvent(spin,'click',function() { self._close(); });
199            wrap.appendChild(spin);
200            imag.onload = function(){};
201        };
202        if (imagePath != '') imag.src = imagePath;
203        return wrap;
204    },
205    _createBoxOn : function(obj,option)
206    {
207        var self = this;
208        if (!obj) return null;
209        // create lightbox object, frame rectangle
210        var box = document.createElement('div');
211        box.id = 'gallery__lightbox';
212        with (box.style) {
213            display = 'none';
214            position = 'absolute';
215            zIndex = '60';
216        }
217        obj.appendChild(box);
218        // create image object to display a target image
219        var img = document.createElement('img');
220        img.id = 'gallery__lightboxImage';
221        self._set_cursor(img);
222        addEvent(img,'click',function(){ self._close(); });
223        addEvent(img,'mouseover',function(){ self._show_action(); });
224        addEvent(img,'mouseout',function(){ self._hide_action(); });
225        box.appendChild(img);
226        var zoom = document.createElement('img');
227        zoom.id = 'gallery__actionImage';
228        with (zoom.style) {
229            display = 'none';
230            position = 'absolute';
231            top = '15px';
232            left = '15px';
233            zIndex = '70';
234        }
235        self._set_cursor(zoom);
236        zoom.src = self._expand;
237        addEvent(zoom,'mouseover',function(){ self._show_action(); });
238        addEvent(zoom,'click', function() { self._zoom(); });
239        box.appendChild(zoom);
240        addEvent(window,'resize',function(){ self._set_size(true); });
241        // close button
242        if (option.closeimg) {
243            var btn = document.createElement('img');
244            btn.id = 'gallery__closeButton';
245            with (btn.style) {
246                display = 'inline';
247                position = 'absolute';
248                right = '10px';
249                top = '10px';
250                zIndex = '80';
251            }
252            btn.src = option.closeimg;
253            self._set_cursor(btn);
254            addEvent(btn,'click',function(){ self._close(); });
255            box.appendChild(btn);
256        }
257        // next button
258        if (option.nextimg) {
259            var btn = document.createElement('img');
260            btn.id = 'gallery__nextButton';
261            with (btn.style) {
262                display = 'inline';
263                position = 'absolute';
264                right = '10px';
265                bottom = '10px';
266                zIndex = '80';
267            }
268            btn.src = option.nextimg;
269            self._set_cursor(btn);
270            addEvent(btn,'click',function(){ self._move(+1) });
271            box.appendChild(btn);
272        }
273        // prev button
274        if (option.previmg) {
275            var btn = document.createElement('img');
276            btn.id = 'gallery__prevButton';
277            with (btn.style) {
278                display = 'inline';
279                position = 'absolute';
280                left = '10px';
281                bottom = '10px';
282                zIndex = '80';
283            }
284            btn.src = option.previmg;
285            self._set_cursor(btn);
286            addEvent(btn,'click',function(){ self._move(-1) });
287            box.appendChild(btn);
288        }
289        // caption text
290        var caption = document.createElement('span');
291        caption.id = 'gallery__lightboxCaption';
292        with (caption.style) {
293            display = 'none';
294            position = 'absolute';
295            zIndex = '80';
296        }
297        box.appendChild(caption);
298        return box;
299    },
300    _set_photo_size : function()
301    {
302        var self = this;
303        if (self._open == -1) return;
304        var imag = self._box.firstChild;
305        var targ = { w:self._page.win.w - 30, h:self._page.win.h - 30 };
306        var orig = { w:self._imgs[self._open].w, h:self._imgs[self._open].h };
307        // shrink image with the same aspect
308        var ratio = 1.0;
309        if ((orig.w >= targ.w || orig.h >= targ.h) && orig.h && orig.w)
310            ratio = ((targ.w / orig.w) < (targ.h / orig.h)) ? targ.w / orig.w : targ.h / orig.h;
311        imag.width  = Math.floor(orig.w * ratio);
312        imag.height = Math.floor(orig.h * ratio);
313        self._expandable = (ratio < 1.0) ? true : false;
314        if (self._ua.isWinIE) self._box.style.display = "block";
315        self._box.style.top  = [self._pos.y + (self._page.win.h - imag.height - 30) / 2,'px'].join('');
316        self._box.style.left = [((self._page.win.w - imag.width - 30) / 2),'px'].join('');
317        self._show_caption(true);
318    },
319    _set_size : function(onResize)
320    {
321        var self = this;
322        if (self._open == -1) return;
323        self._page.update();
324        self._pos.update();
325        var spin = self._wrap.firstChild;
326        if (spin) {
327            var top = (self._page.win.h - spin.height) / 2;
328            if (self._wrap.style.position == 'absolute') top += self._pos.y;
329            spin.style.top  = [top,'px'].join('');
330            spin.style.left = [(self._page.win.w - spin.width - 30) / 2,'px'].join('');
331        }
332        if (self._ua.isWinIE) {
333            self._wrap.style.width  = [self._page.win.w,'px'].join('');
334            self._wrap.style.height = [self._page.h,'px'].join('');
335        }
336        if (onResize) self._set_photo_size();
337    },
338    _show_action : function()
339    {
340        var self = this;
341        if (self._open == -1 || !self._expandable) return;
342        var obj = document.getElementById('gallery__actionImage');
343        if (!obj) return;
344        obj.src = (self._expanded) ? self._shrink : self._expand;
345        obj.style.display = 'inline';
346    },
347    _hide_action : function()
348    {
349        var self = this;
350        var obj = document.getElementById('gallery__actionImage');
351        if (obj) obj.style.display = 'none';
352    },
353    _zoom : function()
354    {
355        var self = this;
356        if (self._expanded) {
357            self._set_photo_size();
358            self._expanded = false;
359        } else if (self._open > -1) {
360            var imag = self._box.firstChild;
361            self._box.style.top  = [self._pos.y,'px'].join('');
362            self._box.style.left = '0px';
363            imag.width  = self._imgs[self._open].w;
364            imag.height = self._imgs[self._open].h;
365            self._show_caption(false);
366            self._expanded = true;
367        }
368        self._show_action();
369    },
370    _show_caption : function(enable)
371    {
372        var self = this;
373        var caption = document.getElementById('gallery__lightboxCaption');
374        if (!caption) return;
375        if (caption.innerHTML.length == 0 || !enable) {
376            caption.style.display = 'none';
377        } else { // now display caption
378            var imag = self._box.firstChild;
379            with (caption.style) {
380                top = [imag.height + 10,'px'].join(''); // 10 is top margin of lightbox
381                left = '0px';
382                width = [imag.width + 20,'px'].join(''); // 20 is total side margin of lightbox
383                height = '1.2em';
384                display = 'block';
385            }
386        }
387    },
388    _move : function(by)
389    {
390        var self = this;
391        var num  = self._open + by;
392        // wrap around at start and end
393        if(num < 0) num = self._imgs.length - 1;
394        if(num >= self._imgs.length) num = 0;
395
396        self._disable_keyboard();
397        self._hide_action();
398        self._box.style.display  = "none";
399        self._show(num);
400    },
401    _show : function(num)
402    {
403        var self = this;
404        var imag = new Image;
405        if (num < 0 || num >= self._imgs.length) return;
406        var loading = document.getElementById('gallery__loadingImage');
407        var caption = document.getElementById('gallery__lightboxCaption');
408        self._open = num; // set opened image number
409        self._set_size(false); // calc and set wrapper size
410        self._wrap.style.display = "block";
411        if (loading) loading.style.display = 'inline';
412        imag.onload = function() {
413            if (self._imgs[self._open].w == -1) {
414                // store original image width and height
415                self._imgs[self._open].w = imag.width;
416                self._imgs[self._open].h = imag.height;
417            }
418            if (caption) caption.innerHTML = self._imgs[self._open].title;
419            self._set_photo_size(); // calc and set lightbox size
420            self._hide_action();
421            self._box.style.display = "block";
422            self._box.firstChild.src = imag.src;
423            self._box.firstChild.setAttribute('title',self._imgs[self._open].title);
424            if (loading) loading.style.display = 'none';
425        };
426        self._expandable = false;
427        self._expanded = false;
428        self._enable_keyboard();
429        imag.src = self._imgs[self._open].src;
430        self._preload_neighbors(num);
431    },
432    _preload_neighbors: function(num){
433        var self = this;
434
435        if((self._imgs.length - 1) > num){
436            var preloadNextImage = new Image();
437            preloadNextImage.src = self._imgs[num + 1].src;
438        }
439        if(num > 0){
440            var preloadPrevImage = new Image();
441            preloadPrevImage.src = self._imgs[num - 1].src;
442        }
443    },
444    _set_cursor : function(obj)
445    {
446        var self = this;
447        if (self._ua.isWinIE && !self._ua.isNewIE) return;
448        obj.style.cursor = 'pointer';
449    },
450    _close : function()
451    {
452        var self = this;
453        self._open = -1;
454        self._disable_keyboard();
455        self._hide_action();
456        self._wrap.style.display = "none";
457        self._box.style.display  = "none";
458    },
459    _enable_keyboard: function()
460    {
461        //globally store refernce to current lightbox object:
462        __lightbox = this;
463        addEvent(document,'keydown',this._keyboard_action);
464    },
465    _disable_keyboard: function()
466    {
467        //remove global pointer:
468        delete __lightbox;
469        removeEvent(document,'keydown',this._keyboard_action);
470    },
471    _keyboard_action: function(e) {
472        var self = __lightbox;
473        var keycode = 0;
474
475        if(e.which){ // mozilla
476            keycode = e.which;
477        }else{ // IE
478            keycode = event.keyCode;
479        }
480
481        var key = String.fromCharCode(keycode).toLowerCase();
482        if((key == 'x') || (key == 'c') || (keycode == 27)){   // close lightbox
483            self._close();
484        } else if( (key == 'p') || (keycode == 37) ){  // display previous image
485            self._move(-1);
486        } else if(key == 'n' || (keycode == 39) ){  // display next image
487            self._move(+1);
488        }
489    }
490};
491
492/**
493 * Add a quicklink to the media popup
494 */
495function gallery_plugin(){
496    var opts = $('media__opts');
497    if(!opts) return;
498    if(!window.opener) return;
499
500    var glbl = document.createElement('label');
501    var glnk = document.createElement('a');
502    var gbrk = document.createElement('br');
503    glnk.name         = 'gallery_plugin';
504    glnk.innerHTML    = 'Add namespace as gallery';
505    glnk.style.cursor = 'pointer';
506
507    glnk.onclick = function(){
508        var h1 = $('media__ns');
509        if(!h1) return;
510        var ns = h1.innerHTML;
511        opener.insertAtCarret('wiki__text','{{gallery>'+ns+'}}');
512        if(!media.keepopen) window.close();
513    };
514
515    opts.appendChild(glbl);
516    glbl.appendChild(glnk);
517    opts.appendChild(gbrk);
518}
519
520// === main ===
521addInitEvent(function() {
522    var lightbox = new LightBox({
523        loadingimg:DOKU_BASE+'lib/plugins/gallery/images/loading.gif',
524        expandimg:DOKU_BASE+'lib/plugins/gallery/images/expand.gif',
525        shrinkimg:DOKU_BASE+'lib/plugins/gallery/images/shrink.gif',
526        closeimg:DOKU_BASE+'lib/plugins/gallery/images/close.gif',
527        nextimg:DOKU_BASE+'lib/plugins/gallery/images/next.gif',
528        previmg:DOKU_BASE+'lib/plugins/gallery/images/prev.gif'
529    });
530    gallery_plugin();
531});
532