Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
save_bvnghean.vn
/
wp-content
/
plugins
/
sneeit-framework
/
js
:
front-carousel.js
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
(function( $ ){ /** * * @param {type} wrapper * @param {type} options * @returns {sneeit-carousel_L6.SneeitCarousel} * * @todo * - cross browser * - bug dots move out of AB after drag * - use refresh rate for responsive to * calculate exactly column and margin */ function SneeitCarousel(ele, opt) { this._ = ele; this.wid = null; this.debug = false; /** * only original items, * before cloning */ this.oItemNum = null; /** * all item, included clones */ this.items = null; this.outer = null; this.stage = null; this.dots = null; this.itemNum = null; this.x = 0; this.xStart = 0; this.xEnd = 0; this.totalDots = 0; /* Javascript float has problem with precision * we will use this to eleminate that precision * The epsilon will never larger than 1/10 pixel */ this.epsilon = 0; /* Reset Distance from xStart to xEnd */ this.resetAB = 0; this.prevColNum = -1; if (typeof(opt) != 'object') { opt = {}; } this.rtl = (this._.css('direction') == 'rtl'); /* * Total original item must be always * larger than column number, * Because if it's lower, so we don't * need to run carousel because * the reader is seeing all items * * It's simple don't make sense */ this.opt = $.extend({}, SneeitCarousel.Defaults, opt); this.colNum = this.opt.columnNumber; this.margin = this.opt.margin; this.wrapperClass = '.' + this.opt.wrapperClass; this.outerClass = '.' + this.opt.outerClass; this.stageClass = '.' + this.opt.stageClass; this.itemClass = '.' + this.opt.itemClass; this.dotsClass = '.' + this.opt.dotsClass; this.dotClass = '.' + this.opt.dotClass; this.navClass = '.' + this.opt.navClass; this.nextClass = '.' + this.opt.nextClass; this.prevClass = '.' + this.opt.prevClass; this.activeClass = '.' + this.opt.activeClass; // validate duration if (isNaN(this.opt.displayDuration)) { this.opt.displayDuration = SneeitCarousel.Defaults.displayDuration; } else { this.opt.displayDuration = Number(this.opt.displayDuration); } if (isNaN(this.opt.animateDuration)) { this.opt.animateDuration = SneeitCarousel.Defaults.animateDuration; } else { this.opt.animateDuration = Number(this.opt.animateDuration); } /* real left */ this.left = this.rtl ? 'right' : 'left'; /* we use LEFT css instead of * margin-left because safari not work */ this.xCSS = this.left; // this.xCSS = 'margin-' + this.left; /* timer for displaying */ this.displaying = null; /* animate */ this.animating = false; /* hover */ this.hover = false; /* drag */ this.drag = false; this.dragging = false; this.init(false); } /** * Default options for the carousel. * @public */ SneeitCarousel.Defaults = { /* number of columns you want to display */ columnNumber: 1, /* item width must be not smaller than * these amount of pixels or we have * to auto decrease column number * good for responsive designs * */ minColumnWidth: 150, /* margin between columns, in pixel */ margin: 20, /* * The PERCENTAGE of margin width related to * wrapper width. The gap will never * larger than this width * * The Unit is PERCENT % */ maxMargin: 6.25, /* How long we will stop to display before animate to * other items. Integer number, unit is millsecond */ displayDuration: 3000, /* How long we will need to animate to * other items. Integer number, unit is millsecond */ animateDuration: 500, /* dots */ dotsClass: 'sneeit-carousel-dots', dotClass: 'sneeit-carousel-dot', dotText: function (args) { return '•' }, /* navigation arrows */ navClass: 'sneeit-carousel-nav', prevClass: 'sneeit-carousel-prev', nextClass: 'sneeit-carousel-next', prevText: function (args) { return '⟨'; }, nextText: function (args) { return '⟩'; }, /* classes */ wrapperClass: 'sneeit-carousel', outerClass: 'sneeit-carousel-outer', stageClass: 'sneeit-carousel-stage', itemClass: 'sneeit-carousel-item', activeClass: 'active', /* callback */ /* fire before start animate */ //animate: function(args) {} /* fire after finish animate */ //animated: function(args) {} }; SneeitCarousel.prototype.animate = function (x, duration) { // we don't need carousel when all items were displayed if (this.colNum >= this.oItemNum) { return; } this.animating = x; if (typeof(x) == 'undefined') { x = this.x - this.iWid; } this.activeDot(x); this.activeNav(x); var animate_option = {}; animate_option[this.xCSS] = x + '%'; if (typeof(duration) == 'undefined') { duration = this.opt.animateDuration; } var that = this; if (typeof(this.opt.animate) == 'function') { this.opt.animate({ this: that, x: x }); } if (this.debug) { console.log('animate', x, duration, animate_option, this); } this.stage.stop().animate(animate_option, duration, function(){ that.x = x; that.animating = false; if (typeof(that.opt.animated) == 'function') { that.opt.animated({ this: that }); } that.display(); }); } SneeitCarousel.prototype.getX = function() { if (this.debug) { console.log('getX'); } var x = this.stage.css(this.xCSS); x = Number(x.replace('px', '')); return x * 100 / this.wid; } /* reset current index if * the window is near the end * of clones * */ SneeitCarousel.prototype.resetX = function() { var reset = false; if (this.x <= this.xEnd) { this.x += this.resetAB; reset = true; } else if (this.x >= this.xStart) { this.x -= this.resetAB; reset = true; } if (reset) { this.stage.css( this.xCSS, this.x + '%' ); } if (this.debug) { console.log('resetX', reset, this); } } SneeitCarousel.prototype.activeItem = function () { /* set active items * only items have X in Start-End * will be set as activ * */ var x = 0; var xStart = this.x; var xEnd = this.x - this.colNum * this.iWid; for (var i = 0; i < this.itemNum; i++) { x = - (i * this.iWid + this.iWid / 2); if (x < xStart && x > xEnd ) { $(this.items[i]).addClass(this.opt.activeClass); } else { $(this.items[i]).removeClass(this.opt.activeClass); } } if (this.debug) { console.log('activeItem', x, xStart, xEnd, this); } } SneeitCarousel.prototype.display = function() { this.resetX(); var that = this; /* active dots, navigation and items */ this.activeDot(this.x); this.activeNav(this.x); this.activeItem(); if (this.debug) { console.log('display', this); return; } /* run to next slider */ this.displaying = setTimeout(function(){ clearTimeout(that.displaying); that.displaying = null; if (that.hover) { return; } that.animate(); }, this.opt.displayDuration); } SneeitCarousel.prototype.stop = function() { if (this.debug) { console.log('stop'); } this.stage.stop(); if (this.displaying != null) { clearTimeout(this.displaying); this.displaying = null; } this.x = this.getX(); } /* we don't need to reinit if the * column did not change than previous * but we need to update the values * that have unit in pixel * */ SneeitCarousel.prototype.init = function(reinit) { if (reinit) { this.stop(); this.colNum = this.opt.columnNumber; this.margin = this.opt.margin; this.stage.css(this.xCSS, 0); this.x = 0; } /* validate column number */ var items = null; if (!reinit) { items = this._.find('>*'); this.oItemNum = items.length; if (!this.oItemNum) { return; } /* the number must not larger than number of items */ if (!this.colNum) { this.colNum = 1; } if (this.colNum > this.oItemNum) { this.colNum = this.oItemNum; } } /* the margin must not larger than max margin */ this.wid = this._.width(); this._.css('width', this.wid + 'px'); if (!this.wid) { return; } if (100 * this.margin / this.wid > this.opt.maxMargin) { this.margin = this.opt.maxMargin * this.wid / 100; } /* decrease column number if item width smaller than min */ var marSum = (this.colNum - 1) * this.margin; if (this.colNum <= 1) { marSum = 0; } /* item width in pixel */ var iWid = (this.wid - marSum) / this.colNum; for ( ; this.colNum > 1 && iWid < this.opt.minColumnWidth; this.colNum-- ) { marSum = (this.colNum - 1) * this.margin; if (this.colNum <= 1) { marSum = 0; } iWid = this.wid / this.colNum; if (this.colNum <= 1 || iWid >= this.opt.minColumnWidth) { break; } } if (0 == this.colNum) { this.colNum = 1; } /* update again the item width to * suitable with new column number * marSum is margin sum in pixel * iWid is item width in pixel * */ marSum = (this.colNum - 1) * this.margin; iWid = (this.wid - marSum) / this.colNum; if (reinit && this.colNum == this.prevColNum) { return; } this.prevColNum = this.colNum; if (!reinit) { /* wrap content with properly class */ items.wrap('<div class="'+this.opt.itemClass+'"></div>'); this._.wrapInner('<div class="'+this.opt.stageClass+'"></div>'); this._.wrapInner('<div class="'+this.opt.outerClass+'"></div>'); /* save element objects */ items = this._.find(this.itemClass); this.stage = this._.find(this.stageClass); this.outer = this._.find(this.outerClass); /* clone items */ items.clone().prependTo(this.stage); items.clone().appendTo(this.stage); this.items = this._.find(this.itemClass); this.itemNum = this.items.length; } /* CALCULATE EVERYTHING IN PERCENT * */ /* stage width in pixel * */ var stageWidPx = this.itemNum * iWid + (this.itemNum - 1) * this.margin; /* margin width related to stage in percent * */ var iMarStage = this.margin * 100 / stageWidPx; /* item width related to wrapper in percent * = item width in pixel + margin in pixel convert to percent * */ this.iWid = (iWid * 100 / this.wid) + (this.margin * 100 / this.wid); /* accept precision in JavaScript float */ this.epsilon = 100 / this.wid / 10; /* the distance that allows you jump * to similar item index in carousel * */ this.resetAB = this.oItemNum * this.iWid; /* the boudaries of x that you need * to reset if x go out of these */ this.xStart = - (this.oItemNum - this.colNum - 1) * this.iWid; this.xEnd = - (this.oItemNum * 2 + this.colNum - 2) * this.iWid; this.totalDots = Math.ceil(this.oItemNum / this.colNum); /* init styles */ this.outer.css({ 'overflow' : 'hidden', 'position': 'relative' }); this.stage.css({ 'position' :'relative', 'width': (stageWidPx * 100 / this.wid) + '%', 'max-width' : 'none' }); this.items.css({ 'width': (iWid * 100 / stageWidPx) + '%', 'float': this.left }); if (iMarStage) { this.items.css('margin-' + this.left, iMarStage + '%'); } $(this.items[0]).css('margin-' + this.left, 0); if (this.debug) { console.log('init', this); } /* display and enable everything */ this.display(); this.enableDots(); if (!reinit) { this.enableDrag(); this.enableKeyboard(); this.enableResponsive(); this.enableNav(); this.enableHover(); /* add this to fire finish event */ this._.addClass(this.opt.wrapperClass); } } SneeitCarousel.prototype.getPageX = function(e) { if (this.debug) { console.log('getPageX'); } if (typeof(e['pageX']) == 'undefined' && typeof(e['originalEvent']['touches'][0]['clientX']) != 'undefined') { return e['originalEvent']['touches'][0]['clientX']; } return e.pageX; } /** * Detect * @returns {undefined} */ SneeitCarousel.prototype.dragStart = function() { } SneeitCarousel.prototype.dragMove = function() { } SneeitCarousel.prototype.dragMove = function() { } SneeitCarousel.prototype.enableDrag = function() { if (this.debug) { console.log('enableDrag'); } /* process mouse drag */ var that = this; this.stage.on('mousedown touchstart', function(e){ e.preventDefault(); if (that.drag !== false) { return false; } /* process if touch event */ e.pageX = that.getPageX(e); /* stop stage, update X and curMargin */ that.drag = e.pageX; that.stop(); return false; }); $(document).on('mousemove touchmove', function(e){ if (that.drag === false) { return; } e.preventDefault(); /* process if touch event */ e.pageX = that.getPageX(e); /* calculate for target x */ if (that.rtl) { that.x -= (e.pageX - that.drag) * 100 / that.wid; } else { that.x += (e.pageX - that.drag) * 100 / that.wid; } if (e.pageX < that.drag) { that.dragging = 'left'; } else if (e.pageX > that.drag) { that.dragging = 'right'; } that.drag = e.pageX; that.stage.css(that.xCSS, that.x + '%'); that.resetX(); return false; }); /* preventing move to href after ending drag on an A tag */ this.stage.find('a[href]').on('click', function(e){ if (that.dragging) { e.preventDefault(); return false; } }); /* when mouse up (end of mouse drag), we will recalculate x, * also animate item back to nearest item border * Priority animate to direction of the mouse move * */ $(document).on('mouseup touchend', function(e){ if (that.drag === false) { return; } that.x = that.getX(); var x = 0; for (var i = 0; i < that.itemNum - 1; i++) { x = - (i * that.iWid); /* find the item which contain current x point */ if (that.x < x - that.epsilon && that.x > x - that.iWid + that.epsilon) { break; } } if (i >= that.itemNum - 1) { that.drag = false; that.dragging = false; that.display(); return; } /* animate depending on drag direction and site direction * to animate to right position */ var x = - (i * that.iWid); if (that.dragging == that.left) { x -= that.iWid; } that.animate(x); /* we don't set down immediately * to prevent click events from a tags */ setTimeout(function(){ that.drag = false; that.dragging = false; }, 5); }); } SneeitCarousel.prototype.activeDot = function(x) { if (this.debug) { return; console.log('activeDot', x, this); } if (!this.dots) { return; } var i = Math.round(Math.abs(x / this.iWid)) % this.oItemNum; i = Math.floor(i / this.colNum); this.dots.removeClass(this.opt.activeClass); $(this.dots[i]).addClass(this.opt.activeClass); } /** * Enable dots as pagination for the carousel * @returns {undefined} */ SneeitCarousel.prototype.enableDots = function() { if (this.debug) { console.log('enableDots'); } if (!this.totalDots || !this.opt.dotsClass || !this.opt.dotClass ) { return; } /* append dot raw HTML content to wrapper */ var dots = ''; var that = this; for (var i = 0; i < this.totalDots; i++) { var dot = ''; if (typeof(this.opt.dotText) == 'function') { dot = this.opt.dotText({ this: that, dotIndex: i, }); } else { dot = this.opt.dotText; } /* seem the user disable the dot, so just return */ if (dot === false) { return; } dots += '<div class="' + this.opt.dotClass + '" data-index="'+i+'">'+dot+'</div>'; } /* if reinit, we have to * remove all and remake html */ if (this.dots != null) { this._.find(this.dotsClass).html(dots); } else { dots = '<div class="' + this.opt.dotsClass + '">'+dots+'</div>'; this._.append(dots); } this.dots = this._.find(this.dotClass); $(this.dots[0]).addClass(this.opt.activeClass); /* action when click dots */ this.dots.click(function(){ var index = $(this).attr('data-index'); if (typeof(index) == 'undefined' || isNaN(index)) { return; } that.stop(); /* set dot index and active state */ index = Number(index); // that.dots.removeClass(that.opt.activeClass); // $(this).addClass(that.opt.activeClass); /* calculate nearest target x */ var x = - index * that.colNum * that.iWid; var AB = x - that.x; var maxMatchPos = that.itemNum / that.oItemNum; var stepMatch = that.resetAB; for (var i = 1; i < maxMatchPos; i++) { var _x = x - i * stepMatch; var _AB = _x - that.x; if (Math.abs(_AB) < Math.abs(AB)) { AB = _AB; } } x = AB + that.x; /* it already stayed at the right position */ if (Math.abs(AB) < that.epsilon) { that.display(); return; } that.animate(x); }); } SneeitCarousel.prototype.activeNav = function(x) { if (this.debug) { return; console.log('activeNav', x, this); } /* previous arrow */ var prevText = ''; var that = this; if (typeof(this.opt.prevText) == 'function') { prevText = this.opt.prevText({ this: that }); } else { prevText = this.opt.prevText; } if (prevText !== false && this.opt.prevClass) { this._.find(this.prevClass).html(prevText); } /* next arrow */ var nextText = ''; if (typeof(this.opt.nextText) == 'function') { nextText = this.opt.nextText({ this: that }); } else { nextText = this.opt.nextText; } if (nextText !== false && this.opt.nextClass) { this._.find(this.nextClass).html(nextText); } } SneeitCarousel.prototype.enableNav = function() { if (this.debug) { console.log('enableNav'); } if (!this.opt.navClass) { return; } /* append arrow HTML content to wrapper */ var arrowsContent = ''; var that = this; /* previous arrow */ var prevText = ''; if (typeof(this.opt.prevText) == 'function') { prevText = this.opt.prevText({ this: that }); } else { prevText = this.opt.prevText; } if (prevText && this.opt.prevClass) { arrowsContent += '<div class="' + this.opt.prevClass + '">'+prevText+'</div>'; } /* next arrow */ var nextText = ''; if (typeof(this.opt.nextText) == 'function') { nextText = this.opt.nextText({ this: that }); } else { nextText = this.opt.nextText; } if (nextText && this.opt.nextClass) { arrowsContent += '<div class="' + this.opt.nextClass + '">'+nextText+'</div>'; } if (!arrowsContent) { return; } this._.append('<div class="' + this.opt.navClass + '">' + arrowsContent + '</div>'); /* action when click arrows */ /* when click Previous Arrow */ if (this.opt.prevClass) { this._.find(this.prevClass).click(function(){ that.prev(); }); } /* when click Next Arrow */ if (this.opt.nextClass) { this._.find(this.nextClass).click(function(){ that.next(); }); } } SneeitCarousel.prototype.prev = function() { if (this.debug) { console.log('prev'); } this.stop(); var i = Math.floor(this.x / this.iWid); var x = (i + 1) * this.iWid; /* the distance must be at least larger * than one item width */ if (this.x - x > - this.iWid + this.epsilon) { x += this.iWid; } /* reset here to prevent move * out of the view area */ if (x > this.xStart) { this.x -= this.resetAB; x -= this.resetAB; this.stage.css(this.xCSS, this.x +'%'); } // animate to the target this.animate(x, 90); } SneeitCarousel.prototype.next = function() { if (this.debug) { console.log('next'); } this.stop(); var i = Math.floor(Math.abs(this.x / this.iWid)); var x = -(i + 1) * this.iWid; /* the distance must be at least larger * than one item width */ if (Math.abs(this.x) > i * this.iWid + this.epsilon) { x -= this.iWid; } /* reset here to prevent move * out of the view area */ if (x < this.xEnd) { this.x += this.resetAB; x += this.resetAB; this.stage.css(this.xCSS, this.x +'%'); } // animate to the target this.animate(x, 90); } SneeitCarousel.prototype.enableKeyboard = function() { if (this.debug) { console.log('enableKeyboard'); } var that = this; $(document).keydown(function(e){ switch(e.which) { case 37: // left that.prev(); break; case 39: // right that.next(); break; default: return; // exit this handler for other keys } e.preventDefault(); // prevent the default action (scroll / move caret) }); } SneeitCarousel.prototype.enableResponsive = function() { if (this.debug) { console.log('enableResponsive'); } var that = this; $(window).resize(function(){ that._.css('width', ''); that.init(true); }); } /** * stop and resume when mouse hover * @returns {undefined} */ SneeitCarousel.prototype.enableHover = function() { if (this.debug) { console.log('enableHover'); } var that = this; this._.on('mouseenter', function(){ that.hover = true; }); this._.on('mouseleave', function(){ that.hover = false; /* only resume if the slider is not displaying * (which will auto animate after the end) * and not animating (because if animating * then we don't need to resume * */ if (!that.displaying && that.animating === false) { that.display(); } }); } /** * The jQuery Plugin for the Sneeit Carousel * @todo Navigation plugin `next` and `prev` * @public */ $.fn.sneeitCarousel = function(option) { return this.each(function() { new SneeitCarousel($(this), option); }); }; })( jQuery );