1/*! jQuery asScrollable - v0.3.1 - 2015-06-15 2* https://github.com/amazingSurge/jquery-asScrollable 3* Copyright (c) 2015 amazingSurge; Licensed GPL */ 4(function(window, document, $, undefined) { 5 "use strict"; 6 7 var pluginName = 'asScrollbar'; 8 9 /** 10 * Animation Frame 11 **/ 12 if (!Date.now) { 13 Date.now = function() { 14 return new Date().getTime(); 15 }; 16 } 17 18 function getTime() { 19 if (typeof window.performance !== 'undefined' && window.performance.now) { 20 return window.performance.now(); 21 } else { 22 return Date.now(); 23 } 24 } 25 26 var vendors = ['webkit', 'moz']; 27 for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { 28 var vp = vendors[i]; 29 window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; 30 window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']); 31 } 32 if (/iP(ad|hone|od).*OS (6|7|8)/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { 33 var lastTime = 0; 34 window.requestAnimationFrame = function(callback) { 35 var now = getTime(); 36 var nextTime = Math.max(lastTime + 16, now); 37 return setTimeout(function() { 38 callback(lastTime = nextTime); 39 }, 40 nextTime - now); 41 }; 42 window.cancelAnimationFrame = clearTimeout; 43 } 44 45 /** 46 * Helper functions 47 **/ 48 function isPercentage(n) { 49 return typeof n === 'string' && n.indexOf('%') != -1; 50 } 51 52 function convertPercentageToFloat(n) { 53 return parseFloat(n.slice(0, -1) / 100, 10); 54 } 55 56 function convertMatrixToArray(value) { 57 if (value && (value.substr(0, 6) == "matrix")) { 58 return value.replace(/^.*\((.*)\)$/g, "$1").replace(/px/g, '').split(/, +/); 59 } 60 return false; 61 } 62 63 /** 64 * Plugin constructor 65 **/ 66 var Plugin = $[pluginName] = function(options, bar) { 67 this.$bar = $(bar); 68 69 options = this.options = $.extend({}, Plugin.defaults, options || {}, this.$bar.data('options') || {}); 70 71 bar.direction = this.options.direction; 72 73 this.classes = { 74 directionClass: options.namespace + '-' + options.direction, 75 barClass: options.barClass ? options.barClass : options.namespace, 76 handleClass: options.handleClass ? options.handleClass : options.namespace + '-handle' 77 }; 78 79 if (this.options.direction === 'vertical') { 80 this.attributes = { 81 axis: 'Y', 82 position: 'top', 83 length: 'height', 84 clientLength: 'clientHeight' 85 }; 86 } else if (this.options.direction === 'horizontal') { 87 this.attributes = { 88 axis: 'X', 89 position: 'left', 90 length: 'width', 91 clientLength: 'clientWidth' 92 }; 93 } 94 95 // Current state information. 96 this._states = {}; 97 98 // Current state information for the drag operation. 99 this._drag = { 100 time: null, 101 pointer: null 102 }; 103 104 // Current timeout 105 this._frameId = null; 106 107 // Current handle position 108 this.handlePosition = 0; 109 110 this.easing = Plugin.easing[this.options.easing] || Plugin.easing.ease; 111 112 this.init(); 113 }; 114 115 Plugin.defaults = { 116 namespace: 'asScrollbar', 117 118 skin: null, 119 handleSelector: null, 120 handleTemplate: '<div class="{{handle}}"></div>', 121 122 barClass: null, 123 handleClass: null, 124 125 disabledClass: 'is-disabled', 126 draggingClass: 'is-dragging', 127 hoveringClass: 'is-hovering', 128 129 direction: 'vertical', 130 131 barLength: null, 132 handleLength: null, 133 134 minHandleLength: 30, 135 maxHandleLength: null, 136 137 mouseDrag: true, 138 touchDrag: true, 139 pointerDrag: true, 140 clickMove: true, 141 clickMoveStep: 0.3, // 0 - 1 142 mousewheel: true, 143 mousewheelSpeed: 50, 144 145 keyboard: true, 146 147 useCssTransforms3d: true, 148 useCssTransforms: true, 149 useCssTransitions: true, 150 151 duration: '500', 152 easing: 'ease' // linear, ease-in, ease-out, ease-in-out 153 }; 154 155 /** 156 * Css features detect 157 **/ 158 var support = {}; 159 Plugin.support = support; 160 (function(support) { 161 /** 162 * Borrowed from Owl carousel
163 **/ 164 var style = $('<support>').get(0).style, 165 prefixes = ['webkit', 'Moz', 'O', 'ms'], 166 events = { 167 transition: { 168 end: { 169 WebkitTransition: 'webkitTransitionEnd', 170 MozTransition: 'transitionend', 171 OTransition: 'oTransitionEnd', 172 transition: 'transitionend' 173 } 174 }, 175 animation: { 176 end: { 177 WebkitAnimation: 'webkitAnimationEnd', 178 MozAnimation: 'animationend', 179 OAnimation: 'oAnimationEnd', 180 animation: 'animationend' 181 } 182 } 183 }, 184 tests = { 185 csstransforms: function() { 186 return !!test('transform'); 187 }, 188 csstransforms3d: function() { 189 return !!test('perspective'); 190 }, 191 csstransitions: function() { 192 return !!test('transition'); 193 }, 194 cssanimations: function() { 195 return !!test('animation'); 196 } 197 }; 198 199 function test(property, prefixed) { 200 var result = false, 201 upper = property.charAt(0).toUpperCase() + property.slice(1); 202 203 if (style[property] !== undefined) { 204 result = property; 205 } 206 if (!result) { 207 $.each(prefixes, function(i, prefix) { 208 if (style[prefix + upper] !== undefined) { 209 result = '-' + prefix.toLowerCase() + '-' + upper; 210 return false; 211 } 212 }); 213 } 214 215 if (prefixed) { 216 return result; 217 } 218 if (result) { 219 return true; 220 } else { 221 return false; 222 } 223 } 224 225 function prefixed(property) { 226 return test(property, true); 227 } 228 229 if (tests.csstransitions()) { 230 /* jshint -W053 */ 231 support.transition = new String(prefixed('transition')) 232 support.transition.end = events.transition.end[support.transition]; 233 } 234 235 if (tests.cssanimations()) { 236 /* jshint -W053 */ 237 support.animation = new String(prefixed('animation')) 238 support.animation.end = events.animation.end[support.animation]; 239 } 240 241 if (tests.csstransforms()) { 242 /* jshint -W053 */ 243 support.transform = new String(prefixed('transform')); 244 support.transform3d = tests.csstransforms3d(); 245 } 246 247 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) { 248 support.touch = true; 249 } else { 250 support.touch = false; 251 } 252 253 if (window.PointerEvent || window.MSPointerEvent) { 254 support.pointer = true; 255 } else { 256 support.pointer = false; 257 } 258 259 support.prefixPointerEvent = function(pointerEvent) { 260 return window.MSPointerEvent ? 261 'MSPointer' + pointerEvent.charAt(9).toUpperCase() + pointerEvent.substr(10) : 262 pointerEvent; 263 } 264 })(support); 265 266 var easingBezier = function(mX1, mY1, mX2, mY2) { 267 function a(aA1, aA2) { 268 return 1.0 - 3.0 * aA2 + 3.0 * aA1; 269 } 270 271 function b(aA1, aA2) { 272 return 3.0 * aA2 - 6.0 * aA1; 273 } 274 275 function c(aA1) { 276 return 3.0 * aA1; 277 } 278 279 // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. 280 function calcBezier(aT, aA1, aA2) { 281 return ((a(aA1, aA2) * aT + b(aA1, aA2)) * aT + c(aA1)) * aT; 282 } 283 284 // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. 285 function getSlope(aT, aA1, aA2) { 286 return 3.0 * a(aA1, aA2) * aT * aT + 2.0 * b(aA1, aA2) * aT + c(aA1); 287 } 288 289 function getTForX(aX) {
290 // Newton raphson iteration 291 var aGuessT = aX; 292 for (var i = 0; i < 4; ++i) { 293 var currentSlope = getSlope(aGuessT, mX1, mX2); 294 if (currentSlope === 0.0) return aGuessT; 295 var currentX = calcBezier(aGuessT, mX1, mX2) - aX; 296 aGuessT -= currentX / currentSlope; 297 } 298 return aGuessT; 299 } 300 301 if (mX1 === mY1 && mX2 === mY2) { 302 return { 303 css: 'linear', 304 fn: function(aX) { 305 return aX; 306 } 307 }; 308 } else { 309 return { 310 css: 'cubic-bezier(' + mX1 + ',' + mY1 + ',' + mX2 + ',' + mY2 + ')', 311 fn: function(aX) { 312 return calcBezier(getTForX(aX), mY1, mY2); 313 } 314 } 315 } 316 }; 317 318 $.extend(Plugin.easing = {}, { 319 'ease': easingBezier(0.25, 0.1, 0.25, 1.0), 320 'linear': easingBezier(0.00, 0.0, 1.00, 1.0), 321 'ease-in': easingBezier(0.42, 0.0, 1.00, 1.0), 322 'ease-out': easingBezier(0.00, 0.0, 0.58, 1.0), 323 'ease-in-out': easingBezier(0.42, 0.0, 0.58, 1.0) 324 }); 325 326 Plugin.prototype = { 327 constructor: Plugin, 328 init: function() { 329 var options = this.options; 330 331 this.$handle = this.$bar.find(this.options.handleSelector); 332 if (this.$handle.length === 0) { 333 this.$handle = $(options.handleTemplate.replace(/\{\{handle\}\}/g, this.classes.handleClass)).appendTo(this.$bar); 334 } else { 335 this.$handle.addClass(this.classes.handleClass); 336 } 337 338 this.$bar.addClass(this.classes.barClass).addClass(this.classes.directionClass).attr('draggable', false); 339 340 if (options.skin) { 341 this.$bar.addClass(options.skin); 342 } 343 if (options.barLength !== null) { 344 this.setBarLength(options.barLength); 345 } 346 347 if (options.handleLength !== null) { 348 this.setHandleLength(options.handleLength); 349 } 350 351 this.updateLength(); 352 353 this.bindEvents(); 354 }, 355 356 trigger: function(eventType) { 357 var method_arguments = Array.prototype.slice.call(arguments, 1), 358 data = [this].concat(method_arguments); 359 360 // event 361 this.$bar.trigger(pluginName + '::' + eventType, data); 362 363 // callback 364 eventType = eventType.replace(/\b\w+\b/g, function(word) { 365 return word.substring(0, 1).toUpperCase() + word.substring(1); 366 }); 367 var onFunction = 'on' + eventType; 368 369 if (typeof this.options[onFunction] === 'function') { 370 this.options[onFunction].apply(this, method_arguments); 371 } 372 }, 373 374 /** 375 * Checks whether the carousel is in a specific state or not. 376 */ 377 is: function(state) { 378 return this._states[state] && this._states[state] > 0; 379 }, 380 381 /** 382 * Enters a state. 383 */ 384 enter: function(state) { 385 if (this._states[state] === undefined) { 386 this._states[state] = 0; 387 } 388 389 this._states[state] ++; 390 }, 391 392 /** 393 * Leaves a state. 394 */ 395 leave: function(state) { 396 this._states[state] --; 397 }, 398 399 eventName: function(events) { 400 if (typeof events !== 'string' || events === '') { 401 return '.' + this.options.namespace; 402 } 403 events = events.split(' '); 404 405 var length = events.length; 406 for (var i = 0; i < length; i++) { 407 events[i] = events[i] + '.' + this.options.namespace; 408 } 409 return events.join(' '); 410 }, 411 412 bindEvents: function() { 413 var self = this; 414 415 if (this.options.mouseDrag) { 416 this.$handle.on(this.eventName('mousedown'), $.proxy(this.onDragStart, this)); 417 this.$handle.on(this.eventName('dragstart selectstart'), function() { 418 return false 419 }); 420 } 421 422 if (this.options.touchDrag && support.touch) { 423 this.$handle.on(this.eventName('touchstart'), $.proxy(this.onDragStart, this)); 424 this.$handle.on(this.eventName('touchcancel'), $.proxy(this.onDragEnd, this)); 425 } 426 427 if (this.options.pointerDrag && support.pointer) { 428 this.$handle.on(this.eventName(support.prefixPointerEvent('pointerdown')), $.proxy(this.onDragStart, this)); 429 this.$handle.on(this.eventName(support.prefixPointerEvent('pointercancel')), $.proxy(this.onDragEnd, this)); 430 } 431 432 if (this.options.clickMove) { 433 this.$bar.on(this.eventName('mousedown'), $.proxy(this.onClick, this)); 434 } 435 436 if (this.options.mousewheel) { 437 this.$bar.on(this.eventName('mousewheel'), function(e, delta) { 438 var offset = self.getHandlePosition(); 439 if (offset <= 0 && delta > 0) { 440 return true; 441 } else if (offset >= self.barLength && delta < 0) { 442 return true; 443 } else { 444 offset = offset - self.options.mousewheelSpeed * delta; 445 446 self.move(offset, true); 447 return false;
448 } 449 }); 450 } 451 452 this.$bar.on(this.eventName('mouseenter'), function() { 453 self.$bar.addClass(self.options.hoveringClass); 454 self.enter('hovering'); 455 self.trigger('hover'); 456 }); 457 458 this.$bar.on(this.eventName('mouseleave'), function() { 459 self.$bar.removeClass(self.options.hoveringClass); 460 461 if (!self.is('hovering')) { 462 return; 463 } 464 self.leave('hovering'); 465 self.trigger('hovered'); 466 }); 467 468 if (this.options.keyboard) { 469 $(document).on(this.eventName('keydown'), function(e) { 470 if (e.isDefaultPrevented && e.isDefaultPrevented()) { 471 return; 472 } 473 474 if (!self.is('hovering')) { 475 return; 476 } 477 var activeElement = document.activeElement; 478 // go deeper if element is a webcomponent 479 while (activeElement.shadowRoot) { 480 activeElement = activeElement.shadowRoot.activeElement; 481 } 482 if ($(activeElement).is(":input,select,option,[contenteditable]")) { 483 return; 484 } 485 var by = 0, 486 to = null; 487 switch (e.which) { 488 case 37: // left 489 case 63232: 490 by = -30; 491 break; 492 case 38: // up 493 case 63233: 494 by = -30; 495 break; 496 case 39: // right 497 case 63234: 498 by = 30; 499 break; 500 case 40: // down 501 case 63235: 502 by = 30; 503 break; 504 case 33: // page up 505 case 63276: 506 by = -90; 507 break; 508 case 32: // space bar 509 case 34: // page down 510 case 63277: 511 by = -90; 512 break; 513 case 35: // end 514 case 63275: 515 to = '100%'; 516 break; 517 case 36: // home 518 case 63273: 519 to = 0; 520 break; 521 default: 522 return; 523 } 524 525 if (by || to !== null) { 526 if (by) { 527 self.moveBy(by, true); 528 } else if (to !== null) { 529 self.moveTo(to, true); 530 } 531 e.preventDefault(); 532 } 533 }); 534 } 535 }, 536 537 onClick: function(event) { 538 if (event.which === 3) { 539 return; 540 } 541 542 if (event.target === this.$handle[0]) { 543 return; 544 } 545 546 this._drag.time = new Date().getTime(); 547 this._drag.pointer = this.pointer(event); 548 549 var offset = this.$handle.offset(), 550 distance = this.distance({ 551 x: offset.left, 552 y: offset.top 553 }, this._drag.pointer), 554 factor = 1; 555 556 if (distance > 0) { 557 distance -= this.handleLength; 558 } else { 559 distance = Math.abs(distance); 560 factor = -1; 561 } 562 563 if (distance > this.barLength * this.options.clickMoveStep) { 564 distance = this.barLength * this.options.clickMoveStep; 565 } 566 this.moveBy(factor * distance, true); 567 }, 568 569 /** 570 * Handles `touchstart` and `mousedown` events. 571 */ 572 onDragStart: function(event) { 573 var self = this; 574 575 if (event.which === 3) { 576 return; 577 } 578 579 // this.$bar.toggleClass(this.options.draggingClass, event.type === 'mousedown'); 580 this.$bar.addClass(this.options.draggingClass); 581 582 this._drag.time = new Date().getTime(); 583 this._drag.pointer = this.pointer(event); 584 585 var callback = function() { 586 self.enter('dragging'); 587 self.trigger('drag'); 588 } 589 590 if (this.options.mouseDrag) { 591 $(document).on(self.eventName('mouseup'), $.proxy(this.onDragEnd, this)); 592 593 $(document).one(self.eventName('mousemove'), $.proxy(function() { 594 $(document).on(self.eventName('mousemove'), $.proxy(this.onDragMove, this)); 595 596 callback(); 597 }, this)); 598 } 599 600 if (this.options.touchDrag && support.touch) { 601 $(document).on(self.eventName('touchend'), $.proxy(this.onDragEnd, this)); 602 603 $(document).one(self.eventName('touchmove'), $.proxy(function() { 604 $(document).on(self.eventName('touchmove'), $.proxy(this.onDragMove, this)); 605 606 callback(); 607 }, this)); 608 } 609 610 if (this.options.pointerDrag && support.pointer) { 611 $(document).on(self.eventName(support.prefixPointerEvent('pointerup')), $.proxy(this.onDragEnd, this)); 612 613 $(document).one(self.eventName(support.prefixPointerEvent('pointermove')), $.proxy(function() { 614 $(document).on(self.eventName(support.prefixPointerEvent('pointermove')), $.proxy(this.onDragMove, this)); 615 616 callback(); 617 }, this)); 618 } 619 620 $(document).on(self.eventName('blur'), $.proxy(this.onDragEnd, this)); 621 }, 622 623 /** 624 * Handles the `touchmove` and `mousemove` events. 625 */ 626 onDragMove: function(event) { 627 var distance = this.distance(this._drag.pointer, this.pointer(event)); 628 629 if (!this.is('dragging')) { 630 return; 631 } 632 633 event.preventDefault(); 634 this.moveBy(distance, true); 635 }, 636 637 /** 638 * Handles the `touchend` and `mouseup` events. 639 */ 640 onDragEnd: function() { 641 $(document).off(this.eventName('mousemove mouseup touchmove touchend pointermove pointerup MSPointerMove MSPointerUp blur')); 642 643 this.$bar.removeClass(this.options.draggingClass); 644 this.handlePosition = this.getHandlePosition(); 645 646 if (!this.is('dragging')) { 647 return; 648 } 649 650 this.leave('dragging'); 651 this.trigger('dragged'); 652 }, 653 654 /** 655 * Gets unified pointer coordinates from event. 656 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 657 */ 658 pointer: function(event) { 659 var result = { 660 x: null, 661 y: null 662 }; 663 664 event = event.originalEvent || event || window.event; 665 666 event = event.touches && event.touches.length ? 667 event.touches[0] : event.changedTouches && event.changedTouches.length ? 668 event.changedTouches[0] : event; 669 670 if (event.pageX) { 671 result.x = event.pageX; 672 result.y = event.pageY; 673 } else { 674 result.x = event.clientX; 675 result.y = event.clientY; 676 } 677 678 return result; 679 }, 680 681 /** 682 * Gets the distance of two pointer. 683 */ 684 distance: function(first, second) { 685 if (this.options.direction === 'vertical') { 686 return second.y - first.y; 687 } else { 688 return second.x - first.x; 689 } 690 }, 691 692 setBarLength: function(length, update) { 693 if (typeof length !== 'undefined') { 694 this.$bar.css(this.attributes.length, length); 695 } 696 if (update !== false) { 697 this.updateLength(); 698 } 699 }, 700 701 setHandleLength: function(length, update) { 702 if (typeof length !== 'undefined') { 703 if (length < this.options.minHandleLength) { 704 length = this.options.minHandleLength; 705 } else if (this.options.maxHandleLength && length > this.options.maxHandleLength) { 706 length = this.options.maxHandleLength; 707 } 708 this.$handle.css(this.attributes.length, length); 709 710 if (update !== false) { 711 this.updateLength(length); 712 } 713 } 714 }, 715 716 updateLength: function(length, barLength) { 717 if (typeof length !== 'undefined') { 718 this.handleLength = length; 719 } else { 720 this.handleLength = this.getHandleLenght(); 721 } 722 if (typeof barLength !== 'undefined') { 723 this.barLength = barLength; 724 } else { 725 this.barLength = this.getBarLength(); 726 } 727 }, 728 729 getBarLength: function() { 730 return this.$bar[0][this.attributes.clientLength]; 731 }, 732 733 getHandleLenght: function() { 734 return this.$handle[0][this.attributes.clientLength]; 735 }, 736 737 getHandlePosition: function() { 738 var value; 739 740 if (this.options.useCssTransforms && support.transform) { 741 value = convertMatrixToArray(this.$handle.css(support.transform)); 742 743 if (!value) { 744 return 0; 745 } 746 747 if (this.attributes.axis === 'X') { 748 value = value[12] || value[4]; 749 } else { 750 value = value[13] || value[5]; 751 } 752 } else { 753 value = this.$handle.css(this.attributes.position); 754 } 755 756 return parseFloat(value.replace('px', '')); 757 }, 758 759 makeHandlePositionStyle: function(value) { 760 var property, x = '0', 761 y = '0'; 762 763 if (this.options.useCssTransforms && support.transform) { 764 if (this.attributes.axis === 'X') { 765 x = value + 'px'; 766 } else { 767 y = value + 'px'; 768 } 769 770 property = support.transform.toString(); 771 772 if (this.options.useCssTransforms3d && support.transform3d) { 773 value = "translate3d(" + x + "," + y + ",0)"; 774 } else { 775 value = "translate(" + x + "," + y + ")"; 776 } 777 } else { 778 property = this.attributes.position; 779 } 780 var temp = {}; 781 temp[property] = value; 782 783 return temp; 784 }, 785 786 setHandlePosition: function(value) { 787 var style = this.makeHandlePositionStyle(value); 788 this.$handle.css(style); 789 790 if (!this.is('dragging')) { 791 this.handlePosition = parseFloat(value); 792 } 793 }, 794 795 moveTo: function(value, trigger, sync) { 796 var type = typeof value; 797 798 if (type === "string") { 799 if (isPercentage(value)) { 800 value = convertPercentageToFloat(value) * (this.barLength - this.handleLength); 801 } 802 803 value = parseFloat(value); 804 type = "number"; 805 } 806 807 if (type !== "number") { 808 return; 809 } 810 811 this.move(value, trigger, sync); 812 }, 813 814 moveBy: function(value, trigger, sync) { 815 var type = typeof value; 816 817 if (type === "string") { 818 if (isPercentage(value)) { 819 value = convertPercentageToFloat(value) * (this.barLength - this.handleLength); 820 } 821 822 value = parseFloat(value); 823 type = "number"; 824 } 825 826 if (type !== "number") { 827 return; 828 } 829 830 this.move(this.handlePosition + value, trigger, sync); 831 }, 832 833 move: function(value, trigger, sync) {
834 if (typeof value !== "number" || this.is('disabled')) { 835 return; 836 } 837 838 if (value < 0) { 839 value = 0; 840 } else if (value + this.handleLength > this.barLength) { 841 value = this.barLength - this.handleLength; 842 } 843 844 if (!this.is('dragging') && sync !== true) { 845 this.doMove(value, this.options.duration, this.options.easing, trigger); 846 } else { 847 this.setHandlePosition(value); 848 849 if (trigger) { 850 this.trigger('change', value / (this.barLength - this.handleLength)); 851 } 852 } 853 }, 854 855 doMove: function(value, duration, easing, trigger) { 856 this.enter('moving'); 857 duration = duration ? duration : this.options.duration; 858 easing = easing ? easing : this.options.easing; 859 860 var self = this, 861 style = this.makeHandlePositionStyle(value); 862 for (var property in style) { 863 break; 864 } 865 866 if (this.options.useCssTransitions && support.transition) { 867 self.enter('transition'); 868 this.prepareTransition(property, duration, easing); 869 870 this.$handle.one(support.transition.end, function() { 871 self.$handle.css(support.transition, ''); 872 873 if (trigger) { 874 self.trigger('change', value / (self.barLength - self.handleLength)); 875 } 876 self.leave('transition'); 877 self.leave('moving'); 878 }); 879 880 self.setHandlePosition(value); 881 } else { 882 self.enter('animating'); 883 884 var startTime = getTime(); 885 var start = self.getHandlePosition(); 886 var end = value; 887 888 var run = function(time) { 889 var percent = (time - startTime) / self.options.duration; 890 891 if (percent > 1) { 892 percent = 1; 893 } 894 895 percent = self.easing.fn(percent); 896 897 var current = parseFloat(start + percent * (end - start), 10); 898 self.setHandlePosition(current); 899 900 if (trigger) { 901 self.trigger('change', current / (self.barLength - self.handleLength)); 902 } 903 904 if (percent === 1) { 905 window.cancelAnimationFrame(self._frameId); 906 self._frameId = null; 907 908 self.leave('animating'); 909 self.leave('moving'); 910 } else { 911 self._frameId = window.requestAnimationFrame(run); 912 } 913 }; 914 915 self._frameId = window.requestAnimationFrame(run); 916 } 917 }, 918 919 prepareTransition: function(property, duration, easing, delay) { 920 var temp = []; 921 if (property) { 922 temp.push(property); 923 } 924 if (duration) { 925 if ($.isNumeric(duration)) { 926 duration = duration + 'ms'; 927 } 928 temp.push(duration); 929 } 930 if (easing) { 931 temp.push(easing); 932 } else { 933 temp.push(this.easing.css); 934 } 935 if (delay) { 936 temp.push(delay); 937 } 938 this.$handle.css(support.transition, temp.join(' ')); 939 }, 940 941 enable: function() { 942 this._states.disabled = 0; 943 944 this.$bar.removeClass(this.options.disabledClass); 945 }, 946 947 disable: function() { 948 this._states.disabled = 1; 949 950 this.$bar.addClass(this.options.disabledClass); 951 }, 952 953 destory: function() { 954 this.$bar.on(this.eventName()); 955 } 956 }; 957 958 $.fn[pluginName] = function(options) { 959 if (typeof options === 'string') { 960 var args = Array.prototype.slice.call(arguments, 1); 961 this.each(function() { 962 var instance = $(this).data(pluginName); 963 if (!instance) { 964 return false;
965 } 966 if (!$.isFunction(instance[options]) || options.charAt(0) === "_") { 967 return false; 968 } 969 // apply method 970 instance[options].apply(instance, args); 971 }); 972 } else { 973 return this.each(function() { 974 if (!$(this).data(pluginName)) { 975 $(this).data(pluginName, new Plugin(options, this)); 976 } 977 }); 978 } 979 }; 980})(window, document, jQuery, undefined); 981 982(function(window, document, $, Scrollbar, undefined) { 983 "use strict"; 984 985 var pluginName = 'asScrollable'; 986 var instanceId = 0; 987 988 /** 989 * Helper functions 990 **/ 991 function getTime() { 992 if (typeof window.performance !== 'undefined' && window.performance.now) { 993 return window.performance.now(); 994 } else { 995 return Date.now(); 996 } 997 } 998 999 function isPercentage(n) { 1000 return typeof n === 'string' && n.indexOf('%') != -1; 1001 } 1002 1003 function conventToPercentage(n) { 1004 if (n < 0) { 1005 n = 0; 1006 } else if (n > 1) { 1007 n = 1; 1008 } 1009 return parseFloat(n).toFixed(4) * 100 + '%'; 1010 } 1011 1012 function convertPercentageToFloat(n) { 1013 return parseFloat(n.slice(0, -1) / 100, 10); 1014 } 1015 1016 var isFFLionScrollbar = (function() { 1017 var isOSXFF, ua, version; 1018 ua = window.navigator.userAgent; 1019 isOSXFF = /(?=.+Mac OS X)(?=.+Firefox)/.test(ua); 1020 if (!isOSXFF) { 1021 return false; 1022 } 1023 version = /Firefox\/\d{2}\./.exec(ua); 1024 if (version) { 1025 version = version[0].replace(/\D+/g, ''); 1026 } 1027 return isOSXFF && +version > 23; 1028 })(); 1029 1030 var Plugin = $[pluginName] = function(options, element) { 1031 this.$element = $(element); 1032 options = this.options = $.extend({}, Plugin.defaults, options || {}, this.$element.data('options') || {}); 1033 1034 this.classes = { 1035 wrap: options.namespace, 1036 content: options.namespace + '-content', 1037 container: options.namespace + '-container', 1038 bar: options.namespace + '-bar', 1039 barHide: options.namespace + '-bar-hide', 1040 skin: options.skin 1041 }; 1042 1043 this.attributes = { 1044 vertical: { 1045 axis: 'Y', 1046 overflow: 'overflow-y', 1047 1048 scroll: 'scrollTop', 1049 scrollLength: 'scrollHeight', 1050 pageOffset: 'pageYOffset', 1051 1052 ffPadding: 'padding-right', 1053 1054 length: 'height', 1055 clientLength: 'clientHeight', 1056 offset: 'offsetHeight', 1057 1058 crossLength: 'width', 1059 crossClientLength: 'clientWidth', 1060 crossOffset: 'offsetWidth' 1061 }, 1062 horizontal: { 1063 axis: 'X', 1064 overflow: 'overflow-x', 1065 1066 scroll: 'scrollLeft', 1067 scrollLength: 'scrollWidth', 1068 pageOffset: 'pageXOffset', 1069 1070 ffPadding: 'padding-bottom', 1071 1072 length: 'width', 1073 clientLength: 'clientWidth', 1074 offset: 'offsetWidth', 1075 1076 crossLength: 'height', 1077 crossClientLength: 'clientHeight', 1078 crossOffset: 'offsetHeight' 1079 } 1080 }; 1081 1082 // Current state information. 1083 this._states = {}; 1084 1085 // Supported direction 1086 this.horizontal = null; 1087 this.vertical = null; 1088 1089 this.$bar = null; 1090 1091 // Current timeout 1092 this._frameId = null; 1093 this._timeoutId = null; 1094 1095 this.instanceId = (++instanceId); 1096 1097 this.easing = Scrollbar.easing[this.options.easing] || Scrollbar.easing.ease; 1098 1099 var position = this.$element.css('position'); 1100 if (this.options.containerSelector) { 1101 this.$container = this.$element.find(this.options.containerSelector); 1102 this.$wrap = this.$element; 1103 1104 if (position == 'static') { 1105 this.$wrap.css('position', 'relative'); 1106 } 1107 } else { 1108 this.$container = this.$element.wrap('<div>'); 1109 this.$wrap = this.$container.parent(); 1110 this.$wrap.height(this.$element.height()); 1111 1112 if (position !== 'static') { 1113 this.$wrap.css('position', position); 1114 } else { 1115 this.$wrap.css('position', 'relative'); 1116 } 1117 } 1118 1119 if (this.options.contentSelector) { 1120 this.$content = this.$container.find(this.options.contentSelector); 1121 } else { 1122 this.$content = this.$container.wrap('<div>'); 1123 this.$container = this.$content.parent(); 1124 } 1125 1126 this.init(); 1127 }; 1128 1129 Plugin.defaults = { 1130 namespace: pluginName, 1131 1132 skin: null, 1133 1134 contentSelector: null, 1135 containerSelector: null, 1136 1137 enabledClass: 'is-enabled', 1138 disabledClass: 'is-disabled', 1139 1140 draggingClass: 'is-dragging', 1141 hoveringClass: 'is-hovering', 1142 scrollingClass: 'is-scrolling', 1143 1144 direction: 'vertical', // vertical, horizontal, both, auto 1145 1146 showOnHover: true, 1147 showOnBarHover: false, 1148 1149 duration: 500, 1150 easing: 'ease-in', // linear, ease, ease-in, ease-out, ease-in-out 1151 1152 responsive: true, 1153 throttle: 20, 1154 1155 scrollbar: {} 1156 }; 1157 1158 Plugin.prototype = { 1159 constructor: Plugin, 1160 1161 init: function() { 1162 switch (this.options.direction) { 1163 case 'vertical': 1164 this.vertical = true; 1165 break; 1166 case 'horizontal': 1167 this.horizontal = true; 1168 break; 1169 case 'both': 1170 this.horizontal = true; 1171 this.vertical = true; 1172 break; 1173 case 'auto': 1174 var overflowX = this.$element.css('overflow-x'), 1175 overflowY = this.$element.css('overflow-y'); 1176 1177 if (overflowX === 'scroll' || overflowX === 'auto') { 1178 this.horizontal = true; 1179 } 1180 if (overflowY === 'scroll' || overflowY === 'auto') { 1181 this.vertical = true; 1182 } 1183 break; 1184 } 1185 1186 if (!this.vertical && !this.horizontal) { 1187 return; 1188 } 1189 1190 this.$wrap.addClass(this.classes.wrap); 1191 this.$container.addClass(this.classes.container); 1192 this.$content.addClass(this.classes.content); 1193 1194 if (this.options.skin) { 1195 this.$wrap.addClass(this.classes.skin); 1196 } 1197 1198 this.$wrap.addClass(this.options.enabledClass); 1199 1200 if (this.vertical) { 1201 this.$wrap.addClass(this.classes.wrap + '-vertical'); 1202 this.initLayout('vertical'); 1203 this.createBar('vertical'); 1204 } 1205 1206 if (this.horizontal) { 1207 this.$wrap.addClass(this.classes.wrap + '-horizontal'); 1208 this.initLayout('horizontal'); 1209 this.createBar('horizontal'); 1210 } 1211 1212 this.bindEvents(); 1213 }, 1214 1215 bindEvents: function() { 1216 var self = this; 1217 var options = this.options; 1218 1219 if (options.responsive) { 1220 $(window).on(this.eventNameWithId('orientationchange'), function() { 1221 self.update.call(self); 1222 }); 1223 $(window).on(this.eventNameWithId('resize'), this.throttle(function() { 1224 self.update.call(self); 1225 }, options.throttle)); 1226 } 1227 1228 if (!this.horizontal && !this.vertical) { 1229 return; 1230 } 1231 1232 this.$wrap.on(this.eventName('mouseenter'), function() { 1233 self.$wrap.addClass(self.options.hoveringClass); 1234 self.enter('hovering'); 1235 self.trigger('hover'); 1236 }); 1237 1238 this.$wrap.on(this.eventName('mouseleave'), function() { 1239 self.$wrap.removeClass(self.options.hoveringClass); 1240 1241 if (!self.is('hovering')) { 1242 return; 1243 } 1244 self.leave('hovering'); 1245 self.trigger('hovered'); 1246 }); 1247 1248 if (options.showOnHover) { 1249 if (options.showOnBarHover) { 1250 this.$bar.on('asScrollbar::hover', function() { 1251 self.showBar(this.direction); 1252 }).on('asScrollbar::hovered', function() { 1253 self.hideBar(this.direction); 1254 }); 1255 } else { 1256 this.$element.on(pluginName + '::hover', $.proxy(this.showBar, this)); 1257 this.$element.on(pluginName + '::hovered', $.proxy(this.hideBar, this)); 1258 } 1259 } 1260 1261 this.$container.on(this.eventName('scroll'), function() { 1262 if (self.horizontal) { 1263 var oldLeft = self.offsetLeft; 1264 self.offsetLeft = self.getOffset('horizontal'); 1265 1266 if (oldLeft !== self.offsetLeft) { 1267 self.trigger('scroll', self.getPercentOffset('horizontal'), 'horizontal'); 1268 1269 if (self.offsetLeft === 0) { 1270 self.trigger('scrolltop', 'horizontal'); 1271 } 1272 if (self.offsetLeft === self.getScrollLength('horizontal')) { 1273 self.trigger('scrollend', 'horizontal'); 1274 } 1275 } 1276 } 1277 1278 if (self.vertical) { 1279 var oldTop = self.offsetTop; 1280 1281 self.offsetTop = self.getOffset('vertical'); 1282 1283 if (oldTop !== self.offsetTop) { 1284 self.trigger('scroll', self.getPercentOffset('vertical'), 'vertical'); 1285 1286 if (self.offsetTop === 0) { 1287 self.trigger('scrolltop', 'vertical'); 1288 } 1289 if (self.offsetTop === self.getScrollLength('vertical')) { 1290 self.trigger('scrollend', 'vertical'); 1291 } 1292 } 1293 } 1294 }); 1295 1296 this.$element.on(pluginName + '::scroll', function(e, api, value, direction) { 1297 if (!self.is('scrolling')) { 1298 self.enter('scrolling'); 1299 self.$wrap.addClass(self.options.scrollingClass); 1300 } 1301 var bar = api.getBarApi(direction); 1302 1303 bar.moveTo(conventToPercentage(value), false, true); 1304 1305 clearTimeout(self._timeoutId); 1306 self._timeoutId = setTimeout(function() { 1307 self.$wrap.removeClass(self.options.scrollingClass); 1308 self.leave('scrolling'); 1309 }, 200); 1310 }); 1311 1312 this.$bar.on('asScrollbar::change', function(e, api, value) { 1313 self.scrollTo(this.direction, conventToPercentage(value), false, true); 1314 }); 1315 1316 this.$bar.on('asScrollbar::drag', function() { 1317 self.$wrap.addClass(self.options.draggingClass); 1318 }).on('asScrollbar::dragged', function() { 1319 self.$wrap.removeClass(self.options.draggingClass); 1320 }); 1321 }, 1322 1323 unbindEvents: function() { 1324 this.$wrap.off(this.eventName()); 1325 this.$element.off(pluginName + '::scroll').off(pluginName + '::hover').off(pluginName + '::hovered'); 1326 this.$container.off(this.eventName()); 1327 $(window).off(this.eventNameWithId()); 1328 }, 1329 1330 initLayout: function(direction) { 1331 if (direction === 'vertical') { 1332 this.$container.css('height', this.$wrap.height()); 1333 } 1334 var attributes = this.attributes[direction], 1335 container = this.$container[0]; 1336 1337 // this.$container.css(attributes.overflow, 'scroll'); 1338 1339 var scrollbarWidth = this.getBrowserScrollbarWidth(direction), 1340 parentLength = container.parentNode[attributes.crossClientLength]; 1341 1342 this.$content.css(attributes.crossLength, parentLength + 'px'); 1343 this.$container.css(attributes.crossLength, scrollbarWidth + parentLength + 'px'); 1344 1345 if (scrollbarWidth === 0 && isFFLionScrollbar) { 1346 this.$container.css(attributes.ffPadding, 16); 1347 } 1348 }, 1349 1350 createBar: function(direction) { 1351 var options = $.extend(this.options.scrollbar, { 1352 namespace: this.classes.bar, 1353 direction: direction, 1354 useCssTransitions: false, 1355 keyboard: false 1356 //mousewheel: false 1357 }); 1358 var $bar = $('<div>'); 1359 $bar.asScrollbar(options); 1360 1361 if (this.options.showOnHover) { 1362 $bar.addClass(this.classes.barHide); 1363 } 1364 1365 $bar.appendTo(this.$wrap); 1366 1367 this['$' + direction] = $bar; 1368 1369 if (this.$bar === null) { 1370 this.$bar = $bar; 1371 } else { 1372 this.$bar = this.$bar.add($bar); 1373 } 1374 1375 this.updateBarHandle(direction); 1376 }, 1377 1378 trigger: function(eventType) { 1379 var method_arguments = Array.prototype.slice.call(arguments, 1), 1380 data = [this].concat(method_arguments); 1381 1382 // event 1383 this.$element.trigger(pluginName + '::' + eventType, data); 1384 1385 // callback 1386 eventType = eventType.replace(/\b\w+\b/g, function(word) { 1387 return word.substring(0, 1).toUpperCase() + word.substring(1); 1388 }); 1389 var onFunction = 'on' + eventType; 1390 1391 if (typeof this.options[onFunction] === 'function') { 1392 this.options[onFunction].apply(this, method_arguments); 1393 } 1394 }, 1395 1396 /** 1397 * Checks whether the carousel is in a specific state or not. 1398 */ 1399 is: function(state) { 1400 return this._states[state] && this._states[state] > 0; 1401 }, 1402 1403 /** 1404 * Enters a state. 1405 */ 1406 enter: function(state) { 1407 if (this._states[state] === undefined) { 1408 this._states[state] = 0; 1409 } 1410 1411 this._states[state] ++; 1412 }, 1413 1414 /** 1415 * Leaves a state. 1416 */ 1417 leave: function(state) { 1418 this._states[state] --; 1419 }, 1420 1421 eventName: function(events) { 1422 if (typeof events !== 'string' || events === '') { 1423 return '.' + this.options.namespace; 1424 } 1425 1426 events = events.split(' '); 1427 var length = events.length; 1428 for (var i = 0; i < length; i++) { 1429 events[i] = events[i] + '.' + this.options.namespace; 1430 } 1431 return events.join(' '); 1432 }, 1433 1434 eventNameWithId: function(events) { 1435 if (typeof events !== 'string' || events === '') { 1436 return this.options.namespace + '-' + this.instanceId; 1437 } 1438 1439 events = events.split(' '); 1440 var length = events.length; 1441 for (var i = 0; i < length; i++) { 1442 events[i] = events[i] + '.' + this.options.namespace + '-' + this.instanceId; 1443 } 1444 return events.join(' '); 1445 }, 1446 1447 /** 1448 * _throttle
1449 * @description Borrowed from Underscore.js 1450 */ 1451 throttle: function(func, wait) { 1452 var _now = Date.now || function() { 1453 return new Date().getTime(); 1454 }; 1455 var context, args, result; 1456 var timeout = null; 1457 var previous = 0; 1458 var later = function() { 1459 previous = _now(); 1460 timeout = null; 1461 result = func.apply(context, args); 1462 context = args = null; 1463 }; 1464 return function() { 1465 var now = _now(); 1466 var remaining = wait - (now - previous); 1467 context = this; 1468 args = arguments; 1469 if (remaining <= 0) { 1470 clearTimeout(timeout); 1471 timeout = null; 1472 previous = now; 1473 result = func.apply(context, args); 1474 context = args = null; 1475 } else if (!timeout) { 1476 timeout = setTimeout(later, remaining); 1477 } 1478 return result; 1479 }; 1480 }, 1481 1482 getBrowserScrollbarWidth: function(direction) { 1483 var attributes = this.attributes[direction], 1484 outer, outerStyle; 1485 if (attributes.scrollbarWidth) { 1486 return attributes.scrollbarWidth; 1487 } 1488 outer = document.createElement('div'); 1489 outerStyle = outer.style; 1490 outerStyle.position = 'absolute'; 1491 outerStyle.width = '100px'; 1492 outerStyle.height = '100px'; 1493 outerStyle.overflow = 'scroll'; 1494 outerStyle.top = '-9999px'; 1495 document.body.appendChild(outer); 1496 attributes.scrollbarWidth = outer[attributes.offset] - outer[attributes.clientLength]; 1497 document.body.removeChild(outer); 1498 return attributes.scrollbarWidth; 1499 }, 1500 1501 getOffset: function(direction) { 1502 var attributes = this.attributes[direction], 1503 container = this.$container[0]; 1504 1505 return (container[attributes.pageOffset] || container[attributes.scroll]); 1506 }, 1507 1508 getPercentOffset: function(direction) { 1509 return this.getOffset(direction) / this.getScrollLength(direction); 1510 }, 1511 1512 getContainerLength: function(direction) { 1513 return this.$container[0][this.attributes[direction].clientLength]; 1514 }, 1515 1516 getScrollLength: function(direction) { 1517 var scrollLength = this.$content[0][this.attributes[direction].scrollLength]; 1518 return scrollLength - this.getContainerLength(direction); 1519 }, 1520 1521 scrollTo: function(direction, value, trigger, sync) { 1522 var type = typeof value; 1523 1524 if (type === "string") { 1525 if (isPercentage(value)) { 1526 value = convertPercentageToFloat(value) * this.getScrollLength(direction); 1527 } 1528 1529 value = parseFloat(value); 1530 type = "number"; 1531 } 1532 1533 if (type !== "number") { 1534 return; 1535 } 1536 1537 this.move(direction, value, trigger, sync); 1538 }, 1539 1540 scrollBy: function(direction, value, trigger, sync) { 1541 var type = typeof value; 1542 1543 if (type === "string") { 1544 if (isPercentage(value)) { 1545 value = convertPercentageToFloat(value) * this.getScrollLength(direction); 1546 } 1547 1548 value = parseFloat(value); 1549 type = "number"; 1550 } 1551 1552 if (type !== "number") { 1553 return; 1554 } 1555 1556 this.move(direction, this.getOffset(direction) + value, trigger, sync); 1557 }, 1558 1559 move: function(direction, value, trigger, sync) { 1560 if (this[direction] !== true || typeof value !== "number") { 1561 return; 1562 } 1563 var self = this; 1564 1565 this.enter('moving'); 1566 1567 if (value < 0) { 1568 value = 0; 1569 } else if (value >
1569 this.getScrollLength(direction)) { 1570 value = this.getScrollLength(direction); 1571 } 1572 1573 var attributes = this.attributes[direction]; 1574 1575 var callback = function() { 1576 self.leave('moving'); 1577 } 1578 1579 if (sync) { 1580 this.$container[0][attributes.scroll] = value; 1581 1582 if (trigger !== false) { 1583 this.trigger('change', value / this.getScrollLength(direction)); 1584 } 1585 callback(); 1586 } else { 1587 self.enter('animating'); 1588 var startTime = getTime(); 1589 var start = self.getOffset(direction); 1590 var end = value; 1591 1592 var run = function(time) { 1593 var percent = (time - startTime) / self.options.duration; 1594 1595 if (percent > 1) { 1596 percent = 1; 1597 } 1598 1599 percent = self.easing.fn(percent); 1600 1601 var current = parseFloat(start + percent * (end - start), 10); 1602 self.$container[0][attributes.scroll] = current; 1603 1604 if (trigger !== false) { 1605 self.trigger('change', value / self.getScrollLength(direction)); 1606 } 1607 1608 if (percent === 1) { 1609 window.cancelAnimationFrame(self._frameId); 1610 self._frameId = null; 1611 1612 self.leave('animating'); 1613 callback(); 1614 } else { 1615 self._frameId = window.requestAnimationFrame(run); 1616 } 1617 }; 1618 1619 self._frameId = window.requestAnimationFrame(run); 1620 } 1621 }, 1622 1623 scrollXto: function(value, trigger, sync) { 1624 return this.scrollTo('horizontal', value, trigger, sync); 1625 }, 1626 1627 scrollYto: function(value, trigger, sync) { 1628 return this.scrollTo('vertical', value, trigger, sync); 1629 }, 1630 1631 scrollXby: function(value, trigger, sync) { 1632 return this.scrollBy('horizontal', value, trigger, sync); 1633 }, 1634 1635 scrollYby: function(value, trigger, sync) { 1636 return this.scrollBy('vertical', value, trigger, sync); 1637 }, 1638 1639 getBar: function(direction) { 1640 if (direction && this['$' + direction]) { 1641 return this['$' + direction]; 1642 } else { 1643 return this.$bar; 1644 } 1645 }, 1646 1647 getBarApi: function(direction) { 1648 return this.getBar(direction).data('asScrollbar'); 1649 }, 1650 1651 getBarX: function() { 1652 return this.getBar('horizontal'); 1653 }, 1654 1655 getBarY: function() { 1656 return this.getBar('vertical'); 1657 }, 1658 1659 showBar: function(direction) { 1660 this.getBar(direction).removeClass(this.classes.barHide); 1661 }, 1662 1663 hideBar: function(direction) { 1664 this.getBar(direction).addClass(this.classes.barHide); 1665 }, 1666 1667 updateBarHandle: function(direction) { 1668 var api = this.getBarApi(direction); 1669 1670 var scrollLength = this.getScrollLength(direction), 1671 containerLength = this.getContainerLength(direction); 1672 1673 if (scrollLength > 0) { 1674 if (api.is('disabled')) { 1675 api.enable(); 1676 } 1677 api.setHandleLength(api.getBarLength() * containerLength / (scrollLength + containerLength), true); 1678 } else { 1679 api.disable(); 1680 } 1681 }, 1682 1683 disable: function() { 1684 if (!this.is('disabled')) { 1685 this.enter('disabled'); 1686 this.$wrap.addClass(this.options.disabledClass).removeClass(this.options.enabledClass); 1687 1688 this.unbindEvents(); 1689 this.unStyle(); 1690 } 1691 }, 1692 1693 enable: function() { 1694 if (this.is('disabled')) { 1695 this.leave('disabled'); 1696 this.$wrap.addClass(this.options.enabledClass).removeClass(this.options.disabledClass); 1697 1698 this.bindEvents(); 1699 this.update(); 1700 } 1701 }, 1702 1703 update: function() { 1704 if (this.is('disabled')) { 1705 return; 1706 } 1707 if (this.vertical) { 1708 this.initLayout('vertical'); 1709 this.updateBarHandle('vertical'); 1710 } 1711 if (this.horizontal) { 1712 this.initLayout('horizontal'); 1713 this.updateBarHandle('horizontal'); 1714 } 1715 }, 1716 unStyle: function() { 1717 if (this.horizontal) { 1718 this.$container.css({ 1719 'height': '', 1720 'padding-bottom': '' 1721 }); 1722 this.$content.css({ 1723 'height': '' 1724 }); 1725 } 1726 if (this.vertical) { 1727 this.$container.css({ 1728 'width': '', 1729 'height': '', 1730 'padding-right': '' 1731 }); 1732 this.$content.css({ 1733 'width': '' 1734 }); 1735 } 1736 if (!this.options.containerSelector) { 1737 this.$wrap.css({ 1738 'height': '' 1739 }); 1740 } 1741 }, 1742 1743 destory: function() { 1744 this.$wrap.removeClass(this.classes.wrap + '-vertical') 1745 .removeClass(this.classes.wrap + '-horizontal') 1746 .removeClass(this.classes.wrap) 1747 .removeClass(this.options.enabledClass) 1748 .removeClass(this.classes.disabledClass); 1749 this.unStyle(); 1750 1751 if (this.$bar) { 1752 this.$bar.remove(); 1753 } 1754 1755 this.unbindEvents(); 1756 1757 1758 if (this.options.containerSelector) { 1759 this.$container.removeClass(this.classes.container); 1760 } else { 1761 this.$container.unwrap(); 1762 } 1763 if (!this.options.contentSelector) { 1764 this.$content.unwrap(); 1765 } 1766 this.$content.removeClass(this.classes.content); 1767 this.$element.data(pluginName, null); 1768 } 1769 } 1770 1771 $.fn[pluginName] = function(options) { 1772 if (typeof options === 'string') { 1773 var method = options; 1774 var method_arguments = Array.prototype.slice.call(arguments, 1); 1775 1776 if (/^\_/.test(method)) { 1777 return false;
1778 } else if ((/^(get)/.test(method))) { 1779 var api = this.first().data(pluginName); 1780 if (api && typeof api[method] === 'function') { 1781 return api[method].apply(api, method_arguments); 1782 } 1783 } else { 1784 return this.each(function() { 1785 var api = $.data(this, pluginName); 1786 if (api && typeof api[method] === 'function') { 1787 api[method].apply(api, method_arguments); 1788 } 1789 }); 1790 } 1791 } else { 1792 return this.each(function() { 1793 if (!$(this).data(pluginName)) { 1794 $(this).data(pluginName, new Plugin(options, this)); 1795 } else { 1796 $(this).data(pluginName).update(); 1797 } 1798 }); 1799 } 1800 return this; 1801 }; 1802 1803})(window, document, jQuery, (function($) { 1804 "use strict" 1805 if ($.asScrollbar === undefined) { 1806 // console.info('lost dependency lib of $.asScrollbar , please load it first !'); 1807 return false; 1808 } else { 1809 return $.asScrollbar; 1810 } 1811}(jQuery)));
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.