1(function($){
2
3    var layeranimation = function(rootNode) {
4        var self = this;
5
6        this.scrollTime = 500;
7        this.waitTime = 4000;
8        this.stepWidth = 20;
9        this.nextItemIntverall = 0.7;
10        this.zIndex = 100;
11        this.offsetWidth = 0;
12        this.isPlaying = true;
13        this.itemButtonClicked = false;
14        this.layerPlayingTimeOut = null;
15
16        this.root = rootNode;
17        rootNode[0].layerAnimation = self;
18
19        this.layerList = null;
20        this.layer = new Array();
21        this.currentLayer = 1;
22        this.currentItem = 0;
23        this.isRunning = false;
24
25        this.run = function(itemNrNew, layerNew) {
26
27            // Set Current Item
28            var itemNr = self.currentItem;
29            if ( typeof itemNrNew == 'number' ) itemNr = itemNrNew;
30
31            // Set Current Layer
32            var layerNr = self.currentLayer;
33            if ( typeof layerNew == 'number' ) layerNr = layerNew;
34
35            // If it does not exist, return
36            if ( !self.layer[layerNr] || !self.layer[layerNr].items[itemNr] ) { self.isRunning = false; return; }
37
38            self.isRunning = true;
39
40            // Get the Item
41            var item =  self.layer[layerNr].items[itemNr];
42            if ( itemNr == 0 && self.isPlaying ) {
43                self.setActive(self.layerList.children().get(layerNr), true, false);
44            }
45
46            // Calc Position + Timeout Step
47            var currentLeft = parseInt(item.elem.css('left'));
48
49            var timeout = item.currentTime / (currentLeft * item.direction) * self.stepWidth;
50
51            if ( itemNr == 0 && currentLeft == self.offsetWidth * item.direction ) {
52                var number = layerNr-1 < 0 ? self.layer.length-1 : layerNr-1;
53                self.layer[number].elem.filter(':not(:animated)').css('opacity', 0)/*fadeTo(self.scrollTime, 0, function(){
54                        self.layer[number].elem.css('z-index', self.zIndex);
55                        console.log("animation done " + itemNr + " " + number);
56                })*/;
57            }
58
59            currentLeft -=  (self.stepWidth * item.direction);
60            if ( ( currentLeft <= 0 && item.direction > 0 ) || ( currentLeft >= 0 && item.direction < 0 ) ) { currentLeft = 0; }
61
62            // Set new Position and Timeout
63            item.elem.css('left', currentLeft);
64            if ( itemNr == 0 ) {
65                self.layer[layerNr].elem.css('left', currentLeft);
66            }
67
68            // Start next Item in Layer after Intervall
69            if ( item.currentTime <= (self.scrollTime * self.nextItemIntverall) ) {
70                window.setTimeout( function() { self.run(itemNr +1, layerNr); }, timeout);
71
72                // Reset previous if next Layer comes
73    //            if ( this.layer.length > 1 && firstStep)
74    //                this.resetLayer(layerNr -1 );
75                self.layer[layerNr].elem.css('z-index', self.zIndex);
76            }
77
78            item.currentTime -= timeout;
79
80            // If this is not the current layer, but an intervalled layer, return
81            if ( itemNrNew || layerNew ) { return; }
82
83            // scrolling done ?
84            if ( itemNr == self.currentItem && (( currentLeft <= 0 && item.direction > 0 ) || ( currentLeft >= 0 && item.direction < 0 )) ) {
85
86                if ( self.currentItem < self.layer[layerNr].items.length -1 ) {
87
88                    self.currentItem++;
89
90                } else {
91
92                    if ( self.layer.length > 1 )
93                        self.resetLayer(layerNr -1 );
94                    self.layer[layerNr].elem.css('z-index', self.zIndex);
95
96                    if ( layerNr < self.layer.length-1 ) {
97                        self.currentLayer++;
98                    } else {
99                        self.currentLayer = 0;
100                    }
101
102                    self.currentItem = 0;
103                    timeout = self.layer[layerNr].waitTime || self.waitTime;
104
105                    $(document).trigger("layeranimation.layerDone", self.layer);
106
107                    if ( ! self.isPlaying || self.layer.length == 1 ) {
108                        self.isRunning = false;
109                        return;
110                    }
111                }
112            }
113
114            // next run routine;
115            self.layerPlayingTimeOut = window.setTimeout( self.run, timeout);
116        };
117
118        this.resetLayer = function(layer, alsoCurrent) {
119
120            if ( layer < 0 ) { layer = self.layer.length-1; }
121            if ( !self.layer[layer] ) { return; }
122
123            var currentLayer = alsoCurrent ? ( self.currentLayer-1 < 0 ? self.layer.length-1 : self.currentLayer-1 ) : self.currentLayer;
124            var offset = layer == currentLayer ? 0 : self.offsetWidth;
125
126            $(self.layer[layer].items).each(function(){
127                this.elem.css({'left': this.direction * offset});
128                this.currentTime = self.scrollTime;
129            });
130
131            // Special for layer one
132            self.layer[layer].elem.css({
133                                        'z-index': self.zIndex +100,
134                                        'left' : self.layer[layer].items[0].direction * offset
135                                        }).fadeTo(0, 1);
136        };
137
138        /* *****************************************************************************
139
140            Build Structure
141
142        ***************************************************************************** */
143
144        this.layerStruct = function() {
145            this.items = new Array();
146            this.elem = null;
147            this.waitTime = self.waitTime;
148        };
149
150        this.itemStruct = function() {
151            this.elem = null;
152            this.direction = +1;
153            this.currentTime = 0;
154            this.next = null;
155        };
156
157        this.layerClick = function(elem) {
158
159            this.Toggle = function(e) {
160
161                this.elem = $(this);
162                if (e.target) this.elem = $(e.target);
163                else if (e.srcElement) this.elem = $(e.srcElement);
164
165                this.isPlayPause = this.elem.hasClass('play-pause');
166                this.active = !this.elem.hasClass('active');
167
168                this.playPauseToggle = function(e) {
169                    if ( this.active ) {
170                        // pause playing
171                        self.Pause();
172                        self.itemButtonClicked = true;
173                    } else {
174                        // start playing
175                        self.itemButtonClicked = false;
176                        self.Resume();
177                    }
178                };
179
180                this.layerToggle = function(e) {
181                    self.setActive( this.elem, this.active, this.isPlayPause);
182                    if ( this.active ) {
183
184                        if ( self.layer.length == 1 ) return;
185                        // stop all animation
186                        self.Pause();
187                        var resetLayer = self.currentLayer-1;
188                        if ( self.isRunning ) {
189                            window.clearTimeout(self.layerPlayingTimeOut);
190                            self.resetLayer(self.currentLayer);
191                        }
192
193    //                    self.layer[self.currentLayer].elem.style.zIndex = self.zIndex;
194    //                    var resetLayer = self.currentLayer-1;
195                        if ( resetLayer < 0 ) resetLayer = self.layer.length -1;
196
197                        // reset Layer for position calculation
198                        self.currentItem = 0;
199
200                        // get current Position
201                        self.currentLayer = this.elem.parent().children().index(this.elem);
202
203                        // Set Playmode to pause
204                        self.setActive( this.elem.parent().children().last(), true, true );
205
206                        // Reset Layers manually to 0px
207                        // Set zIndex and reset previous entry
208                        self.layer[self.currentLayer].elem.css({'z-index': self.zIndex, 'left':0});
209                        self.layer[self.currentLayer].elem.children().css('left', 0);
210
211                        var timeout = self.layer[self.currentLayer].waitTime;
212
213                        self.resetLayer(self.currentLayer-1);
214                        if ( resetLayer != self.currentLayer ) self.resetLayer(resetLayer);
215
216                        // prepare next Layer for animation
217                        if ( self.currentLayer < self.layer.length-1 ) {
218                            self.currentLayer++;
219                        } else {
220                            self.currentLayer = 0;
221                        }
222
223                        // disable hover re-enable function
224                        self.itemButtonClicked = true;
225                        window.setTimeout(function() {
226                            // start playing
227                            self.Resume();
228                        }, timeout);
229
230                        $(document).trigger("layeranimation.layerDone", self.layer);
231                    } else {
232
233                        // start playing
234                        self.itemButtonClicked = false;
235                        self.Resume();
236                    }
237                };
238
239                return this.isPlayPause ? this.playPauseToggle() : this.layerToggle();
240            };
241
242            elem.click(this.Toggle);
243        };
244
245        this.setActive = function(elem, active, isPlayPause) {
246
247            elem = $(elem);
248
249            // Reset "active" on each
250            if ( !isPlayPause ) {
251                elem.parent().children().removeClass('active');
252            }
253
254            // set "active" on current
255            if ( active ) {
256                elem.addClass('active');
257            } else if ( isPlayPause ) {
258                elem.removeClass('active');
259            }
260        };
261
262        // Pause all animation if still playing
263        this.Pause = function() {
264
265            if ( ! self.isPlaying ) return;
266            if ( self.itemButtonClicked ) return;
267
268            self.isPlaying = false;
269            if ( !self.isRunning ) window.clearTimeout(self.layerPlayingTimeOut);
270            self.setActive( self.layerList.children().last(), true, true );
271        };
272
273        // resume animation if not playing
274        this.Resume = function() {
275
276            if ( self.isPlaying ) return;
277            if ( self.itemButtonClicked ) return;
278            if ( self.layer.length == 1 ) return;
279
280            self.setActive( self.layerList.children().last(), false, true );
281            self.isPlaying = true;
282            if ( !self.isRunning ) self.layerPlayingTimeOut = window.setTimeout( self.run, 2000);
283        };
284
285        this.togglePlayState = function( active ) {
286            if ( active ) {
287                self.itemButtonClicked = false;
288                self.Resume();
289            } else {
290                self.Pause();
291                // do not re-enable automatically
292                self.itemButtonClicked = true;
293            }
294        };
295
296        this.init = function() {
297
298            if ( !self.root || (document.documentMode && document.documentMode < 8) || self.root.find('div[type=layer]').length < 1)
299            {
300              return;
301            }
302
303            self.layerList = $('<ul/>').addClass('layeranimation_layer').css('display', 'inline-block').appendTo(self.root);
304            self.root.removeClass('noscripting').addClass('scripting');
305
306            // make clean
307            self.layer = new Array();
308
309            // Each Layer
310            self.root.find('div[type=layer]').each(function()
311            {
312                var innerLayer = new self.layerStruct();
313                innerLayer.elem = $(this);
314                innerLayer.waitTime = innerLayer.elem.attr('timing') * 1000 || self.timeout;
315                innerLayer.elem.show().css({
316                                        'z-index': self.zIndex + 100,
317                                        transitionDuration: (self.scrollTime / 1000 * 2) + 's'
318                                    });
319
320                if ( self.offsetWidth == 0 ) {
321                    self.offsetWidth = innerLayer.elem.width(); // Offset from the first layer.
322                }
323
324                if ( self.layer.length <= 1 && innerLayer.elem.hasClass('fixed') ) {
325                    innerLayer.elem.css('z-index', 100);
326                } else {
327                    innerLayer.elem.bind('mouseover', self.Pause);
328                    innerLayer.elem.bind('mouseout', self.Resume);
329
330                    self.layer.push(innerLayer);
331
332                    var layerListItem = $('<li/>').text(self.layer.length).attr('title', 'skip to page ' + self.layer.length).addClass(self.layer.length <= 1 ? 'active' : '');
333
334                    new self.layerClick(layerListItem);
335                    self.layerList.append(layerListItem);
336                    self.layerList.width(self.layerList.width() + layerListItem.width() * 1.3);
337                }
338
339                innerLayer.elem.find('div.item').each(function(){
340
341                    var innerItem = new self.itemStruct();
342                    innerItem.elem = $(this);
343                    innerItem.direction = innerItem.elem.hasClass('right') ? -1 : 1;
344                    innerItem.currentTime = self.scrollTime;
345
346                    if ( self.layer.length <= 1 || innerLayer.elem.hasClass('fixed') ) {
347                        innerItem.elem.css('left', 0);
348                    } else {
349                        innerItem.elem.css('left', innerItem.direction * self.offsetWidth);
350                        if ( innerLayer.items.length < 1 && !innerItem.elem.hasClass('first') ) {
351                            innerLayer.elem.css('left', innerItem.direction * self.offsetWidth);
352                        }
353                    }
354
355                    if ( innerLayer.items.length < 1 && !innerItem.elem.hasClass('first') ) {
356                        innerItem.elem.addClass('first');
357                    }
358
359                    innerLayer.items.push(innerItem);
360                    innerItem.elem.find('img').on('load', function(e) {
361                        e.currentTarget.loaded = true;
362                    });
363                });
364            });
365
366            var layerListItem = $('<li/>').addClass('play-pause').attr('title', 'pause animation').appendTo(self.layerList);
367            self.layerList.width(self.layerList.width() + layerListItem.width());
368            self.layerList.css('display', ''); // This is not hide, it is remove inline-block from above
369            new self.layerClick(layerListItem, self);
370
371            this.layerPlayingTimeOut = window.setTimeout( self.run, self.layer[0].waitTime);
372
373            // Check if layeranimation is in viewport
374            var animationHeight = self.root.height();
375            var originalAnimationTop = self.root.offset().top;
376            var onScroolResize = function() {
377
378                var scrollTop = $(window).scrollTop();
379                var windowHeight = $(window).height();
380
381                if ( (scrollTop >= originalAnimationTop+animationHeight || scrollTop+windowHeight <= originalAnimationTop ) && self.isPlaying )
382                {
383                    // stopPlaying
384                    self.Pause();
385                }
386                else if ( (scrollTop < originalAnimationTop+animationHeight && scrollTop+windowHeight > originalAnimationTop ) && !self.isPlaying  )
387                {
388                    self.Resume();
389                }
390            };
391
392            $(document).bind('scroll resize touchmove touchend', onScroolResize);
393        };
394
395        this.toggleCSSSaveState = function( $elem, save ) {
396            // Stow away or get the current css
397
398            var currentStyle = (save?'':'save-') + 'style';
399            var saveStyle = (!save?'':'save-') + 'style';
400
401            $elem.attr(saveStyle, $elem.attr(currentStyle));
402            $elem.attr(currentStyle, '');
403        };
404
405        this.prevWidth = null;
406        this.resizeLayers = function() {
407
408            // Only on changes of the width.
409            var newWidth = this.root.width();
410            if ( this.prevWidth == newWidth ) { return; }
411            this.prevWidth = newWidth;
412
413            // Each Layer
414            $.each(self.layer, function(index)
415            {
416                var currentLayer = this;
417                this.elem.css('height', ''); // Reset for new cycle
418
419                var setHeight = function() {
420                    var layerHeight = 0;
421                    $.each(currentLayer.items, function(){
422                        this.elem.css('height', ''); // Reset for new cycle
423                        layerHeight = Math.max( layerHeight, this.elem.height() );
424                    });
425
426                    currentLayer.elem.height(layerHeight);
427                };
428
429                var checkImageLoadedStatus = function() {
430                    // check load status of images
431                    var loaded = true;
432                    $.each(currentLayer.items, function(){
433                        this.elem.find('img').each(function(){
434                            loaded = loaded && (this.loaded || self.IsImageOk(this));
435                        });
436                    });
437
438                    if ( !loaded ) {
439                        window.setTimeout( checkImageLoadedStatus, 100 );
440                    } else {
441                       setHeight();
442                    }
443                };
444
445                checkImageLoadedStatus();
446            });
447        };
448
449        this.IsImageOk = function(img) {
450            // http://stackoverflow.com/questions/1977871/check-if-an-image-is-loaded-no-errors-in-javascript
451            // During the onload event, IE correctly identifies any images that
452            // weren’t downloaded as not complete. Others should too. Gecko-based
453            // browsers act like NS4 in that they report this incorrectly.
454            if (!img.complete) {
455                return false;
456            }
457
458            // However, they do have two very useful properties: naturalWidth and
459            // naturalHeight. These give the true size of the image. If it failed
460            // to load, either of these should be zero.
461
462            if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) {
463                return false;
464            }
465
466            // No other way of checking: assume it’s ok.
467            return true;
468        };
469
470        this.activationStatus = function(activate) {
471
472            if ( ! self.layerList ) {
473                return;
474            }
475
476            self.togglePlayState( activate );
477
478            // Layer selection list
479            self.layerList.toggle( activate );
480            self.root.removeClass( (activate?'no':'') + 'scripting').addClass( (!activate?'no':'') + 'scripting');
481
482            // Each Layer
483            self.offsetWidth = activate ? 0 : self.offsetWidth;
484            $(self.layer).each(function(index)
485            {
486                self.toggleCSSSaveState( this.elem, !activate );
487                $(this.items).each(function(){
488                    self.toggleCSSSaveState( this.elem, !activate );
489                });
490
491                if ( activate ) {
492                    if ( self.offsetWidth == 0 ) {
493                        self.offsetWidth = $(this.elem).width(); // Offset from the first layer.
494                    }
495                    self.resetLayer(index, true);
496                }
497            });
498
499            self.resizeLayers();
500        };
501    };
502
503    var initialize = function() {
504        $('div.layeranimation').each(function(){
505            (new layeranimation($(this))).init();
506        }).on('layeranimation.activate', function(e, activate){
507            this.layerAnimation.activationStatus(activate);
508        }).on('layeranimation.resize', function(e, activate){
509            this.layerAnimation.resizeLayers();
510        });
511    };
512
513    // On load
514    $(initialize);
515
516})(jQuery);
517