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