1 2 3/* ========================================================================= *\ 4 vmcarousel plugin by Vedmant 5\* ========================================================================= */ 6 7(function ($, window, document, undefined) { 8 "use strict"; 9 10 var pluginName = 'vmcarousel'; 11 12 /** 13 * Defaults 14 * 15 * @type {} 16 */ 17 var defaults = { 18 delay: 4000, 19 speed: 500, 20 autoplay: true, 21 items_to_show: 0, // 0 for auto calc 22 min_items_to_show: 2, 23 items_to_slide: 1, 24 dont_cut: true, 25 centered: false, 26 start_item: 0, 27 start_item_centered: false, 28 infinite: false, 29 changed_slide: $.noop() 30 }; 31 32 /** 33 * Plugin constructor 34 * 35 * @param element 36 * @param options 37 * @constructor 38 */ 39 function Plugin(element, options) 40 { 41 this._name = pluginName; 42 this.element = element; 43 this.$element = $(element); 44 var data_options = parse_data_options(this.$element.data('options')); 45 this.options = $.extend({}, defaults, options); 46 this.options = $.extend({}, this.options, data_options); 47 this.init(); 48 } 49 50 /** 51 * Parse data-options attribute options 52 * 53 * @param data_options_raw 54 * @returns {Array} 55 */ 56 function parse_data_options(data_options_raw) 57 { 58 if(data_options_raw === undefined) return []; 59 var options = []; 60 data_options_raw.split(';').forEach(function(el){ 61 var pair = el.split(':'); 62 if(pair.length == 2) options[pair[0].trim()] = pair[1].trim(); 63 }); 64 return options; 65 } 66 67 68 /** 69 * Plugin functions 70 */ 71 Plugin.prototype = { 72 73 /** 74 * Plugin init 75 */ 76 init: function () 77 { 78 var that = this; 79 80 // Add class 81 this.$element.addClass('vmcarousel'); 82 83 // Wrap 84 this.$viewport = this.$element.wrap('<div class="vmc-viewport"></div>').parent(); 85 this.$container = this.$viewport.wrap('<div class="vmc-container"></div>').parent(); 86 87 // Some initial procedures with slides 88 this.init_slides(); 89 90 // Items vars 91 this.$orig_items = this.$element.find('>li'); 92 this.$items = this.$orig_items; 93 this.orig_items_count = this.$orig_items.length; 94 this.items_count = this.$items.length; 95 this.orig_item_width = this.$items.outerWidth(true); 96 this.item_width = this.orig_item_width; 97 98 // Other vars 99 this.current_position = 0; 100 101 // Init functions 102 this.calc_variables(); 103 this.init_infinite(this.options.start_item); 104 this.init_controls(); 105 this.update_state(); 106 107 // Reorder slides to make start item at the center 108 if(this.options.start_item_centered) 109 this.reorder_to_center(this.options.start_item); 110 111 // Initial set slide 112 if( ! this.options.infinite) 113 this.set_slide(this.options.start_item); 114 else 115 this.set_active_infinite(this.options.start_item); 116 117 // Start timer 118 if (this.options.autoplay) this.start_timer(); 119 120 // Window resize event 121 $(window).resize(function () { that.resize() }); 122 }, 123 124 /** 125 * Calculate all needed variables 126 */ 127 calc_variables: function() 128 { 129 this.viewport_width = this.$viewport.width(); 130 131 // Calc items to show 132 this.items_to_show = this.options.items_to_show; 133 if( ! this.options.items_to_show || (this.orig_item_width * this.items_to_show) > this.viewport_width) { 134 this.items_to_show = Math.floor(this.viewport_width / this.orig_item_width); 135 } 136 137 // Set odd number for centered type for not to cut items 138 if(this.options.centered && this.options.dont_cut) { 139 this.items_to_show = this.items_to_show % 2 ? this.items_to_show : this.items_to_show - 1; 140 } 141 142 // Min items to show 143 if(this.items_to_show < this.options.min_items_to_show) this.items_to_show = this.options.min_items_to_show; 144 145 // Calc item width for centered or dont_cut 146 if(this.options.centered || this.options.dont_cut) { 147 this.item_width = Math.floor(this.viewport_width / this.items_to_show); 148 if(this.item_width < this.orig_item_width) this.item_width = this.orig_item_width; 149 this.$items.width(this.item_width); 150 this.full_items_width = this.item_width * this.items_count; 151 this.$element.css({width: this.full_items_width + 'px'}); 152 } 153 154 // Calc items to slide 155 this.items_to_slide = this.options.items_to_slide; 156 if( ! this.options.items_to_slide) 157 this.items_to_slide = Math.floor(this.viewport_width / this.item_width); 158 if(this.items_to_slide > this.items_to_show) this.items_to_slide = this.items_to_show; 159 160 if(this.items_to_slide <= 0) this.items_to_slide = 1; 161 162 this.hide_controls = this.items_count <= this.items_to_show; 163 164 this.infinite_initial_margin = - this.item_width; 165 if(this.items_to_show % 2 == 0) this.infinite_initial_margin += this.item_width / 2; 166 167 }, 168 169 /** 170 * Update carousel state (clases, so on) 171 */ 172 update_state: function() 173 { 174 this.$element.css({transition: 'transform ' + this.options.speed / 1000 + 's'}); 175 176 if(this.hide_controls) this.$container.addClass('hide-control
176s'); 177 else this.$container.removeClass('hide-controls'); 178 }, 179 180 /** 181 * Set slides properties 182 */ 183 init_slides: function() 184 { 185 this.$element.find('>li').each(function(i){ 186 $(this).attr('data-slide', i); 187 }); 188 }, 189 190 /** 191 * Init controls 192 */ 193 init_controls: function() 194 { 195 var that = this; 196 197 // Controls 198 this.$btn_left = this.$container.append('<a href="" class="vmc-arrow-left"></a>').find('.vmc-arrow-left'); 199 this.$btn_right = this.$container.append('<a href="" class="vmc-arrow-right"></a>').find('.vmc-arrow-right'); 200 201 // Bind controls 202 this.$btn_left.click(function (e) { 203 e.preventDefault(); 204 that.slide_relative(-1); 205 }); 206 this.$btn_right.click(function (e) { 207 e.preventDefault(); 208 that.slide_relative(1); 209 }); 210 }, 211 212 /** 213 * Reorder slider to place item at the center 214 * 215 * @param position 216 */ 217 reorder_to_center: function(position) 218 { 219 // Dont reorder if 2 or less items 220 if(this.orig_items_count < 3) return; 221 222 // Calc shift times and direction 223 var shift_count = Math.floor(this.orig_items_count / 2) - position; 224 var dir = shift_count > 0 ? -1 : 1; 225 226 // Shift items 227 shift_count = Math.abs(shift_count); 228 for(var i = 0; i < shift_count; i++) this.switch_slides(dir); 229 }, 230 231 /** 232 * Move to exact slide 233 * 234 * @param slide 235 */ 236 set_slide: function(slide) 237 { 238 var position = this.$element.find('>
238[data-slide="'+slide+'"]').index(); 239 240 this.slide_relative(position); 241 }, 242 243 /** 244 * Slide n items forth or back 245 * 246 * @param offset 247 */ 248 slide_relative: function (offset) 249 { 250 if(this.options.centered && this.options.infinite) 251 this.slide_relative_centered_infinite(offset); 252 else if(this.options.centered) 253 this.slide_relative_centered(offset); 254 else 255 this.slide_relative_left(offset); 256 }, 257 258 /** 259 * Slide n items forth or back for left mode 260 * 261 * @param offset 262 */ 263 slide_relative_left: function (offset) 264 { 265 var new_position = this.current_position + (offset * this.items_to_slide); 266 267 // If now is ribbon tail on go back reverse to slide_count step 268 if (this.current_position == this.items_count && offset < 0) { 269 new_position = (Math.floor(this.items_count / this.items_to_slide) + offset) * this.items_to_slide; 270 271 // Show ribbon tail (last slide to right border) 272 } else if (new_position < 0 || (this.items_to_slide > (this.items_count - new_position) && new_position < this.items_count)) { 273 new_position = this.items_count - this.items_to_show; 274 275 // Scroll to beggining 276 } else if (new_position > (this.items_count - this.items_to_show)) { 277 new_position = 0; 278 } 279 280 var margin_left = - this.item_width * new_position; 281 282 // Animate slide 283 this.animate_slide(margin_left); 284 285 this.change_slide(new_position, new_position); 286 }, 287 288 /** 289 * Slide n items forth or back for centered mode 290 * 291 * @param offset 292 */ 293 slide_relative_centered: function (offset) 294 { 295 var new_position = this.current_position + (offset * this.items_to_slide); 296 297 if (new_position < 0) { 298 new_position = this.items_count - 1; 299 300 // Scroll to beggining 301 } else if (new_position >= this.items_count) { 302 new_position = 0; 303 } 304 305 var margin_left = this.viewport_width / 2 - (this.item_width * (new_position + 1) - this.item_width / 2); 306 307 // Animate slide 308 this.animate_slide(margin_left); 309 310 var new_active_slide = this.$items.eq(new_position).attr('data-slide'); 311 312 this.change_slide(new_position, new_active_slide); 313 }, 314 315 /** 316 * Init infinite carousel feature 317 */ 318 init_infinite: function (start_item) 319 { 320 if( ! this.options.infinite) return; 321 322 this.make_clones(); 323 324 this.calc_variables(); 325 326 this.$element.css("margin-left", this.infinite_initial_margin + "px"); 327 328 }, 329 330 /** 331 * Make clones for infinite carousel 332 */ 333 make_clones: function () 334 { 335 var times = 1; 336 if(this.items_count < this.items_to_show) 337 times = Math.ceil(this.items_to_show / this.items_count); 338 339 for(var i = 0; i < times; i++) { 340 this.$element.prepend(this.$orig_items.clone().addClass('vmc-clone')); 341 } 342 343 this.$items = this.$element.find('>li'); 344 this.items_count = this.$items.length; 345 }, 346 347 /** 348 * Slide n items forth or back for centered mode with infinite mode 349 * 350 * @param offset 351 */ 352 slide_relative_centered_infinite: function (offset) 353 { 354 var that = this; 355 356 // Only one item to slide 357 offset = offset < 0 ? -1 : 1; 358 359 var margin_left = this.infinite_initial_margin - this.item_width * offset; 360 361 //if(this.items_to_show % 2 == 0) margin_left += this.item_width / 2; 362 363 var new_position = Math.ceil(this.items_to_show / 2) + offset; 364 365 var new_active_slide = this.$items.eq(new_position).attr('data-slide'); 366 367 this.animate_slide(margin_left, function(e){ 368 369 that.switch_slides(offset); 370 371 that.$element.css("margin-left", that.infinite_initial_margin + "px"); 372 373 }, 'margin'); 374 375 this.change_slide(new_position, new_active_slide); 376 }, 377 378 /** 379 * Place first slide at the end or last slide before first 380 * 381 * @param dir 382 */ 383 switch_slides: function(dir) 384 { 385 var that = this; 386 387 // Switch last or first item 388 if(dir > 0) { 389 that.$items.last().after(that.$items.first()); 390 } else { 391 that.$items.first().before(that.$items.last()); 392 } 393 394 // Reload elements 395 that.$items = that.$element.find('>li'); 396 }, 397 398 /** 399 * Set first active slide for infinite carousel 400 * 401 */ 402 set_active_infinite: function(position) 403 { 404 var center_position = Math.ceil(this.items_to_show / 2); 405 406 for(var i = 0; i < this.orig_items_count; i++) { 407 this.switch_slides(1);
408 if(this.$items.eq(center_position).attr('data-slide') == position) { 409 this.$items.eq(center_position).addClass('vmc_active'); 410 return true; 411 } 412 } 413 414 return false; 415 }, 416 417 /** 418 * Change slide 419 * 420 * @param new_position 421 * @param margin_left 422 */ 423 change_slide: function (new_position, new_active_slide) 424 { 425 var that = this; 426 427 // Update current position 428 this.current_position = new_position; 429 // Add active class 430 this.$items.removeClass('vmc_active').eq(this.current_position).addClass('vmc_active'); 431 // Restart timer 432 if (this.options.autoplay) this.start_timer(); 433 // Call callback 434 if (typeof this.options.changed_slide === "function") { 435 this.options.changed_slide.call(this, new_active_slide); 436 } 437 }, 438 439 /** 440 * Slide animation 441 * 442 * @param margin_left 443 */ 444 animate_slide: function (margin_left, complete, type) 445 { 446 var that = this; 447 448 if(type == undefined) type = 'css3'; 449 if(complete == undefined) complete = $.noop(); 450 451 if (Modernizr.csstransitions && type == 'css3') { 452 this.$element.css("transform", "translate3d(" + margin_left + "px,0px,0px)"); 453 this.$element.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', complete); 454 } else { 455 this.$element.stop(true).animate({'margin-left': margin_left + 'px'}, this.options.speed, 'swing', complete); 456 } 457 }, 458 459 /** 460 * Resize event 461 */ 462 resize: function () 463 { 464 this.calc_variables(); 465 466 this.update_state(); 467 468 // Update slider position 469 this.slide_relative(0); 470 }, 471 472 /** 473 * Start timer 474 */ 475 start_timer: function () 476 { 477 var that = this; 478 if (this.timer_id != 0) clearTimeout(this.timer_id); 479 this.timer_id = setTimeout(function () { 480 that.slide_relative(1); 481 }, this.options.delay); 482 }, 483 484 /** 485 * Stop timer 486 */ 487 stop_timer: function () 488 { 489 clearTimeout(this.timer_id); 490 this.timer_id = 0; 491 } 492 493 } // Plugin.prototype 494 495 /** 496 * Attach to Jquery 497 * 498 * @param options 499 * @returns {*} 500 */ 501 $.fn[pluginName] = function (options) { 502 var args = [].slice.call(arguments, 1); 503 return this.each(function () { 504 if (!$.data(this, 'plugin_' + pluginName)) 505 $.data(this, 'plugin_' + pluginName, new Plugin(this, options)); 506 else if ($.isFunction(Plugin.prototype[options])) 507 $.data(this, 'plugin_' + pluginName)[options].apply($.data(this, 'plugin_' + pluginName), args); 508 }); 509 } 510 511 // Auto init for tags with data-vmcarousel attribute 512 $('[data-vmcarousel]').vmcarousel(); 513 514})(jQuery, window, document); 515
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.