ok
Direktori : /home/keydecors/www/test/js/ |
Current File : /home/keydecors/www/test/js/owl.carousel.min.js |
/** * @name Owl Carousel - code name Phenix * @author Bartosz Wojciechowski * @release 2014 * Licensed under MIT * * @version 2.0.0-beta.1.8 * @versionNotes Not compatibile with Owl Carousel <2.0.0 */ /* {0,0} )_) "" To do: * Lazy Load Icon * prevent animationend bubling * itemsScaleUp * Test Zepto Callback events list: onInitBefore onInitAfter onResponsiveBefore onResponsiveAfter onTransitionStart onTransitionEnd onTouchStart onTouchEnd onChangeState onLazyLoaded onVideoPlay onVideoStop Custom events list: next.owl prev.owl goTo.owl jumpTo.owl addItem.owl removeItem.owl refresh.owl play.owl stop.owl stopVideo.owl */ ;(function ( $, window, document, undefined ) { var defaults = { items: 3, loop: false, center: false, mouseDrag: true, touchDrag: true, pullDrag: true, freeDrag: false, margin: 0, stagePadding: 0, merge: false, mergeFit: true, autoWidth: false, autoHeight: false, startPosition: 0, URLhashListener: false, nav: false, navRewind: true, navText: ['prev','next'], slideBy: 1, dots: true, dotsEach: false, dotData: false, lazyLoad: false, lazyContent: false, autoplay: false, autoplayTimeout: 5000, autoplayHoverPause: false, smartSpeed: 250, fluidSpeed: false, autoplaySpeed: false, navSpeed: false, dotsSpeed: false, dragEndSpeed: false, responsive: {}, responsiveRefreshRate : 200, responsiveBaseElement: window, responsiveClass: false, video: false, videoHeight: false, videoWidth: false, animateOut: false, animateIn: false, fallbackEasing: 'swing', callbacks: false, info: false, nestedItemSelector: false, itemElement: 'div', stageElement: 'div', //Classes and Names themeClass: 'owl-theme', baseClass: 'owl-carousel', itemClass: 'owl-item', centerClass: 'center', activeClass: 'active', navContainerClass: 'owl-nav', navClass: ['owl-prev','owl-next'], controlsClass: 'owl-controls', dotClass: 'owl-dot', dotsClass: 'owl-dots', autoHeightClass: 'owl-height' }; // Reference to DOM elements // Those with $ sign are jQuery objects var dom = { el: null, // main element $el: null, // jQuery main element stage: null, // stage $stage: null, // jQuery stage oStage: null, // outer stage $oStage: null, // $ outer stage $items: null, // all items, clones and originals included $oItems: null, // original items $cItems: null, // cloned items only $cc: null, $navPrev: null, $navNext: null, $page: null, $nav: null, $content: null }; /** * Variables * @since 2.0.0 */ // Only for development process // Widths var width = { el: 0, stage: 0, item: 0, prevWindow: 0, cloneLast: 0 }; // Numbers var num = { items: 0, oItems: 0, cItems: 0, active: 0, merged: [], nav: [], allPages: 0 }; // Positions var pos = { start: 0, max: 0, maxValue: 0, prev: 0, current: 0, currentAbs: 0, currentPage:0, stage: 0, items: [], lsCurrent: 0 }; // Drag/Touches var drag = { start: 0, startX: 0, startY: 0, current: 0, currentX: 0, currentY: 0, offsetX: 0, offsetY: 0, distance: null, startTime: 0, endTime: 0, updatedX: 0, targetEl: null }; // Speeds var speed = { onDragEnd: 300, nav: 300, css2speed: 0 }; // States var state = { isTouch: false, isScrolling: false, isSwiping: false, direction: false, inMotion: false, autoplay: false, lazyContent: false }; // Event functions references var e = { _onDragStart: null, _onDragMove: null, _onDragEnd: null, _transitionEnd: null, _resizer: null, _responsiveCall:null, _goToLoop: null, _checkVisibile: null, _autoplay: null, _pause: null, _play: null, _stop: null }; function Owl( element, options ) { // add basic Owl information to dom element element.owlCarousel = { 'name': 'Owl Carousel', 'author': 'Bartosz Wojciechowski', 'version': '2.0.0-beta.1.8', 'released': '03.05.2014' }; // Attach variables to object // Only for development process this.options = $.extend( {}, defaults, options); this._options = $.extend( {}, defaults, options); this.dom = $.extend( {}, dom); this.width = $.extend( {}, width); this.num = $.extend( {}, num); this.pos = $.extend( {}, pos); this.drag = $.extend( {}, drag); this.speed = $.extend( {}, speed); this.state = $.extend( {}, state); this.e = $.extend( {}, e); this.dom.el = element; this.dom.$el = $(element); this.init(); } /** * init * @since 2.0.0 */ Owl.prototype.init = function(){ this.fireCallback('onInitBefore'); //Add base class if(!this.dom.$el.hasClass(this.options.baseClass)){ this.dom.$el.addClass(this.options.baseClass); } //Add theme class if(!this.dom.$el.hasClass(this.options.themeClass)){ this.dom.$el.addClass(this.options.themeClass); } //Add theme class if(this.options.rtl){ this.dom.$el.addClass('owl-rtl'); } // Check support this.browserSupport(); // Sort responsive items in array this.sortOptions(); // Update options.items on given size this.setResponsiveOptions(); if(this.options.autoWidth && this.state.imagesLoaded !== true){ var imgs = this.dom.$el.find('img'); if(imgs.length){ this.preloadAutoWidthImages(imgs); return false; } } // Get and store window width // iOS safari likes to trigger unnecessary resize event this.width.prevWindow = this.windowWidth(); // create stage object this.createStage(); // Append local content this.fetchContent(); // attach generic events this.eventsCall(); // attach custom control events this.addCustomEvents(); // attach generic events this.internalEvents(); this.dom.$el.addClass('owl-loading'); this.refresh(true); this.dom.$el.removeClass('owl-loading').addClass('owl-loaded'); this.fireCallback('onInitAfter'); }; /** * sortOptions * @desc Sort responsive sizes * @since 2.0.0 */ Owl.prototype.sortOptions = function(){ var resOpt = this.options.responsive; this.responsiveSorted = {}; var keys = [], i, j, k; for (i in resOpt){ keys.push(i); } keys = keys.sort(function (a, b) {return a - b;}); for (j = 0; j < keys.length; j++){ k = keys[j]; this.responsiveSorted[k] = resOpt[k]; } }; /** * setResponsiveOptions * @since 2.0.0 */ Owl.prototype.setResponsiveOptions = function(){ if(this.options.responsive === false){return false;} var width = this.windowWidth(); var resOpt = this.options.responsive; var i,j,k, minWidth; // overwrite non resposnive options for(k in this._options){ if(k !== 'responsive'){ this.options[k] = this._options[k]; } } // find responsive width for (i in this.responsiveSorted){ if(i<= width){ minWidth = i; // set responsive options for(j in this.responsiveSorted[minWidth]){ this.options[j] = this.responsiveSorted[minWidth][j]; } } } this.num.breakpoint = minWidth; // Responsive Class if(this.options.responsiveClass){ this.dom.$el.attr('class', function(i, c){ return c.replace(/\b owl-responsive-\S+/g, ''); }).addClass('owl-responsive-'+minWidth); } }; /** * optionsLogic * @desc Update option logic if necessery * @since 2.0.0 */ Owl.prototype.optionsLogic = function(){ // Toggle Center class this.dom.$el.toggleClass('owl-center',this.options.center); // Scroll per - 'page' option will scroll per visible items number // You can set this to any other number below visible items. if(this.options.slideBy && this.options.slideBy === 'page'){ this.options.slideBy = this.options.items; } else if(this.options.slideBy > this.options.items){ this.options.slideBy = this.options.items; } // if items number is less than in body if(this.options.loop && this.num.oItems < this.options.items){ this.options.loop = false; } if(this.num.oItems <= this.options.items){ this.options.navRewind = false; } if(this.options.autoWidth){ this.options.stagePadding = false; this.options.dotsEach = 1; this.options.merge = false; } if(this.state.lazyContent){ this.options.loop = false; this.options.merge = false; this.options.dots = false; this.options.freeDrag = false; this.options.lazyContent = true; } if((this.options.animateIn || this.options.animateOut) && this.options.items === 1 && this.support3d){ this.state.animate = true; } else {this.state.animate = false;} }; /** * createStage * @desc Create stage and Outer-stage elements * @since 2.0.0 */ Owl.prototype.createStage = function(){ var oStage = document.createElement('div'); var stage = document.createElement(this.options.stageElement); oStage.className = 'owl-stage-outer'; stage.className = 'owl-stage'; oStage.appendChild(stage); this.dom.el.appendChild(oStage); this.dom.oStage = oStage; this.dom.$oStage = $(oStage); this.dom.stage = stage; this.dom.$stage = $(stage); oStage = null; stage = null; }; /** * createItem * @desc Create item container * @since 2.0.0 */ Owl.prototype.createItem = function(){ var item = document.createElement(this.options.itemElement); item.className = this.options.itemClass; return item; }; /** * fetchContent * @since 2.0.0 */ Owl.prototype.fetchContent = function(extContent){ if(extContent){ this.dom.$content = (extContent instanceof jQuery) ? extContent : $(extContent); } else if(this.options.nestedItemSelector){ this.dom.$content= this.dom.$el.find('.'+this.options.nestedItemSelector).not('.owl-stage-outer'); } else { this.dom.$content= this.dom.$el.children().not('.owl-stage-outer'); } // content length this.num.oItems = this.dom.$content.length; // init Structure if(this.num.oItems !== 0){ this.initStructure(); } }; /** * initStructure * @param [refresh] - if refresh and not lazyContent then dont create normal structure * @since 2.0.0 */ Owl.prototype.initStructure = function(){ // lazyContent needs at least 3*items if(this.options.lazyContent && this.num.oItems >= this.options.items*3){ this.state.lazyContent = true; } else { this.state.lazyContent = false; } if(this.state.lazyContent){ // start position this.pos.currentAbs = this.options.items; //remove lazy content from DOM this.dom.$content.remove(); } else { // create normal structure this.createNormalStructure(); } }; /** * createNormalStructure * @desc Create normal structure for small/mid weight content * @since 2.0.0 */ Owl.prototype.createNormalStructure = function(){ for(var i = 0; i < this.num.oItems; i++){ // fill 'owl-item' with content var item = this.fillItem(this.dom.$content,i); // append into stage this.dom.$stage.append(item); } this.dom.$content = null; }; /** * createCustomStructure * @since 2.0.0 */ Owl.prototype.createCustomStructure = function(howManyItems){ for(var i = 0; i < howManyItems; i++){ var emptyItem = this.createItem(); var item = $(emptyItem); this.setData(item,false); this.dom.$stage.append(item); } }; /** * createLazyContentStructure * @desc Create lazyContent structure for large content and better mobile experience * @since 2.0.0 */ Owl.prototype.createLazyContentStructure = function(refresh){ if(!this.state.lazyContent){return false;} // prevent recreate - to do if(refresh && this.dom.$stage.children().length === this.options.items*3){ return false; } // remove items from stage this.dom.$stage.empty(); // create custom structure this.createCustomStructure(3*this.options.items); }; /** * fillItem * @desc Fill empty item container with provided content * @since 2.0.0 * @param [content] - string/$dom - passed owl-item * @param [i] - index in jquery object * return $ new object */ Owl.prototype.fillItem = function(content,i){ var emptyItem = this.createItem(); var c = content[i] || content; // set item data var traversed = this.traversContent(c); this.setData(emptyItem,false,traversed); return $(emptyItem).append(c); }; /** * traversContent * @since 2.0.0 * @param [c] - content * return object */ Owl.prototype.traversContent = function(c){ var $c = $(c), dotValue, hashValue; if(this.options.dotData){ dotValue = $c.find('[data-dot]').andSelf().data('dot'); } // update URL hash if(this.options.URLhashListener){ hashValue = $c.find('[data-hash]').andSelf().data('hash'); } return { dot : dotValue || false, hash : hashValue || false }; }; /** * setData * @desc Set item jQuery Data * @since 2.0.0 * @param [item] - dom - passed owl-item * @param [cloneObj] - $dom - passed clone item */ Owl.prototype.setData = function(item,cloneObj,traversed){ var dot,hash; if(traversed){ dot = traversed.dot; hash = traversed.hash; } var itemData = { index: false, indexAbs: false, posLeft: false, clone: false, active: false, loaded: false, lazyLoad: false, current: false, width: false, center: false, page: false, hasVideo: false, playVideo: false, dot: dot, hash: hash }; // copy itemData to cloned item if(cloneObj){ itemData = $.extend({}, itemData, cloneObj.data('owl-item')); } $(item).data('owl-item', itemData); }; /** * updateLocalContent * @since 2.0.0 */ Owl.prototype.updateLocalContent = function(){ this.dom.$oItems = this.dom.$stage.find('.'+this.options.itemClass).filter(function(){ return $(this).data('owl-item').clone === false; }); this.num.oItems = this.dom.$oItems.length; //update index on original items for(var k = 0; k<this.num.oItems; k++){ var item = this.dom.$oItems.eq(k); item.data('owl-item').index = k; } }; /** * checkVideoLinks * @desc Check if for any videos links * @since 2.0.0 */ Owl.prototype.checkVideoLinks = function(){ if(!this.options.video){return false;} var videoEl,item; for(var i = 0; i<this.num.items; i++){ item = this.dom.$items.eq(i); if(item.data('owl-item').hasVideo){ continue; } videoEl = item.find('.owl-video'); if(videoEl.length){ this.state.hasVideos = true; this.dom.$items.eq(i).data('owl-item').hasVideo = true; videoEl.css('display','none'); this.getVideoInfo(videoEl,item); } } }; /** * getVideoInfo * @desc Get Video ID and Type (YouTube/Vimeo only) * @since 2.0.0 */ Owl.prototype.getVideoInfo = function(videoEl,item){ var info, type, id, vimeoId = videoEl.data('vimeo-id'), youTubeId = videoEl.data('youtube-id'), width = videoEl.data('width') || this.options.videoWidth, height = videoEl.data('height') || this.options.videoHeight, url = videoEl.attr('href'); if(vimeoId){ type = 'vimeo'; id = vimeoId; } else if(youTubeId){ type = 'youtube'; id = youTubeId; } else if(url){ id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/); if (id[3].indexOf('youtu') > -1) { type = 'youtube'; } else if (id[3].indexOf('vimeo') > -1) { type = 'vimeo'; } id = id[6]; } else { throw new Error('Missing video link.'); } item.data('owl-item').videoType = type; item.data('owl-item').videoId = id; item.data('owl-item').videoWidth = width; item.data('owl-item').videoHeight = height; info = { type: type, id: id }; // Check dimensions var dimensions = width && height ? 'style="width:'+width+'px;height:'+height+'px;"' : ''; // wrap video content into owl-video-wrapper div videoEl.wrap('<div class="owl-video-wrapper"'+dimensions+'></div>'); this.createVideoTn(videoEl,info); }; /** * createVideoTn * @desc Create Video Thumbnail * @since 2.0.0 */ Owl.prototype.createVideoTn = function(videoEl,info){ var tnLink,icon,height; var customTn = videoEl.find('img'); var srcType = 'src'; var lazyClass = ''; var that = this; if(this.options.lazyLoad){ srcType = 'data-src'; lazyClass = 'owl-lazy'; } // Custom thumbnail if(customTn.length){ addThumbnail(customTn.attr(srcType)); customTn.remove(); return false; } function addThumbnail(tnPath){ icon = '<div class="owl-video-play-icon"></div>'; if(that.options.lazyLoad){ tnLink = '<div class="owl-video-tn '+ lazyClass +'" '+ srcType +'="'+ tnPath +'"></div>'; } else{ tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + tnPath + ')"></div>'; } videoEl.after(tnLink); videoEl.after(icon); } if(info.type === 'youtube'){ var path = "http://img.youtube.com/vi/"+ info.id +"/hqdefault.jpg"; addThumbnail(path); } else if(info.type === 'vimeo'){ $.ajax({ type:'GET', url: 'http://vimeo.com/api/v2/video/' + info.id + '.json', jsonp: 'callback', dataType: 'jsonp', success: function(data){ var path = data[0].thumbnail_large; addThumbnail(path); if(that.options.loop){ that.updateItemState(); } } }); } }; /** * stopVideo * @since 2.0.0 */ Owl.prototype.stopVideo = function(){ this.fireCallback('onVideoStop'); var item = this.dom.$items.eq(this.state.videoPlayIndex); item.find('.owl-video-frame').remove(); item.removeClass('owl-video-playing'); this.state.videoPlay = false; }; /** * playVideo * @since 2.0.0 */ Owl.prototype.playVideo = function(ev){ this.fireCallback('onVideoPlay'); if(this.state.videoPlay){ this.stopVideo(); } var videoLink,videoWrap, target = $(ev.target || ev.srcElement), item = target.closest('.'+this.options.itemClass); var videoType = item.data('owl-item').videoType, id = item.data('owl-item').videoId, width = item.data('owl-item').videoWidth || Math.floor(item.data('owl-item').width - this.options.margin), height = item.data('owl-item').videoHeight || this.dom.$stage.height(); if(videoType === 'youtube'){ videoLink = "<iframe width=\""+ width +"\" height=\""+ height +"\" src=\"http://www.youtube.com/embed/" + id + "?autoplay=1&v=" + id + "\" frameborder=\"0\" allowfullscreen></iframe>"; } else if(videoType === 'vimeo'){ videoLink = '<iframe src="http://player.vimeo.com/video/'+ id +'?autoplay=1" width="'+ width +'" height="'+ height +'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'; } item.addClass('owl-video-playing'); this.state.videoPlay = true; this.state.videoPlayIndex = item.data('owl-item').indexAbs; videoWrap = $('<div style="height:'+ height +'px; width:'+ width +'px" class="owl-video-frame">' + videoLink + '</div>'); target.after(videoWrap); }; /** * loopClone * @desc Make a clones for infinity loop * @since 2.0.0 */ Owl.prototype.loopClone = function(){ if(!this.options.loop || this.state.lazyContent || this.num.oItems < this.options.items){return false;} var firstClone, lastClone, i, num = this.options.items, lastNum = this.num.oItems-1; // if neighbour margin then add one more duplicat if(this.options.stagePadding && this.options.items === 1){ num+=1; } this.num.cItems = num * 2; for(i = 0; i < num; i++){ // Clone item var first = this.dom.$oItems.eq(i).clone(true,true); var last = this.dom.$oItems.eq(lastNum-i).clone(true,true); firstClone = $(first[0]).addClass('cloned'); lastClone = $(last[0]).addClass('cloned'); // set clone data // Somehow data has reference to same data id in cash this.setData(firstClone[0],first); this.setData(lastClone[0],last); firstClone.data('owl-item').clone = true; lastClone.data('owl-item').clone = true; this.dom.$stage.append(firstClone); this.dom.$stage.prepend(lastClone); firstClone = lastClone = null; } this.dom.$cItems = this.dom.$stage.find('.'+this.options.itemClass).filter(function(){ return $(this).data('owl-item').clone === true; }); }; /** * reClone * @desc Update Cloned elements * @since 2.0.0 */ Owl.prototype.reClone = function(){ // remove cloned items if(this.dom.$cItems !== null){ // && (this.num.oItems !== 0 && this.num.oItems <= this.options.items)){ this.dom.$cItems.remove(); this.dom.$cItems = null; this.num.cItems = 0; } if(!this.options.loop){ return; } // generete new elements this.loopClone(); }; /** * calculate * @desc Update item index data * @since 2.0.0 */ Owl.prototype.calculate = function(){ var i,j,k,dist,posLeft=0,fullWidth=0; // element width minus neighbour this.width.el = this.dom.$el.width() - (this.options.stagePadding*2); //to check this.width.view = this.dom.$el.width(); // calculate width minus addition margins var elMinusMargin = this.width.el - (this.options.margin * (this.options.items === 1 ? 0 : this.options.items -1)); // calculate element width and item width this.width.el = this.width.el + this.options.margin; this.width.item = ((elMinusMargin / this.options.items) + this.options.margin).toFixed(3); this.dom.$items = this.dom.$stage.find('.owl-item'); this.num.items = this.dom.$items.length; //change to autoWidths if(this.options.autoWidth){ this.dom.$items.css('width',''); } // Set grid array this.pos.items = []; this.num.merged = []; this.num.nav = []; // item distances if(this.options.rtl){ dist = this.options.center ? -((this.width.el)/2) : 0; } else { dist = this.options.center ? (this.width.el)/2 : 0; } this.width.mergeStage = 0; // Calculate items positions for(i = 0; i<this.num.items; i++){ // check merged items if(this.options.merge){ var mergeNumber = this.dom.$items.eq(i).find('[data-merge]').attr('data-merge') || 1; if(this.options.mergeFit && mergeNumber > this.options.items){ mergeNumber = this.options.items; } this.num.merged.push(parseInt(mergeNumber)); this.width.mergeStage += this.width.item * this.num.merged[i]; } else { this.num.merged.push(1); } // Array based on merged items used by dots and navigation if(this.options.loop){ if(i>=this.num.cItems/2 && i<this.num.cItems/2+this.num.oItems){ this.num.nav.push(this.num.merged[i]); } } else { this.num.nav.push(this.num.merged[i]); } var iWidth = this.width.item * this.num.merged[i]; // autoWidth item size if(this.options.autoWidth){ iWidth = this.dom.$items.eq(i).width() + this.options.margin; if(this.options.rtl){ this.dom.$items[i].style.marginLeft = this.options.margin + 'px'; } else { this.dom.$items[i].style.marginRight = this.options.margin + 'px'; } } // push item position into array this.pos.items.push(dist); // update item data this.dom.$items.eq(i).data('owl-item').posLeft = posLeft; this.dom.$items.eq(i).data('owl-item').width = iWidth; // dist starts from middle of stage if center // posLeft always starts from 0 if(this.options.rtl){ dist += iWidth; posLeft += iWidth; } else{ dist -= iWidth; posLeft -= iWidth; } fullWidth -= Math.abs(iWidth); // update position if center if(this.options.center){ this.pos.items[i] = !this.options.rtl ? this.pos.items[i] - (iWidth/2) : this.pos.items[i] + (iWidth/2); } } if(this.options.autoWidth){ this.width.stage = this.options.center ? Math.abs(fullWidth) : Math.abs(dist); } else { this.width.stage = Math.abs(fullWidth); } //update indexAbs on all items var allItems = this.num.oItems + this.num.cItems; for(j = 0; j< allItems; j++){ this.dom.$items.eq(j).data('owl-item').indexAbs = j; } // Set Min and Max this.setMinMax(); // Recalculate grid this.setSizes(); }; /** * setMinMax * @since 2.0.0 */ Owl.prototype.setMinMax = function(){ // set Min var minimum = this.dom.$oItems.eq(0).data('owl-item').indexAbs; this.pos.min = 0; this.pos.minValue = this.pos.items[minimum]; // set max position if(!this.options.loop){ this.pos.max = this.num.oItems-1; } if(this.options.loop){ this.pos.max = this.num.oItems+this.options.items; } if(!this.options.loop && !this.options.center){ this.pos.max = this.num.oItems-this.options.items; } if(this.options.loop && this.options.center){ this.pos.max = this.num.oItems+this.options.items; } //set max value this.pos.maxValue = this.pos.items[this.pos.max]; //Max for autoWidth content if((!this.options.loop && !this.options.center && this.options.autoWidth) || (this.options.merge && !this.options.center) ){ var revert = this.options.rtl ? 1 : -1; for (i = 0; i < this.pos.items.length; i++) { if( (this.pos.items[i] * revert) < this.width.stage-this.width.el ){ this.pos.max = i+1; } } this.pos.maxValue = this.options.rtl ? this.width.stage-this.width.el : -(this.width.stage-this.width.el); this.pos.items[this.pos.max] = this.pos.maxValue; } // Set loop boundries if(this.options.center){ this.pos.loop = this.pos.items[0]-this.pos.items[this.num.oItems]; } else { this.pos.loop = -this.pos.items[this.num.oItems]; } //if is less items if(this.num.oItems < this.options.items && !this.options.center){ this.pos.max = 0; this.pos.maxValue = this.pos.items[0]; } }; /** * setSizes * @desc Set sizes on elements (from collectData function) * @since 2.0.0 */ Owl.prototype.setSizes = function(){ // show neighbours if(this.options.stagePadding !== false){ this.dom.oStage.style.paddingLeft = this.options.stagePadding + 'px'; this.dom.oStage.style.paddingRight = this.options.stagePadding + 'px'; } // CRAZY FIX!!! Doublecheck this! //if(this.width.stagePrev > this.width.stage){ if(this.options.rtl){ window.setTimeout(function(){ this.dom.stage.style.width = this.width.stage + 'px'; }.bind(this),0); } else{ this.dom.stage.style.width = this.width.stage + 'px'; } for(var i=0; i<this.num.items; i++){ // Set items width if(!this.options.autoWidth){ this.dom.$items[i].style.width = this.width.item - (this.options.margin) + 'px'; } // add margin if(this.options.rtl){ this.dom.$items[i].style.marginLeft = this.options.margin + 'px'; } else { this.dom.$items[i].style.marginRight = this.options.margin + 'px'; } if(this.num.merged[i] !== 1 && !this.options.autoWidth){ this.dom.$items[i].style.width = (this.width.item * this.num.merged[i]) - (this.options.margin) + 'px'; } } // save prev stage size this.width.stagePrev = this.width.stage; }; /** * responsive * @desc Responsive function update all data by calling refresh() * @since 2.0.0 */ Owl.prototype.responsive = function(){ if(!this.num.oItems){return false;} // If El width hasnt change then stop responsive var elChanged = this.isElWidthChanged(); if(!elChanged){return false;} // if Vimeo Fullscreen mode var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement; if(fullscreenElement){ if($(fullscreenElement.parentNode).hasClass('owl-video-frame')){ this.setSpeed(0); this.state.isFullScreen = true; } } if(fullscreenElement && this.state.isFullScreen && this.state.videoPlay){ return false; } // Comming back from fullscreen if(this.state.isFullScreen){ this.state.isFullScreen = false; return false; } // check full screen mode and window orientation if (this.state.videoPlay) { if(this.state.orientation !== window.orientation){ this.state.orientation = window.orientation; return false; } } this.fireCallback('onResponsiveBefore'); this.state.responsive = true; this.refresh(); this.state.responsive = false; this.fireCallback('onResponsiveAfter'); }; /** * refresh * @desc Refresh method is basically collection of functions that are responsible for Owl responsive functionality * @since 2.0.0 */ Owl.prototype.refresh = function(init){ if(this.state.videoPlay){ this.stopVideo(); } // Update Options for given width this.setResponsiveOptions(); //set lazy structure this.createLazyContentStructure(true); // update info about local content this.updateLocalContent(); // udpate options this.optionsLogic(); // if no items then stop if(this.num.oItems === 0){ if(this.dom.$page !== null){ this.dom.$page.hide(); } return false; } // Hide and Show methods helps here to set a proper widths. // This prevents Scrollbar to be calculated in stage width this.dom.$stage.addClass('owl-refresh'); // Remove clones and generate new ones this.reClone(); // calculate this.calculate(); //aaaand show. this.dom.$stage.removeClass('owl-refresh'); // to do // lazyContent last position on refresh if(this.state.lazyContent){ this.pos.currentAbs = this.options.items; } this.initPosition(init); // jump to last position if(!this.state.lazyContent && !init){ this.jumpTo(this.pos.current,false); // fix that } //Check for videos ( YouTube and Vimeo currently supported) this.checkVideoLinks(); this.updateItemState(); // Update controls this.rebuildDots(); this.updateControls(); // update drag events //this.updateEvents(); // update autoplay this.autoplay(); this.autoHeight(); this.state.orientation = window.orientation; this.watchVisibility(); }; /** * updateItemState * @desc Update information about current state of items (visibile, hidden, active, etc.) * @since 2.0.0 */ Owl.prototype.updateItemState = function(update){ if(!this.state.lazyContent){ this.updateActiveItems(); } else { this.updateLazyContent(update); } if(this.options.center){ this.dom.$items.eq(this.pos.currentAbs) .addClass(this.options.centerClass) .data('owl-item').center = true; } if(this.options.lazyLoad){ this.lazyLoad(); } }; /** * updateActiveItems * @since 2.0.0 */ Owl.prototype.updateActiveItems = function(){ var i,j,item,ipos,iwidth,wpos,stage,outsideView,foundCurrent; // clear states for(i = 0; i<this.num.items; i++){ this.dom.$items.eq(i).data('owl-item').active = false; this.dom.$items.eq(i).data('owl-item').current = false; this.dom.$items.eq(i).removeClass(this.options.activeClass).removeClass(this.options.centerClass); } this.num.active = 0; stageX = this.pos.stage; view = this.options.rtl ? this.width.view : -this.width.view; for(j = 0; j<this.num.items; j++){ item = this.dom.$items.eq(j); ipos = item.data('owl-item').posLeft; iwidth = item.data('owl-item').width; outsideView = this.options.rtl ? ipos + iwidth : ipos - iwidth; if( (this.op(ipos,'<=',stageX) && (this.op(ipos,'>',stageX + view))) || (this.op(outsideView,'<',stageX) && this.op(outsideView,'>',stageX + view)) ){ this.num.active++; if(this.options.freeDrag && !foundCurrent){ foundCurrent = true; this.pos.current = item.data('owl-item').index; this.pos.currentAbs = item.data('owl-item').indexAbs; } item.data('owl-item').active = true; item.data('owl-item').current = true; item.addClass(this.options.activeClass); if(!this.options.lazyLoad){ item.data('owl-item').loaded = true; } if(this.options.loop && (this.options.lazyLoad || this.options.center)){ this.updateClonedItemsState(item.data('owl-item').index); } } } }; /** * updateClonedItemsState * @desc Set current state on sibilings items for lazyLoad and center * @since 2.0.0 */ Owl.prototype.updateClonedItemsState = function(activeIndex){ //find cloned center var center, $el,i; if(this.options.center){ center = this.dom.$items.eq(this.pos.currentAbs).data('owl-item').index; } for(i = 0; i<this.num.items; i++){ $el = this.dom.$items.eq(i); if( $el.data('owl-item').index === activeIndex ){ $el.data('owl-item').current = true; if($el.data('owl-item').index === center ){ $el.addClass(this.options.centerClass); } } } }; /** * updateLazyPosition * @desc Set current state on sibilings items for lazyLoad and center * @since 2.0.0 */ Owl.prototype.updateLazyPosition = function(){ var jumpTo = this.pos.goToLazyContent || 0; this.pos.lcMovedBy = Math.abs(this.options.items - this.pos.currentAbs); if(this.options.items < this.pos.currentAbs ){ this.pos.lcCurrent += this.pos.currentAbs - this.options.items; this.state.lcDirection = 'right'; } else if(this.options.items > this.pos.currentAbs ){ this.pos.lcCurrent -= this.options.items - this.pos.currentAbs; this.state.lcDirection = 'left'; } this.pos.lcCurrent = jumpTo !== 0 ? jumpTo : this.pos.lcCurrent; if(this.pos.lcCurrent >= this.dom.$content.length){ this.pos.lcCurrent = this.pos.lcCurrent-this.dom.$content.length; } else if(this.pos.lcCurrent < -this.dom.$content.length+1){ this.pos.lcCurrent = this.pos.lcCurrent+this.dom.$content.length; } if(this.options.startPosition>0){ this.pos.lcCurrent = this.options.startPosition; this._options.startPosition = this.options.startPosition = 0; } this.pos.lcCurrentAbs = this.pos.lcCurrent < 0 ? this.pos.lcCurrent+this.dom.$content.length : this.pos.lcCurrent; }; /** * updateLazyContent * @param [update] - boolean - update call by content manipulations * @since 2.0.0 */ Owl.prototype.updateLazyContent = function(update){ if(this.pos.lcCurrent === undefined){ this.pos.lcCurrent = 0; this.pos.current = this.pos.currentAbs = this.options.items; } if(!update){ this.updateLazyPosition(); } var i,j,item,contentPos,content,freshItem,freshData; if(this.state.lcDirection !== false){ for(i = 0; i<this.pos.lcMovedBy; i++){ if(this.state.lcDirection === 'right'){ item = this.dom.$stage.find('.owl-item').eq(0); //.appendTo(this.dom.$stage); item.appendTo(this.dom.$stage); } if(this.state.lcDirection === 'left'){ item = this.dom.$stage.find('.owl-item').eq(-1); item.prependTo(this.dom.$stage); } item.data('owl-item').active = false; } } // recollect this.dom.$items = this.dom.$stage.find('.owl-item'); for(j = 0; j<this.num.items; j++){ // to do this.dom.$items.eq(j).removeClass(this.options.centerClass); // get Content contentPos = this.pos.lcCurrent + j - this.options.items;// + this.options.startPosition; if(contentPos >= this.dom.$content.length){ contentPos = contentPos - this.dom.$content.length; } if(contentPos < -this.dom.$content.length){ contentPos = contentPos + this.dom.$content.length; } content = this.dom.$content.eq(contentPos); freshItem = this.dom.$items.eq(j); freshData = freshItem.data('owl-item'); if(freshData.active === false || this.pos.goToLazyContent !== 0 || update === true){ freshItem.empty(); freshItem.append(content.clone(true,true)); freshData.active = true; freshData.current = true; if(!this.options.lazyLoad){ freshData.loaded = true; } else { freshData.loaded = false; } } } this.pos.goToLazyContent = 0; this.pos.current = this.pos.currentAbs = this.options.items; this.setSpeed(0); this.animStage(this.pos.items[this.options.items]); }; /** * eventsCall * @desc Save internal event references and add event based functions like transitionEnd,responsive etc. * @since 2.0.0 */ Owl.prototype.eventsCall = function(){ // Save events references this.e._onDragStart = function(e){this.onDragStart(e); }.bind(this); this.e._onDragMove = function(e){this.onDragMove(e); }.bind(this); this.e._onDragEnd = function(e){this.onDragEnd(e); }.bind(this); this.e._transitionEnd = function(e){this.transitionEnd(e); }.bind(this); this.e._resizer = function(){this.responsiveTimer(); }.bind(this); this.e._responsiveCall =function(){this.responsive(); }.bind(this); this.e._preventClick = function(e){this.preventClick(e); }.bind(this); this.e._goToHash = function(){this.goToHash(); }.bind(this); this.e._goToPage = function(e){this.goToPage(e); }.bind(this); this.e._ap = function(){this.autoplay(); }.bind(this); this.e._play = function(){this.play(); }.bind(this); this.e._pause = function(){this.pause(); }.bind(this); this.e._playVideo = function(e){this.playVideo(e); }.bind(this); this.e._navNext = function(e){ if($(e.target).hasClass('disabled')){return false;} e.preventDefault(); this.next(); }.bind(this); this.e._navPrev = function(e){ if($(e.target).hasClass('disabled')){return false;} e.preventDefault(); this.prev(); }.bind(this); }; /** * responsiveTimer * @desc Check Window resize event with 200ms delay / this.options.responsiveRefreshRate * @since 2.0.0 */ Owl.prototype.responsiveTimer = function(){ if(this.windowWidth() === this.width.prevWindow){ return false; } window.clearInterval(this.e._autoplay); window.clearTimeout(this.resizeTimer); this.resizeTimer = window.setTimeout(this.e._responsiveCall, this.options.responsiveRefreshRate); this.width.prevWindow = this.windowWidth(); }; /** * internalEvents * @desc Checks for touch/mouse drag options and add necessery event handlers. * @since 2.0.0 */ Owl.prototype.internalEvents = function(){ var isTouch = isTouchSupport(); var isTouchIE = isTouchSupportIE(); if(isTouch && !isTouchIE){ this.dragType = ['touchstart','touchmove','touchend','touchcancel']; } else if(isTouch && isTouchIE){ this.dragType = ['MSPointerDown','MSPointerMove','MSPointerUp','MSPointerCancel']; } else { this.dragType = ['mousedown','mousemove','mouseup']; } if( (isTouch || isTouchIE) && this.options.touchDrag){ //touch cancel event this.on(document, this.dragType[3], this.e._onDragEnd); } else { // firefox startdrag fix - addeventlistener doesnt work here :/ this.dom.$stage.on('dragstart', function() {return false;}); if(this.options.mouseDrag){ //disable text select this.dom.stage.onselectstart = function(){return false;}; } else { // enable text select this.dom.$el.addClass('owl-text-select-on'); } } // Video Play Button event delegation this.dom.$stage.on(this.dragType[2], '.owl-video-play-icon', this.e._playVideo); if(this.options.URLhashListener){ this.on(window, 'hashchange', this.e._goToHash, false); } if(this.options.autoplayHoverPause){ var that = this; this.dom.$stage.on('mouseover', this.e._pause ); this.dom.$stage.on('mouseleave', this.e._ap ); } // Catch transitionEnd event if(this.transitionEndVendor){ this.on(this.dom.stage, this.transitionEndVendor, this.e._transitionEnd, false); } // Responsive if(this.options.responsive !== false){ this.on(window, 'resize', this.e._resizer, false); } this.updateEvents(); }; /** * updateEvents * @since 2.0.0 */ Owl.prototype.updateEvents = function(){ if(this.options.touchDrag && (this.dragType[0] === 'touchstart' || this.dragType[0] === 'MSPointerDown')){ this.on(this.dom.stage, this.dragType[0], this.e._onDragStart,false); } else if(this.options.mouseDrag && this.dragType[0] === 'mousedown'){ this.on(this.dom.stage, this.dragType[0], this.e._onDragStart,false); } else { this.off(this.dom.stage, this.dragType[0], this.e._onDragStart); } }; /** * onDragStart * @desc touchstart/mousedown event * @since 2.0.0 */ Owl.prototype.onDragStart = function(event){ var ev = event.originalEvent || event || window.event; // prevent right click if (ev.which === 3) { return false; } if(this.dragType[0] === 'mousedown'){ this.dom.$stage.addClass('owl-grab'); } this.fireCallback('onTouchStart'); this.drag.startTime = new Date().getTime(); this.setSpeed(0); this.state.isTouch = true; this.state.isScrolling = false; this.state.isSwiping = false; this.drag.distance = 0; // if is 'touchstart' var isTouchEvent = ev.type === 'touchstart'; var pageX = isTouchEvent ? event.targetTouches[0].pageX : (ev.pageX || ev.clientX); var pageY = isTouchEvent ? event.targetTouches[0].pageY : (ev.pageY || ev.clientY); //get stage position left this.drag.offsetX = this.dom.$stage.position().left - this.options.stagePadding; this.drag.offsetY = this.dom.$stage.position().top; if(this.options.rtl){ this.drag.offsetX = this.dom.$stage.position().left + this.width.stage - this.width.el + this.options.margin; } //catch position // ie to fix if(this.state.inMotion && this.support3d){ var animatedPos = this.getTransformProperty(); this.drag.offsetX = animatedPos; this.animStage(animatedPos); } else if(this.state.inMotion && !this.support3d ){ this.state.inMotion = false; return false; } this.drag.startX = pageX - this.drag.offsetX; this.drag.startY = pageY - this.drag.offsetY; this.drag.start = pageX - this.drag.startX; this.drag.targetEl = ev.target || ev.srcElement; this.drag.updatedX = this.drag.start; // to do/check //prevent links and images dragging; //this.drag.targetEl.draggable = false; this.on(document, this.dragType[1], this.e._onDragMove, false); this.on(document, this.dragType[2], this.e._onDragEnd, false); }; /** * onDragMove * @desc touchmove/mousemove event * @since 2.0.0 */ Owl.prototype.onDragMove = function(event){ if (!this.state.isTouch){ return; } if (this.state.isScrolling){ return; } var neighbourItemWidth=0; var ev = event.originalEvent || event || window.event; // if is 'touchstart' var isTouchEvent = ev.type == 'touchmove'; var pageX = isTouchEvent ? ev.targetTouches[0].pageX : (ev.pageX || ev.clientX); var pageY = isTouchEvent ? ev.targetTouches[0].pageY : (ev.pageY || ev.clientY); // Drag Direction this.drag.currentX = pageX - this.drag.startX; this.drag.currentY = pageY - this.drag.startY; this.drag.distance = this.drag.currentX - this.drag.offsetX; // Check move direction if (this.drag.distance < 0) { this.state.direction = this.options.rtl ? 'right' : 'left'; } else if(this.drag.distance > 0){ this.state.direction = this.options.rtl ? 'left' : 'right'; } // Loop if(this.options.loop){ if(this.op(this.drag.currentX, '>', this.pos.minValue) && this.state.direction === 'right' ){ this.drag.currentX -= this.pos.loop; }else if(this.op(this.drag.currentX, '<', this.pos.maxValue) && this.state.direction === 'left' ){ this.drag.currentX += this.pos.loop; } } else { // pull var minValue = this.options.rtl ? this.pos.maxValue : this.pos.minValue; var maxValue = this.options.rtl ? this.pos.minValue : this.pos.maxValue; var pull = this.options.pullDrag ? this.drag.distance / 5 : 0; this.drag.currentX = Math.max(Math.min(this.drag.currentX, minValue + pull), maxValue + pull); } // Lock browser if swiping horizontal if ((this.drag.distance > 8 || this.drag.distance < -8)) { if (ev.preventDefault !== undefined) { ev.preventDefault(); } else { ev.returnValue = false; } this.state.isSwiping = true; } this.drag.updatedX = this.drag.currentX; // Lock Owl if scrolling if ((this.drag.currentY > 16 || this.drag.currentY < -16) && this.state.isSwiping === false) { this.state.isScrolling = true; this.drag.updatedX = this.drag.start; } this.animStage(this.drag.updatedX); }; /** * onDragEnd * @desc touchend/mouseup event * @since 2.0.0 */ Owl.prototype.onDragEnd = function(event){ if (!this.state.isTouch){ return; } if(this.dragType[0] === 'mousedown'){ this.dom.$stage.removeClass('owl-grab'); } this.fireCallback('onTouchEnd'); //prevent links and images dragging; //this.drag.targetEl.draggable = true; //remove drag event listeners this.state.isTouch = false; this.state.isScrolling = false; this.state.isSwiping = false; //to check if(this.drag.distance === 0 && this.state.inMotion !== true){ this.state.inMotion = false; return false; } // prevent clicks while scrolling this.drag.endTime = new Date().getTime(); var compareTimes = this.drag.endTime - this.drag.startTime; var distanceAbs = Math.abs(this.drag.distance); //to test if(distanceAbs > 3 || compareTimes > 300){ this.removeClick(this.drag.targetEl); } var closest = this.closest(this.drag.updatedX); this.setSpeed(this.options.dragEndSpeed, false, true); this.animStage(this.pos.items[closest]); //if pullDrag is off then fire transitionEnd event manually when stick to border if(!this.options.pullDrag && this.drag.updatedX === this.pos.items[closest]){ this.transitionEnd(); } this.drag.distance = 0; this.off(document, this.dragType[1], this.e._onDragMove); this.off(document, this.dragType[2], this.e._onDragEnd); }; /** * removeClick * @desc Attach preventClick function to disable link while swipping * @since 2.0.0 * @param [target] - clicked dom element */ Owl.prototype.removeClick = function(target){ this.drag.targetEl = target; this.on(target,'click', this.e._preventClick, false); }; /** * preventClick * @desc Add preventDefault for any link and then remove removeClick event hanlder * @since 2.0.0 */ Owl.prototype.preventClick = function(ev){ if(ev.preventDefault) { ev.preventDefault(); }else { ev.returnValue = false; } if(ev.stopPropagation){ ev.stopPropagation(); } this.off(this.drag.targetEl,'click',this.e._preventClick,false); }; /** * getTransformProperty * @desc catch stage position while animate (only css3) * @since 2.0.0 */ Owl.prototype.getTransformProperty = function(){ var transform = window.getComputedStyle(this.dom.stage, null).getPropertyValue(this.vendorName + 'transform'); //var transform = this.dom.$stage.css(this.vendorName + 'transform') transform = transform.replace(/matrix(3d)?\(|\)/g, '').split(','); var matrix3d = transform.length === 16; return matrix3d !== true ? transform[4] : transform[12]; }; /** * closest * @desc Get closest item after touchend/mouseup * @since 2.0.0 * @param [x] - curent position in pixels * return position in pixels */ Owl.prototype.closest = function(x){ var newX = 0, pull = 30; if(!this.options.freeDrag){ // Check closest item for(var i = 0; i< this.num.items; i++){ if(x > this.pos.items[i]-pull && x < this.pos.items[i]+pull){ newX = i; }else if(this.op(x,'<',this.pos.items[i]) && this.op(x,'>',this.pos.items[i+1 || this.pos.items[i] - this.width.el]) ){ newX = this.state.direction === 'left' ? i+1 : i; } } } //non loop boundries if(!this.options.loop){ if(this.op(x,'>',this.pos.minValue)){ newX = x = this.pos.min; } else if(this.op(x,'<',this.pos.maxValue)){ newX = x = this.pos.max; } } if(!this.options.freeDrag){ // set positions this.pos.currentAbs = newX; this.pos.current = this.dom.$items.eq(newX).data('owl-item').index; } else { this.updateItemState(); return x; } return newX; }; /** * animStage * @desc animate stage position (both css3/css2) and perform onChange functions/events * @since 2.0.0 * @param [x] - curent position in pixels */ Owl.prototype.animStage = function(pos){ // if speed is 0 the set inMotion to false if(this.speed.current !== 0 && this.pos.currentAbs !== this.pos.min){ this.fireCallback('onTransitionStart'); this.state.inMotion = true; } var posX = this.pos.stage = pos, style = this.dom.stage.style; if(this.support3d){ translate = 'translate3d(' + posX + 'px'+',0px, 0px)'; style[this.transformVendor] = translate; } else if(this.state.isTouch){ style.left = posX+'px'; } else { this.dom.$stage.animate({left: posX},this.speed.css2speed, this.options.fallbackEasing, function(){ if(this.state.inMotion){ this.transitionEnd(); } }.bind(this)); } this.onChange(); }; /** * updatePosition * @desc Update current positions * @since 2.0.0 * @param [pos] - number - new position */ Owl.prototype.updatePosition = function(pos){ // if no items then stop if(this.num.oItems === 0){return false;} // to do //if(pos > this.num.items){pos = 0;} if(pos === undefined){return false;} //pos - new current position var nextPos = pos; this.pos.prev = this.pos.currentAbs; if(this.state.revert){ this.pos.current = this.dom.$items.eq(nextPos).data('owl-item').index; this.pos.currentAbs = nextPos; return; } if(!this.options.loop){ if(this.options.navRewind){ nextPos = nextPos > this.pos.max ? this.pos.min : (nextPos < 0 ? this.pos.max : nextPos); } else { nextPos = nextPos > this.pos.max ? this.pos.max : (nextPos <= 0 ? 0 : nextPos); } } else { nextPos = nextPos >= this.num.oItems ? this.num.oItems-1 : nextPos; } this.pos.current = this.dom.$oItems.eq(nextPos).data('owl-item').index; this.pos.currentAbs = this.dom.$oItems.eq(nextPos).data('owl-item').indexAbs; }; /** * setSpeed * @since 2.0.0 * @param [speed] - number * @param [pos] - number - next position - use this param to calculate smartSpeed * @param [drag] - boolean - if drag is true then smart speed is disabled * return speed */ Owl.prototype.setSpeed = function(speed,pos,drag) { var s = speed, nextPos = pos; if((s === false && s !== 0 && drag !== true) || s === undefined){ //Double check this // var nextPx = this.pos.items[nextPos]; // var currPx = this.pos.stage // var diff = Math.abs(nextPx-currPx); // var s = diff/1 // if(s>1000){ // s = 1000; // } var diff = Math.abs(nextPos - this.pos.prev); diff = diff === 0 ? 1 : diff; if(diff>6){diff = 6;} s = diff * this.options.smartSpeed; } if(s === false && drag === true){ s = this.options.smartSpeed; } if(s === 0){s=0;} if(this.support3d){ var style = this.dom.stage.style; style.webkitTransitionDuration = style.MsTransitionDuration = style.msTransitionDuration = style.MozTransitionDuration = style.OTransitionDuration = style.transitionDuration = (s / 1000) + 's'; } else{ this.speed.css2speed = s; } this.speed.current = s; return s; }; /** * jumpTo * @since 2.0.0 * @param [pos] - number - next position - use this param to calculate smartSpeed * @param [update] - boolean - if drag is true then smart speed is disabled */ Owl.prototype.jumpTo = function(pos,update){ if(this.state.lazyContent){ this.pos.goToLazyContent = pos; } this.updatePosition(pos); this.setSpeed(0); this.animStage(this.pos.items[this.pos.currentAbs]); if(update !== true){ this.updateItemState(); } }; /** * goTo * @since 2.0.0 * @param [pos] - number * @param [speed] - speed in ms * @param [speed] - speed in ms */ Owl.prototype.goTo = function(pos,speed){ if(this.state.lazyContent && this.state.inMotion){ return false; } this.updatePosition(pos); if(this.state.animate){speed = 0;} this.setSpeed(speed,this.pos.currentAbs); if(this.state.animate){this.animate();} this.animStage(this.pos.items[this.pos.currentAbs]); }; /** * next * @since 2.0.0 */ Owl.prototype.next = function(optionalSpeed){ var s = optionalSpeed || this.options.navSpeed; if(this.options.loop && !this.state.lazyContent){ this.goToLoop(this.options.slideBy, s); }else{ this.goTo(this.pos.current + this.options.slideBy, s); } }; /** * prev * @since 2.0.0 */ Owl.prototype.prev = function(optionalSpeed){ var s = optionalSpeed || this.options.navSpeed; if(this.options.loop && !this.state.lazyContent){ this.goToLoop(-this.options.slideBy, s); }else{ this.goTo(this.pos.current-this.options.slideBy, s); } }; /** * goToLoop * @desc Go to given position if loop is enabled - used only internal * @since 2.0.0 * @param [distance] - number -how far to go * @param [speed] - number - speed in ms */ Owl.prototype.goToLoop = function(distance,speed){ var revert = this.pos.currentAbs, prevPosition = this.pos.currentAbs, newPosition = this.pos.currentAbs + distance, direction = prevPosition - newPosition < 0 ? true : false; this.state.revert = true; if(newPosition < 1 && direction === false){ this.state.bypass = true; revert = this.num.items - (this.options.items-prevPosition) - this.options.items; this.jumpTo(revert,true); } else if(newPosition >= this.num.items - this.options.items && direction === true ){ this.state.bypass = true; revert = prevPosition - this.num.oItems; this.jumpTo(revert,true); } window.clearTimeout(this.e._goToLoop); this.e._goToLoop = window.setTimeout(function(){ this.state.bypass = false; this.goTo(revert + distance, speed); this.state.revert = false; }.bind(this), 30); }; /** * initPosition * @since 2.0.0 */ Owl.prototype.initPosition = function(init){ if( !this.dom.$oItems || !init || this.state.lazyContent ){return false;} var pos = this.options.startPosition; if(this.options.startPosition === 'URLHash'){ pos = this.options.startPosition = this.hashPosition(); } else if(typeof this.options.startPosition !== Number && !this.options.center){ this.options.startPosition = 0; } this.dom.oStage.scrollLeft = 0; this.jumpTo(pos,true); }; /** * goToHash * @since 2.0.0 */ Owl.prototype.goToHash = function(){ var pos = this.hashPosition(); if(pos === false){ pos = 0; } this.dom.oStage.scrollLeft = 0; this.goTo(pos,this.options.navSpeed); }; /** * hashPosition * @desc Find hash in URL then look into items to find contained ID * @since 2.0.0 * return hashPos - number of item */ Owl.prototype.hashPosition = function(){ var hash = window.location.hash.substring(1), hashPos; if(hash === ""){return false;} for(var i=0;i<this.num.oItems; i++){ if(hash === this.dom.$oItems.eq(i).data('owl-item').hash){ hashPos = i; } } return hashPos; }; /** * Autoplay * @since 2.0.0 */ Owl.prototype.autoplay = function(){ if(this.options.autoplay && !this.state.videoPlay){ window.clearInterval(this.e._autoplay); this.e._autoplay = window.setInterval(this.e._play, this.options.autoplayTimeout); } else { window.clearInterval(this.e._autoplay); this.state.autoplay=false; } }; /** * play * @param [timeout] - Integrer * @param [speed] - Integrer * @since 2.0.0 */ Owl.prototype.play = function(timeout, speed){ // if tab is inactive - doesnt work in <IE10 if(document.hidden === true){return false;} // overwrite default options (custom options are always priority) if(!this.options.autoplay){ this._options.autoplay = this.options.autoplay = true; this._options.autoplayTimeout = this.options.autoplayTimeout = timeout || this.options.autoplayTimeout || 4000; this._options.autoplaySpeed = speed || this.options.autoplaySpeed; } if(this.options.autoplay === false || this.state.isTouch || this.state.isScrolling || this.state.isSwiping || this.state.inMotion){ window.clearInterval(this.e._autoplay); return false; } if(!this.options.loop && this.pos.current >= this.pos.max){ window.clearInterval(this.e._autoplay); this.goTo(0); } else { this.next(this.options.autoplaySpeed); } this.state.autoplay=true; }; /** * stop * @since 2.0.0 */ Owl.prototype.stop = function(){ this._options.autoplay = this.options.autoplay = false; this.state.autoplay = false; window.clearInterval(this.e._autoplay); }; Owl.prototype.pause = function(){ window.clearInterval(this.e._autoplay); }; /** * transitionEnd * @desc event used by css3 animation end and $.animate callback like transitionEnd,responsive etc. * @since 2.0.0 */ Owl.prototype.transitionEnd = function(event){ // if css2 animation then event object is undefined if(event !== undefined){ event.stopPropagation(); // Catch only owl-stage transitionEnd event var eventTarget = event.target || event.srcElement || event.originalTarget; if(eventTarget !== this.dom.stage){ return false; } } this.state.inMotion = false; this.updateItemState(); this.autoplay(); this.fireCallback('onTransitionEnd'); }; /** * isElWidthChanged * @desc Check if element width has changed * @since 2.0.0 */ Owl.prototype.isElWidthChanged = function(){ var newElWidth = this.dom.$el.width() - this.options.stagePadding,//to check prevElWidth = this.width.el + this.options.margin; return newElWidth !== prevElWidth; }; /** * windowWidth * @desc Get Window/responsiveBaseElement width * @since 2.0.0 */ Owl.prototype.windowWidth = function() { if(this.options.responsiveBaseElement !== window){ this.width.window = $(this.options.responsiveBaseElement).width(); } else if (window.innerWidth){ this.width.window = window.innerWidth; } else if (document.documentElement && document.documentElement.clientWidth){ this.width.window = document.documentElement.clientWidth; } return this.width.window; }; /** * Controls * @desc Calls controls container, navigation and dots creator * @since 2.0.0 */ Owl.prototype.controls = function(){ var cc = document.createElement('div'); cc.className = this.options.controlsClass; this.dom.$el.append(cc); this.dom.$cc = $(cc); }; /** * updateControls * @since 2.0.0 */ Owl.prototype.updateControls = function(){ if(this.dom.$cc === null && (this.options.nav || this.options.dots)){ this.controls(); } if(this.dom.$nav === null && this.options.nav){ this.createNavigation(this.dom.$cc[0]); } if(this.dom.$page === null && this.options.dots){ this.createDots(this.dom.$cc[0]); } if(this.dom.$nav !== null){ if(this.options.nav){ this.dom.$nav.show(); this.updateNavigation(); } else { this.dom.$nav.hide(); } } if(this.dom.$page !== null){ if(this.options.dots){ this.dom.$page.show(); this.updateDots(); } else { this.dom.$page.hide(); } } }; /** * createNavigation * @since 2.0.0 * @param [cc] - dom element - Controls Container */ Owl.prototype.createNavigation = function(cc){ // Create nav container var nav = document.createElement('div'); nav.className = this.options.navContainerClass; cc.appendChild(nav); // Create left and right buttons var navPrev = document.createElement('div'), navNext = document.createElement('div'); navPrev.className = this.options.navClass[0]; navNext.className = this.options.navClass[1]; nav.appendChild(navPrev); nav.appendChild(navNext); this.dom.$nav = $(nav); this.dom.$navPrev = $(navPrev).html(this.options.navText[0]); this.dom.$navNext = $(navNext).html(this.options.navText[1]); // add events to do //this.on(navPrev, this.dragType[2], this.e._navPrev, false); //this.on(navNext, this.dragType[2], this.e._navNext, false); //FF fix? this.dom.$nav.on(this.dragType[2], '.'+this.options.navClass[0], this.e._navPrev); this.dom.$nav.on(this.dragType[2], '.'+this.options.navClass[1], this.e._navNext); }; /** * createNavigation * @since 2.0.0 * @param [cc] - dom element - Controls Container */ Owl.prototype.createDots = function(cc){ // Create dots container var page = document.createElement('div'); page.className = this.options.dotsClass; cc.appendChild(page); // save reference this.dom.$page = $(page); // add events //this.on(page, this.dragType[2], this.e._goToPage, false); // FF fix? To test! var that = this; this.dom.$page.on(this.dragType[2], '.'+this.options.dotClass, goToPage); function goToPage(e){ e.preventDefault(); var page = $(this).data('page'); that.goTo(page,that.options.dotsSpeed); } // build dots this.rebuildDots(); }; /** * goToPage * @desc Event used by dots * @since 2.0.0 */ // Owl.prototype.goToPage = function(e){ // console.log(e.taget); // var page = $(e.currentTarget).data('page') // this.goTo(page,this.options.dotsSpeed); // return false; // }; /** * rebuildDots * @since 2.0.0 */ Owl.prototype.rebuildDots = function(){ if(this.dom.$page === null){return false;} var each, dot, span, counter = 0, last = 0, i, page=0, roundPages = 0; each = this.options.dotsEach || this.options.items; // display full dots if center if(this.options.center || this.options.dotData){ each = 1; } // clear dots this.dom.$page.html(''); for(i = 0; i < this.num.nav.length; i++){ if(counter >= each || counter === 0){ dot = document.createElement('div'); dot.className = this.options.dotClass; span = document.createElement('span'); dot.appendChild(span); var $dot = $(dot); if(this.options.dotData){ $dot.html(this.dom.$oItems.eq(i).data('owl-item').dot); } $dot.data('page',page); $dot.data('goToPage',roundPages); this.dom.$page.append(dot); counter = 0; roundPages++; } this.dom.$oItems.eq(i).data('owl-item').page = roundPages-1; //add merged items counter += this.num.nav[i]; page++; } // find rest of dots if(!this.options.loop && !this.options.center){ for(var j = this.num.nav.length-1; j >= 0; j--){ last += this.num.nav[j]; this.dom.$oItems.eq(j).data('owl-item').page = roundPages-1; if(last >= each){ break; } } } this.num.allPages = roundPages-1; }; /** * updateDots * @since 2.0.0 */ Owl.prototype.updateDots = function(){ var dots = this.dom.$page.children(); var itemIndex = this.dom.$oItems.eq(this.pos.current).data('owl-item').page; for(var i = 0; i < dots.length; i++){ var dotPage = dots.eq(i).data('goToPage'); if(dotPage===itemIndex){ this.pos.currentPage = i; dots.eq(i).addClass('active'); }else{ dots.eq(i).removeClass('active'); } } }; /** * updateNavigation * @since 2.0.0 */ Owl.prototype.updateNavigation = function(){ var isNav = this.options.nav; this.dom.$navNext.toggleClass('disabled',!isNav); this.dom.$navPrev.toggleClass('disabled',!isNav); if(!this.options.loop && isNav && !this.options.navRewind){ if(this.pos.current <= 0){ this.dom.$navPrev.addClass('disabled'); } if(this.pos.current >= this.pos.max){ this.dom.$navNext.addClass('disabled'); } } }; Owl.prototype.insertContent = function(content){ this.dom.$stage.empty(); this.fetchContent(content); this.refresh(); }; /** * addItem - Add an item * @since 2.0.0 * @param [content] - dom element / string '<div>content</div>' * @param [pos] - number - position */ Owl.prototype.addItem = function(content,pos){ pos = pos || 0; if(this.state.lazyContent){ this.dom.$content = this.dom.$content.add($(content)); this.updateItemState(true); } else { // wrap content var item = this.fillItem(content); // if carousel is empty then append item if(this.dom.$oItems.length === 0){ this.dom.$stage.append(item); } else { // append item var it = this.dom.$oItems.eq(pos); if(pos !== -1){it.before(item);} else {it.after(item);} } // update and calculate carousel this.refresh(); } }; /** * removeItem - Remove an Item * @since 2.0.0 * @param [pos] - number - position */ Owl.prototype.removeItem = function(pos){ if(this.state.lazyContent){ this.dom.$content.splice(pos,1); this.updateItemState(true); } else { this.dom.$oItems.eq(pos).remove(); this.refresh(); } }; /** * addCustomEvents * @desc Add custom events by jQuery .on method * @since 2.0.0 */ Owl.prototype.addCustomEvents = function(){ this.e.next = function(e,s){this.next(s); }.bind(this); this.e.prev = function(e,s){this.prev(s); }.bind(this); this.e.goTo = function(e,p,s){this.goTo(p,s); }.bind(this); this.e.jumpTo = function(e,p){this.jumpTo(p); }.bind(this); this.e.addItem = function(e,c,p){this.addItem(c,p); }.bind(this); this.e.removeItem = function(e,p){this.removeItem(p);}.bind(this); this.e.refresh = function(e){this.refresh(); }.bind(this); this.e.destroy = function(e){this.destroy(); }.bind(this); this.e.autoHeight = function(e){this.autoHeight(true);}.bind(this); this.e.stop = function(){this.stop(); }.bind(this); this.e.play = function(e,t,s){this.play(t,s); }.bind(this); this.e.insertContent = function(e,d){this.insertContent(d); }.bind(this); this.dom.$el.on('next.owl',this.e.next); this.dom.$el.on('prev.owl',this.e.prev); this.dom.$el.on('goTo.owl',this.e.goTo); this.dom.$el.on('jumpTo.owl',this.e.jumpTo); this.dom.$el.on('addItem.owl',this.e.addItem); this.dom.$el.on('removeItem.owl',this.e.removeItem); this.dom.$el.on('destroy.owl',this.e.destroy); this.dom.$el.on('refresh.owl',this.e.refresh); this.dom.$el.on('autoHeight.owl',this.e.autoHeight); this.dom.$el.on('play.owl',this.e.play); this.dom.$el.on('stop.owl',this.e.stop); this.dom.$el.on('stopVideo.owl',this.e.stop); this.dom.$el.on('insertContent.owl',this.e.insertContent); }; /** * on * @desc On method for adding internal events * @since 2.0.0 */ Owl.prototype.on = function (element, event, listener, capture) { if (element.addEventListener) { element.addEventListener(event, listener, capture); } else if (element.attachEvent) { element.attachEvent('on' + event, listener); } }; /** * off * @desc Off method for removing internal events * @since 2.0.0 */ Owl.prototype.off = function (element, event, listener, capture) { if (element.removeEventListener) { element.removeEventListener(event, listener, capture); } else if (element.detachEvent) { element.detachEvent('on' + event, listener); } }; /** * fireCallback * @since 2.0.0 * @param event - string - event name * @param data - object - additional options - to do */ Owl.prototype.fireCallback = function(event, data){ if(!this.options.callbacks){return;} if(this.dom.el.dispatchEvent){ // dispatch event var evt = document.createEvent('CustomEvent'); //evt.initEvent(event, false, true ); evt.initCustomEvent(event, true, true, data); return this.dom.el.dispatchEvent(evt); } else if (!this.dom.el.dispatchEvent){ // There is no clean solution for custom events name in <=IE8 // But if you know better way, please let me know :) return this.dom.$el.trigger(event); } }; /** * watchVisibility * @desc check if el is visible - handy if Owl is inside hidden content (tabs etc.) * @since 2.0.0 */ Owl.prototype.watchVisibility = function(){ // test on zepto if(!isElVisible(this.dom.el)) { this.dom.$el.addClass('owl-hidden'); window.clearInterval(this.e._checkVisibile); this.e._checkVisibile = window.setInterval(checkVisible.bind(this),500); } function isElVisible(el) { return el.offsetWidth > 0 && el.offsetHeight > 0; } function checkVisible(){ if (isElVisible(this.dom.el)) { this.dom.$el.removeClass('owl-hidden'); this.refresh(); window.clearInterval(this.e._checkVisibile); } } }; /** * onChange * @since 2.0.0 */ Owl.prototype.onChange = function(){ if(!this.state.isTouch && !this.state.bypass && !this.state.responsive ){ if (this.options.nav || this.options.dots) { this.updateControls(); } this.autoHeight(); this.fireCallback('onChangeState'); } if(!this.state.isTouch && !this.state.bypass){ // set Status to do this.storeInfo(); // stopVideo if(this.state.videoPlay){ this.stopVideo(); } } }; /** * storeInfo * store basic information about current states * @since 2.0.0 */ Owl.prototype.storeInfo = function(){ var currentPosition = this.state.lazyContent ? this.pos.lcCurrentAbs || 0 : this.pos.current; var allItems = this.state.lazyContent ? this.dom.$content.length-1 : this.num.oItems; this.info = { items: this.options.items, allItems: allItems, currentPosition:currentPosition, currentPage: this.pos.currentPage, allPages: this.num.allPages, autoplay: this.state.autoplay, windowWidth: this.width.window, elWidth: this.width.el, breakpoint: this.num.breakpoint }; if (typeof this.options.info === 'function') { this.options.info.apply(this,[this.info,this.dom.el]); } }; /** * autoHeight * @since 2.0.0 */ Owl.prototype.autoHeight = function(callback){ if(this.options.autoHeight !== true && callback !== true){ return false; } if(!this.dom.$oStage.hasClass(this.options.autoHeightClass)){ this.dom.$oStage.addClass(this.options.autoHeightClass); } var loaded = this.dom.$items.eq(this.pos.currentAbs); var stage = this.dom.$oStage; var iterations = 0; var isLoaded = window.setInterval(function() { iterations += 1; if(loaded.data('owl-item').loaded){ stage.height(loaded.height() + 'px'); clearInterval(isLoaded); } else if(iterations === 500){ clearInterval(isLoaded); } }, 100); }; /** * preloadAutoWidthImages * @desc still to test * @since 2.0.0 */ Owl.prototype.preloadAutoWidthImages = function(imgs){ var loaded = 0; var that = this; imgs.each(function(i,el){ var $el = $(el); var img = new Image(); img.onload = function(){ loaded++; $el.attr('src',img.src); $el.css('opacity',1); if(loaded >= imgs.length){ that.state.imagesLoaded = true; that.init(); } } img.src = $el.attr('src') || $el.attr('data-src') || $el.attr('data-src-retina');; }) }; /** * lazyLoad * @desc lazyLoad images * @since 2.0.0 */ Owl.prototype.lazyLoad = function(){ var attr = isRetina() ? 'data-src-retina' : 'data-src'; var src, img,i; for(i = 0; i < this.num.items; i++){ var $item = this.dom.$items.eq(i); if( $item.data('owl-item').current === true && $item.data('owl-item').loaded === false){ img = $item.find('.owl-lazy'); src = img.attr(attr); src = src || img.attr('data-src'); if(src){ img.css('opacity','0'); this.preload(img,$item); } } } }; /** * preload * @since 2.0.0 */ Owl.prototype.preload = function(images,$item){ var that = this; // fix this later images.each(function(i,el){ var $el = $(el); var img = new Image(); img.onload = function(){ $item.data('owl-item').loaded = true; if($el.is('img')){ $el.attr('src',img.src); }else{ $el.css('background-image','url(' + img.src + ')'); } $el.css('opacity',1); that.fireCallback('onLazyLoaded'); }; img.src = $el.attr('data-src') || $el.attr('data-src-retina'); }); }; /** * animate * @since 2.0.0 */ Owl.prototype.animate = function(){ var prevItem = this.dom.$items.eq(this.pos.prev), prevPos = Math.abs(prevItem.data('owl-item').width) * this.pos.prev, currentItem = this.dom.$items.eq(this.pos.currentAbs), currentPos = Math.abs(currentItem.data('owl-item').width) * this.pos.currentAbs; if(this.pos.currentAbs === this.pos.prev){ return false; } var pos = currentPos - prevPos; var tIn = this.options.animateIn; var tOut = this.options.animateOut; var that = this; removeStyles = function(){ $(this).css({ "left" : "" }) .removeClass('animated owl-animated-out owl-animated-in') .removeClass(tIn) .removeClass(tOut); that.transitionEnd(); }; if(tOut){ prevItem .css({ "left" : pos + "px" }) .addClass('animated owl-animated-out '+tOut) .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', removeStyles); } if(tIn){ currentItem .addClass('animated owl-animated-in '+tIn) .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', removeStyles); } }; /** * destroy * @desc Remove Owl structure and events :( * @since 2.0.0 */ Owl.prototype.destroy = function(){ window.clearInterval(this.e._autoplay); if(this.dom.$el.hasClass(this.options.themeClass)){ this.dom.$el.removeClass(this.options.themeClass); } if(this.options.responsive !== false){ this.off(window, 'resize', this.e._resizer); } if(this.transitionEndVendor){ this.off(this.dom.stage, this.transitionEndVendor, this.e._transitionEnd); } if(this.options.mouseDrag || this.options.touchDrag){ this.off(this.dom.stage, this.dragType[0], this.e._onDragStart); if(this.options.mouseDrag){ this.off(document, this.dragType[3], this.e._onDragStart); } if(this.options.mouseDrag){ this.dom.$stage.off('dragstart', function() {return false;}); this.dom.stage.onselectstart = function(){}; } } if(this.options.URLhashListener){ this.off(window, 'hashchange', this.e._goToHash); } this.dom.$el.off('next.owl',this.e.next); this.dom.$el.off('prev.owl',this.e.prev); this.dom.$el.off('goTo.owl',this.e.goTo); this.dom.$el.off('jumpTo.owl',this.e.jumpTo); this.dom.$el.off('addItem.owl',this.e.addItem); this.dom.$el.off('removeItem.owl',this.e.removeItem); this.dom.$el.off('refresh.owl',this.e.refresh); this.dom.$el.off('autoHeight.owl',this.e.autoHeight); this.dom.$el.off('play.owl',this.e.play); this.dom.$el.off('stop.owl',this.e.stop); this.dom.$el.off('stopVideo.owl',this.e.stop); this.dom.$stage.off('click',this.e._playVideo); if(this.dom.$cc !== null){ this.dom.$cc.remove(); } if(this.dom.$cItems !== null){ this.dom.$cItems.remove(); } this.e = null; this.dom.$el.data('owlCarousel',null); delete this.dom.el.owlCarousel; this.dom.$stage.unwrap(); this.dom.$items.unwrap(); this.dom.$items.contents().unwrap(); this.dom = null; }; /** * Opertators * @desc Used to calculate RTL * @param [a] - Number - left side * @param [o] - String - operator * @param [b] - Number - right side * @since 2.0.0 */ Owl.prototype.op = function(a,o,b){ var rtl = this.options.rtl; switch(o) { case '<': return rtl ? a > b : a < b; case '>': return rtl ? a < b : a > b; case '>=': return rtl ? a <= b : a >= b; case '<=': return rtl ? a >= b : a <= b; default: break; } }; /** * Opertators * @desc Used to calculate RTL * @since 2.0.0 */ Owl.prototype.browserSupport = function(){ this.support3d = isPerspective(); if(this.support3d){ this.transformVendor = isTransform(); // take transitionend event name by detecting transition var endVendors = ['transitionend','webkitTransitionEnd','transitionend','oTransitionEnd']; this.transitionEndVendor = endVendors[isTransition()]; // take vendor name from transform name this.vendorName = this.transformVendor.replace(/Transform/i,''); this.vendorName = this.vendorName !== '' ? '-'+this.vendorName.toLowerCase()+'-' : ''; } this.state.orientation = window.orientation; }; // Pivate methods // CSS detection; function isStyleSupported(array){ var p,s,fake = document.createElement('div'),list = array; for(p in list){ s = list[p]; if(typeof fake.style[s] !== 'undefined'){ fake = null; return [s,p]; } } return [false]; } function isTransition(){ return isStyleSupported(['transition','WebkitTransition','MozTransition','OTransition'])[1]; } function isTransform() { return isStyleSupported(['transform','WebkitTransform','MozTransform','OTransform','msTransform'])[0]; } function isPerspective(){ return isStyleSupported(['perspective','webkitPerspective','MozPerspective','OPerspective','MsPerspective'])[0]; } function isTouchSupport(){ return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints); } function isTouchSupportIE(){ return window.navigator.msPointerEnabled; } function isRetina(){ return window.devicePixelRatio > 1; } $.fn.owlCarousel = function ( options ) { return this.each(function () { if (!$(this).data('owlCarousel')) { $(this).data( 'owlCarousel', new Owl( this, options )); } }); }; })( window.Zepto || window.jQuery, window, document ); //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind //The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called. if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; }