[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('scrollview-paginator', function (Y, NAME) { 9 10 /** 11 * Provides a plugin that adds pagination support to ScrollView instances 12 * 13 * @module scrollview-paginator 14 */ 15 var getClassName = Y.ClassNameManager.getClassName, 16 SCROLLVIEW = 'scrollview', 17 CLASS_HIDDEN = getClassName(SCROLLVIEW, 'hidden'), 18 CLASS_PAGED = getClassName(SCROLLVIEW, 'paged'), 19 UI = (Y.ScrollView) ? Y.ScrollView.UI_SRC : 'ui', 20 INDEX = 'index', 21 SCROLL_X = 'scrollX', 22 SCROLL_Y = 'scrollY', 23 TOTAL = 'total', 24 DISABLED = 'disabled', 25 HOST = 'host', 26 SELECTOR = 'selector', 27 AXIS = 'axis', 28 DIM_X = 'x', 29 DIM_Y = 'y'; 30 31 /** 32 * Scrollview plugin that adds support for paging 33 * 34 * @class ScrollViewPaginator 35 * @namespace Plugin 36 * @extends Plugin.Base 37 * @constructor 38 */ 39 function PaginatorPlugin() { 40 PaginatorPlugin.superclass.constructor.apply(this, arguments); 41 } 42 43 Y.extend(PaginatorPlugin, Y.Plugin.Base, { 44 45 /** 46 * Designated initializer 47 * 48 * @method initializer 49 * @param {Object} Configuration object for the plugin 50 */ 51 initializer: function (config) { 52 var paginator = this, 53 host = paginator.get(HOST); 54 55 // Initialize & default 56 paginator._pageDims = []; 57 paginator._pageBuffer = 1; 58 paginator._optimizeMemory = false; 59 60 // Cache some values 61 paginator._host = host; 62 paginator._bb = host._bb; 63 paginator._cb = host._cb; 64 paginator._cIndex = paginator.get(INDEX); 65 paginator._cAxis = paginator.get(AXIS); 66 67 // Apply configs 68 if (config._optimizeMemory) { 69 paginator._optimizeMemory = config._optimizeMemory; 70 } 71 72 if (config._pageBuffer) { 73 paginator._pageBuffer = config._pageBuffer; 74 } 75 76 // Attach event bindings 77 paginator._bindAttrs(); 78 }, 79 80 /** 81 * 82 * 83 * @method _bindAttrs 84 * @private 85 */ 86 _bindAttrs: function () { 87 var paginator = this; 88 89 // Event listeners 90 paginator.after({ 91 'indexChange': paginator._afterIndexChange, 92 'axisChange': paginator._afterAxisChange 93 }); 94 95 // Host method listeners 96 paginator.beforeHostMethod('scrollTo', paginator._beforeHostScrollTo); 97 paginator.beforeHostMethod('_mousewheel', paginator._beforeHostMousewheel); 98 paginator.beforeHostMethod('_flick', paginator._beforeHostFlick); 99 paginator.afterHostMethod('_onGestureMoveEnd', paginator._afterHostGestureMoveEnd); 100 paginator.afterHostMethod('_uiDimensionsChange', paginator._afterHostUIDimensionsChange); 101 paginator.afterHostMethod('syncUI', paginator._afterHostSyncUI); 102 103 // Host event listeners 104 paginator.afterHostEvent('render', paginator._afterHostRender); 105 paginator.afterHostEvent('scrollEnd', paginator._afterHostScrollEnded); 106 }, 107 108 /** 109 * After host render 110 * 111 * @method _afterHostRender 112 * @param e {EventFacade} The event facade 113 * @protected 114 */ 115 _afterHostRender: function () { 116 var paginator = this, 117 bb = paginator._bb, 118 host = paginator._host, 119 index = paginator._cIndex, 120 paginatorAxis = paginator._cAxis, 121 pageNodes = paginator._getPageNodes(), 122 size = pageNodes.size(), 123 pageDim = paginator._pageDims[index]; 124 125 if (paginatorAxis[DIM_Y]) { 126 host._maxScrollX = pageDim.maxScrollX; 127 } 128 else if (paginatorAxis[DIM_X]) { 129 host._maxScrollY = pageDim.maxScrollY; 130 } 131 132 // Set the page count 133 paginator.set(TOTAL, size); 134 135 // Jump to the index 136 if (index !== 0) { 137 paginator.scrollToIndex(index, 0); 138 } 139 140 // Add the paginator class 141 bb.addClass(CLASS_PAGED); 142 143 // Trigger the optimization process 144 paginator._optimize(); 145 }, 146 147 /** 148 * After host syncUI 149 * 150 * @method _afterHostSyncUI 151 * @param e {EventFacade} The event facade 152 * @protected 153 */ 154 _afterHostSyncUI: function () { 155 var paginator = this, 156 host = paginator._host, 157 pageNodes = paginator._getPageNodes(), 158 size = pageNodes.size(); 159 160 // Set the page count 161 paginator.set(TOTAL, size); 162 163 // If paginator's 'axis' property is to be automatically determined, inherit host's property 164 if (paginator._cAxis === undefined) { 165 paginator._set(AXIS, host.get(AXIS)); 166 } 167 }, 168 169 /** 170 * After host _uiDimensionsChange 171 * 172 * @method _afterHostUIDimensionsChange 173 * @param e {EventFacade} The event facade 174 * @protected 175 */ 176 _afterHostUIDimensionsChange: function () { 177 178 var paginator = this, 179 host = paginator._host, 180 dims = host._getScrollDims(), 181 widgetWidth = dims.offsetWidth, 182 widgetHeight = dims.offsetHeight, 183 pageNodes = paginator._getPageNodes(); 184 185 // Inefficient. Should not reinitialize every page every syncUI 186 pageNodes.each(function (node, i) { 187 var scrollWidth = node.get('scrollWidth'), 188 scrollHeight = node.get('scrollHeight'), 189 maxScrollX = Math.max(0, scrollWidth - widgetWidth), // Math.max to ensure we don't set it to a negative value 190 maxScrollY = Math.max(0, scrollHeight - widgetHeight); 191 192 // Don't initialize any page _pageDims that already have been. 193 if (!paginator._pageDims[i]) { 194 195 paginator._pageDims[i] = { 196 197 // Current scrollX & scrollY positions (default to 0) 198 scrollX: 0, 199 scrollY: 0, 200 201 // Maximum scrollable values 202 maxScrollX: maxScrollX, 203 maxScrollY: maxScrollY, 204 205 // Height & width of the page 206 width: scrollWidth, 207 height: scrollHeight 208 }; 209 210 } else { 211 paginator._pageDims[i].maxScrollX = maxScrollX; 212 paginator._pageDims[i].maxScrollY = maxScrollY; 213 } 214 215 }); 216 }, 217 218 /** 219 * Executed before host.scrollTo 220 * 221 * @method _beforeHostScrollTo 222 * @param x {Number} The x-position to scroll to. (null for no movement) 223 * @param y {Number} The y-position to scroll to. (null for no movement) 224 * @param {Number} [duration] Duration, in ms, of the scroll animation (default is 0) 225 * @param {String} [easing] An easing equation if duration is set 226 * @param {String} [node] The node to move 227 * @protected 228 */ 229 _beforeHostScrollTo: function (x, y, duration, easing, node) { 230 var paginator = this, 231 host = paginator._host, 232 gesture = host._gesture, 233 index = paginator._cIndex, 234 paginatorAxis = paginator._cAxis, 235 pageNodes = paginator._getPageNodes(), 236 gestureAxis; 237 238 if (gesture) { 239 gestureAxis = gesture.axis; 240 241 // Null the opposite axis so it won't be modified by host.scrollTo 242 if (gestureAxis === DIM_Y) { 243 x = null; 244 } else { 245 y = null; 246 } 247 248 // If they are scrolling against the specified axis, pull out the page's node to have its own offset 249 if (paginatorAxis[gestureAxis] === false) { 250 node = pageNodes.item(index); 251 } 252 253 } 254 255 // Return the modified argument list 256 return new Y.Do.AlterArgs("new args", [x, y, duration, easing, node]); 257 }, 258 259 /** 260 * Executed after host._gestureMoveEnd 261 * Determines if the gesture should page prev or next (if at all) 262 * 263 * @method _afterHostGestureMoveEnd 264 * @param e {EventFacade} The event facade 265 * @protected 266 */ 267 _afterHostGestureMoveEnd: function () { 268 269 // This was a flick, so we don't need to do anything here 270 if (this._host._gesture.flick) { 271 return; 272 } 273 274 var paginator = this, 275 host = paginator._host, 276 gesture = host._gesture, 277 index = paginator._cIndex, 278 paginatorAxis = paginator._cAxis, 279 gestureAxis = gesture.axis, 280 isHorizontal = (gestureAxis === DIM_X), 281 delta = gesture[(isHorizontal ? 'deltaX' : 'deltaY')], 282 isForward = (delta > 0), 283 pageDims = paginator._pageDims[index], 284 halfway = pageDims[(isHorizontal ? 'width' : 'height')] / 2, 285 isHalfway = (Math.abs(delta) >= halfway), 286 canScroll = paginatorAxis[gestureAxis], 287 rtl = host.rtl; 288 289 if (canScroll) { 290 if (isHalfway) { // TODO: This condition should probably be configurable 291 // Fire next()/prev() 292 paginator[(rtl === isForward ? 'prev' : 'next')](); 293 } 294 // Scrollback 295 else { 296 paginator.scrollToIndex(paginator.get(INDEX)); 297 } 298 } 299 }, 300 301 /** 302 * Executed before host._mousewheel 303 * Prevents mousewheel events in some conditions 304 * 305 * @method _beforeHostMousewheel 306 * @param e {EventFacade} The event facade 307 * @protected 308 */ 309 _beforeHostMousewheel: function (e) { 310 var paginator = this, 311 host = paginator._host, 312 bb = host._bb, 313 isForward = (e.wheelDelta < 0), 314 paginatorAxis = paginator._cAxis; 315 316 // Only if the mousewheel event occurred on a DOM node inside the BB 317 if (bb.contains(e.target) && paginatorAxis[DIM_Y]) { 318 319 // Fire next()/prev() 320 paginator[(isForward ? 'next' : 'prev')](); 321 322 // prevent browser default behavior on mousewheel 323 e.preventDefault(); 324 325 // Block host._mousewheel from running 326 return new Y.Do.Prevent(); 327 } 328 }, 329 330 /** 331 * Executed before host._flick 332 * Prevents flick events in some conditions 333 * 334 * @method _beforeHostFlick 335 * @param e {EventFacade} The event facade 336 * @protected 337 */ 338 _beforeHostFlick: function (e) { 339 340 // If the widget is disabled 341 if (this._host.get(DISABLED)) { 342 return false; 343 } 344 345 // The drag was out of bounds, so do nothing (which will cause a snapback) 346 if (this._host._isOutOfBounds()){ 347 return new Y.Do.Prevent(); 348 } 349 350 var paginator = this, 351 host = paginator._host, 352 gesture = host._gesture, 353 paginatorAxis = paginator.get(AXIS), 354 flick = e.flick, 355 velocity = flick.velocity, 356 flickAxis = flick.axis || false, 357 isForward = (velocity < 0), 358 canScroll = paginatorAxis[flickAxis], 359 rtl = host.rtl; 360 361 // Store the flick data in the this._host._gesture object so it knows this was a flick 362 if (gesture) { 363 gesture.flick = flick; 364 } 365 366 // Can we scroll along this axis? 367 if (canScroll) { 368 369 // Fire next()/prev() 370 paginator[(rtl === isForward ? 'prev' : 'next')](); 371 372 // Prevent flicks on the paginated axis 373 if (paginatorAxis[flickAxis]) { 374 return new Y.Do.Prevent(); 375 } 376 } 377 }, 378 379 /** 380 * Executes after host's 'scrollEnd' event 381 * Runs cleanup operations 382 * 383 * @method _afterHostScrollEnded 384 * @param e {EventFacade} The event facade 385 * @protected 386 */ 387 _afterHostScrollEnded: function () { 388 var paginator = this, 389 host = paginator._host, 390 index = paginator._cIndex, 391 scrollX = host.get(SCROLL_X), 392 scrollY = host.get(SCROLL_Y), 393 paginatorAxis = paginator._cAxis; 394 395 if (paginatorAxis[DIM_Y]) { 396 paginator._pageDims[index].scrollX = scrollX; 397 } else { 398 paginator._pageDims[index].scrollY = scrollY; 399 } 400 401 paginator._optimize(); 402 }, 403 404 /** 405 * index attr change handler 406 * 407 * @method _afterIndexChange 408 * @param e {EventFacade} The event facade 409 * @protected 410 */ 411 _afterIndexChange: function (e) { 412 var paginator = this, 413 host = paginator._host, 414 index = e.newVal, 415 pageDims = paginator._pageDims[index], 416 hostAxis = host._cAxis, 417 paginatorAxis = paginator._cAxis; 418 419 // Cache the new index value 420 paginator._cIndex = index; 421 422 // For dual-axis instances, we need to hack some host properties to the 423 // current page's max height/width and current stored offset 424 if (hostAxis[DIM_X] && hostAxis[DIM_Y]) { 425 if (paginatorAxis[DIM_Y]) { 426 host._maxScrollX = pageDims.maxScrollX; 427 host.set(SCROLL_X, pageDims.scrollX, { src: UI }); 428 } 429 else if (paginatorAxis[DIM_X]) { 430 host._maxScrollY = pageDims.maxScrollY; 431 host.set(SCROLL_Y, pageDims.scrollY, { src: UI }); 432 } 433 } 434 435 if (e.src !== UI) { 436 paginator.scrollToIndex(index); 437 } 438 }, 439 440 /** 441 * Optimization: Hides the pages not near the viewport 442 * 443 * @method _optimize 444 * @protected 445 */ 446 _optimize: function () { 447 448 if (!this._optimizeMemory) { 449 return false; 450 } 451 452 var paginator = this, 453 currentIndex = paginator._cIndex, 454 pageNodes = paginator._getStage(currentIndex); 455 456 // Show the pages in/near the viewport & hide the rest 457 paginator._showNodes(pageNodes.visible); 458 paginator._hideNodes(pageNodes.hidden); 459 }, 460 461 /** 462 * Optimization: Determines which nodes should be visible, and which should be hidden. 463 * 464 * @method _getStage 465 * @param index {Number} The page index # intended to be in focus. 466 * @return {object} 467 * @protected 468 */ 469 _getStage: function (index) { 470 var paginator = this, 471 pageBuffer = paginator._pageBuffer, 472 pageCount = paginator.get(TOTAL), 473 pageNodes = paginator._getPageNodes(), 474 start = Math.max(0, index - pageBuffer), 475 end = Math.min(pageCount, index + 1 + pageBuffer); // noninclusive 476 477 return { 478 visible: pageNodes.splice(start, end - start), 479 hidden: pageNodes 480 }; 481 }, 482 483 /** 484 * A utility method to show node(s) 485 * 486 * @method _showNodes 487 * @param nodeList {Object} The list of nodes to show 488 * @protected 489 */ 490 _showNodes: function (nodeList) { 491 if (nodeList) { 492 nodeList.removeClass(CLASS_HIDDEN).setStyle('visibility', ''); 493 } 494 }, 495 496 /** 497 * A utility method to hide node(s) 498 * 499 * @method _hideNodes 500 * @param nodeList {Object} The list of nodes to hide 501 * @protected 502 */ 503 _hideNodes: function (nodeList) { 504 if (nodeList) { 505 nodeList.addClass(CLASS_HIDDEN).setStyle('visibility', 'hidden'); 506 } 507 }, 508 509 /** 510 * Gets a nodeList for the "pages" 511 * 512 * @method _getPageNodes 513 * @protected 514 * @return {nodeList} 515 */ 516 _getPageNodes: function () { 517 var paginator = this, 518 host = paginator._host, 519 cb = host._cb, 520 pageSelector = paginator.get(SELECTOR), 521 pageNodes = (pageSelector ? cb.all(pageSelector) : cb.get('children')); 522 523 return pageNodes; 524 }, 525 526 /** 527 * Scroll to the next page, with animation 528 * 529 * @method next 530 */ 531 next: function () { 532 var paginator = this, 533 scrollview = paginator._host, 534 index = paginator._cIndex, 535 target = index + 1, 536 total = paginator.get(TOTAL); 537 538 // If the widget is disabled, ignore 539 if (scrollview.get(DISABLED)) { 540 return; 541 } 542 543 // If the target index is greater than the page count, ignore 544 if (target >= total) { 545 return; 546 } 547 548 // Update the index 549 paginator.set(INDEX, target); 550 }, 551 552 /** 553 * Scroll to the previous page, with animation 554 * 555 * @method prev 556 */ 557 prev: function () { 558 var paginator = this, 559 scrollview = paginator._host, 560 index = paginator._cIndex, 561 target = index - 1; 562 563 // If the widget is disabled, ignore 564 if (scrollview.get(DISABLED)) { 565 return; 566 } 567 568 // If the target index is before the first page, ignore 569 if (target < 0) { 570 return; 571 } 572 573 // Update the index 574 paginator.set(INDEX, target); 575 }, 576 577 /** 578 * Deprecated for 3.7.0. 579 * @method scrollTo 580 * @deprecated 581 */ 582 scrollTo: function () { 583 return this.scrollToIndex.apply(this, arguments); 584 }, 585 586 /** 587 * Scroll to a given page in the scrollview 588 * 589 * @method scrollToIndex 590 * @since 3.7.0 591 * @param index {Number} The index of the page to scroll to 592 * @param {Number} [duration] The number of ms the animation should last 593 * @param {String} [easing] The timing function to use in the animation 594 */ 595 scrollToIndex: function (index, duration, easing) { 596 var paginator = this, 597 host = paginator._host, 598 pageNode = paginator._getPageNodes().item(index), 599 scrollAxis = (paginator._cAxis[DIM_X] ? SCROLL_X : SCROLL_Y), 600 scrollOffset = pageNode.get(scrollAxis === SCROLL_X ? 'offsetLeft' : 'offsetTop'); 601 602 duration = (duration !== undefined) ? duration : PaginatorPlugin.TRANSITION.duration; 603 easing = (easing !== undefined) ? easing : PaginatorPlugin.TRANSITION.easing; 604 605 // Set the index ATTR to the specified index value 606 paginator.set(INDEX, index, { src: UI }); 607 608 // Makes sure the viewport nodes are visible 609 paginator._showNodes(pageNode); 610 611 // Scroll to the offset 612 host.set(scrollAxis, scrollOffset, { 613 duration: duration, 614 easing: easing 615 }); 616 }, 617 618 /** 619 * Setter for 'axis' attribute 620 * 621 * @method _axisSetter 622 * @param val {Mixed} A string ('x', 'y', 'xy') to specify which axis/axes to allow scrolling on 623 * @param name {String} The attribute name 624 * @return {Object} An object to specify scrollability on the x & y axes 625 * 626 * @protected 627 */ 628 _axisSetter: function (val) { 629 630 // Turn a string into an axis object 631 if (Y.Lang.isString(val)) { 632 return { 633 x: (val.match(/x/i) ? true : false), 634 y: (val.match(/y/i) ? true : false) 635 }; 636 } 637 }, 638 639 640 /** 641 * After listener for the axis attribute 642 * 643 * @method _afterAxisChange 644 * @param e {EventFacade} The event facade 645 * @protected 646 */ 647 _afterAxisChange: function (e) { 648 this._cAxis = e.newVal; 649 } 650 651 // End prototype properties 652 653 }, { 654 655 // Static properties 656 657 /** 658 * The identity of the plugin 659 * 660 * @property NAME 661 * @type String 662 * @default 'pluginScrollViewPaginator' 663 * @readOnly 664 * @protected 665 * @static 666 */ 667 NAME: 'pluginScrollViewPaginator', 668 669 /** 670 * The namespace on which the plugin will reside 671 * 672 * @property NS 673 * @type String 674 * @default 'pages' 675 * @static 676 */ 677 NS: 'pages', 678 679 /** 680 * The default attribute configuration for the plugin 681 * 682 * @property ATTRS 683 * @type {Object} 684 * @static 685 */ 686 ATTRS: { 687 688 /** 689 * Specifies ability to scroll on x, y, or x and y axis/axes. 690 * If unspecified, it inherits from the host instance. 691 * 692 * @attribute axis 693 * @type String 694 */ 695 axis: { 696 setter: '_axisSetter', 697 writeOnce: 'initOnly' 698 }, 699 700 /** 701 * CSS selector for a page inside the scrollview. The scrollview 702 * will snap to the closest page. 703 * 704 * @attribute selector 705 * @type {String} 706 * @default null 707 */ 708 selector: { 709 value: null 710 }, 711 712 /** 713 * The active page number for a paged scrollview 714 * 715 * @attribute index 716 * @type {Number} 717 * @default 0 718 */ 719 index: { 720 value: 0 721 }, 722 723 /** 724 * The total number of pages 725 * 726 * @attribute total 727 * @type {Number} 728 * @default 0 729 */ 730 total: { 731 value: 0 732 } 733 }, 734 735 /** 736 * The default snap to current duration and easing values used on scroll end. 737 * 738 * @property SNAP_TO_CURRENT 739 * @static 740 */ 741 TRANSITION: { 742 duration: 300, 743 easing: 'ease-out' 744 } 745 746 // End static properties 747 748 }); 749 750 Y.namespace('Plugin').ScrollViewPaginator = PaginatorPlugin; 751 752 753 }, '3.17.2', {"requires": ["plugin", "classnamemanager"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |