[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/scrollview-paginator/ -> scrollview-paginator.js (source)

   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"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1