PageSourceSearch

https://www.obec-holovousy.cz/bundles/headerfooter/js/slideshow2/js/slideshow.js?v=v6.5.0

js obec-holovousy.cz collected 2026-10-03 02:42:24 UTC 44,293 bytes, 1,128 lines download raw bytes

1/**
2Script: Slideshow.js
3	Slideshow - A javascript class for Mootools to stream and animate the presentation of images on your website.
4
5License:
6	MIT-style license.
7
8Copyright:
9	Copyright (c) 2011 [Aeron Glemann](http://www.electricprism.com/aeron/).
10
11Dependencies:
12	Mootools 1.3.1 Core: Fx.Morph, Fx.Tween, Selectors, Element.Dimensions.
13	Mootools 1.3.1.1 More: Assets.
14*/
15(function () {
16    WhenPaused = 1 << 0;
17    WhenPlaying = 1 << 1;
18    OnStart = 1 << 2;
19
20    Slideshow = new Class({
21        Implements: [Chain, Events, Options],
22
23        options: {
24            /*
25			onComplete: $empty,
26			onEnd: $empty,
27			onStart: $empty,*/
28            accesskeys: {
29                first: { key: 'shift left', label: 'Shift + Leftwards Arrow' },
30                prev: { key: 'left', label: 'Leftwards Arrow' },
31                pause: { key: 'p', label: 'P' },
32                next: { key: 'right', label: 'Rightwards Arrow' },
33                last: { key: 'shift right', label: 'Shift + Rightwards Arrow' },
34            },
35            captions: true,
36            center: true,
37            classes: [
38                /*'slideshow', 'first', 'prev', 'play', 'pause', 'next', 'last', 'images', 'captions', 'controller', 'thumbnails', 'hidden', 'visible', 'inactive', 'active', 'loader'*/
39            ],
40            controller: true,
41            data: null,
42            delay: 2000,
43            duration: 1000,
44            fast: false,
45            height: false,
46            href: '',
47            hu: '',
48            linked: false,
49            loader: true,
50            loop: true,
51            match: /\?slide=(\d+)$/,
52            overlap: true,
53            paused: false,
54            random: false,
55            replace: [/(\.[^\.]+)$/, 't$1'],
56            resize: 'fill',
57            slide: 0,
58            thumbnails: true,
59            titles: false,
60            transition: 'sine:in:out',
61            width: false,
62        },
63
64        /**
65	Constructor: initialize
66		Creates an instance of the Slideshow class.
67
68	Arguments:
69		element - (element) The wrapper element.
70		data - (array or object) The images and optional thumbnails, captions and links for the show.
71		options - (object) The options below.
72
73	Syntax:
74		var myShow = new Slideshow(element, data, options);
75	*/
76
77        initialize: function (el, data, options) {
78            this.setOptions(options);
79            this.el = document.id(el);
80            if (!this.el) return;
81            var match = window.location.href.match(this.options.match);
82            this.slide = this._slide = this.options.match && match ? match[1].toInt() : this.options.slide;
83            this.counter = this.timeToNextTransition = this.timeToTransitionComplete = 0;
84            this.direction = 'left';
85            this.cache = {};
86            this.paused = false;
87            if (!this.options.overlap) this.options.duration *= 2;
88            var anchor = this.el.getElement('a') || new Element('a');
89            if (!this.options.href) this.options.href = anchor.get('href') || '';
90
91            if (!this.options.target) this.options.target = '_self';
92
93            if (this.options.hu.length && !this.options.hu.test(/\/$/)) this.options.hu += '/';
94            if (this.options.fast === true) this.options.fast = WhenPaused | WhenPlaying;
95
96            // styles
97
98            var keys =
99                    'slideshow first prev play pause next last images captions controller thumbnails hidden visible inactive active loader'.split(
100                        ' ',
101                    ),
102                values = keys.map(function (key, i) {
103                    return this.options.classes[i] || key;
104                }, this);
105            this.classes = values.associate(keys);
106            this.classes.get = function () {
107                var str = '.' + this.slideshow;
108                for (var i = 0, l = arguments.length; i < l; i++) str += '-' + this[arguments[i]];
109                return str;
110            }.bind(this.classes);
111
112            // data
113
114            if (!data) {
115                this.options.hu = '';
116                data = {};
117                var thumbnails = this.el.getElements(this.classes.get('thumbnails') + ' img');
118                this.el.getElements(this.classes.get('images') + ' img').each(function (img, i) {
119                    var src = img.src,
120                        caption = img.alt || img.title,
121                        href = img.getParent().href,
122                        thumbnail = thumbnails[i] ? thumbnails[i].src : '';
123                    data[src] = { caption: caption, href: href, thumbnail: thumbnail };
124                });
125            }
126            var loaded = this.load(data);
127            if (!loaded) return;
128
129            // events
130
131            this.events = {};
132            this.events.push = function (type, fn) {
133                if (!this[type]) this[type] = [];
134                this[type].push(fn);
135                document.addEvent(type, fn);
136                return this;
137            }.bind(this.events);
138
139            this.accesskeys = {};
140            for (action in this.options.accesskeys) {
141                var obj = this.options.accesskeys[action];
142                this.accesskeys[action] = accesskey = { label: obj.label };
143                ['shift', 'control', 'alt'].each(function (modifier) {
144                    var re = new RegExp(modifier, 'i');
145                    accesskey[modifier] = obj.key.test(re);
146                    obj.key = obj.key.replace(re, '');
147                });
148                accesskey.key = obj.key.trim();
149            }
150
151            this.events.push(
152                'keyup',
153                function (e) {
154                    Object.each(
155                        this.accesskeys,
156                        function (accesskey, action) {
157                            if (
158                                e.key == accesskey.key &&
159                                e.shift == accesskey.shift &&
160                                e.control == accesskey.control &&
161                                e.alt == accesskey.alt
162                            )
163                                this[action]();
164                        },
165                        this,
166                    );
167                }.bind(this),
168            );
169
170            // required elements
171
172            var el = this.el.getElement(this.classes.get('images')),
173                img = this.el.getElement('img') || new Element('img'),
174                images = el
175                    ? el.empty()
176                    : new Element('div', { class: this.classes.get('images').substr(1) }).inject(this.el),
177                div = images.getSize();
178            this.height = this.options.height || div.y;
179            this.width = this.options.width || div.x;
180            images.set({ styles: { height: this.height, width: this.width } });
181            this.el.store('images', images);
182            this.a = this.image = img;
183            if (Browser.ie && Browser.version >= 7) this.a.style.msInterpolationMode = 'bicubic';
184            this.a.set('styles', { display: 'none' });
185            this.b = this.a.clone();
186            [this.a, this.b].each(function (img) {
187                anchor.clone().cloneEvents(anchor).grab(img).inject(images);
188            });
189
190            // optional elements
191
192            this.options.captions && new Caption(this);
193            this.options.controller && new Controller(this);
194            this.options.loader && new Loader(this);
195            this.options.thumbnails && new Thumbnails(this);
196
197            // begin show
198
199            this._preload(this.options.fast & OnStart);
200        },
201
202        /**
203	Public method: go
204		Jump directly to a slide in the show.
205
206	Arguments:
207		n - (integer) The index number of the image to jump to, 0 being the first image in the show.
208
209	Syntax:
210		myShow.go(n);
211	*/
212
213        go: function (n, direction) {
214            var nextSlide = (this.slide + this.data.images.length) % this.data.images.length;
215            if (n == nextSlide || Date.now() < this.timeToTransitionComplete) return;
216            clearTimeout(this.timer);
217            this.timeToNextTransition = 0;
218            this.direction = direction ? direction : n < this._slide ? 'right' : 'left';
219            this.slide = this._slide = n;
220            if (this.preloader) this.preloader = this.preloader.destroy();
221            this._preload(this.options.fast & WhenPlaying || (this.paused && this.options.fast & WhenPaused));
222        },
223
224        /**
225	Public method: first
226		Goes to the first image in the show.
227
228	Syntax:
229		myShow.first();
230	*/
231
232        first: function () {
233            this.prev(true);
234        },
235
236        /**
237	Public method: prev
238		Goes to the previous image in the show.
239
240	Syntax:
241		myShow.prev();
242	*/
243
244        prev: function (first) {
245            var n = 0;
246            if (!first) {
247                if (this.options.random) {
248                    if (this.showed.i < 2) return;
249                    this.showed.i -= 2;
250                    n = this.showed.array[this.showed.i];
251                } else n = (this.slide - 1 + this.data.images.length) % this.data.images.length;
252            }
253            this.go(n, 'right');
254        },
255
256        /**
257	Public method: pause
258		Toggles play / pause state of the show.
259
260	Arguments:
261		p - (undefined, 1 or 0) Call pause with no arguments to toggle the pause state. Call pause(1) to force pause, or pause(0) to force play.
262
263	Syntax:
264		myShow.pause(p);
265	*/
266
267        pause: function (p) {
268            if (p != undefined) this.paused = p ? false : true;
269            if (this.paused) {
270                // play
271                this.paused = false;
272                this.timeToTransitionComplete = Date.now() + this.timeToTransitionComplete;
273                this.timer = this._preload.delay(50, this);
274                [this.a, this.b].each(function (img) {
275                    ['morph', 'tween'].each(function (p) {
276                        if (this.retrieve(p)) this.get(p).resume();
277                    }, img);
278                });
279                this.controller && this.el.retrieve('pause').getParent().removeClass(this.classes.play);
280            } else {
281                // pause
282                this.paused = true;
283                this.timeToTransitionComplete = this.timeToTransitionComplete - Date.now();
284                clearTimeout(this.timer);
285                [this.a, this.b].each(function (img) {
286                    ['morph', 'tween'].each(function (p) {
287                        if (this.retrieve(p)) this.get(p).pause();
288                    }, img);
289                });
290                this.controller && this.el.retrieve('pause').getParent().addClass(this.classes.play);
291            }
292        },
293
294        /**
295	Public method: next
296		Goes to the next image in the show.
297
298	Syntax:
299		myShow.next();
300	*/
301
302        next: function (last) {
303            var n = last ? this.data.images.length - 1 : this._slide;
304            this.go(n, 'left');
305        },
306
307        /**
308	Public method: last
309		Goes to the last image in the show.
310
311	Syntax:
312		myShow.last();
313	*/
314
315        last: function () {
316            this.next(true);
317        },
318
319        /**
320	Public method: load
321		Loads a new data set into the show: will stop the current show, rewind and rebuild thumbnails if applicable.
322
323	Arguments:
324		data - (array or object) The images and optional thumbnails, captions and links for the show.
325
326	Syntax:
327		myShow.load(data);
328	*/
329
330        load: function (data) {
331            this.firstrun = true;
332            this.showed = { array: [], i: 0 };
333            if (typeOf(data) == 'array') {
334                this.options.captions = false;
335                data = new Array(data.length).associate(
336                    data.map(function (image, i) {
337                        return image + '?' + i;
338                    }),
339                );
340            }
341            this.data = { images: [], captions: [], hrefs: [], thumbnails: [], targets: [], titles: [] };
342            for (var image in data) {
343                var obj = data[image] || {},
344                    image = this.options.hu + image,
345                    caption = obj.caption ? obj.caption.trim() : '',
346                    href = obj.href ? obj.href.trim() : this.options.linked ? image : this.options.href,
347                    target = obj.target ? obj.target.trim() : '_self',
348                    thumbnail = obj.thumbnail
349                        ? this.options.hu + obj.thumbnail.trim()
350                        : image.replace(this.options.replace[0], this.options.replace[1]),
351                    title = caption
352                        .replace(/<.+?>/gm, '')
353                        .replace(/</g, '&lt;')
354                        .replace(/>/g, '&gt;')
355                        .replace(/"/g, "'");
356                this.data.images.push(image);
357                this.data.captions.push(caption);
358                this.data.hrefs.push(href);
359                this.data.targets.push(target);
360                this.data.thumbnails.push(thumbnail);
361                this.data.titles.push(title);
362            }
363            if (this.options.random) this.slide = this._slide = Number.random(0, this.data.images.length - 1);
364
365            // only run when data is loaded dynamically into an existing slideshow instance
366
367            if (this.options.thumbnails && this.el.retrieve('thumbnails')) this._thumbnails();
368            if (this.el.retrieve('images')) {
369                [this.a, this.b].each(function (img) {
370                    ['morph', 'tween'].each(function (p) {
371                        if (this.retrieve(p)) this.get(p).cancel();
372                    }, img);
373                });
374                this.slide = this._slide = this.timeToTransitionComplete = 0;
375                this.go(0);
376            }
377            return this.data.images.length;
378        },
379
380        /**
381	Public method: destroy
382		Destroys a Slideshow instance.
383
384	Arguments:
385		p - (string) The images and optional thumbnails, captions and links for the show.
386
387	Syntax:
388		myShow.destroy(p);
389	*/
390
391        destroy: function (p) {
392            Object.each(this.events, function (array, e) {
393                if ('each' in array)
394                    array.each(function (fn) {
395                        document.removeEvent(e, fn);
396                    });
397            });
398            this.pause(1);
399            'caption loader thumbnails'.split(' ').each(function (i, timer) {
400                this.options[i] && (timer = this[i].retrieve('timer')) && clearTimeout(timer);
401            }, this);
402            typeOf(this.el[p]) == 'function' && this.el[p]();
403            delete this.el.uid;
404        },
405
406        /**
407	Private method: preload
408		Preloads the next slide in the show, once loaded triggers the show, updates captions, thumbnails, etc.
409	*/
410
411        _preload: function (fast) {
412            var src = this.data.images[this._slide].replace(/([^?]+).*/, '$1'),
413                cached = (loaded = !!this.cache[src]);
414            if (!cached) {
415                if (!this.preloader)
416                    this.preloader = new Asset.image(src, {
417                        onerror: function () {
418                            // do something
419                        },
420                        onload: function () {
421                            this.store('loaded', true);
422                        },
423                    });
424                loaded = this.preloader.retrieve('loaded') && this.preloader.get('width');
425            }
426            if (loaded && Date.now() > this.timeToNextTransition && Date.now() > this.timeToTransitionComplete) {
427                var src = this.data.images[this._slide].replace(/([^?]+).*/, '$1');
428                if (this.preloader) {
429                    this.cache[src] = {
430                        height: this.preloader.get('height'),
431                        src: src,
432                        width: this.preloader.get('width'),
433                    };
434                }
435                if (this.stopped) {
436                    if (this.options.captions)
437                        this.caption.get('morph').cancel().start(this.classes.get('captions', 'hidden'));
438                    this.pause(1);
439                    if (this.end) this.fireEvent('end');
440                    this.stopped = this.end = false;
441                    return;
442                }
443                this.image = this.counter % 2 ? this.b : this.a;
444                this.image.set('styles', {
445                    display: 'block',
446                    height: null,
447                    visibility: 'hidden',
448                    width: null,
449                    zIndex: this.counter,
450                });
451                this.image.set(this.cache[src]);
452                this.image.width = this.cache[src].width;
453                this.image.height = this.cache[src].height;
454                this.options.resize && this._resize(this.image);
455                this.options.center && this._center(this.image);
456                var anchor = this.image.getParent();
457                if (this.data.hrefs[this._slide]) {
458                    anchor.set('href', this.data.hrefs[this._slide]);
459                    anchor.set('target', this.data.targets[this._slide]);
460                } else {
461                    anchor.erase('href');
462                    anchor.erase('target');
463                }
464                var title = this.data.titles[this._slide];
465                this.image.set('alt', title);
466                this.options.titles && anchor.set('title', title);
467                this.options.loader && this.loader.fireEvent('hide');
468                this.options.captions && this.caption.fireEvent('update', fast);
469                this.options.thumbnails && this.thumbnails.fireEvent('update', fast);
470                this._show(fast);
471                this._loaded(fast);
472            } else {
473                if (Date.now() > this.timeToNextTransition && this.options.loader) this.loader.fireEvent('show');
474                this.timer = this._preload.delay(50, this, fast);
475            }
476        },
477
478        /**
479	Private method: show
480		Does the slideshow effect.
481	*/
482
483        _show: function (fast) {
484            if (!this.image.retrieve('morph')) {
485                var options = this.options.overlap ? { link: 'cancel' } : { link: 'chain' };
486                $$(this.a, this.b).set(
487                    'morph',
488                    Object.merge(options, {
489                        duration: this.options.duration,
490                        onStart: this._start.bind(this),
491                        onComplete: this._complete.bind(this),
492                        transition: this.options.transition,
493                    }),
494                );
495            }
496            var hidden = this.classes.get('images', this.direction == 'left' ? 'next' : 'prev'),
497                visible = this.classes.get('images', 'visible'),
498                img = this.counter % 2 ? this.a : this.b;
499            if (fast) {
500                img.get('morph').cancel().set(hidden);
501                this.image.get('morph').cancel().set(visible);
502            } else {
503                if (this.options.overlap) {
504                    img.get('morph').set(visible);
505                    this.image.get('morph').set(hidden).start(visible);
506                } else {
507                    var fn = function (visible) {
508                        this.image.get('morph').start(visible);
509                    }.pass(visible, this);
510                    if (this.firstrun) return fn();
511                    hidden = this.classes.get('images', this.direction == 'left' ? 'prev' : 'next');
512                    this.image.get('morph').set(hidden);
513                    img.get('morph').set(visible).start(hidden).chain(fn);
514                }
515            }
516        },
517
518        /**
519	Private method: loaded
520		Run after the current image has been loaded, sets up the next image to be shown.
521	*/
522
523        _loaded: function (fast) {
524            this.counter++;
525            this.timeToNextTransition = Date.now() + this.options.duration + this.options.delay;
526            this.direction = 'left';
527            this.timeToTransitionComplete = fast ? 0 : Date.now() + this.options.duration;
528            if (this._slide == this.data.images.length - 1 && !this.options.loop && !this.options.random)
529                this.stopped = this.end = true;
530            if (this.options.random) {
531                this.showed.i++;
532                if (this.showed.i >= this.showed.array.length) {
533                    var n = this._slide;
534                    if (this.showed.array.getLast() != n) this.showed.array.push(n);
535                    while (this._slide == n) this.slide = this._slide = Number.random(0, this.data.images.length - 1);
536                } else this.slide = this._slide = this.showed.array[this.showed.i];
537            } else {
538                this.slide = this._slide;
539                this._slide = (this.slide + 1) % this.data.images.length;
540            }
541            if (this.image.getStyle('visibility') != 'visible')
542                (function () {
543                    this.image.setStyle('visibility', 'visible');
544                }).delay(1, this);
545            if (this.preloader) this.preloader = this.preloader.destroy();
546            this.paused || this._preload();
547        },
548
549        /**
550	Private method: center
551		Center an image.
552	*/
553
554        _center: function (img) {
555            var size = img.getSize(),
556                h = size.y,
557                w = size.x;
558            img.set('styles', { left: (w - this.width) / -2, top: (h - this.height) / -2 });
559        },
560
561        /**
562	Private method: resize
563		Resizes an image.
564	*/
565
566        _resize: function (img) {
567            var h = img.get('height').toFloat(),
568                w = img.get('width').toFloat(),
569                dh = this.height / h,
570                dw = this.width / w;
571            if (this.options.resize == 'fit') dh = dw = dh > dw ? dw : dh;
572            if (this.options.resize == 'fill') dh = dw = dh > dw ? dh : dw;
573            img.set('styles', { height: Math.ceil(h * dh), width: Math.ceil(w * dw) });
574        },
575
576        /**
577	Private method: start
578		Callback on start of slide change.
579	*/
580
581        _start: function () {
582            this.fireEvent('start');
583        },
584
585        /**
586	Private method: complete
587		Callback on start of slide change.
588	*/
589
590        _complete: function () {
591            if (this.firstrun && this.options.paused) this.pause(1);
592            this.firstrun = false;
593            this.fireEvent('complete');
594        },
595    });
596
597    /**
598	Private method: captions
599		Builds the optional caption element, adds interactivity.
600		This method can safely be removed if the captions option is not enabled.
601	*/
602
603    var Caption = new Class({
604        Implements: [Chain, Events, Options],
605
606        options: {
607            /*
608			duration: 500,
609			fps: 50,
610			transition: 'sine:in:out',
611			unit: false, */
612            delay: 0,
613            link: 'cancel',
614        },
615
616        initialize: function (slideshow) {
617            if (!slideshow) return;
618            var options = slideshow.options.captions;
619            if (options === true) options = {};
620            this.setOptions(options);
621            var el = slideshow.el.getElement(slideshow.classes.get('captions')),
622                caption = el
623                    ? el.dispose().empty()
624                    : new Element('div', { class: slideshow.classes.get('captions').substr(1) });
625            slideshow.caption = caption;
626            caption
627                .set({
628                    'aria-busy': false,
629                    'aria-hidden': false,
630                    events: { update: this.update.bind(slideshow) },
631                    morph: this.options,
632                    role: 'description',
633                })
634                .store('delay', this.options.delay);
635            if (!caption.get('id')) caption.set('id', 'Slideshow-' + Date.now());
636            slideshow.el.retrieve('images').set('aria-labelledby', caption.get('id'));
637            caption.inject(slideshow.el);
638        },
639
640        update: function (fast) {
641            var empty = !this.data.captions[this._slide].length,
642                timer;
643            if ((timer = this.caption.retrieve('timer'))) clearTimeout(timer);
644            if (fast) {
645                var p = empty ? 'hidden' : 'visible';
646                this.caption
647                    .set({ 'aria-hidden': empty, html: this.data.captions[this._slide] })
648                    .get('morph')
649                    .cancel()
650                    .set(this.classes.get('captions', p));
651            } else {
652                var fn1 = empty
653                    ? function (caption) {
654                          this.caption.store(
655                              'timer',
656                              setTimeout(
657                                  function (caption) {
658                                      this.caption.set('html', caption).morph(this.classes.get('captions', 'hidden'));
659                                  }.pass(caption, this),
660                                  this.caption.retrieve('delay'),
661                              ),
662                          );
663                      }.pass(this.data.captions[this._slide], this)
664                    : function (caption) {
665                          this.caption.store(
666                              'timer',
667                              setTimeout(
668                                  function (caption) {
669                                      this.caption.set('html', caption).morph(this.classes.get('captions', 'visible'));
670                                  }.pass(caption, this),
671                                  this.caption.retrieve('delay'),
672                              ),
673                          );
674                      }.pass(this.data.captions[this._slide], this);
675                var fn2 = function () {
676                    this.caption.set('aria-busy', false);
677                }.bind(this);
678                this.caption
679                    .set('aria-busy', true)
680                    .get('morph')
681                    .cancel()
682                    .start(this.classes.get('captions', 'hidden'))
683                    .chain(fn1, fn2);
684            }
685        },
686    });
687
688    /**
689	Private method: controller
690	  Builds the optional controller element, adds interactivity.
691	  This method can safely be removed if the controller option is not enabled.
692	*/
693
694    var Controller = new Class({
695        Implements: [Chain, Events, Options],
696
697        options: {
698            /*
699			duration: 500,
700			fps: 50,
701			transition: 'sine:in:out',
702			unit: false, */
703            link: 'cancel',
704        },
705
706        initialize: function (slideshow) {
707            if (!slideshow) return;
708            var options = slideshow.options.captions;
709            if (options === true) options = {};
710            this.setOptions(options);
711            var el = slideshow.el.getElement(slideshow.classes.get('controller')),
712                controller = el
713                    ? el.dispose().empty()
714                    : new Element('div', { class: slideshow.classes.get('controller').substr(1) });
715            slideshow.controller = controller;
716            controller.set({
717                'aria-hidden': false,
718                role: 'menubar',
719            });
720            var ul = new Element('ul', { role: 'menu' }).inject(controller),
721                i = 0;
722            Object.each(
723                slideshow.accesskeys,
724                function (accesskey, action) {
725                    var li = new Element('li', {
726                        class:
727                            action == 'pause' && this.options.paused
728                                ? this.classes.play + ' ' + this.classes[action]
729                                : this.classes[action],
730                    }).inject(ul);
731                    var a = this.el.retrieve(
732                        action,
733                        new Element('a', {
734                            role: 'menuitem',
735                            tabindex: i++,
736                            title: accesskey.label,
737                        }).inject(li),
738                    );
739                    a.set('events', {
740                        click: function (action) {
741                            this[action]();
742                        }.pass(action, this),
743                        mouseenter: function (active) {
744                            this.addClass(active);
745                        }.pass(this.classes.active, a),
746                        mouseleave: function (active) {
747                            this.removeClass(active);
748                        }.pass(this.classes.active, a),
749                    });
750                },
751                slideshow,
752            );
753            controller
754                .set({
755                    events: {
756                        hide: this.hide.pass(slideshow.classes.get('controller', 'hidden'), controller),
757                        show: this.show.pass(slideshow.classes.get('controller', 'visible'), controller),
758                    },
759                    morph: this.options,
760                })
761                .store('hidden', false);
762            slideshow.events
763                .push('keydown', this.keydown.bind(slideshow))
764                .push('keyup', this.keyup.bind(slideshow))
765                .push('mousemove', this.mousemove.bind(slideshow));
766            controller.inject(slideshow.el).fireEvent('hide');
767        },
768
769        hide: function (hidden) {
770            if (this.get('aria-hidden') == 'false') this.set('aria-hidden', true).morph(hidden);
771        },
772
773        keydown: function (e) {
774            Object.each(
775                this.accesskeys,
776                function (accesskey, action) {
777                    if (
778                        e.key == accesskey.key &&
779                        e.shift == accesskey.shift &&
780                        e.control == accesskey.control &&
781                        e.alt == accesskey.alt
782                    ) {
783                        if (this.controller.get('aria-hidden') == 'true')
784                            this.controller.get('morph').set(this.classes.get('controller', 'visible'));
785                        this.el.retrieve(action).fireEvent('mouseenter');
786                    }
787                },
788                this,
789            );
790        },
791
792        keyup: function (e) {
793            Object.each(
794                this.accesskeys,
795                function (accesskey, action) {
796                    if (
797                        e.key == accesskey.key &&
798                        e.shift == accesskey.shift &&
799                        e.control == accesskey.control &&
800                        e.alt == accesskey.alt
801                    ) {
802                        if (this.controller.get('aria-hidden') == 'true')
803                            this.controller.set('aria-hidden', false).fireEvent('hide');
804                        this.el.retrieve(action).fireEvent('mouseleave');
805                    }
806                },
807                this,
808            );
809        },
810
811        mousemove: function (e) {
812            var images = this.el.retrieve('images').getCoordinates(),
813                action =
814                    e.page.x > images.left &&
815                    e.page.x < images.right &&
816                    e.page.y > images.top &&
817                    e.page.y < images.bottom
818                        ? 'show'
819                        : 'hide';
820            this.controller.fireEvent(action);
821        },
822
823        show: function (visible) {
824            if (this.get('aria-hidden') == 'true') this.set('aria-hidden', false).morph(visible);
825        },
826    });
827
828    /**
829	Private method: loader
830		Builds the optional loader element, adds interactivity.
831		This method can safely be removed if the loader option is not enabled.
832	*/
833
834    var Loader = new Class({
835        Implements: [Chain, Events, Options],
836
837        options: {
838            /*
839			duration: 500,
840			transition: 'sine:in:out',
841			unit: false, */
842            fps: 20,
843            link: 'cancel',
844        },
845
846        initialize: function (slideshow) {
847            if (!slideshow) return;
848            var options = slideshow.options.loader;
849            if (options === true) options = {};
850            this.setOptions(options);
851            var loader = new Element('div', {
852                'aria-hidden': false,
853                class: slideshow.classes.get('loader').substr(1),
854                morph: this.options,
855                role: 'progressbar',
856            })
857                .store('animate', false)
858                .store('i', 0)
859                .store('delay', 1000 / this.options.fps)
860                .inject(slideshow.el);
861            slideshow.loader = loader;
862            var url = loader
863                .getStyle('backgroundImage')
864                .replace(/url\(['"]?(.*?)['"]?\)/, '$1')
865                .trim();
866            if (url) {
867                if (url.test(/\.png$/) && Browser.ie && Browser.version < 7)
868                    loader.setStyles({
869                        backgroundImage: 'none',
870                        filter:
871                            'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' +
872                            url +
873                            '", sizingMethod="crop")',
874                    });
875                new Asset.image(url, {
876                    onload: function () {
877                        var size = loader.getSize(),
878                            width = this.get('width'),
879                            height = this.get('height');
880                        if (width > size.x)
881                            loader
882                                .store('x', size.x)
883                                .store('animate', 'x')
884                                .store('frames', (width / size.x).toInt());
885                        if (height > size.y)
886                            loader
887                                .store('y', size.y)
888                                .store('animate', 'y')
889                                .store('frames', (height / size.y).toInt());
890                    },
891                });
892            }
893            loader.set('events', {
894                animate: this.animate.bind(loader),
895                hide: this.hide.pass(slideshow.classes.get('loader', 'hidden'), loader),
896                show: this.show.pass(slideshow.classes.get('loader', 'visible'), loader),
897            });
898            loader.fireEvent('hide');
899        },
900
901        animate: function () {
902            var animate = this.retrieve('animate');
903            if (!animate) return;
904            var i = (this.retrieve('i').toInt() + 1) % this.retrieve('frames');
905            this.store('i', i);
906            var n = i * this.retrieve(animate) + 'px';
907            if (animate == 'x') this.setStyle('backgroundPosition', n + ' 0px');
908            if (animate == 'y') this.setStyle('backgroundPosition', '0px ' + n);
909        },
910
911        hide: function (hidden) {
912            if (this.get('aria-hidden') == 'false') {
913                this.set('aria-hidden', true).morph(hidden);
914                if (this.retrieve('animate')) clearTimeout(this.retrieve('timer'));
915            }
916        },
917
918        show: function (visible) {
919            if (this.get('aria-hidden') == 'true') {
920                this.set('aria-hidden', false).morph(visible);
921                if (this.retrieve('animate')) {
922                    this.store(
923                        'timer',
924                        function () {
925                            this.fireEvent('animate');
926                        }.periodical(this.retrieve('delay'), this),
927                    );
928                }
929            }
930        },
931    });
932
933    /**
934	Private method: thumbnails
935		Builds the optional thumbnails element, adds interactivity.
936		This method can safely be removed if the thumbnails option is not enabled.
937	*/
938
939    var Thumbnails = new Class({
940        Implements: [Chain, Events, Options],
941
942        options: {
943            /*
944			duration: 500,
945			transition: 'sine:in:out',
946			unit: false, */
947            columns: null,
948            fps: 50,
949            link: 'cancel',
950            position: null,
951            rows: null,
952            scroll: null,
953        },
954
955        initialize: function (slideshow) {
956            var options = slideshow.options.thumbnails === true ? {} : slideshow.options.thumbnails;
957            this.setOptions(options);
958            var el = slideshow.el.getElement(slideshow.classes.get('thumbnails')),
959                thumbnails = el
960                    ? el.empty()
961                    : new Element('div', { class: slideshow.classes.get('thumbnails').substr(1) });
962            slideshow.thumbnails = thumbnails;
963            thumbnails.set({ role: 'menubar', styles: { overflow: 'hidden' } });
964            var uid = thumbnails.retrieve('uid', 'Slideshow-' + Date.now()),
965                ul = new Element('ul', {
966                    role: 'menu',
967                    styles: { left: 0, position: 'absolute', top: 0 },
968                    tween: { link: 'cancel' },
969                }).inject(thumbnails);
970            slideshow.data.thumbnails.each(function (thumbnail, i) {
971                var li = new Element('li', { id: uid + i }).inject(ul),
972                    a = new Element('a', {
973                        class: slideshow.classes.get('thumbnails', 'hidden').substr(1),
974                        events: {
975                            click: this.click.pass(i, slideshow),
976                        },
977                        href: slideshow.data.images[i],
978                        morph: this.options,
979                        role: 'menuitem',
980                        tabindex: i,
981                    })
982                        .store('uid', i)
983                        .inject(li);
984                if (slideshow.options.titles) a.set('title', slideshow.data.titles[i]);
985                new Asset.image(thumbnail, {
986                    onload: this.onload.pass(i, slideshow),
987                }).inject(a);
988            }, this);
989            thumbnails.set('events', {
990                scroll: this.scroll.bind(thumbnails),
991                update: this.update.bind(slideshow),
992            });
993            var coords = thumbnails.getCoordinates();
994            if (!options.scroll) options.scroll = coords.height > coords.width ? 'y' : 'x';
995            var props =
996                options.scroll == 'y' ? 'top bottom height y width'.split(' ') : 'left right width x height'.split(' ');
997            thumbnails.store('props', props).store('delay', 1000 / this.options.fps);
998            slideshow.events.push('mousemove', this.mousemove.bind(thumbnails));
999            thumbnails.inject(slideshow.el);
1000        },
1001
1002        click: function (i) {
1003            this.go(i);
1004            return false;
1005        },
1006
1007        mousemove: function (e) {
1008            var coords = this.getCoordinates();
1009            if (
1010                e.page.x > coords.left &&
1011                e.page.x < coords.right &&
1012                e.page.y > coords.top &&
1013                e.page.y < coords.bottom
1014            ) {
1015                this.store('page', e.page);
1016                if (!this.retrieve('mouseover')) {
1017                    this.store('mouseover', true);
1018                    this.store(
1019                        'timer',
1020                        function () {
1021                            this.fireEvent('scroll');
1022                        }.periodical(this.retrieve('delay'), this),
1023                    );
1024                }
1025            } else {
1026                if (this.retrieve('mouseover')) {
1027                    this.store('mouseover', false);
1028                    clearTimeout(this.retrieve('timer'));
1029                }
1030            }
1031        },
1032
1033        onload: function (i) {
1034            var thumbnails = this.thumbnails,
1035                a = thumbnails.getElements('a')[i];
1036            if (a) {
1037                (function (a) {
1038                    var visible = i == this.slide ? 'active' : 'inactive';
1039                    a.store('loaded', true)
1040                        .get('morph')
1041                        .set(this.classes.get('thumbnails', 'hidden'))
1042                        .start(this.classes.get('thumbnails', visible));
1043                }).delay(Math.max(1000 / this.data.thumbnails.length, 100), this, a);
1044            }
1045            if (thumbnails.retrieve('limit')) return;
1046            var props = thumbnails.retrieve('props'),
1047                options = this.options.thumbnails,
1048                pos = props[1],
1049                length = props[2],
1050                width = props[4],
1051                li = thumbnails.getElement('li:nth-child(' + (i + 1) + ')').getCoordinates();
1052            if (options.columns || options.rows) {
1053                thumbnails.setStyles({ height: this.height, width: this.width });
1054                if (options.columns.toInt()) thumbnails.setStyle('width', li.width * options.columns.toInt());
1055                if (options.rows.toInt()) thumbnails.setStyle('height', li.height * options.rows.toInt());
1056            }
1057            var div = thumbnails.getCoordinates();
1058            if (options.position) {
1059                if (options.position.test(/bottom|top/))
1060                    thumbnails.setStyles({ bottom: 'auto', top: 'auto' }).setStyle(options.position, -div.height);
1061                if (options.position.test(/left|right/))
1062                    thumbnails.setStyles({ left: 'auto', right: 'auto' }).setStyle(options.position, -div.width);
1063            }
1064            var units = Math.floor(div[width] / li[width]),
1065                x = Math.ceil(this.data.images.length / units),
1066                r = this.data.images.length % units,
1067                len = x * li[length],
1068                ul = thumbnails.getElement('ul').setStyle(length, len);
1069            ul.getElements('li').setStyles({ height: li.height, width: li.width });
1070            thumbnails.store('limit', div[length] - len);
1071        },
1072
1073        scroll: function (n, fast) {
1074            var div = this.getCoordinates(),
1075                ul = this.getElement('ul').getPosition(),
1076                props = this.retrieve('props'),
1077                axis = props[3],
1078                delta,
1079                pos = props[0],
1080                size = props[2],
1081                value,
1082                tween = this.getElement('ul').set('tween', { property: pos }).get('tween');
1083            if (n != undefined) {
1084                var uid = this.retrieve('uid'),
1085                    li = document.id(uid + n).getCoordinates();
1086                delta = div[pos] + div[size] / 2 - li[size] / 2 - li[pos];
1087                value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
1088                tween[fast ? 'set' : 'start'](value);
1089            } else {
1090                var area = div[props[2]] / 3,
1091                    page = this.retrieve('page'),
1092                    velocity = -(this.retrieve('delay') * 0.01);
1093                if (page[axis] < div[pos] + area) delta = (page[axis] - div[pos] - area) * velocity;
1094                else if (page[axis] > div[pos] + div[size] - area)
1095                    delta = (page[axis] - div[pos] - div[size] + area) * velocity;
1096                if (delta) {
1097                    value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
1098                    tween.set(value);
1099                }
1100            }
1101        },
1102
1103        update: function (fast) {
1104            var thumbnails = this.thumbnails,
1105                uid = thumbnails.retrieve('uid');
1106            thumbnails.getElements('a').each(function (a, i) {
1107                if (a.retrieve('loaded')) {
1108                    if (a.retrieve('uid') == this._slide) {
1109                        if (!a.retrieve('active', false)) {
1110                            a.store('active', true);
1111                            var active = this.classes.get('thumbnails', 'active');
1112                            if (fast) a.get('morph').set(active);
1113                            else a.morph(active);
1114                        }
1115                    } else {
1116                        if (a.retrieve('active', true)) {
1117                            a.store('active', false);
1118                            var inactive = this.classes.get('thumbnails', 'inactive');
1119                            if (fast) a.get('morph').set(inactive);
1120                            else a.morph(inactive);
1121                        }
1122                    }
1123                }
1124            }, this);
1125            if (!thumbnails.retrieve('mouseover')) thumbnails.fireEvent('scroll', [this._slide, fast]);
1126        },
1127    });
1128})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.