1/** 2 * Copyright (c) 2013-present, Guido Bouman 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 */ 7 8/* global jQuery */ 9 10// Utility for creating objects in older browsers 11if (typeof Object.create !== 'function') { 12 Object.create = function (obj) { 13 function F() { } 14 F.prototype = obj; 15 return new F(); 16 }; 17} 18 19/*! 20 * jQuery panelSnap 21 * Version 0.15.1 22 * 23 * Requires: 24 * - jQuery 1.7 or higher (no jQuery.migrate needed) 25 * 26 * https://github.com/guidobouman/jquery-panelsnap 27 */ 28(function ($, window, document) { 29 'use strict'; 30 31 var pluginName = 'panelSnap'; 32 var storageName = 'plugin_' + pluginName; 33 34 var pluginObject = { 35 36 isMouseDown: false, 37 isSnapping: false, 38 enabled: true, 39 scrollOffset: 0, 40 41 init: function (options, container) { 42 var self = this; 43 44 self.container = container; 45 self.$container = $(container); 46 47 self.$eventContainer = self.$container; 48 self.$snapContainer = self.$container; 49 50 if (self.$container.is('body')) { 51 self.$eventContainer = $(document); 52 self.$snapContainer = $(document.scrollingElement || document.documentElement); 53 54 var ua = navigator.userAgent; 55 if (ua.indexOf('WebKit') !== -1 && ua.indexOf('Chrome') === -1) { 56 self.$snapContainer = $('body'); 57 } 58 } 59 60 self.options = $.extend(true, {}, $.fn.panelSnap.options, options); 61 62 self.bind(); 63 64 if (self.options.$menu !== false && $('.active', self.options.$menu).length > 0) { 65 $('.active', self.options.$menu).click(); 66 } else { 67 var $target = self.getPanel(':first'); 68 self.activatePanel($target); 69 } 70 71 return self; 72 }, 73 74 bind: function () { 75 var self = this; 76 77 self.bindProxied(self.$eventContainer, 'scrollstop', self.scrollStop); 78 self.bindProxied(self.$eventContainer, 'mousewheel', self.mouseWheel); 79 self.bindProxied(self.$eventContainer, 'mousedown', self.mouseDown); 80 self.bindProxied(self.$eventContainer, 'mouseup', self.mouseUp); 81 82 self.bindProxied($(window), 'resizestop', self.resize); 83 84 if (self.options.$menu) { 85 self.bindProxied(self.options.$menu, 'click', self.captureMenuClick, self.options.menuSelector); 86 } 87 88 if (self.options.navigation.keys.nextKey || self.options.navigation.keys.prevKey) { 89 self.bindProxied($(window), 'keydown', self.keyDown); 90 } 91 92 if (self.options.navigation.buttons.$nextButton) { 93 self.bindProxied(self.options.navigation.buttons.$nextButton, 'click', self.captureNextClick); 94 } 95 96 if (self.options.navigation.buttons.$prevButton) { 97 self.bindProxied(self.options.navigation.buttons.$prevButton, 'click', self.capturePrevClick); 98 } 99 }, 100 101 bindProxied: function ($element, event, method, selector) { 102 var self = this; 103 104 selector = typeof selector === 'string' ? selector : null; 105 106 $element.on(event + self.options.namespace, selector, $.proxy(function (e) { 107 return method.call(self, e); 108 }, self)); 109 }, 110 111 destroy: function () { 112 var self = this; 113 114 // Gotta love namespaced events! 115 self.$eventContainer.off(self.options.namespace); 116 117 $(window).off(self.options.namespace); 118 119 if (self.options.$menu !== false) { 120 $(self.options.menuSelector, self.options.$menu).off(self.options.namespace); 121 } 122 123 self.$container.removeData(storageName); 124 }, 125 126 scrollStop: function (e) { 127 var self = this; 128 var $target; 129 130 e.stopPropagation(); 131 132 if (self.isMouseDown) { 133 return; 134 } 135 136 if (self.isSnapping) { 137 return; 138 } 139 140 // Check if enabled or just 1 panel in viewport 141 var panelsInViewPort = self.getPanelsInViewport(); 142 if (!self.enabled || panelsInViewPort.length < 2) { 143 $target = panelsInViewPort.eq(0); 144 if (!$target.is(self.getPanel('.active'))) { 145 self.activatePanel($target); 146 } 147 148 return; 149 } 150 151 var offset = self.$snapContainer.scrollTop(); 152 var scrollDifference = offset - self.scrollOffset; 153 var overThreshold = Math.abs(scrollDifference) > self.options.directionThreshold; 154 155 var panelNumber; 156 if (scrollDifference > 0) { 157 panelNumber = overThreshold ? 1 : 0; 158 } else if (scrollDifference < 0) { 159 panelNumber = overThreshold ? 0 : 1; 160 } else { 161 // Nothing to scroll, get out. 162 return; 163 } 164 165 $target = panelsInViewPort.eq(panelNumber); 166 167 var maxOffset = self.$container[0].scrollHeight - self.scrollInterval; 168 if (offset <= 0 || offset >= maxOffset) { 169 // Only activate, prevent stuttering 170 self.activatePanel($target); 171 // Set scrollOffset to a sane number for next scroll 172 self.scrollOffset = offset <= 0 ? 0 : maxOffset; 173 } else { 174 self.snapToPanel($target); 175 } 176 }, 177 178 getPanelsInViewport: function () { 179 var self = this; 180 181 var viewport = { top: self.$snapContainer.scrollTop() }; 182 viewport.bottom = viewport.top + self.$snapContainer.height(); 183 184 var panels = self.getPanel().filter(function (_, el) { 185 var $el = $(el); 186 var bounds; 187 188 if (self.$container.is('body')) { 189 bounds = $el.offset(); 190 } else { 191 bounds = $el.position(); 192 bounds.top += self.$snapContainer.scrollTop(); 193 } 194 195 bounds.bottom = bounds.top + $el.outerHeight(); 196 197 return !(viewport.bottom < bounds.top || viewport.top > bounds.bottom); 198 }); 199 200 return panels; 201 }, 202 203 mouseWheel: function () { 204 var self = this; 205 206 // This event only fires when the user actually scrolls with their input device. 207 // Be it a trackpad, legacy mouse or anything else. 208 209 if (self.isSnapping) { 210 self.scrollOffset = self.$snapContainer.scrollTop(); 211 self.$snapContainer.stop(true); 212 self.isSnapping = false;
213 } 214 }, 215 216 mouseDown: function () { 217 var self = this; 218 219 self.isMouseDown = true; 220 }, 221 222 mouseUp: function (e) { 223 var self = this; 224 225 self.isMouseDown = false; 226 227 if (self.scrollOffset !== self.$snapContainer.scrollTop()) { 228 self.scrollStop(e); 229 } 230 }, 231 232 keyDown: function (e) { 233 var self = this; 234 235 var nav = self.options.navigation; 236 237 if (!self.enabled) { 238 return; 239 } 240 241 switch (e.which) { 242 case nav.keys.prevKey: 243 case nav.keys.nextKey: 244 e.preventDefault(); 245 break; 246 247 // no default 248 } 249 250 if (self.isSnapping) { 251 return; 252 } 253 254 switch (e.which) { 255 case nav.keys.prevKey: 256 self.snapTo('prev', nav.wrapAround); 257 break; 258 259 case nav.keys.nextKey: 260 self.snapTo('next', nav.wrapAround); 261 break; 262 263 // no default 264 } 265 }, 266 267 captureNextClick: function (e) { 268 var self = this; 269 270 e.preventDefault(); 271 272 if (self.isSnapping) { 273 return; 274 } 275 276 self.snapTo('next', self.options.navigation.wrapAround); 277 }, 278 279 capturePrevClick: function (e) { 280 var self = this; 281 282 e.preventDefault(); 283 284 if (self.isSnapping) { 285 return; 286 } 287 288 self.snapTo('prev', self.options.navigation.wrapAround); 289 }, 290 291 resize: function () { 292 var self = this; 293 294 if (!self.enabled) { 295 return; 296 } 297 298 var $target = self.getPanel('.active'); 299 300 self.snapToPanel($target); 301 }, 302 303 captureMenuClick: function (e) { 304 var self = this; 305 306 var panel = $(e.currentTarget).data('panel'); 307 var $target = self.getPanel('[data-panel="' + panel + '"]'); 308 309 self.snapToPanel($target); 310 311 return false; 312 }, 313 314 snapToPanel: function ($target) { 315 var self = this; 316 317 if (!$target.jquery) { 318 return; 319 } 320 321 self.isSnapping = true; 322 323 self.options.onSnapStart.call(self, $target); 324 self.$container.trigger('panelsnap:start', [$target]); 325 326 var scrollTarget = 0; 327 if (self.$container.is('body')) { 328 scrollTarget = $target.offset().top; 329 } else { 330 scrollTarget = self.$snapContainer.scrollTop() + $target.position().top; 331 } 332 333 scrollTarget -= self.options.offset; 334 335 var isScrollingUp = self.scrollOffset > scrollTarget; 336 var isLargeTarget = $target.outerHeight() > self.$snapContainer.outerHeight(); 337 if (isScrollingUp && isLargeTarget) { 338 // Snap to bottom of target 339 scrollTarget += $target.outerHeight(); 340 scrollTarget -= self.$snapContainer.outerHeight(); 341 } 342 343 self.$snapContainer.stop(true).delay(self.options.delay).animate({ 344 scrollTop: scrollTarget 345 }, self.options.slideSpeed, self.options.easing, function () { 346 // Set scrollOffset to scrollTop 347 // (not to scrollTarget since on iPad those sometimes differ) 348 self.scrollOffset = self.$snapContainer.scrollTop(); 349 self.isSnapping = false; 350 351 // Call callback 352 self.options.onSnapFinish.call(self, $target); 353 self.$container.trigger('panelsnap:finish', [$target]); 354 355 self.activatePanel($target); 356 }); 357 }, 358 359 activatePanel: function ($target) { 360 var self = this; 361 362 self.getPanel('.active').removeClass('active'); 363 $target.addClass('active'); 364 365 if (self.options.$menu !== false) { 366 var activeItemSelector = self.options.menuSelector + '.active'; 367 $(activeItemSelector, self.options.$menu).removeClass('active'); 368 369 var attribute = '[data-panel="' + $target.data('panel') + '"]'; 370 var itemSelector = self.options.menuSelector + attribute; 371 var $itemToActivate = $(itemSelector, self.options.$menu); 372 $itemToActivate.addClass('active'); 373 } 374 375 var nav = self.options.navigation; 376 377 if (!nav.wrapAround) { 378 var $panels = self.getPanel(); 379 var index = $panels.index(self.getPanel('.active')); 380 381 if (nav.buttons.$nextButton !== false) { 382 $target = $panels.eq(index + 1); 383 if ($target.length < 1) { 384 $(nav.buttons.$nextButton).attr('aria-disabled', 'true'); 385 $(nav.buttons.$nextButton).addClass('disabled'); 386 } else { 387 $(nav.buttons.$nextButton).attr('aria-disabled', 'false'); 388 $(nav.buttons.$nextButton).removeClass('disabled'); 389 } 390 } 391 392 if (nav.buttons.$prevButton !== false) { 393 if (index < 1) { 394 $(nav.buttons.$prevButton).attr('aria-disabled', 'true'); 395 $(nav.buttons.$prevButton).addClass('disabled'); 396 } else { 397 $(nav.buttons.$prevButton).attr('aria-disabled', 'false'); 398 $(nav.buttons.$prevButton).removeClass('disabled'); 399 } 400 } 401 } 402 403 self.options.onActivate.call(self, $target); 404 self.$container.trigger('panelsnap:activate', [$target]); 405 }, 406 407 getPanel: function (selector) { 408 var self = this; 409 410 if (typeof selector === 'undefined') { 411 selector = ''; 412 } 413 414 return $(self.options.panelSelector + selector, self.$container); 415 }, 416 417 snapTo: function (target, wrap) { 418 var self = this; 419 420 if (typeof wrap !== 'boolean') { 421 wrap = true; 422 } 423 424 var $panels = self.getPanel(); 425 var index = $panels.index(self.getPanel('.active')); 426 var $target; 427 428 switch (target) { 429 case 'prev': 430 $target = $panels.eq(index - 1); 431 if (index < 1 && !wrap) { 432 $target = []; // Clear target, because negative indexes wrap automatically 433 } 434 break; 435 436 case 'next': 437 $target = $panels.eq(index + 1); 438 if ($target.length < 1 && wrap) { 439 $target = $panels.filter(':first'); 440 } 441 break; 442 443 case 'first': 444 $target = $panels.filter(':first'); 445 break; 446 447 case 'last': 448 $target = $panels.filter(':last'); 449 break; 450 451 // no default 452 } 453 454 if ($target.length > 0) { 455 self.snapToPanel($target); 456 } 457 }, 458 459 enable: function () { 460 var self = this; 461 462 // Gather scrollOffset for next scroll 463 self.scrollOffset = self.$snapContainer.scrollTop(); 464 465 self.enabled = true; 466 }, 467 468 disable: function () { 469 var self = this; 470 471 self.enabled = false;
472 }, 473 474 toggle: function () { 475 var self = this; 476 477 if (self.enabled) { 478 self.disable(); 479 } else { 480 self.enable(); 481 } 482 } 483 484 }; 485 486 $.fn[pluginName] = function (options) { 487 var args = Array.prototype.slice.call(arguments); 488 489 return this.each(function () { 490 var pluginInstance = $.data(this, storageName); 491 if (typeof options === 'object' || options === 'init' || !options) { 492 if (!pluginInstance) { 493 if (options === 'init') { 494 options = args[1] || {}; 495 } 496 497 pluginInstance = Object.create(pluginObject).init(options, this); 498 $.data(this, storageName, pluginInstance); 499 } else { 500 $.error('Plugin is already initialized for this object.'); 501 } 502 } else if (!pluginInstance) { 503 $.error('Plugin is not initialized for this object yet.'); 504 } else if (pluginInstance[options]) { 505 var method = options; 506 options = args.slice(1); 507 pluginInstance[method].apply(pluginInstance, options); 508 } else { 509 $.error('Method ' + options + ' does not exist on jQuery.panelSnap.'); 510 } 511 }); 512 }; 513 514 $.fn[pluginName].options = { 515 $menu: false, 516 menuSelector: 'a', 517 panelSelector: '> section', 518 namespace: '.panelSnap', 519 onSnapStart: function () { }, 520 onSnapFinish: function () { }, 521 onActivate: function () { }, 522 directionThreshold: 50, 523 slideSpeed: 200, 524 delay: 0, 525 easing: 'linear', 526 offset: 0, 527 navigation: { 528 keys: { 529 nextKey: false, 530 prevKey: false 531 }, 532 buttons: {
533 $nextButton: false, 534 $prevButton: false 535 }, 536 wrapAround: false 537 } 538 }; 539}(jQuery, window, document)); 540 541/*! 542 * Special flavoured jQuery Mobile scrollstart & scrollstop events. 543 * Version 0.1.3 544 * 545 * Requires: 546 * - jQuery 1.7.1 or higher (no jQuery.migrate needed) 547 */ 548(function ($) { 549 // Also handles the scrollstop event 550 $.event.special.scrollstart = { 551 552 enabled: true, 553 554 setup: function () { 555 var thisObject = this; 556 var $this = $(thisObject); 557 var timer; 558 var isTouching; 559 560 $this.data('scrollwatch', true); 561 562 function trigger(event, scrolling) { 563 event.type = scrolling ? 'scrollstart' : 'scrollstop'; 564 $this.trigger(event); 565 } 566 567 $this.on('touchstart', function () { 568 isTouching = true; 569 }); 570 571 $this.on('touchleave touchcancel touchend', function () { 572 isTouching = false; 573 setTimeout(function () { 574 clearTimeout(timer); 575 }, 50); 576 }); 577 578 $this.on('touchmove scroll', function (event) { 579 if (isTouching) { 580 return; 581 } 582 583 if (!$.event.special.scrollstart.enabled) { 584 return; 585 } 586 587 if (!$.event.special.scrollstart.scrolling) { 588 $.event.special.scrollstart.scrolling = true; 589 trigger(event, true); 590 } 591 592 clearTimeout(timer); 593 timer = setTimeout(function () { 594 $.event.special.scrollstart.scrolling = false; 595 trigger(event, false); 596 }, 50); 597 }); 598 } 599 600 }; 601 602 // Proxies scrollstart when needed 603 $.event.special.scrollstop = { 604 605 setup: function () { 606 var thisObject = this; 607 var $this = $(thisObject); 608 609 if (!$this.data('scrollwatch')) { 610 $(this).on('scrollstart', function () { }); 611 } 612 } 613 614 }; 615}(jQuery)); 616 617/*! 618 * Resizestart and resizestop events. 619 * Version 0.0.1 620 * 621 * Requires: 622 * - jQuery 1.7.1 or higher (no jQuery.migrate needed) 623 */ 624(function ($) { 625 // Also handles the resizestop event 626 $.event.special.resizestart = { 627 628 enabled: true, 629 630 setup: function () { 631 var thisObject = this; 632 var $this = $(thisObject); 633 var timer; 634 635 $this.data('resizewatch', true); 636 637 function trigger(event, resizing) { 638 event.type = resizing ? 'resizestart' : 'resizestop'; 639 $this.trigger(event); 640 } 641 642 $this.on('resize', function (event) { 643 if (!$.event.special.resizestart.enabled) { 644 return; 645 } 646 647 if (!$.event.special.resizestart.resizing) { 648 $.event.special.resizestart.resizing = true; 649 trigger(event, true); 650 } 651 652 clearTimeout(timer); 653 timer = setTimeout(function () { 654 $.event.special.resizestart.resizing = false; 655 trigger(event, false); 656 }, 200); 657 }); 658 } 659 660 }; 661 662 // Proxies resizestart when needed 663 $.event.special.resizestop = { 664 665 setup: function () { 666 var thisObject = this; 667 var $this = $(thisObject); 668 669 if (!$this.data('resizewatch')) { 670 $(this).on('resizestart', function () { }); 671 } 672 } 673 674 }; 675}(jQuery)); 676 677/* eslint-disable */ 678 679/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) 680 * Licensed under the MIT License (LICENSE.txt). 681 * 682 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. 683 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. 684 * Thanks to: Seamus Leahy for adding deltaX and deltaY 685 * 686 * Version: 3.0.6 687 * 688 * Requires: 1.2.2+ 689 */ 690(function ($) { 691 692 var types = ['DOMMouseScroll', 'mousewheel']; 693 694 if ($.event.fixHooks) { 695 for (var i = types.length; i;) { 696 $.event.fixHooks[types[--i]] = $.event.mouseHooks; 697 } 698 } 699 700 $.event.special.mousewheel = { 701 setup: function () { 702 if (this.addEventListener) { 703 for (var i = types.length; i;) { 704 this.addEventListener(types[--i], handler, false); 705 } 706 } else { 707 this.onmousewheel = handler; 708 } 709 }, 710 711 teardown: function () { 712 if (this.removeEventListener) { 713 for (var i = types.length; i;) { 714 this.removeEventListener(types[--i], handler, false); 715 } 716 } else { 717 this.onmousewheel = null; 718 } 719 } 720 }; 721 722 $.fn.extend({ 723 mousewheel: function (fn) { 724 return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); 725 }, 726 727 unmousewheel: function (fn) { 728 return this.unbind('mousewheel', fn); 729 } 730 }); 731 732 function handler(event) { 733 var orgEvent = event || window.event, 734 args = [].slice.call(arguments, 1), 735 delta = 0, 736 returnValue = true, 737 deltaX = 0, 738 deltaY = 0; 739 740 event = $.event.fix(orgEvent); 741 event.type = 'mousewheel'; 742 743 // Old school scrollwheel delta 744 if (orgEvent.wheelDelta) { delta = orgEvent.wheelDelta / 120; } 745 if (orgEvent.detail) { delta = -orgEvent.detail / 3; } 746 747 // New school multidimensional scroll (touchpads) deltas 748 deltaY = delta; 749 750 // Gecko 751 if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) { 752 deltaY = 0; 753 deltaX = -1 * delta; 754 } 755 756 // Webkit 757 if (orgEvent.wheelDeltaY !== undefined) { deltaY = orgEvent.wheelDeltaY / 120; } 758 if (orgEvent.wheelDeltaX !== undefined) { deltaX = -1 * orgEvent.wheelDeltaX / 120; } 759 760 // Add event and delta to the front of the arguments 761 args.unshift(event, delta, deltaX, deltaY); 762 763 return ($.event.dispatch || $.event.handle).apply(this, args); 764 } 765 766})(jQuery); 767/* eslint-enable */
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.