function initButtons(){$(".scrollNextDoAction").click(function(){var a=$(".inview");var b=a.next().attr("id");if(b){goToByScroll(b)}$("#upButton").show(500)});$(".scrollPreviousDoAction").click(function(){var a=$(".inview");var b=a.prev().attr("id");if(b){goToByScroll(b)}});$("#subMenu").localScroll();$("#subMenu .displayTooltipDoAction").hover(function(a){$("#subMenu .tips").hide();$(a.target).next("div").show()});$.fn.qtip.styles.etsw={width:{min:100,max:150},background:"#b21f24",color:"#f2f2f2",textAlign:"center",border:{width:2,radius:5,color:"#b21f24"},tip:"bottomLeft",name:"dark"};$(".showtip").qtip({style:{name:"etsw",tip:true},position:{corner:{target:"leftMiddle",tooltip:"rightMiddle"}},content:{text:false},hide:{effect:{type:"slide"}},show:{effect:{type:"grow"}}})}function goToByScroll(a){$("html,body").animate({scrollTop:$("#"+a).offset().top+10},"slow")} function action_submitForm(a){ if ( !$(this).hasClass('noAjax') ){ a.preventDefault();$(".submitFormDoAction").val("Sending");var b=$(a.target).serialize();var c=$(a.target).find(" :input");c.each(function(a,b){$(this).attr("disabled","true")});$.ajax({url:"ajax/sendMail.php",type:"POST",dataType:"json",data:b,success:function(a,b,d){if(!a||a.status!="success"){c.each(function(a,b){$(this).removeAttr("disabled")});$(".submitFormDoAction").val("Send");var e="Opps! Something wrong happened.
";if(a.message){e+=a.message}$("#status").html(e);return false}if(a.status=="success"){$(".submitFormDoAction").val("Send");c.each(function(a,b){$(this).removeAttr("disabled")});$("#status").html("Thank you for your email, we will get back to you shortly.")}},error:function(a,b,d){c.each(function(a,b){$(this).removeAttr("disabled")});$(".submitFormDoAction").val("Send");$("#status").html("There was an error. Please try again.");return false;if(typeof console!="undefined")console.dir(a);return false}})}} function initAll(){$(".submitFormDoAction").die("click").live("click",function(){$(this).closest("form").submit()});$("form").submit(action_submitForm)}$(document).ready(initAll);$(document).ready(function(a){$(".grindSignature").hover(function(){$("#grindSignature").fadeIn()},function(){$("#grindSignature").fadeOut()})})/** * jQuery.LocalScroll - Animated scrolling navigation, using anchors. * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com * Dual licensed under MIT and GPL. * Date: 3/11/2009 * @author Ariel Flesler * @version 1.2.7 **/ ;(function($){var l=location.href.replace(/#.*/,'');var g=$.localScroll=function(a){$('body').localScroll(a)};g.defaults={duration:1e3,axis:'y',event:'click',stop:true,target:window,reset:true};g.hash=function(a){if(location.hash){a=$.extend({},g.defaults,a);a.hash=false;if(a.reset){var e=a.duration;delete a.duration;$(a.target).scrollTo(0,a);a.duration=e}i(0,location,a)}};$.fn.localScroll=function(b){b=$.extend({},g.defaults,b);return b.lazy?this.bind(b.event,function(a){var e=$([a.target,a.target.parentNode]).filter(d)[0];if(e)i(a,e,b)}):this.find('a,area').filter(d).bind(b.event,function(a){i(a,this,b)}).end().end();function d(){return!!this.href&&!!this.hash&&this.href.replace(this.hash,'')==l&&(!b.filter||$(this).is(b.filter))}};function i(a,e,b){var d=e.hash.slice(1),f=document.getElementById(d)||document.getElementsByName(d)[0];if(!f)return;if(a)a.preventDefault();var h=$(b.target);if(b.lock&&h.is(':animated')||b.onBefore&&b.onBefore.call(b,a,f,h)===false)return;if(b.stop)h.stop(true);if(b.hash){var j=f.id==d?'id':'name',k=$(' ').attr(j,d).css({position:'absolute',top:$(window).scrollTop(),left:$(window).scrollLeft()});f[j]='';$('body').prepend(k);location=e.hash;k.remove();f[j]=d}h.scrollTo(f,b).trigger('notify.serialScroll',[f])}})(jQuery);/** * jQuery.ScrollTo - Easy element scrolling using jQuery. * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com * Dual licensed under MIT and GPL. * Date: 5/25/2009 * @author Ariel Flesler * @version 1.4.2 * * http://flesler.blogspot.com/2007/10/jqueryscrollto.html */ ;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);/** * author Remy Sharp * url http://remysharp.com/2009/01/26/element-in-view-event-plugin/ */ (function ($) { function getViewportHeight() { var height = window.innerHeight; // Safari, Opera var mode = document.compatMode; if ( (mode || !$.support.boxModel) ) { // IE, Gecko height = (mode == 'CSS1Compat') ? document.documentElement.clientHeight : // Standards document.body.clientHeight; // Quirks } return height; } $(window).scroll(function () { var vpH = getViewportHeight(), scrolltop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop), elems = []; // naughty, but this is how it knows which elements to check for $.each($.cache, function () { if (this.events && this.events.inview) { elems.push(this.handle.elem); } }); if (elems.length) { $(elems).each(function () { var $el = $(this), top = $el.offset().top, height = $el.height(), inview = $el.data('inview') || false; if (scrolltop > (top + height) || scrolltop + vpH < top) { if (inview) { $el.data('inview', false); $el.trigger('inview', [ false ]); } } else if (scrolltop < (top + height)) { if (!inview) { $el.data('inview', true); $el.trigger('inview', [ true ]); } } }); } }); // kick the event to pick up any elements already in view. // note however, this only works if the plugin is included after the elements are bound to 'inview' $(function () { $(window).scroll(); }); })(jQuery); /*! * jQuery UI 1.8 * * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * * http://docs.jquery.com/UI */ ;jQuery.ui || (function($) { //Helper functions and ui object $.ui = { version: "1.8", // $.ui.plugin is deprecated. Use the proxy pattern instead. plugin: { add: function(module, option, set) { var proto = $.ui[module].prototype; for(var i in set) { proto.plugins[i] = proto.plugins[i] || []; proto.plugins[i].push([option, set[i]]); } }, call: function(instance, name, args) { var set = instance.plugins[name]; if(!set || !instance.element[0].parentNode) { return; } for (var i = 0; i < set.length; i++) { if (instance.options[set[i][0]]) { set[i][1].apply(instance.element, args); } } } }, contains: function(a, b) { return document.compareDocumentPosition ? a.compareDocumentPosition(b) & 16 : a !== b && a.contains(b); }, hasScroll: function(el, a) { //If overflow is hidden, the element might have extra content, but the user wants to hide it if ($(el).css('overflow') == 'hidden') { return false; } var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop', has = false; if (el[scroll] > 0) { return true; } // TODO: determine which cases actually cause this to happen // if the element doesn't have the scroll set, see if it's possible to // set the scroll el[scroll] = 1; has = (el[scroll] > 0); el[scroll] = 0; return has; }, isOverAxis: function(x, reference, size) { //Determines when x coordinate is over "b" element axis return (x > reference) && (x < (reference + size)); }, isOver: function(y, x, top, left, height, width) { //Determines when x, y coordinates is over "b" element return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width); }, keyCode: { BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38 } }; //jQuery plugins $.fn.extend({ _focus: $.fn.focus, focus: function(delay, fn) { return typeof delay === 'number' ? this.each(function() { var elem = this; setTimeout(function() { $(elem).focus(); (fn && fn.call(elem)); }, delay); }) : this._focus.apply(this, arguments); }, enableSelection: function() { return this .attr('unselectable', 'off') .css('MozUserSelect', '') .unbind('selectstart.ui'); }, disableSelection: function() { return this .attr('unselectable', 'on') .css('MozUserSelect', 'none') .bind('selectstart.ui', function() { return false; }); }, scrollParent: function() { var scrollParent; if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { scrollParent = this.parents().filter(function() { return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); }).eq(0); } else { scrollParent = this.parents().filter(function() { return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); }).eq(0); } return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; }, zIndex: function(zIndex) { if (zIndex !== undefined) { return this.css('zIndex', zIndex); } if (this.length) { var elem = $(this[0]), position, value; while (elem.length && elem[0] !== document) { // Ignore z-index if position is set to a value where z-index is ignored by the browser // This makes behavior of this function consistent across browsers // WebKit always returns auto if the element is positioned position = elem.css('position'); if (position == 'absolute' || position == 'relative' || position == 'fixed') { // IE returns 0 when zIndex is not specified // other browsers return a string // we ignore the case of nested elements with an explicit value of 0 //
value = parseInt(elem.css('zIndex')); if (!isNaN(value) && value != 0) { return value; } } elem = elem.parent(); } } return 0; } }); //Additional selectors $.extend($.expr[':'], { data: function(elem, i, match) { return !!$.data(elem, match[3]); }, focusable: function(element) { var nodeName = element.nodeName.toLowerCase(), tabIndex = $.attr(element, 'tabindex'); return (/input|select|textarea|button|object/.test(nodeName) ? !element.disabled : 'a' == nodeName || 'area' == nodeName ? element.href || !isNaN(tabIndex) : !isNaN(tabIndex)) // the element and all of its ancestors must be visible // the browser may report that the area is hidden && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length; }, tabbable: function(element) { var tabIndex = $.attr(element, 'tabindex'); return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable'); } }); })(jQuery); /*! * jQuery UI Widget 1.8 * * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * * http://docs.jquery.com/UI/Widget */ (function( $ ) { var _remove = $.fn.remove; $.fn.remove = function( selector, keepData ) { return this.each(function() { if ( !keepData ) { if ( !selector || $.filter( selector, [ this ] ).length ) { $( "*", this ).add( this ).each(function() { $( this ).triggerHandler( "remove" ); }); } } return _remove.call( $(this), selector, keepData ); }); }; $.widget = function( name, base, prototype ) { var namespace = name.split( "." )[ 0 ], fullName; name = name.split( "." )[ 1 ]; fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } // create selector for plugin $.expr[ ":" ][ fullName ] = function( elem ) { return !!$.data( elem, name ); }; $[ namespace ] = $[ namespace ] || {}; $[ namespace ][ name ] = function( options, element ) { // allow instantiation without initializing for simple inheritance if ( arguments.length ) { this._createWidget( options, element ); } }; var basePrototype = new base(); // we need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from // $.each( basePrototype, function( key, val ) { // if ( $.isPlainObject(val) ) { // basePrototype[ key ] = $.extend( {}, val ); // } // }); basePrototype.options = $.extend( {}, basePrototype.options ); $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { namespace: namespace, widgetName: name, widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, widgetBaseClass: fullName }, prototype ); $.widget.bridge( name, $[ namespace ][ name ] ); }; $.widget.bridge = function( name, object ) { $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string", args = Array.prototype.slice.call( arguments, 1 ), returnValue = this; // allow multiple hashes to be passed on init options = !isMethodCall && args.length ? $.extend.apply( null, [ true, options ].concat(args) ) : options; // prevent calls to internal methods if ( isMethodCall && options.substring( 0, 1 ) === "_" ) { return returnValue; } if ( isMethodCall ) { this.each(function() { var instance = $.data( this, name ), methodValue = instance && $.isFunction( instance[options] ) ? instance[ options ].apply( instance, args ) : instance; if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue; return false; } }); } else { this.each(function() { var instance = $.data( this, name ); if ( instance ) { if ( options ) { instance.option( options ); } instance._init(); } else { $.data( this, name, new object( options, this ) ); } }); } return returnValue; }; }; $.Widget = function( options, element ) { // allow instantiation without initializing for simple inheritance if ( arguments.length ) { this._createWidget( options, element ); } }; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", options: { disabled: false }, _createWidget: function( options, element ) { // $.widget.bridge stores the plugin instance, but we do it anyway // so that it's stored even before the _create function runs this.element = $( element ).data( this.widgetName, this ); this.options = $.extend( true, {}, this.options, $.metadata && $.metadata.get( element )[ this.widgetName ], options ); var self = this; this.element.bind( "remove." + this.widgetName, function() { self.destroy(); }); this._create(); this._init(); }, _create: function() {}, _init: function() {}, destroy: function() { this.element .unbind( "." + this.widgetName ) .removeData( this.widgetName ); this.widget() .unbind( "." + this.widgetName ) .removeAttr( "aria-disabled" ) .removeClass( this.widgetBaseClass + "-disabled " + this.namespace + "-state-disabled" ); }, widget: function() { return this.element; }, option: function( key, value ) { var options = key, self = this; if ( arguments.length === 0 ) { // don't return a reference to the internal hash return $.extend( {}, self.options ); } if (typeof key === "string" ) { if ( value === undefined ) { return this.options[ key ]; } options = {}; options[ key ] = value; } $.each( options, function( key, value ) { self._setOption( key, value ); }); return self; }, _setOption: function( key, value ) { this.options[ key ] = value; if ( key === "disabled" ) { this.widget() [ value ? "addClass" : "removeClass"]( this.widgetBaseClass + "-disabled" + " " + this.namespace + "-state-disabled" ) .attr( "aria-disabled", value ); } return this; }, enable: function() { return this._setOption( "disabled", false ); }, disable: function() { return this._setOption( "disabled", true ); }, _trigger: function( type, event, data ) { var callback = this.options[ type ]; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); data = data || {}; // copy original event properties over to the new event // this would happen if we could call $.event.fix instead of $.Event // but we don't have a way to force an event to be fixed multiple times if ( event.originalEvent ) { for ( var i = $.event.props.length, prop; i; ) { prop = $.event.props[ --i ]; event[ prop ] = event.originalEvent[ prop ]; } } this.element.trigger( event, data ); return !( $.isFunction(callback) && callback.call( this.element[0], event, data ) === false || event.isDefaultPrevented() ); } }; })( jQuery ); (function ($) { $.widget("ui.rcarousel", { _create: function() { var data, $root = $( this.element ), _self = this, options = this.options; // if options were default there should be no problem // check if user set options before init: $('element').rcarousel({with: "foo", visible: 3}); // in above example exception will be thrown because 'with' should be a number! this._checkOptionsValidity( this.options ); // for every carousel create a data object and keeps it in the element this._createDataObject(); data = $root.data( "data" ); // create wrapper inside root element; this is needed for animating $root .addClass( "ui-carousel" ) .children() .wrapAll( "
" ); // save all children of root element in ‘paths’ array this._saveElements(); // make pages using paginate algorithm this._generatePages(); this._loadElements(); this._setCarouselWidth(); this._setCarouselHeight(); // handle default event handlers $( options.navigation.next ).click( function( event ) { _self.next(); event.preventDefault(); } ); $( options.navigation.prev ).click( function( event ) { _self.prev(); event.preventDefault(); } ); data.navigation.next = $( options.navigation.next ); data.navigation.prev = $( options.navigation.prev ); // stop on hover feature $root.hover( function() { if ( options.auto.enabled ) { clearInterval( data.interval ); data.hoveredOver = true; } }, function() { if ( options.auto.enabled ) { data.hoveredOver = false; _self._autoMode( options.auto.direction ); } } ); this._setStep(); // if auto mode is enabled run it if ( options.auto.enabled ) { this._autoMode( options.auto.direction ); } // broadcast event this._trigger( "start" ); }, _addElement: function( jQueryElement, direction ) { var $root = $( this.element ), $content = $root.find( "div.wrapper" ), options = this.options; jQueryElement .width( options.width ) .height( options.height ); if ( options.orientation === "horizontal" ) { $( jQueryElement ).css( "marginRight", options.margin ); } else { $( jQueryElement ).css({ marginBottom: options.margin, "float": "none" }); } if ( direction === "prev" ) { // clone event handlers and data as well $content.prepend( jQueryElement.clone(true, true) ); } else { $content.append( jQueryElement.clone(true, true) ); } }, append: function( jqElements ) { var $root = $( this.element ), data = $root.data( "data" ); // add new elements jqElements.each( function( i, el ) { data.paths.push( $(el) ); } ); data.oldPage = data.pages[data.oldPageIndex].slice(0); data.appended = true; // rebuild pages this._generatePages(); }, _autoMode: function( direction ) { var options = this.options, data = $( this.element ).data( "data" ); if ( direction === "next" ) { data.interval = setTimeout( $.proxy(this.next, this), options.auto.interval ); } else { data.interval = setTimeout( $.proxy(this.prev, this), options.auto.interval ); } }, _checkOptionsValidity: function( options ) { var i, self = this, _correctSteps = ""; // for every element in options object check its validity $.each(options, function( key, value ) { switch ( key ) { case "visible": // visible should be a positive integer if ( !value || typeof value !== "number" || value <= 0 || (Math.ceil(value) - value > 0) ) { throw new Error( "visible should be defined as a positive integer" ); } break; case "step": if ( !value || typeof value !== "number" || value <= 0 || (Math.ceil(value) - value > 0) ) { throw new Error( "step should be defined as a positive integer" ); } else if ( value > self.options.visible ) { // for example for visible: 3 the following array of values for 'step' is valid // 3 <= step >= 1 by 1 ==> [1,2,3] // output correct values for ( i = 1; i <= Math.floor(options.visible); i++ ) { _correctSteps += ( i < Math.floor(value) ) ? i + ", " : i; } throw new Error( "Only following step values are correct: " + _correctSteps ); } break; case "width": // width & height is defined by default so you can omit them to some extent if ( !value || typeof value !== "number" || value <= 0 || Math.ceil(value) - value > 0 ) { throw new Error( "width should be defined as a positive integer" ); } break; case "height": if ( !value || typeof value !== "number" || value <= 0 || Math.ceil(value) - value > 0 ) { throw new Error("height should be defined as a positive integer"); } break; case "speed": if ( !value && value !== 0 ) { throw new Error("speed should be defined as a number or a string"); } if ( typeof value === "number" && value < 0 ) { throw new Error( "speed should be a positive number" ); } else if ( typeof value === "string" && !(value === "slow" || value === "normal" || value === "fast") ) { throw new Error( 'Only "slow", "normal" and "fast" values are valid' ); } break; case "navigation": if ( !value || $.isPlainObject(value) === false ) { throw new Error( "navigation should be defined as an object with at least one of the properties: 'prev' or 'next' in it"); } if ( value.prev && typeof value.prev !== "string" ) { throw new Error( "navigation.prev should be defined as a string and point to '.class' or '#id' of an element" ); } if ( value.next && typeof value.next !== "string" ) { throw new Error(" navigation.next should be defined as a string and point to '.class' or '#id' of an element" ); } break; case "auto": if ( typeof value.direction !== "string" ) { throw new Error( "direction should be defined as a string" ); } if ( !(value.direction === "next" || value.direction === "prev") ) { throw new Error( "direction: only 'right' and 'left' values are valid" ); } if ( isNaN(value.interval) || typeof value.interval !== "number" || value.interval < 0 || Math.ceil(value.interval) - value.interval > 0 ) { throw new Error( "interval should be a positive number" ); } break; case "margin": if ( isNaN(value) || typeof value !== "number" || value < 0 || Math.ceil(value) - value > 0 ) { throw new Error( "margin should be a positive number" ); } break; } } ); }, _createDataObject: function() { var $root = $( this.element ); $root.data("data", { paths: [], pathsLen: 0, pages: [], lastPage: [], oldPageIndex: 0, pageIndex: 0, navigation: {}, animated: false, appended: false, hoveredOver: false } ); }, _generatePages: function() { var self = this, options = this.options, data = $( this.element ).data( "data" ), _visible = options.visible, _pathsLen = data.paths.length; // having 10 elements: A, B, C, D, E, F, G, H, I, J the algorithm // creates 3 pages for ‘visible: 5’ and ‘step: 4’: // [ABCDE], [EFGHI], [FGHIJ] function _init() { // init creates the last page [FGHIJ] and remembers it data.pages = []; data.lastPage = []; data.pages[0] = []; // init last page for ( var i = _pathsLen - 1; i >= _pathsLen - _visible; i-- ) { data.lastPage.unshift( data.paths[i] ); } // and first page for ( var i = 0; i < _visible; i++ ) { data.pages[0][data.pages[0].length] = data.paths[i]; } } function _islastPage( page ) { var _isLast = false; for ( var i = 0; i < data.lastPage.length; i++ ) { if ( data.lastPage[i].get(0) === page[i].get(0) ) { _isLast = true; } else { _isLast = false; break; } } return _isLast; } function _append( start, end, atIndex ) { var _index = atIndex || data.pages.length; if ( !atIndex ) { data.pages[_index] = []; } for ( var i = start; i < end; i++ ) { data.pages[_index].push( data.paths[i] ); } return _index; } function _paginate() { var _isBeginning = true, _complement = false, _start = options.step, _end, _index, _oldFirstEl, _oldLastEl; // continue until you reach the last page // we start from the 2nd page (1st page has been already initiated) while ( !_islastPage(data.pages[data.pages.length - 1]) || _isBeginning ) { _isBeginning = false; _end = _start + _visible; // we cannot exceed _pathsLen if ( _end > _pathsLen ) { _end = _pathsLen; } // when we run ouf of elements (_end - _start < _visible) we must add the difference at the begining // in our example the 3rd page is [FGHIJ] and J element is added in the second step // first we add [FGHI] as old elements // we must assure that we have always ‘visible’ (5 in our example) elements if ( _end - _start < _visible ) { _complement = true; } else { _complement = false; } if ( _complement ) { // first add old elemets; for 3rd page it adds [FGHI…] // remember the page we add to (_index) _oldFirstEl = _start - ( _visible - (_end - _start) ); _oldLastEl = _oldFirstEl + ( _visible - (_end - _start) ); _index = _append( _oldFirstEl, _oldLastEl ); // then add new elements; for 3th page it is J element: // [fghiJ] _append( _start, _end, _index ); } else { // normal pages like [ABCDE], [EFGHI] _append( _start, _end ); // next step _start += options.step; } } } // go! _init(); _paginate(); }, getCurrentPage: function() { var data = $( this.element ).data( "data" ); return data.pageIndex + 1; }, getTotalPages: function() { var data = $( this.element ).data( "data" ); return data.pages.length; }, goToPage: function( page ) { var _by, data = $( this.element ).data( "data" ); if ( !data.animated && page !== data.pageIndex ) { data.animated = true; if ( page > data.pages.length - 1 ) { page = data.pages.length - 1; } else if ( page < 0 ) { page = 0; } data.pageIndex = page; _by = page - data.oldPageIndex; if ( _by >= 0 ) { //move by n elements from current index this._goToNextPage( _by ); } else { this._goToPrevPage( _by ); } data.oldPageIndex = page; } }, _loadElements: function(elements, direction) { var options = this.options, data = $( this.element ).data( "data" ), _dir = direction || "next", _elem = elements || data.pages[options.startAtPage], _start = 0, _end = _elem.length; if ( _dir === "next" ) { for ( var i = _start; i < _end; i++ ) { this._addElement( _elem[i], _dir ); } } else { for ( var i = _end - 1; i >= _start; i-- ) { this._addElement( _elem[i], _dir ); } } }, _goToPrevPage: function( by ) { var _page, _oldPage, _dist, _index, _animOpts, $lastEl, _unique, _pos, _theSame, $root = $( this.element ), self = this, options = this.options, data = $( this.element ).data( "data" ); // pick pages if ( data.appended ) { _oldPage = data.oldPage; } else { _oldPage = data.pages[data.oldPageIndex]; } _index = data.oldPageIndex + by; _page = data.pages[_index].slice( 0 ); // For example, the first time widget was initiated there were 5 // elements: A, B, C, D, E and 3 pages for visible 2 and step 2: // AB, CD, DE. Then a user loaded next 5 elements so there were // 10 already: A, B, C, D, E, F, G, H, I, J and 5 pages: // AB, CD, EF, GH and IJ. If the other elemets were loaded when // CD page was shown (from 5 elements) ‘_theSame’ is true because // we compare the same // pages, that is, the 2nd page from 5 elements and the 2nd from // 10 elements. Thus what we do next is to decrement the index and // loads the first page from 10 elements. $( _page ).each( function( i, el ) { if ( el.get(0) === $(_oldPage[i]).get(0) ) { _theSame = true; } else { _theSame = false; } } ); if ( data.appended && _theSame ) { if ( data.pageIndex === 0 ) { _index = data.pageIndex = data.pages.length - 1; } else { _index = --data.pageIndex; } _page = data.pages[_index].slice( 0 ); } // check if last element from _page appears in _oldPage // for [ABCDFGHIJ] elements there are 3 pages for ‘visible’ = 6 and // ‘step’ = 2: [ABCDEF], [CDEFGH] and [EFGHIJ]; going from the 3rd // to the 2nd page we only loads 2 elements: [CD] because all // remaining were loaded already $lastEl = _page[_page.length - 1].get( 0 ); for ( var i = _oldPage.length - 1; i >= 0; i-- ) { if ( $lastEl === $(_oldPage[i]).get(0) ) { _unique = false; _pos = i; break; } else { _unique = true; } } if ( !_unique ) { while ( _pos >= 0 ) { if ( _page[_page.length - 1].get(0) === _oldPage[_pos].get(0) ) { // this element is unique _page.pop(); } --_pos; } } // load new elements self._loadElements( _page, "prev" ); // calculate the distance _dist = options.width * _page.length + ( options.margin * _page.length ); if (options.orientation === "horizontal") { _animOpts = {scrollLeft: 0}; $root.scrollLeft( _dist ); } else { _animOpts = {scrollTop: 0}; $root.scrollTop( _dist ); } $root .animate(_animOpts, options.speed, function () { self._removeOldElements( "last", _page.length ); data.animated = false; if ( !data.hoveredOver && options.auto.enabled ) { // if autoMode is on and you change page manually clearInterval( data.interval ); self._autoMode( options.auto.direction ); } // scrolling is finished, send an event self._trigger("pageLoaded", null, {page: _index}); }); // reset to deafult data.appended = false; }, _goToNextPage: function( by ) { var _page, _oldPage, _dist, _index, _animOpts, $firstEl, _unique, _pos, _theSame, $root = $( this.element ), options = this.options, data = $root.data( "data" ), self = this; // pick pages if ( data.appended ) { _oldPage = data.oldPage; } else { _oldPage = data.pages[data.oldPageIndex]; } _index = data.oldPageIndex + by; _page = data.pages[_index].slice( 0 ); // For example, the first time widget was initiated there were 5 // elements: A, B, C, D, E and 2 pages for visible 4 and step 3: // ABCD and BCDE. Then a user loaded next 5 elements so there were // 10 already: A, B, C, D, E, F, G, H, I, J and 3 pages: // ABCD, DEFG and GHIJ. If the other elemets were loaded when // ABCD page was shown (from 5 elements) ‘_theSame’ is true because // we compare the same // pages, that is, the first pages from 5 elements and the first from // 10 elements. Thus what we do next is to increment the index and // loads the second page from 10 elements. $( _page ).each( function( i, el ) { if ( el.get(0) === $(_oldPage[i]).get(0) ) { _theSame = true; } else { _theSame = false; } } ); if ( data.appended && _theSame ) { _page = data.pages[++data.pageIndex].slice( 0 ); } // check if 1st element from _page appears in _oldPage // for [ABCDFGHIJ] elements there are 3 pages for ‘visible’ = 6 and // ‘step’ = 2: [ABCDEF], [CDEFGH] and [EFGHIJ]; going from the 2nd // to the 3rd page we only loads 2 elements: [IJ] because all // remaining were loaded already $firstEl = _page[0].get( 0 ); for ( var i = 0; i < _page.length; i++) { if ( $firstEl === $(_oldPage[i]).get(0) ) { _unique = false; _pos = i; break; } else { _unique = true; } } if ( !_unique ) { while ( _pos < _oldPage.length ) { if ( _page[0].get(0) === _oldPage[_pos].get(0) ) { _page.shift(); } ++_pos; } } // load new elements this._loadElements( _page, "next" ); // calculate the distance _dist = options.width * _page.length + ( options.margin * _page.length ); if ( options.orientation === "horizontal" ) { _animOpts = {scrollLeft: "+=" + _dist}; } else { _animOpts = {scrollTop: "+=" + _dist}; } $root .animate(_animOpts, options.speed, function() { self._removeOldElements( "first", _page.length ); if ( options.orientation === "horizontal" ) { $root.scrollLeft( 0 ); } else { $root.scrollTop( 0 ); } data.animated = false; if ( !data.hoveredOver && options.auto.enabled ) { // if autoMode is on and you change page manually clearInterval( data.interval ); self._autoMode( options.auto.direction ); } // scrolling is finished, send an event self._trigger( "pageLoaded", null, {page: _index}); }); // reset to deafult data.appended = false; }, next: function() { var options = this.options, data = $( this.element ).data( "data" ); if ( !data.animated ) { data.animated = true; if ( !data.appended ) { ++data.pageIndex; } if ( data.pageIndex > data.pages.length - 1 ) { data.pageIndex = 0; } // move by one element from current index this._goToNextPage( data.pageIndex - data.oldPageIndex ); data.oldPageIndex = data.pageIndex; } }, prev: function() { var options = this.options, data = $( this.element ).data( "data" ); if ( !data.animated ) { data.animated = true; if ( !data.appended ) { --data.pageIndex; } if ( data.pageIndex < 0 ) { data.pageIndex = data.pages.length - 1; } // move left by one element from current index this._goToPrevPage( data.pageIndex - data.oldPageIndex ); data.oldPageIndex = data.pageIndex; } }, _removeOldElements: function(position, length) { // remove 'step' elements var $root = $( this.element ); for ( var i = 0; i < length; i++ ) { if ( position === "first" ) { $root .find( "div.wrapper" ) .children() .first() .remove(); } else { $root .find( "div.wrapper" ) .children() .last() .remove(); } } }, _saveElements: function() { var $el, $root = $( this.element ), $elements = $root.find( "div.wrapper" ).children(), data = $root.data( "data" ); $elements.each( function( i, el ) { $el = $( el ); // keep element’s data and events data.paths.push( $el.clone(true, true) ); $el.remove(); } ); }, _setOption: function( key, value ) { var _newOptions, options = this.options, data = $( this.element ).data( "data" ); switch (key) { case "speed": this._checkOptionsValidity({speed: value}); options.speed = value; $.Widget.prototype._setOption.apply( this, arguments ); break; case "auto": _newOptions = $.extend( options.auto, value ); this._checkOptionsValidity({auto: _newOptions}); if ( options.auto.enabled ) { this._autoMode( options.auto.direction ); } } }, _setStep: function(s) { // calculate a step var _step, options = this.options, data = $( this.element ).data( "data" ); _step = s || options.step; options.step = _step; data.step = options.width * _step; }, _setCarouselHeight: function() { var _newHeight, $root = $( this.element ), data = $( this.element ).data( "data" ), options = this.options; if ( options.orientation === "vertical" ) { _newHeight = options.visible * options.height + options.margin * (options.visible - 1) + options.border; } else { _newHeight = options.height + options.border; } $root.height(_newHeight); }, _setCarouselWidth: function() { var _newWidth, $root = $( this.element ), options = this.options, data = $( this.element ).data( "data" ); if ( options.orientation === "horizontal" ) { _newWidth = options.visible * options.width + options.margin * (options.visible - 1); } else { _newWidth = options.width; } // set carousel width and disable overflow: auto $root.css({ width: _newWidth, overflow: "hidden" }); }, options: { visible: 3, step: 3, width: 100, height: 100, speed: 1000, margin: 0, border:0, orientation: "horizontal", auto: { enabled: false, direction: "next", interval: 5000 }, startAtPage: 0, navigation: { next: "#ui-carousel-next", prev: "#ui-carousel-prev" } } }); }(jQuery));