1 /**
2 * @author Alexander Farkas
3 * v. 1.22
4 */
5 (function ($)
6 {
7 if (!document.defaultView || !document.defaultView.getComputedStyle)
8 { // IE6-IE8
9 var oldCurCSS = $.curCSS;
10 $.curCSS = function (elem, name, force)
11 {
12 if (name === 'background-position')
13 {
14 name = 'backgroundPosition';
15 }
16 if (name !== 'backgroundPosition' || !elem.currentStyle || elem.currentStyle[name])
17 {
18 return oldCurCSS.apply(this, arguments);
19 }
20 var style = elem.style;
21 if (!force && style && style[name])
22 {
23 return style[name];
24 }
25 return oldCurCSS(elem, 'backgroundPositionX', force) + ' ' + oldCurCSS(elem, 'backgroundPositionY', force);
26 };
27 }
28
29 var oldAnim = $.fn.animate;
30 $.fn.animate = function (prop)
31 {
32 if ('background-position' in prop)
33 {
34 prop.backgroundPosition = prop['background-position'];
35 delete prop['background-position'];
36 }
37 if ('backgroundPosition' in prop)
38 {
39 prop.backgroundPosition = '(' + prop.backgroundPosition;
40 }
41 return oldAnim.apply(this, arguments);
42 };
43
44 function toArray(strg)
45 {
46 strg = strg.replace(/left|top/g, '0px');
47 strg = strg.replace(/right|bottom/g, '100%');
48 strg = strg.replace(/([0-9\.]+)(\s|\)|$)/g, "$1px$2");
49 var res = strg.match(/(-?[0-9\.]+)(px|\%|em|pt)\s(-?[0-9\.]+)(px|\%|em|pt)/);
50 return [parseFloat(res[1], 10), res[2], parseFloat(res[3], 10), res[3]];
51 }
52
53 $.fx.step.backgroundPosition = function (fx)
54 {
55 if (!fx.bgPosReady)
56 {
57 var start = $.curCSS(fx.elem, 'backgroundPosition');
58 if (!start)
59 {//FF2 no inline-style fallback
60 start = '0px 0px';
61 }
62
63 start = toArray(start);
64 fx.start = [start[0], start[2]];
65 var end = toArray(fx.end);
66 fx.end = [end[0], end[2]];
67
68 fx.unit = [end[1], end[3]];
69 fx.bgPosReady = true;
70 }
71 //return;
72 var nowPosX = [];
73 nowPosX[0] = ((fx.end[0] - fx.start[0]) * fx.pos) + fx.start[0] + fx.unit[0];
74 nowPosX[1] = ((fx.end[1] - fx.start[1]) * fx.pos) + fx.start[1] + fx.unit[1];
75 fx.elem.style.backgroundPosition = nowPosX[0] + ' ' + nowPosX[1];
76
77 };
78 })(jQuery);
79
80
81
82 ;(function( $, window, document, undefined ){
83
84 // utility function that generates the "dots" navigation
85 function generateNavigation($el, count, config) {
86 var i, html = "",
87 width = count * 32;
88
89 html += "<ol class='" + config.navigationClass + "' style='margin-left: -" + width/2 + "px; width: " + width + "px'>";
90 for (i = 0; i < count; i++) {
91 html += "<li><a " + (i === 0 ? "class='selected'" : "" ) + " href='#" + (i) + "'>slide</a></li>";
92 }
93 html += "</ol>";
94
95 $el.append(html);
96 }
97
98 function sweepOut($el, windowWidth) {
99 var dfr = $.Deferred(),
100 pos = $el.position(),
101 width = $el.width(),
102 delta, final,
103 options = $el.data("tlrkAnimOptions");
104
105 windowWidth = windowWidth || $(window).width(); // check if the windowWidth is passed, if not - get it
106
107 delta = windowWidth - pos.left;
108 final = -(delta);
109
110 setTimeout(function(){
111 $el.animate({left: final, opacity: "toggle"}, options.speed, options.easing, function(){
112 dfr.resolve();
113 });
114 }, options.delay);
115
116 return dfr.promise();
117 }
118
119 function sweepIn($el, windowWidth, frameLeft) {
120 var dfr = $.Deferred(),
121 options = $el.data("tlrkAnimOptions"),
122 positionData = $el.data("tlrkOriginalPos"),
123 final = positionData.position.left,
124 rightEdge;
125
126 windowWidth = windowWidth || $(window).width(); // check if the windowWidth is passed, if not - get it
127
128 $el.css({opacity: 0, display: "block"}); // move it outside the right edge of the screen
129 $el.css("left", function(current){
130 return current + windowWidth - frameLeft;
131 });
132
133 setTimeout(function(){
134 $el.animate({left: final, opacity: 1}, options.speed, options.easing, function(){
135 dfr.resolve();
136 });
137 }, options.delay);
138
139 return dfr.promise();
140 }
141
142
143 // two pass function that first iterates all the elements and gets their position/width/height
144 // and then sets their position to absolute
145 function absolutize($elements) {
146
147 // todo - move it to separate function and do it just once
148 // gather the original position/dimension data for all elements
149 $elements.each(function(){
150 var $t = $(this);
151
152 if ($t.data("tlrkOriginalPos")) return
153
154 $t.data("tlrkOriginalPos", {
155 position: $t.position(),
156 width: $t.width(),
157 height: $t.height(),
158 css_pos: $t.css("position"),
159 css_left: $t.css("left"),
160 css_top: $t.css("top"),
161 css_width: $t.css("width") || "auto",
162 css_height: $t.css("height") || "auto"
163 });
164
165 });
166
167 // set the absolute position
168 $elements.each(function(){
169 var $t = $(this),
170 opos = $t.data("tlrkOriginalPos");
171
172 $t.css({
173 position: "absolute",
174 left: opos.position.left,
175
176 width: opos.width,
177 height: opos.height
178 });
179 });
180 }
181
182 function restoreFrameElements($elements) {
183 $elements.each(function(){
184 var $t = $(this),
185 opos = $t.data("tlrkOriginalPos");
186
187 if (!opos) return
188
189 $t.css({
190 position: opos.css_pos,
191 left: opos.css_left,
192 top: opos.css_top,
193 width: opos.css_width,
194 height: opos.css_height
195 });
196 });
197
198 }
199
200 var TlrkSlider = function( elem, options ){
201 this.elem = elem;
202 this.$elem = $(elem);
203 this.options = options;
204 };
205
206 // the plugin prototype
207 TlrkSlider.prototype = {
208 defaults: {
209
210
211 defaultElementOptions: {
212 speed: 1200,
213 easing: "easeInOutBack",
214 // interval before the element starts moving when the fadeIn/Out functions are called
215 // it's a good idea to give different delays for the different elements
216 // if all have the same delay they'll start moving all together
217 delay: 100
218 },
219
220 // dispose elements are these that are not included in the elements object
221 // but affect the document flow and will be fadedIn/Out
222 disposeDelay: 100, // delay for the dispose elements
223 disposeSpeed: 1000, // how quickly they'll fadeOut/In
224
225 delayBetweenTransition: 1000, // time between starting fadeOut and fadeIn
226 delayAnimation: 7000, // time between auto changing the current frame
227
228 loop: true, // if true when clicking next on the last frame the slider jumps to the first one
229
230 autoStart: true, // start the automatic looping through the frames on init
231
232 framesSelector: "section", // selector for the frames inside the slider
233
234 elements: {
235 "p": {delay: 100, speed: 1000, easing: "easeInOutBack"}
236 },
237
238 navigation: true, // the dots navigation on the bottom
239 navigationClass: "slider-nav",
240
241 // callbacks
242 // another way to "catch" these events is with
243 // $(-slider-element-).bind("animationStart")
244 animationStart: null,
245 animationEnd: null
246 },
247
248 init: function() {
249 var c, e, element, $element,
250 that = this,
251 $firstFrame;
252
253 c = this.config = $.extend({}, this.defaults, this.options);
254
255 this.elem.style.position = "relative"; // make the wrapping element relative
256
257 // basics
258 this.$frames = this.$elem.find(c.framesSelector);
259 this.framesCount = this.$frames.length;
260 this.currentFrame = 0;
261 this.queue = [];
262
263 this._$elementsByFrame = {};
264 this._$disposeElementsByFrame = {};
265
266 for (i = 0; i < this.framesCount; i++) {
267 this._$elementsByFrame[i] = this._getFrameElements(i); // cache the $elements by frame
268 this._$disposeElementsByFrame[i] = this._getDisposeFrameElements(i); // cache the rest of the tree for each frame
269 }
270
271 if (c.navigation) {
272 generateNavigation(this.$elem, this.framesCount, c);
273 this.$navigation = this.$elem.find("."+c.navigationClass);
274 }
275
276 // bindings
277 this.$elem.find(".slider-nav").delegate("a", "click", function(e){
278 var frame = this.getAttribute("href").split("#")[1];
279 that.go.call(that, frame);
280 return false;
281 });
282
283 this.$elem // internal bindings for the callbacks
284 .bind("animationStart", function(){
285 if ($.isFunction(c.animationStart)) {c.animationStart.apply(that, arguments);}
286 })
287 .bind("animationEnd", function(){
288 if ($.isFunction(c.animationEnd)) {c.animationEnd.apply(that, arguments);}
289 })
290 ;
291
292 // start animation?
293 if (c.autoStart) {
294 this.start();
295 } else {
296 this.running = false;
297 }
298
299 return this;
300 },
301
302 start: function(instant) {
303 var that = this;
304
305 if (this.timer) { // we'll clear the current timer
306 window.clearTimeout(this.timer);
307 }
308
309 this.running = true;
310
311 if (instant) {
312 that.nextFrame();
313 } else {
314 this.timer = window.setTimeout(function(){ that.nextFrame.call(that) }, that.config.delayAnimation);
315 }
316 },
317
318 stop: function() {
319 if (!this.running) return; // we are not running
320
321 this.running = false;
322 window.clearTimeout(this.timer);
323 },
324
325 // main function for changing frames
326 selectFrame: function(frame, dfr) {
327 var c = this.config, // shorthand for the config
328 that = this,
329 dfr = dfr || $.Deferred(),
330 dFadeIn = $.Deferred(),
331 dFadeOut = $.Deferred();
332
333 if (isNaN(frame) || frame < 0 || frame > this.framesCount || frame === this.currentFrame) {
334 dfr.reject();
335 return dfr.promise();
336 }
337
338 // clear the animation loop interval if the animation is running
339 if (this.running && this.timer) {
340 window.clearTimeout(this.timer);
341 }
342
343 // check if we are currenly running an animation.
344 if (this.animated && this.queue.length > 0) {
345 // wait for the last item in the queue to finish
346 this.queue[this.queue.length-1].done(function(){
347 that.selectFrame(frame, dfr); // and call again the selectFrame
348 })
349 return dfr.promise();
350 }
351
352 this.animated = true;
353 this.$elem.trigger("animationStart", [this, frame]);
354
355 this.queue.push(dfr);
356
357 // fade the frames
358 dFadeOut = this._fadeOutFrame(this.currentFrame);
359
360 // hide the fadetout frame
361 dFadeOut.done(function(){
362 that.$frames.eq(that.currentFrame).hide();
363 });
364
365 window.setTimeout(function(){ // then wait delayBetweenTransition and fadeIn the new frame
366 dFadeIn = that._fadeInFrame.call(that, frame).done(function(){
367 // when both the fadeIn and fadeOut are done we'll resolve the selectFrame promise
368 $.when(dFadeOut, dFadeIn).done(function(){
369 that.animated = false;
370 that.queue.shift();
371 that.$elem.trigger("animationEnd", [that]);
372 that.currentFrame = frame;
373 dfr.resolve();
374 });
375 });
376 }, c.delayBetweenTransition);
377
378 // navigation html change
379 if (this.config.navigation) {
380 this.$navigation.find(".selected").removeClass("selected").end()
381 .find("a").eq(frame).addClass("selected");
382 }
383
384 dfr.done(function(){ // we'll resume the loop animation after the transitions are done
385 if (that.running) {
386 that.start();
387 }
388 });
389
390 return dfr.promise();
391 },
392
393 _fadeFrame: function(frame, callback, direction) {
394 var dfr = $.Deferred(),
395 $frame = this.$frames.eq(frame),
396 $elements = this._$elementsByFrame[frame],
397 windowWidth = $(window).width(), // cache it before the animations, so we don't have to check it for each element
398 i, len,
399 that = this,
400 elementAnimations = [],
401 $disposeElements = this._$disposeElementsByFrame[frame],
402 $affectedElements,
403 frameLeft = $frame.offset().left;
404
405 direction = direction || "out";
406
407 if (!$.isFunction(callback)) return; // do nothing if there's no callback passed
408
409 $affectedElements = $elements.add($disposeElements);
410
411 // position absolute the animation and dispose elements
412 absolutize($affectedElements);
413
414 // toggle the dispose elements
415 if ($disposeElements.length > 0) {
416 window.setTimeout(function(){
417 $disposeElements[direction === "out" ? "fadeOut" : "fadeIn"](that.config.disposeSpeed);
418 }, this.config.disposeDelay);
419 }
420
421 // invoke the callback for each element
422 // the callback must return a promise
423 $elements.each(function(){
424 elementAnimations.push( callback.call(that, $(this), windowWidth, frameLeft) );
425 });
426
427 // wait for all the elements to finish their animation
428 $.when.apply(this, elementAnimations).done(function(){
429 //restoreFrameElements($affectedElements); // and restore the elements' position
430 dfr.resolve(); // resolve the fade function
431 });
432
433 return dfr.promise();
434 },
435
436 _fadeOutFrame: function(frame) {
437 var dfr = $.Deferred(),
438 $frame = this.$frames.eq(frame),
439 $disposeElements = this._$disposeElementsByFrame[frame];
440
441 this._fadeFrame(frame, this._animationOut, "out").done(function(){
442 dfr.resolve();
443 })
444
445 return dfr.promise();
446 },
447
448 _fadeInFrame: function(frame) {
449 var dfr = $.Deferred(),
450 $frame = this.$frames.eq(frame),
451 $elements = this._$elementsByFrame[frame];
452
453 this._restoreFrame(frame);
454
455 $frame.show();
456
457 this._fadeFrame(frame, this._animationIn, "in").done(function(){
458 dfr.resolve();
459 });
460
461 return dfr.promise();
462 },
463
464 _restoreFrame: function(frame){
465 if (!frame) return
466 restoreFrameElements( this._$elementsByFrame[frame].add(this._$disposeElementsByFrame[frame]) );
467 },
468
469 nextFrame: function() {
470 var frame = this.currentFrame+1,
471 dfr = $.Deferred();
472
473 if (frame > this.framesCount-1) {
474 if (this.config.loop) {
475 frame = 0;
476 } else {
477 dfr.reject();
478 }
479 };
480
481 this.selectFrame(frame).done(function(){
482 dfr.resolve();
483 });
484
485 return dfr.promise();
486 },
487
488 prevFrame: function() {
489 var frame = this.currentFrame-1,
490 dfr = $.Deferred();
491
492 if (frame < 0) {
493 if (this.config.loop) {
494 frame = this.framesCount-1;
495 } else {
496 dfr.reject();
497 return dfr.promise();
498 }
499 }
500
501 this.selectFrame(frame).done(function(){
502 dfr.resolve();
503 });
504
505 return dfr.promise();
506 },
507
508 go: function(str) { // shorthand
509 switch (str) {
510 case "next":
511 case "+1":
512 this.nextFrame();
513 break;
514
515 case "prev":
516 case "-1":
517 this.prevFrame();
518 break;
519
520 case "first":
521 this.selectFrame(0);
522 break;
523
524 case "last":
525 this.selectFrame(this.framesCount-1);
526 break;
527
528 default:
529 if (isNaN(str)) return;
530 this.selectFrame(Number(str));
531 }
532 },
533
534 // returns jquery collection of animation elements
535 _getFrameElements: function(frame) {
536 var $frame = this.$frames.eq(frame),
537 elements = this.config.elements,
538 e, elementOptions,
539 $found, $frameElements = $([]);
540
541 for (e in elements) {
542 elementOptions = elements[e];
543 $found = $frame.find(e);
544 $found.addClass("t-frame-element").data("tlrkAnimOptions", $.extend({}, this.defaults.defaultElementOptions, elementOptions ));
545 $frameElements = $frameElements.add($found);
546 }
547
548 return $frameElements;
549 },
550
551 // returns jquery collection of elements that have to be faded out
552 // i.e. elements on the same level as the animation elements
553 // that doesn't contain other animation elements
554 _getDisposeFrameElements: function(frame) {
555 var $disposeElements = $([]),
556 $frame = this.$frames.eq(frame),
557 $elements = this._$elementsByFrame[frame];
558
559 $elements.each(function(){
560 var $t = $(this),
561 $siblings = $t.siblings().not(".t-frame-element");
562
563 $siblings.each(function(){
564 var $t = $(this);
565 // check if the node is not already marked and doesn't contains other frame elements
566 if (!$t.hasClass("t-frame-dispose") && $t.find(".t-frame-element").length === 0) {
567 $t.addClass("t-frame-dispose");
568 $disposeElements = $disposeElements.add($t);
569 }
570 });
571
572 });
573 return $disposeElements;
574 },
575
576
577 // expose the internal animationIn/Out functions that are called for each element in the frame
578 // two arguments are passed - the $element which have to be animated and the window width
579 _animationIn: sweepIn,
580 _animationOut: sweepOut
581
582 }
583
584 TlrkSlider.defaults = TlrkSlider.prototype.defaults;
585
586 $.fn.tlrkSlider = function(options) {
587 var otherArgs = Array.prototype.slice.call(arguments, 1);
588
589 return this.each(function() {
590 var $el = $(this),
591 pluginData = $el.data("tlrkSlider");
592
593 if (!pluginData) { // check if the slider is already attached
594 pluginData = new TlrkSlider(this, options).init();
595 $el.data("tlrkSlider", pluginData);
596 return;
597 }
598
599 //change the options or call a method
600 if (typeof options === "string") {
601
602 // setting / getting option(s)
603 if (options === "option") {
604
605 if (typeof otherArgs[0] === "string" && typeof otherArgs[1] !== "undefined") { // set an option value
606 pluginData.config[otherArgs[0]] = otherArgs[1];
607 }
608
609 if (typeof otherArgs[0] === "object") { // extend the config with new options
610 pluginData.config = $.extend(pluginData.config, otherArgs[0]);
611 }
612
613 } else { // call a method?
614 try {
615 pluginData[options].apply(pluginData, otherArgs);
616 } catch(ex) {
617 throw "Error calling a plugin method (" + ex + ")";
618 }
619 }
620 }
621 });
622 };
623
624 window.TlrkSlider = TlrkSlider;
625
626 })( jQuery, window , document );
627
628 $(document).ready(function(){
629 var $backgrounds = $(".header-content").find(".parallax-bg"),
630 LAYER_OFFSET = 30,
631 PRLX_SPEED = 1500,
632 $slider;
633
634 $slider = $("#slider").tlrkSlider({
635 autoStart: true,
636 animationStart: function(ev, slider, step){
637 var max_steps = this.framesCount;
638 $backgrounds.each(function(idx, el){
639 var pos = (step * (100 / max_steps)) + (LAYER_OFFSET * idx);
640 $(this).animate({"backgroundPosition": pos + "% 0"}, PRLX_SPEED);
641 });
642 },
643 elements: {
644 "img": {delay: 10},
645 "h2": {delay: 500},
646 ".copy": {delay: 800},
647 ".button": {delay: 1000}
648 }
649 });
650
651 $(".header-content")
652 .hover(
653 function(){$(this).find(".slider-prev, .slider-next").show();},
654 function(){$(this).find(".slider-prev, .slider-next").hide();}
655 )
656 .find(".slider-prev").click(function(){$slider.tlrkSlider("go", "prev"); return false; }).end()
657 .find(".slider-next").click(function(){$slider.tlrkSlider("go", "next"); return false; });
658
659 });