Version 3.17.2

APIs

  • Begin typing in the search box above to see results.
Show:

File: scrollview/js/paginator-plugin.js

/**
 * Provides a plugin that adds pagination support to ScrollView instances
 *
 * @module scrollview-paginator
 */
var getClassName = Y.ClassNameManager.getClassName,
 SCROLLVIEW = 'scrollview',
 CLASS_HIDDEN = getClassName(SCROLLVIEW, 'hidden'),
 CLASS_PAGED = getClassName(SCROLLVIEW, 'paged'),
 UI = (Y.ScrollView) ? Y.ScrollView.UI_SRC : 'ui',
 INDEX = 'index',
 SCROLL_X = 'scrollX',
 SCROLL_Y = 'scrollY',
 TOTAL = 'total',
 DISABLED = 'disabled',
 HOST = 'host',
 SELECTOR = 'selector',
 AXIS = 'axis',
 DIM_X = 'x',
 DIM_Y = 'y';
/**
 * Scrollview plugin that adds support for paging
 *
 * @class ScrollViewPaginator
 * @namespace Plugin
 * @extends Plugin.Base
 * @constructor
 */
function PaginatorPlugin() {
 PaginatorPlugin.superclass.constructor.apply(this, arguments);
}
Y.extend(PaginatorPlugin, Y.Plugin.Base, {
 /**
 * Designated initializer
 *
 * @method initializer
 * @param {Object} Configuration object for the plugin
 */
 initializer: function (config) {
 var paginator = this,
 host = paginator.get(HOST);
 // Initialize & default
 paginator._pageDims = [];
 paginator._pageBuffer = 1;
 paginator._optimizeMemory = false;
 // Cache some values
 paginator._host = host;
 paginator._bb = host._bb;
 paginator._cb = host._cb;
 paginator._cIndex = paginator.get(INDEX);
 paginator._cAxis = paginator.get(AXIS);
 // Apply configs
 if (config._optimizeMemory) {
 paginator._optimizeMemory = config._optimizeMemory;
 }
 if (config._pageBuffer) {
 paginator._pageBuffer = config._pageBuffer;
 }
 // Attach event bindings
 paginator._bindAttrs();
 },
 /**
 *
 *
 * @method _bindAttrs
 * @private
 */
 _bindAttrs: function () {
 var paginator = this;
 // Event listeners
 paginator.after({
 'indexChange': paginator._afterIndexChange,
 'axisChange': paginator._afterAxisChange
 });
 // Host method listeners
 paginator.beforeHostMethod('scrollTo', paginator._beforeHostScrollTo);
 paginator.beforeHostMethod('_mousewheel', paginator._beforeHostMousewheel);
 paginator.beforeHostMethod('_flick', paginator._beforeHostFlick);
 paginator.afterHostMethod('_onGestureMoveEnd', paginator._afterHostGestureMoveEnd);
 paginator.afterHostMethod('_uiDimensionsChange', paginator._afterHostUIDimensionsChange);
 paginator.afterHostMethod('syncUI', paginator._afterHostSyncUI);
 // Host event listeners
 paginator.afterHostEvent('render', paginator._afterHostRender);
 paginator.afterHostEvent('scrollEnd', paginator._afterHostScrollEnded);
 },
 /**
 * After host render
 *
 * @method _afterHostRender
 * @param e {EventFacade} The event facade
 * @protected
 */
 _afterHostRender: function () {
 var paginator = this,
 bb = paginator._bb,
 host = paginator._host,
 index = paginator._cIndex,
 paginatorAxis = paginator._cAxis,
 pageNodes = paginator._getPageNodes(),
 size = pageNodes.size(),
 pageDim = paginator._pageDims[index];
 if (paginatorAxis[DIM_Y]) {
 host._maxScrollX = pageDim.maxScrollX;
 }
 else if (paginatorAxis[DIM_X]) {
 host._maxScrollY = pageDim.maxScrollY;
 }
 // Set the page count
 paginator.set(TOTAL, size);
 // Jump to the index
 if (index !== 0) {
 paginator.scrollToIndex(index, 0);
 }
 // Add the paginator class
 bb.addClass(CLASS_PAGED);
 // Trigger the optimization process
 paginator._optimize();
 },
 /**
 * After host syncUI
 *
 * @method _afterHostSyncUI
 * @param e {EventFacade} The event facade
 * @protected
 */
 _afterHostSyncUI: function () {
 var paginator = this,
 host = paginator._host,
 pageNodes = paginator._getPageNodes(),
 size = pageNodes.size();
 // Set the page count
 paginator.set(TOTAL, size);
 // If paginator's 'axis' property is to be automatically determined, inherit host's property
 if (paginator._cAxis === undefined) {
 paginator._set(AXIS, host.get(AXIS));
 }
 },
 /**
 * After host _uiDimensionsChange
 *
 * @method _afterHostUIDimensionsChange
 * @param e {EventFacade} The event facade
 * @protected
 */
 _afterHostUIDimensionsChange: function () {
 var paginator = this,
 host = paginator._host,
 dims = host._getScrollDims(),
 widgetWidth = dims.offsetWidth,
 widgetHeight = dims.offsetHeight,
 pageNodes = paginator._getPageNodes();
 // Inefficient. Should not reinitialize every page every syncUI
 pageNodes.each(function (node, i) {
 var scrollWidth = node.get('scrollWidth'),
 scrollHeight = node.get('scrollHeight'),
 maxScrollX = Math.max(0, scrollWidth - widgetWidth), // Math.max to ensure we don't set it to a negative value
 maxScrollY = Math.max(0, scrollHeight - widgetHeight);
 // Don't initialize any page _pageDims that already have been.
 if (!paginator._pageDims[i]) {
 paginator._pageDims[i] = {
 // Current scrollX & scrollY positions (default to 0)
 scrollX: 0,
 scrollY: 0,
 // Maximum scrollable values
 maxScrollX: maxScrollX,
 maxScrollY: maxScrollY,
 // Height & width of the page
 width: scrollWidth,
 height: scrollHeight
 };
 } else {
 paginator._pageDims[i].maxScrollX = maxScrollX;
 paginator._pageDims[i].maxScrollY = maxScrollY;
 }
 });
 },
 /**
 * Executed before host.scrollTo
 *
 * @method _beforeHostScrollTo
 * @param x {Number} The x-position to scroll to. (null for no movement)
 * @param y {Number} The y-position to scroll to. (null for no movement)
 * @param {Number} [duration] Duration, in ms, of the scroll animation (default is 0)
 * @param {String} [easing] An easing equation if duration is set
 * @param {String} [node] The node to move
 * @protected
 */
 _beforeHostScrollTo: function (x, y, duration, easing, node) {
 var paginator = this,
 host = paginator._host,
 gesture = host._gesture,
 index = paginator._cIndex,
 paginatorAxis = paginator._cAxis,
 pageNodes = paginator._getPageNodes(),
 gestureAxis;
 if (gesture) {
 gestureAxis = gesture.axis;
 // Null the opposite axis so it won't be modified by host.scrollTo
 if (gestureAxis === DIM_Y) {
 x = null;
 } else {
 y = null;
 }
 // If they are scrolling against the specified axis, pull out the page's node to have its own offset
 if (paginatorAxis[gestureAxis] === false) {
 node = pageNodes.item(index);
 }
 }
 // Return the modified argument list
 return new Y.Do.AlterArgs("new args", [x, y, duration, easing, node]);
 },
 /**
 * Executed after host._gestureMoveEnd
 * Determines if the gesture should page prev or next (if at all)
 *
 * @method _afterHostGestureMoveEnd
 * @param e {EventFacade} The event facade
 * @protected
 */
 _afterHostGestureMoveEnd: function () {
 // This was a flick, so we don't need to do anything here
 if (this._host._gesture.flick) {
 return;
 }
 var paginator = this,
 host = paginator._host,
 gesture = host._gesture,
 index = paginator._cIndex,
 paginatorAxis = paginator._cAxis,
 gestureAxis = gesture.axis,
 isHorizontal = (gestureAxis === DIM_X),
 delta = gesture[(isHorizontal ? 'deltaX' : 'deltaY')],
 isForward = (delta > 0),
 pageDims = paginator._pageDims[index],
 halfway = pageDims[(isHorizontal ? 'width' : 'height')] / 2,
 isHalfway = (Math.abs(delta) >= halfway),
 canScroll = paginatorAxis[gestureAxis],
 rtl = host.rtl;
 if (canScroll) {
 if (isHalfway) { // TODO: This condition should probably be configurable
 // Fire next()/prev()
 paginator[(rtl === isForward ? 'prev' : 'next')]();
 }
 // Scrollback
 else {
 paginator.scrollToIndex(paginator.get(INDEX));
 }
 }
 },
 /**
 * Executed before host._mousewheel
 * Prevents mousewheel events in some conditions
 *
 * @method _beforeHostMousewheel
 * @param e {EventFacade} The event facade
 * @protected
 */
 _beforeHostMousewheel: function (e) {
 var paginator = this,
 host = paginator._host,
 bb = host._bb,
 isForward = (e.wheelDelta < 0),
 paginatorAxis = paginator._cAxis;
 // Only if the mousewheel event occurred on a DOM node inside the BB
 if (bb.contains(e.target) && paginatorAxis[DIM_Y]) {
 // Fire next()/prev()
 paginator[(isForward ? 'next' : 'prev')]();
 // prevent browser default behavior on mousewheel
 e.preventDefault();
 // Block host._mousewheel from running
 return new Y.Do.Prevent();
 }
 },
 /**
 * Executed before host._flick
 * Prevents flick events in some conditions
 *
 * @method _beforeHostFlick
 * @param e {EventFacade} The event facade
 * @protected
 */
 _beforeHostFlick: function (e) {
 // If the widget is disabled
 if (this._host.get(DISABLED)) {
 return false;
 }
 // The drag was out of bounds, so do nothing (which will cause a snapback)
 if (this._host._isOutOfBounds()){
 return new Y.Do.Prevent();
 }
 var paginator = this,
 host = paginator._host,
 gesture = host._gesture,
 paginatorAxis = paginator.get(AXIS),
 flick = e.flick,
 velocity = flick.velocity,
 flickAxis = flick.axis || false,
 isForward = (velocity < 0),
 canScroll = paginatorAxis[flickAxis],
 rtl = host.rtl;
 // Store the flick data in the this._host._gesture object so it knows this was a flick
 if (gesture) {
 gesture.flick = flick;
 }
 // Can we scroll along this axis?
 if (canScroll) {
 // Fire next()/prev()
 paginator[(rtl === isForward ? 'prev' : 'next')]();
 // Prevent flicks on the paginated axis
 if (paginatorAxis[flickAxis]) {
 return new Y.Do.Prevent();
 }
 }
 },
 /**
 * Executes after host's 'scrollEnd' event
 * Runs cleanup operations
 *
 * @method _afterHostScrollEnded
 * @param e {EventFacade} The event facade
 * @protected
 */
 _afterHostScrollEnded: function () {
 var paginator = this,
 host = paginator._host,
 index = paginator._cIndex,
 scrollX = host.get(SCROLL_X),
 scrollY = host.get(SCROLL_Y),
 paginatorAxis = paginator._cAxis;
 if (paginatorAxis[DIM_Y]) {
 paginator._pageDims[index].scrollX = scrollX;
 } else {
 paginator._pageDims[index].scrollY = scrollY;
 }
 paginator._optimize();
 },
 /**
 * index attr change handler
 *
 * @method _afterIndexChange
 * @param e {EventFacade} The event facade
 * @protected
 */
 _afterIndexChange: function (e) {
 var paginator = this,
 host = paginator._host,
 index = e.newVal,
 pageDims = paginator._pageDims[index],
 hostAxis = host._cAxis,
 paginatorAxis = paginator._cAxis;
 // Cache the new index value
 paginator._cIndex = index;
 // For dual-axis instances, we need to hack some host properties to the
 // current page's max height/width and current stored offset
 if (hostAxis[DIM_X] && hostAxis[DIM_Y]) {
 if (paginatorAxis[DIM_Y]) {
 host._maxScrollX = pageDims.maxScrollX;
 host.set(SCROLL_X, pageDims.scrollX, { src: UI });
 }
 else if (paginatorAxis[DIM_X]) {
 host._maxScrollY = pageDims.maxScrollY;
 host.set(SCROLL_Y, pageDims.scrollY, { src: UI });
 }
 }
 if (e.src !== UI) {
 paginator.scrollToIndex(index);
 }
 },
 /**
 * Optimization: Hides the pages not near the viewport
 *
 * @method _optimize
 * @protected
 */
 _optimize: function () {
 if (!this._optimizeMemory) {
 return false;
 }
 var paginator = this,
 currentIndex = paginator._cIndex,
 pageNodes = paginator._getStage(currentIndex);
 // Show the pages in/near the viewport & hide the rest
 paginator._showNodes(pageNodes.visible);
 paginator._hideNodes(pageNodes.hidden);
 },
 /**
 * Optimization: Determines which nodes should be visible, and which should be hidden.
 *
 * @method _getStage
 * @param index {Number} The page index # intended to be in focus.
 * @return {object}
 * @protected
 */
 _getStage: function (index) {
 var paginator = this,
 pageBuffer = paginator._pageBuffer,
 pageCount = paginator.get(TOTAL),
 pageNodes = paginator._getPageNodes(),
 start = Math.max(0, index - pageBuffer),
 end = Math.min(pageCount, index + 1 + pageBuffer); // noninclusive
 return {
 visible: pageNodes.splice(start, end - start),
 hidden: pageNodes
 };
 },
 /**
 * A utility method to show node(s)
 *
 * @method _showNodes
 * @param nodeList {Object} The list of nodes to show
 * @protected
 */
 _showNodes: function (nodeList) {
 if (nodeList) {
 nodeList.removeClass(CLASS_HIDDEN).setStyle('visibility', '');
 }
 },
 /**
 * A utility method to hide node(s)
 *
 * @method _hideNodes
 * @param nodeList {Object} The list of nodes to hide
 * @protected
 */
 _hideNodes: function (nodeList) {
 if (nodeList) {
 nodeList.addClass(CLASS_HIDDEN).setStyle('visibility', 'hidden');
 }
 },
 /**
 * Gets a nodeList for the "pages"
 *
 * @method _getPageNodes
 * @protected
 * @return {nodeList}
 */
 _getPageNodes: function () {
 var paginator = this,
 host = paginator._host,
 cb = host._cb,
 pageSelector = paginator.get(SELECTOR),
 pageNodes = (pageSelector ? cb.all(pageSelector) : cb.get('children'));
 return pageNodes;
 },
 /**
 * Scroll to the next page, with animation
 *
 * @method next
 */
 next: function () {
 var paginator = this,
 scrollview = paginator._host,
 index = paginator._cIndex,
 target = index + 1,
 total = paginator.get(TOTAL);
 // If the widget is disabled, ignore
 if (scrollview.get(DISABLED)) {
 return;
 }
 // If the target index is greater than the page count, ignore
 if (target >= total) {
 return;
 }
 // Update the index
 paginator.set(INDEX, target);
 },
 /**
 * Scroll to the previous page, with animation
 *
 * @method prev
 */
 prev: function () {
 var paginator = this,
 scrollview = paginator._host,
 index = paginator._cIndex,
 target = index - 1;
 // If the widget is disabled, ignore
 if (scrollview.get(DISABLED)) {
 return;
 }
 // If the target index is before the first page, ignore
 if (target < 0) {
 return;
 }
 // Update the index
 paginator.set(INDEX, target);
 },
 /**
 * Deprecated for 3.7.0.
 * @method scrollTo
 * @deprecated
 */
 scrollTo: function () {
 return this.scrollToIndex.apply(this, arguments);
 },
 /**
 * Scroll to a given page in the scrollview
 *
 * @method scrollToIndex
 * @since 3.7.0
 * @param index {Number} The index of the page to scroll to
 * @param {Number} [duration] The number of ms the animation should last
 * @param {String} [easing] The timing function to use in the animation
 */
 scrollToIndex: function (index, duration, easing) {
 var paginator = this,
 host = paginator._host,
 pageNode = paginator._getPageNodes().item(index),
 scrollAxis = (paginator._cAxis[DIM_X] ? SCROLL_X : SCROLL_Y),
 scrollOffset = pageNode.get(scrollAxis === SCROLL_X ? 'offsetLeft' : 'offsetTop');
 duration = (duration !== undefined) ? duration : PaginatorPlugin.TRANSITION.duration;
 easing = (easing !== undefined) ? easing : PaginatorPlugin.TRANSITION.easing;
 // Set the index ATTR to the specified index value
 paginator.set(INDEX, index, { src: UI });
 // Makes sure the viewport nodes are visible
 paginator._showNodes(pageNode);
 // Scroll to the offset
 host.set(scrollAxis, scrollOffset, {
 duration: duration,
 easing: easing
 });
 },
 /**
 * Setter for 'axis' attribute
 *
 * @method _axisSetter
 * @param val {Mixed} A string ('x', 'y', 'xy') to specify which axis/axes to allow scrolling on
 * @param name {String} The attribute name
 * @return {Object} An object to specify scrollability on the x & y axes
 *
 * @protected
 */
 _axisSetter: function (val) {
 // Turn a string into an axis object
 if (Y.Lang.isString(val)) {
 return {
 x: (val.match(/x/i) ? true : false),
 y: (val.match(/y/i) ? true : false)
 };
 }
 },
 /**
 * After listener for the axis attribute
 *
 * @method _afterAxisChange
 * @param e {EventFacade} The event facade
 * @protected
 */
 _afterAxisChange: function (e) {
 this._cAxis = e.newVal;
 }
 // End prototype properties
}, {
 // Static properties
 /**
 * The identity of the plugin
 *
 * @property NAME
 * @type String
 * @default 'pluginScrollViewPaginator'
 * @readOnly
 * @protected
 * @static
 */
 NAME: 'pluginScrollViewPaginator',
 /**
 * The namespace on which the plugin will reside
 *
 * @property NS
 * @type String
 * @default 'pages'
 * @static
 */
 NS: 'pages',
 /**
 * The default attribute configuration for the plugin
 *
 * @property ATTRS
 * @type {Object}
 * @static
 */
 ATTRS: {
 /**
 * Specifies ability to scroll on x, y, or x and y axis/axes.
 * If unspecified, it inherits from the host instance.
 *
 * @attribute axis
 * @type String
 */
 axis: {
 setter: '_axisSetter',
 writeOnce: 'initOnly'
 },
 /**
 * CSS selector for a page inside the scrollview. The scrollview
 * will snap to the closest page.
 *
 * @attribute selector
 * @type {String}
 * @default null
 */
 selector: {
 value: null
 },
 /**
 * The active page number for a paged scrollview
 *
 * @attribute index
 * @type {Number}
 * @default 0
 */
 index: {
 value: 0
 },
 /**
 * The total number of pages
 *
 * @attribute total
 * @type {Number}
 * @default 0
 */
 total: {
 value: 0
 }
 },
 /**
 * The default snap to current duration and easing values used on scroll end.
 *
 * @property SNAP_TO_CURRENT
 * @static
 */
 TRANSITION: {
 duration: 300,
 easing: 'ease-out'
 }
 // End static properties
});
Y.namespace('Plugin').ScrollViewPaginator = PaginatorPlugin;
 

AltStyle によって変換されたページ (->オリジナル) /