| Index: third_party/polymer/components/core-list/core-list.html
|
| diff --git a/third_party/polymer/components/core-list/core-list.html b/third_party/polymer/components/core-list/core-list.html
|
| deleted file mode 100644
|
| index 27f111387734beefd04e76270004d595d1244162..0000000000000000000000000000000000000000
|
| --- a/third_party/polymer/components/core-list/core-list.html
|
| +++ /dev/null
|
| @@ -1,1306 +0,0 @@
|
| -<!--
|
| -Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
| -This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
| -The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
| -The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
| -Code distributed by Google as part of the polymer project is also
|
| -subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
| --->
|
| -
|
| -<!--
|
| -`core-list` displays a virtual, 'infinite' list. The template inside the
|
| -`core-list` element represents the DOM to create for each list item. The
|
| -`data` property specifies an array of list item data.
|
| -
|
| -For performance reasons, not every item in the list is rendered at once; instead
|
| -a small subset of actual template elements (enough to fill the viewport) are
|
| -rendered and reused as the user scrolls. As such, it is important that all
|
| -state of the list template be bound to the model driving it, since the view
|
| -may be reused with a new model at any time. Particularly, any state that
|
| -may change as the result of a user interaction with the list item must be
|
| -bound to the model to avoid view state inconsistency.
|
| -
|
| -### Template model
|
| -
|
| -List item templates should bind to template models of the following structure:
|
| -
|
| - {
|
| - index: 0, // data index for this item
|
| - selected: false, // selection state for this item
|
| - model: { // user data corresponding to data[index]
|
| - /* user item data */
|
| - }
|
| - }
|
| -
|
| -For example, given the following data array:
|
| -
|
| - [
|
| - {name: 'Bob', checked: true},
|
| - {name: 'Tim', checked: false},
|
| - ...
|
| - ]
|
| -
|
| -The following code would render the list (note the `name` and `checked`
|
| -properties are bound from the `model` object provided to the template
|
| -scope):
|
| -
|
| - <core-list data="{{data}}">
|
| - <template>
|
| - <div class="row {{ {selected: selected} | tokenList }}">
|
| - List row: {{index}}, User data from model: {{model.name}}
|
| - <input type="checkbox" checked="{{model.checked}}">
|
| - </div>
|
| - </template>
|
| - </core-list>
|
| -
|
| -### Selection
|
| -
|
| -By default, the list supports selection via tapping. Styling selected items
|
| -should be done via binding to the `selected` property of each model (see examples
|
| -above. The data model for the selected item (for single-selection) or array of
|
| -models (for multi-selection) is published to the `selection` property.
|
| -
|
| -### Grouping **(experimental)**
|
| -
|
| -`core-list` supports showing dividers between groups of data by setting the
|
| -`groups` property to an array containing group information. An element with
|
| -a `divider` attribute set should be supplied a the top level of the template
|
| -next to the template item to provide the divider template. The template model
|
| -contains extra fields when `groups` is used, as follows:
|
| -
|
| - {
|
| - index: 0, // data index for this item
|
| - groupIndex: 0, // group index for this item
|
| - groupItemIndex: 0, // index within group for this item
|
| - selected: false, // selection state for this item
|
| - model: { // user data corresponding to data[index]
|
| - /* user item data */
|
| - },
|
| - groupModel: { // user group data corresponding to groups[index]
|
| - /* user group data */
|
| - }
|
| - }
|
| -
|
| -Groups may be specified one of two ways (users should choose the data format
|
| -that closest matches their source data, to avoid the performance impact of
|
| -needing totransform data to fit the required structure):
|
| -
|
| -1. Flat data array - In this scenario, the `data` array is provided as
|
| -a flat list of models. Group lengths are determined by the `length` property
|
| -on each group object, with the `data` property providing user-specified group
|
| -data, typically for binding to dividers. For example:
|
| -
|
| - data = [
|
| - { name: 'Adam' },
|
| - { name: 'Alex' },
|
| - { name: 'Bob' },
|
| - { name: 'Chuck' },
|
| - { name: 'Cathy' },
|
| - ...
|
| - ];
|
| -
|
| - groups = [
|
| - { length: 2, data: { letter: 'A' } },
|
| - { length: 1, data: { letter: 'B' } },
|
| - { length: 2, data: { letter: 'C' } },
|
| - ...
|
| - ];
|
| -
|
| - <core-list data="{{data}}" groups="{{groups}}">
|
| - <template>
|
| - <div divider class="divider">{{groupModel.letter}}</div>
|
| - <div class="item">{{model.name}}</div>
|
| - </template>
|
| - </core-list>
|
| -
|
| -2. Nested data array - In this scenario, the `data` array is a nested
|
| -array of arrays of models, where each array determines the length of the
|
| -group, and the `groups` models provide the user-specified data directly.
|
| -For example:
|
| -
|
| - data = [
|
| - [ { name: 'Adam' }, { name: 'Alex' } ],
|
| - [ { name: 'Bob' } ],
|
| - [ { name: 'Chuck' }, { name: 'Cathy' } ],
|
| - ...
|
| - ];
|
| -
|
| - groups = [
|
| - { letter: 'A' },
|
| - { letter: 'B' },
|
| - { letter: 'C' },
|
| - ...
|
| - ];
|
| -
|
| - <core-list data="{{data}}" groups="{{groups}}">
|
| - <template>
|
| - <div divider class="divider">{{groupModel.letter}}</div>
|
| - <div class="item">{{model.name}}</div>
|
| - </template>
|
| - </core-list>
|
| -
|
| -### Grid layout **(experimental)**
|
| -
|
| -`core-list` supports a grid layout in addition to linear layout by setting
|
| -the `grid` attribute. In this case, the list template item must have both fixed
|
| -width and height (e.g. via CSS), with the desired width of each grid item
|
| -specified by the `width` attribute. Based on this, the number of items
|
| -per row are determined automatically based on the size of the list viewport.
|
| -
|
| -### Non-native scrollers **(experimental)**
|
| -
|
| -By default, core-list assumes the `scrollTarget` (if set) is a native scrollable
|
| -element (e.g. `overflow:auto` or `overflow:y`) that fires the `scroll` event and
|
| -whose scroll position can be read/set via the `scrollTop` property.
|
| -`core-list` provides experimental support for setting `scrollTarget`
|
| -to a custom scroller element (e.g. a JS-based scroller) as long as it provides
|
| -the following abstract API:
|
| -
|
| - - `getScrollTop()` - returns the current scroll position
|
| - - `setScrollTop(y)` - sets the current scroll position
|
| - - Fires a `scroll` event indicating when the scroll position has changed
|
| -
|
| -@group Polymer Core Elements
|
| -@element core-list
|
| --->
|
| -<link rel="import" href="../polymer/polymer.html">
|
| -<link rel="import" href="../core-selection/core-selection.html">
|
| -<link rel="import" href="../core-resizable/core-resizable.html">
|
| -
|
| -<polymer-element name="core-list" tabindex="-1">
|
| -<template>
|
| - <core-selection id="selection" multi="{{multi}}" on-core-select="{{selectedHandler}}"></core-selection>
|
| - <link rel="stylesheet" href="core-list.css">
|
| - <div id="viewport" class="core-list-viewport"><content></content></div>
|
| -</template>
|
| -<script>
|
| -(function() {
|
| -
|
| - var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
|
| - var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
|
| -
|
| - Polymer(Polymer.mixin({
|
| -
|
| - publish: {
|
| - /**
|
| - * Fired when an item element is tapped.
|
| - *
|
| - * @event core-activate
|
| - * @param {Object} detail
|
| - * @param {Object} detail.item the item element
|
| - */
|
| -
|
| - /**
|
| - * An array of source data for the list to display. Elements
|
| - * from this array will be set to the `model` peroperty on each
|
| - * template instance scope for binding.
|
| - *
|
| - * When `groups` is used, this array may either be flat, with
|
| - * the group lengths specified in the `groups` array; otherwise
|
| - * `data` may be specified as an array of arrays, such that the
|
| - * each array in `data` specifies a group. See examples above.
|
| - *
|
| - * @attribute data
|
| - * @type array
|
| - * @default null
|
| - */
|
| - data: null,
|
| -
|
| - /**
|
| - * An array of data conveying information about groupings of items
|
| - * in the `data` array. Elements from this array will be set to the
|
| - * `groupModel` property of each template instance scope for binding.
|
| - *
|
| - * When `groups` is used, template children with the `divider` attribute
|
| - * will be shown above each group. Typically data from the `groupModel`
|
| - * would be bound to dividers.
|
| - *
|
| - * If `data` is specified as a flat array, the `groups` array must
|
| - * contain objects of the format `{ length: n, data: {...} }`, where
|
| - * `length` determines the number of items from the `data` array
|
| - * that should be grouped, and `data` specifies the user data that will
|
| - * be assigned to the `groupModel` property on the template instance
|
| - * scope.
|
| - *
|
| - * If `data` is specified as a nested array of arrays, group lengths
|
| - * are derived from these arrays, so each object in `groups` need only
|
| - * contain the user data to be assigned to `groupModel`.
|
| - *
|
| - * @attribute groups
|
| - * @type array
|
| - * @default null
|
| - */
|
| - groups: null,
|
| -
|
| - /**
|
| - *
|
| - * An optional element on which to listen for scroll events.
|
| - *
|
| - * @attribute scrollTarget
|
| - * @type Element
|
| - * @default core-list
|
| - */
|
| - scrollTarget: null,
|
| -
|
| - /**
|
| - *
|
| - * When true, tapping a row will select the item, placing its data model
|
| - * in the set of selected items retrievable via the `selection` property.
|
| - *
|
| - * Note that tapping focusable elements within the list item will not
|
| - * result in selection, since they are presumed to have their own action.
|
| - *
|
| - * @attribute selectionEnabled
|
| - * @type {boolean}
|
| - * @default true
|
| - */
|
| - selectionEnabled: true,
|
| -
|
| - /**
|
| - *
|
| - * Set to true to support multiple selection. Note, existing selection
|
| - * state is maintained only when changing `multi` from `false` to `true`;
|
| - * it is cleared when changing from `true` to `false`.
|
| - *
|
| - * @attribute multi
|
| - * @type boolean
|
| - * @default false
|
| - */
|
| - multi: false,
|
| -
|
| - /**
|
| - *
|
| - * Data record (or array of records, if `multi: true`) corresponding to
|
| - * the currently selected set of items.
|
| - *
|
| - * @attribute selection
|
| - * @type {any}
|
| - * @default null
|
| - */
|
| - selection: null,
|
| -
|
| - /**
|
| - *
|
| - * When true, the list is rendered as a grid. Grid items must be fixed
|
| - * height and width, with the width of each item specified in the `width`
|
| - * property.
|
| - *
|
| - * @attribute grid
|
| - * @type boolean
|
| - * @default false
|
| - */
|
| - grid: false,
|
| -
|
| - /**
|
| - *
|
| - * When `grid` is used, `width` determines the width of each grid item.
|
| - * This property has no meaning when not in `grid` mode.
|
| - *
|
| - * @attribute width
|
| - * @type number
|
| - * @default null
|
| - */
|
| - width: null,
|
| -
|
| - /**
|
| - * The approximate height of a list item, in pixels. This is used only for determining
|
| - * the number of physical elements to render based on the viewport size
|
| - * of the list. Items themselves may vary in height between each other
|
| - * depending on their data model. There is typically no need to adjust
|
| - * this value unless the average size is much larger or smaller than the default.
|
| - *
|
| - * @attribute height
|
| - * @type number
|
| - * @default 200
|
| - */
|
| - height: 200,
|
| -
|
| - /**
|
| - * The amount of scrolling runway the list keeps rendered, as a factor of
|
| - * the list viewport size. There is typically no need to adjust this value
|
| - * other than for performance tuning. Larger value correspond to more
|
| - * physical elements being rendered.
|
| - *
|
| - * @attribute runwayFactor
|
| - * @type number
|
| - * @default 4
|
| - */
|
| - runwayFactor: 4
|
| -
|
| - },
|
| -
|
| - eventDelegates: {
|
| - tap: 'tapHandler',
|
| - 'core-resize': 'updateSize'
|
| - },
|
| -
|
| - // Local cache of scrollTop
|
| - _scrollTop: 0,
|
| -
|
| - observe: {
|
| - 'isAttached data grid width template scrollTarget': 'initialize',
|
| - 'multi selectionEnabled': '_resetSelection'
|
| - },
|
| -
|
| - ready: function() {
|
| - this._boundScrollHandler = this.scrollHandler.bind(this);
|
| - this._boundPositionItems = this._positionItems.bind(this);
|
| - this._oldMulti = this.multi;
|
| - this._oldSelectionEnabled = this.selectionEnabled;
|
| - this._virtualStart = 0;
|
| - this._virtualCount = 0;
|
| - this._physicalStart = 0;
|
| - this._physicalOffset = 0;
|
| - this._physicalSize = 0;
|
| - this._physicalSizes = [];
|
| - this._physicalAverage = 0;
|
| - this._itemSizes = [];
|
| - this._dividerSizes = [];
|
| - this._repositionedItems = [];
|
| -
|
| - this._aboveSize = 0;
|
| -
|
| - this._nestedGroups = false;
|
| - this._groupStart = 0;
|
| - this._groupStartIndex = 0;
|
| - },
|
| -
|
| - attached: function() {
|
| - this.isAttached = true;
|
| - this.template = this.querySelector('template');
|
| - if (!this.template.bindingDelegate) {
|
| - this.template.bindingDelegate = this.element.syntax;
|
| - }
|
| - this.resizableAttachedHandler();
|
| - },
|
| -
|
| - detached: function() {
|
| - this.isAttached = false;
|
| - if (this._target) {
|
| - this._target.removeEventListener('scroll', this._boundScrollHandler);
|
| - }
|
| - this.resizableDetachedHandler();
|
| - },
|
| -
|
| - /**
|
| - * To be called by the user when the list is manually resized
|
| - * or shown after being hidden.
|
| - *
|
| - * @method updateSize
|
| - */
|
| - updateSize: function() {
|
| - if (!this._positionPending && !this._needItemInit) {
|
| - this._resetIndex(this._getFirstVisibleIndex() || 0);
|
| - this.initialize();
|
| - }
|
| - },
|
| -
|
| - _resetSelection: function() {
|
| - if (((this._oldMulti != this.multi) && !this.multi) ||
|
| - ((this._oldSelectionEnabled != this.selectionEnabled) &&
|
| - !this.selectionEnabled)) {
|
| - this._clearSelection();
|
| - this.refresh();
|
| - } else {
|
| - this.selection = this.$.selection.getSelection();
|
| - }
|
| - this._oldMulti = this.multi;
|
| - this._oldSelectionEnabled = this.selectionEnabled;
|
| - },
|
| -
|
| - // Adjust virtual start index based on changes to backing data
|
| - _adjustVirtualIndex: function(splices, group) {
|
| - if (this._targetSize === 0) {
|
| - return;
|
| - }
|
| - var totalDelta = 0;
|
| - for (var i=0; i<splices.length; i++) {
|
| - var s = splices[i];
|
| - var idx = s.index;
|
| - var gidx, gitem;
|
| - if (group) {
|
| - gidx = this.data.indexOf(group);
|
| - idx += this.virtualIndexForGroup(gidx);
|
| - }
|
| - // We only need to care about changes happening above the current position
|
| - if (idx >= this._virtualStart) {
|
| - break;
|
| - }
|
| - var delta = Math.max(s.addedCount - s.removed.length, idx - this._virtualStart);
|
| - totalDelta += delta;
|
| - this._physicalStart += delta;
|
| - this._virtualStart += delta;
|
| - if (this._grouped) {
|
| - if (group) {
|
| - gitem = s.index;
|
| - } else {
|
| - var g = this.groupForVirtualIndex(s.index);
|
| - gidx = g.group;
|
| - gitem = g.groupIndex;
|
| - }
|
| - if (gidx == this._groupStart && gitem < this._groupStartIndex) {
|
| - this._groupStartIndex += delta;
|
| - }
|
| - }
|
| - }
|
| - // Adjust offset/scroll position based on total number of items changed
|
| - if (this._virtualStart < this._physicalCount) {
|
| - this._resetIndex(this._getFirstVisibleIndex() || 0);
|
| - } else {
|
| - totalDelta = Math.max((totalDelta / this._rowFactor) * this._physicalAverage, -this._physicalOffset);
|
| - this._physicalOffset += totalDelta;
|
| - this._scrollTop = this.setScrollTop(this._scrollTop + totalDelta);
|
| - }
|
| - },
|
| -
|
| - _updateSelection: function(splices) {
|
| - for (var i=0; i<splices.length; i++) {
|
| - var s = splices[i];
|
| - for (var j=0; j<s.removed.length; j++) {
|
| - var d = s.removed[j];
|
| - this.$.selection.setItemSelected(d, false);
|
| - }
|
| - }
|
| - },
|
| -
|
| - groupsChanged: function() {
|
| - if (!!this.groups != this._grouped) {
|
| - this.updateSize();
|
| - }
|
| - },
|
| -
|
| - initialize: function() {
|
| - if (!this.template || !this.isAttached) {
|
| - return;
|
| - }
|
| -
|
| - // TODO(kschaaf): Checking arguments.length currently the only way to
|
| - // know that the array was mutated as opposed to newly assigned; need
|
| - // a better API for Polymer observers
|
| - var splices;
|
| - if (arguments.length == 1) {
|
| - splices = arguments[0];
|
| - if (!this._nestedGroups) {
|
| - this._adjustVirtualIndex(splices);
|
| - }
|
| - this._updateSelection(splices);
|
| - } else {
|
| - this._clearSelection();
|
| - }
|
| -
|
| - // Initialize scroll target
|
| - var target = this.scrollTarget || this;
|
| - if (this._target !== target) {
|
| - this.initializeScrollTarget(target);
|
| - }
|
| -
|
| - // Initialize data
|
| - this.initializeData(splices, false);
|
| - },
|
| -
|
| - initializeScrollTarget: function(target) {
|
| - // Listen for scroll events
|
| - if (this._target) {
|
| - this._target.removeEventListener('scroll', this._boundScrollHandler, false);
|
| - }
|
| - this._target = target;
|
| - target.addEventListener('scroll', this._boundScrollHandler, false);
|
| - // Support for non-native scrollers (must implement abstract API):
|
| - // getScrollTop, setScrollTop, sync
|
| - if ((target != this) && target.setScrollTop && target.getScrollTop) {
|
| - this.setScrollTop = function(val) {
|
| - target.setScrollTop(val);
|
| - return target.getScrollTop();
|
| - };
|
| - this.getScrollTop = target.getScrollTop.bind(target);
|
| - this.syncScroller = target.sync ? target.sync.bind(target) : function() {};
|
| - // Adjusting scroll position on non-native scrollers is risky
|
| - this.adjustPositionAllowed = false;
|
| - } else {
|
| - this.setScrollTop = function(val) {
|
| - target.scrollTop = val;
|
| - return target.scrollTop;
|
| - };
|
| - this.getScrollTop = function() {
|
| - return target.scrollTop;
|
| - };
|
| - this.syncScroller = function() {};
|
| - this.adjustPositionAllowed = true;
|
| - }
|
| - // Only use -webkit-overflow-touch from iOS8+, where scroll events are fired
|
| - if (IOS_TOUCH_SCROLLING) {
|
| - target.style.webkitOverflowScrolling = 'touch';
|
| - // Adjusting scrollTop during iOS momentum scrolling is "no bueno"
|
| - this.adjustPositionAllowed = false;
|
| - }
|
| - // Force overflow as necessary
|
| - this._target.style.willChange = 'transform';
|
| - if (getComputedStyle(this._target).position == 'static') {
|
| - this._target.style.position = 'relative';
|
| - }
|
| - this.style.overflowY = (target == this) ? 'auto' : null;
|
| - },
|
| -
|
| - updateGroupObservers: function(splices) {
|
| - // If we're going from grouped to non-grouped, remove all observers
|
| - if (!this._nestedGroups) {
|
| - if (this._groupObservers && this._groupObservers.length) {
|
| - splices = [{
|
| - index: 0,
|
| - addedCount: 0,
|
| - removed: this._groupObservers
|
| - }];
|
| - } else {
|
| - splices = null;
|
| - }
|
| - }
|
| - // Otherwise, create observers for all groups, unless this is a group splice
|
| - if (this._nestedGroups) {
|
| - splices = splices || [{
|
| - index: 0,
|
| - addedCount: this.data.length,
|
| - removed: []
|
| - }];
|
| - }
|
| - if (splices) {
|
| - var observers = this._groupObservers || [];
|
| - // Apply the splices to the observer array
|
| - for (var i=0; i<splices.length; i++) {
|
| - var s = splices[i], j;
|
| - var args = [s.index, s.removed.length];
|
| - if (s.removed.length) {
|
| - for (j=s.index; j<s.removed.length; j++) {
|
| - observers[j].close();
|
| - }
|
| - }
|
| - if (s.addedCount) {
|
| - for (j=s.index; j<s.addedCount; j++) {
|
| - var o = new ArrayObserver(this.data[j]);
|
| - args.push(o);
|
| - o.open(this.getGroupDataHandler(this.data[j]));
|
| - }
|
| - }
|
| - observers.splice.apply(observers, args);
|
| - }
|
| - this._groupObservers = observers;
|
| - }
|
| - },
|
| -
|
| - getGroupDataHandler: function(group) {
|
| - return function(splices) {
|
| - this.groupDataChanged(splices, group);
|
| - }.bind(this);
|
| - },
|
| -
|
| - groupDataChanged: function(splices, group) {
|
| - this._adjustVirtualIndex(splices, group);
|
| - this._updateSelection(splices);
|
| - this.initializeData(null, true);
|
| - },
|
| -
|
| - initializeData: function(splices, groupUpdate) {
|
| - var i;
|
| -
|
| - // Calculate row-factor for grid layout
|
| - if (this.grid) {
|
| - if (!this.width) {
|
| - throw 'Grid requires the `width` property to be set';
|
| - }
|
| - this._rowFactor = Math.floor(this._target.offsetWidth / this.width) || 1;
|
| - var cs = getComputedStyle(this._target);
|
| - var padding = parseInt(cs.paddingLeft || 0) + parseInt(cs.paddingRight || 0);
|
| - this._rowMargin = (this._target.offsetWidth - (this._rowFactor * this.width) - padding) / 2;
|
| - } else {
|
| - this._rowFactor = 1;
|
| - this._rowMargin = 0;
|
| - }
|
| -
|
| - // Count virtual data size, depending on whether grouping is enabled
|
| - if (!this.data || !this.data.length) {
|
| - this._virtualCount = 0;
|
| - this._grouped = false;
|
| - this._nestedGroups = false;
|
| - } else if (this.groups) {
|
| - this._grouped = true;
|
| - this._nestedGroups = Array.isArray(this.data[0]);
|
| - if (this._nestedGroups) {
|
| - if (this.groups.length != this.data.length) {
|
| - throw 'When using nested grouped data, data.length and groups.length must agree!';
|
| - }
|
| - this._virtualCount = 0;
|
| - for (i=0; i<this.groups.length; i++) {
|
| - this._virtualCount += this.data[i] && this.data[i].length;
|
| - }
|
| - } else {
|
| - this._virtualCount = this.data.length;
|
| - var len = 0;
|
| - for (i=0; i<this.groups.length; i++) {
|
| - len += this.groups[i].length;
|
| - }
|
| - if (len != this.data.length) {
|
| - throw 'When using groups data, the sum of group[n].length\'s and data.length must agree!';
|
| - }
|
| - }
|
| - var g = this.groupForVirtualIndex(this._virtualStart);
|
| - this._groupStart = g.group;
|
| - this._groupStartIndex = g.groupIndex;
|
| - } else {
|
| - this._grouped = false;
|
| - this._nestedGroups = false;
|
| - this._virtualCount = this.data.length;
|
| - }
|
| -
|
| - // Update grouped array observers used when group data is nested
|
| - if (!groupUpdate) {
|
| - this.updateGroupObservers(splices);
|
| - }
|
| -
|
| - // Add physical items up to a max based on data length, viewport size, and extra item overhang
|
| - var currentCount = this._physicalCount || 0;
|
| - var height = this._target.offsetHeight;
|
| - if (!height && this._target.offsetParent) {
|
| - console.warn('core-list must either be sized or be inside an overflow:auto div that is sized');
|
| - }
|
| - this._physicalCount = Math.min(Math.ceil(height / (this._physicalAverage || this.height)) * this.runwayFactor * this._rowFactor, this._virtualCount);
|
| - this._physicalCount = Math.max(currentCount, this._physicalCount);
|
| - this._physicalData = this._physicalData || new Array(this._physicalCount);
|
| - var needItemInit = false;
|
| - while (currentCount < this._physicalCount) {
|
| - var model = this.templateInstance ? Object.create(this.templateInstance.model) : {};
|
| - this._physicalData[currentCount++] = model;
|
| - needItemInit = true;
|
| - }
|
| - this.template.model = this._physicalData;
|
| - this.template.setAttribute('repeat', '');
|
| - this._dir = 0;
|
| -
|
| - // If we've added new items, wait until the template renders then
|
| - // initialize the new items before refreshing
|
| - if (!this._needItemInit) {
|
| - if (needItemInit) {
|
| - this._needItemInit = true;
|
| - this.resetMetrics();
|
| - this.onMutation(this, this.initializeItems);
|
| - } else {
|
| - this.refresh();
|
| - }
|
| - }
|
| - },
|
| -
|
| - initializeItems: function() {
|
| - var currentCount = this._physicalItems && this._physicalItems.length || 0;
|
| - this._physicalItems = this._physicalItems || [new Array(this._physicalCount)];
|
| - this._physicalDividers = this._physicalDividers || new Array(this._physicalCount);
|
| - for (var i = 0, item = this.template.nextElementSibling;
|
| - item && i < this._physicalCount;
|
| - item = item.nextElementSibling) {
|
| - if (item.getAttribute('divider') != null) {
|
| - this._physicalDividers[i] = item;
|
| - } else {
|
| - this._physicalItems[i++] = item;
|
| - }
|
| - }
|
| - this.refresh();
|
| - this._needItemInit = false;
|
| - },
|
| -
|
| - _updateItemData: function(force, physicalIndex, virtualIndex, groupIndex, groupItemIndex) {
|
| - var physicalItem = this._physicalItems[physicalIndex];
|
| - var physicalDatum = this._physicalData[physicalIndex];
|
| - var virtualDatum = this.dataForIndex(virtualIndex, groupIndex, groupItemIndex);
|
| - var needsReposition;
|
| - if (force || physicalDatum.model != virtualDatum) {
|
| - // Set model, index, and selected fields
|
| - physicalDatum.model = virtualDatum;
|
| - physicalDatum.index = virtualIndex;
|
| - physicalDatum.physicalIndex = physicalIndex;
|
| - physicalDatum.selected = this.selectionEnabled && virtualDatum ?
|
| - this._selectedData.get(virtualDatum) : null;
|
| - // Set group-related fields
|
| - if (this._grouped) {
|
| - var groupModel = this.groups[groupIndex];
|
| - physicalDatum.groupModel = groupModel && (this._nestedGroups ? groupModel : groupModel.data);
|
| - physicalDatum.groupIndex = groupIndex;
|
| - physicalDatum.groupItemIndex = groupItemIndex;
|
| - physicalItem._isDivider = this.data.length && (groupItemIndex === 0);
|
| - physicalItem._isRowStart = (groupItemIndex % this._rowFactor) === 0;
|
| - } else {
|
| - physicalDatum.groupModel = null;
|
| - physicalDatum.groupIndex = null;
|
| - physicalDatum.groupItemIndex = null;
|
| - physicalItem._isDivider = false;
|
| - physicalItem._isRowStart = (virtualIndex % this._rowFactor) === 0;
|
| - }
|
| - // Hide physical items when not in use (no model assigned)
|
| - physicalItem.hidden = !virtualDatum;
|
| - var divider = this._physicalDividers[physicalIndex];
|
| - if (divider && (divider.hidden == physicalItem._isDivider)) {
|
| - divider.hidden = !physicalItem._isDivider;
|
| - }
|
| - needsReposition = !force;
|
| - } else {
|
| - needsReposition = false;
|
| - }
|
| - return needsReposition || force;
|
| - },
|
| -
|
| - scrollHandler: function() {
|
| - if (IOS_TOUCH_SCROLLING) {
|
| - // iOS sends multiple scroll events per rAF
|
| - // Align work to rAF to reduce overhead & artifacts
|
| - if (!this._raf) {
|
| - this._raf = requestAnimationFrame(function() {
|
| - this._raf = null;
|
| - this.refresh();
|
| - }.bind(this));
|
| - }
|
| - } else {
|
| - this.refresh();
|
| - }
|
| - },
|
| -
|
| - resetMetrics: function() {
|
| - this._physicalAverage = 0;
|
| - this._physicalAverageCount = 0;
|
| - },
|
| -
|
| - updateMetrics: function(force) {
|
| - // Measure physical items & dividers
|
| - var totalSize = 0;
|
| - var count = 0;
|
| - for (var i=0; i<this._physicalCount; i++) {
|
| - var item = this._physicalItems[i];
|
| - if (!item.hidden) {
|
| - var size = this._itemSizes[i] = item.offsetHeight;
|
| - if (item._isDivider) {
|
| - var divider = this._physicalDividers[i];
|
| - if (divider) {
|
| - size += (this._dividerSizes[i] = divider.offsetHeight);
|
| - }
|
| - }
|
| - this._physicalSizes[i] = size;
|
| - if (item._isRowStart) {
|
| - totalSize += size;
|
| - count++;
|
| - }
|
| - }
|
| - }
|
| - this._physicalSize = totalSize;
|
| -
|
| - // Measure other DOM
|
| - this._viewportSize = this.$.viewport.offsetHeight;
|
| - this._targetSize = this._target.offsetHeight;
|
| -
|
| - // Measure content in scroller before virtualized items
|
| - if (this._target != this) {
|
| - this._aboveSize = this.offsetTop;
|
| - } else {
|
| - this._aboveSize = parseInt(getComputedStyle(this._target).paddingTop);
|
| - }
|
| -
|
| - // Calculate average height
|
| - if (count) {
|
| - totalSize = (this._physicalAverage * this._physicalAverageCount) + totalSize;
|
| - this._physicalAverageCount += count;
|
| - this._physicalAverage = Math.round(totalSize / this._physicalAverageCount);
|
| - }
|
| - },
|
| -
|
| - getGroupLen: function(group) {
|
| - group = arguments.length ? group : this._groupStart;
|
| - if (this._nestedGroups) {
|
| - return this.data[group].length;
|
| - } else {
|
| - return this.groups[group].length;
|
| - }
|
| - },
|
| -
|
| - changeStartIndex: function(inc) {
|
| - this._virtualStart += inc;
|
| - if (this._grouped) {
|
| - while (inc > 0) {
|
| - var groupMax = this.getGroupLen() - this._groupStartIndex - 1;
|
| - if (inc > groupMax) {
|
| - inc -= (groupMax + 1);
|
| - this._groupStart++;
|
| - this._groupStartIndex = 0;
|
| - } else {
|
| - this._groupStartIndex += inc;
|
| - inc = 0;
|
| - }
|
| - }
|
| - while (inc < 0) {
|
| - if (-inc > this._groupStartIndex) {
|
| - inc += this._groupStartIndex;
|
| - this._groupStart--;
|
| - this._groupStartIndex = this.getGroupLen();
|
| - } else {
|
| - this._groupStartIndex += inc;
|
| - inc = this.getGroupLen();
|
| - }
|
| - }
|
| - }
|
| - // In grid mode, virtualIndex must alway start on a row start!
|
| - if (this.grid) {
|
| - if (this._grouped) {
|
| - inc = this._groupStartIndex % this._rowFactor;
|
| - } else {
|
| - inc = this._virtualStart % this._rowFactor;
|
| - }
|
| - if (inc) {
|
| - this.changeStartIndex(-inc);
|
| - }
|
| - }
|
| - },
|
| -
|
| - getRowCount: function(dir) {
|
| - if (!this.grid) {
|
| - return dir;
|
| - } else if (!this._grouped) {
|
| - return dir * this._rowFactor;
|
| - } else {
|
| - if (dir < 0) {
|
| - if (this._groupStartIndex > 0) {
|
| - return -Math.min(this._rowFactor, this._groupStartIndex);
|
| - } else {
|
| - var prevLen = this.getGroupLen(this._groupStart-1);
|
| - return -Math.min(this._rowFactor, prevLen % this._rowFactor || this._rowFactor);
|
| - }
|
| - } else {
|
| - return Math.min(this._rowFactor, this.getGroupLen() - this._groupStartIndex);
|
| - }
|
| - }
|
| - },
|
| -
|
| - _virtualToPhysical: function(virtualIndex) {
|
| - var physicalIndex = (virtualIndex - this._physicalStart) % this._physicalCount;
|
| - return physicalIndex < 0 ? this._physicalCount + physicalIndex : physicalIndex;
|
| - },
|
| -
|
| - groupForVirtualIndex: function(virtual) {
|
| - if (!this._grouped) {
|
| - return {};
|
| - } else {
|
| - var group;
|
| - for (group=0; group<this.groups.length; group++) {
|
| - var groupLen = this.getGroupLen(group);
|
| - if (groupLen > virtual) {
|
| - break;
|
| - } else {
|
| - virtual -= groupLen;
|
| - }
|
| - }
|
| - return {group: group, groupIndex: virtual };
|
| - }
|
| - },
|
| -
|
| - virtualIndexForGroup: function(group, groupIndex) {
|
| - groupIndex = groupIndex ? Math.min(groupIndex, this.getGroupLen(group)) : 0;
|
| - group--;
|
| - while (group >= 0) {
|
| - groupIndex += this.getGroupLen(group--);
|
| - }
|
| - return groupIndex;
|
| - },
|
| -
|
| - dataForIndex: function(virtual, group, groupIndex) {
|
| - if (this.data) {
|
| - if (this._nestedGroups) {
|
| - if (virtual < this._virtualCount) {
|
| - return this.data[group][groupIndex];
|
| - }
|
| - } else {
|
| - return this.data[virtual];
|
| - }
|
| - }
|
| - },
|
| -
|
| - // Refresh the list at the current scroll position.
|
| - refresh: function() {
|
| - var i, deltaCount;
|
| -
|
| - // Determine scroll position & any scrollDelta that may have occurred
|
| - var lastScrollTop = this._scrollTop;
|
| - this._scrollTop = this.getScrollTop();
|
| - var scrollDelta = this._scrollTop - lastScrollTop;
|
| - this._dir = scrollDelta < 0 ? -1 : scrollDelta > 0 ? 1 : 0;
|
| -
|
| - // Adjust virtual items and positioning offset if scroll occurred
|
| - if (Math.abs(scrollDelta) > Math.max(this._physicalSize, this._targetSize)) {
|
| - // Random access to point in list: guess new index based on average size
|
| - deltaCount = Math.round((scrollDelta / this._physicalAverage) * this._rowFactor);
|
| - deltaCount = Math.max(deltaCount, -this._virtualStart);
|
| - deltaCount = Math.min(deltaCount, this._virtualCount - this._virtualStart - 1);
|
| - this._physicalOffset += Math.max(scrollDelta, -this._physicalOffset);
|
| - this.changeStartIndex(deltaCount);
|
| - // console.log(this._scrollTop, 'Random access to ' + this._virtualStart, this._physicalOffset);
|
| - } else {
|
| - // Incremental movement: adjust index by flipping items
|
| - var base = this._aboveSize + this._physicalOffset;
|
| - var margin = 0.3 * Math.max((this._physicalSize - this._targetSize, this._physicalSize));
|
| - this._upperBound = base + margin;
|
| - this._lowerBound = base + this._physicalSize - this._targetSize - margin;
|
| - var flipBound = this._dir > 0 ? this._upperBound : this._lowerBound;
|
| - if (((this._dir > 0 && this._scrollTop > flipBound) ||
|
| - (this._dir < 0 && this._scrollTop < flipBound))) {
|
| - var flipSize = Math.abs(this._scrollTop - flipBound);
|
| - for (i=0; (i<this._physicalCount) && (flipSize > 0) &&
|
| - ((this._dir < 0 && this._virtualStart > 0) ||
|
| - (this._dir > 0 && this._virtualStart < this._virtualCount-this._physicalCount)); i++) {
|
| - var idx = this._virtualToPhysical(this._dir > 0 ?
|
| - this._virtualStart :
|
| - this._virtualStart + this._physicalCount -1);
|
| - var size = this._physicalSizes[idx];
|
| - flipSize -= size;
|
| - var cnt = this.getRowCount(this._dir);
|
| - // console.log(this._scrollTop, 'flip ' + (this._dir > 0 ? 'down' : 'up'), cnt, this._virtualStart, this._physicalOffset);
|
| - if (this._dir > 0) {
|
| - // When scrolling down, offset is adjusted based on previous item's size
|
| - this._physicalOffset += size;
|
| - // console.log(' ->', this._virtualStart, size, this._physicalOffset);
|
| - }
|
| - this.changeStartIndex(cnt);
|
| - if (this._dir < 0) {
|
| - this._repositionedItems.push(this._virtualStart);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Assign data to items lazily if scrolling, otherwise force
|
| - if (this._updateItems(!scrollDelta)) {
|
| - // Position items after bindings resolve (method varies based on O.o impl)
|
| - if (Observer.hasObjectObserve) {
|
| - this.async(this._boundPositionItems);
|
| - } else {
|
| - Platform.flush();
|
| - Platform.endOfMicrotask(this._boundPositionItems);
|
| - }
|
| - }
|
| - },
|
| -
|
| - _updateItems: function(force) {
|
| - var i, virtualIndex, physicalIndex;
|
| - var needsReposition = false;
|
| - var groupIndex = this._groupStart;
|
| - var groupItemIndex = this._groupStartIndex;
|
| - for (i = 0; i < this._physicalCount; ++i) {
|
| - virtualIndex = this._virtualStart + i;
|
| - physicalIndex = this._virtualToPhysical(virtualIndex);
|
| - // Update physical item with new user data and list metadata
|
| - needsReposition =
|
| - this._updateItemData(force, physicalIndex, virtualIndex, groupIndex, groupItemIndex) || needsReposition;
|
| - // Increment
|
| - groupItemIndex++;
|
| - if (this.groups && groupIndex < this.groups.length - 1) {
|
| - if (groupItemIndex >= this.getGroupLen(groupIndex)) {
|
| - groupItemIndex = 0;
|
| - groupIndex++;
|
| - }
|
| - }
|
| - }
|
| - return needsReposition;
|
| - },
|
| -
|
| - _positionItems: function() {
|
| - var i, virtualIndex, physicalIndex, physicalItem;
|
| -
|
| - // Measure
|
| - this.updateMetrics();
|
| -
|
| - // Pre-positioning tasks
|
| - if (this._dir < 0) {
|
| - // When going up, remove offset after measuring size for
|
| - // new data for item being moved from bottom to top
|
| - while (this._repositionedItems.length) {
|
| - virtualIndex = this._repositionedItems.pop();
|
| - physicalIndex = this._virtualToPhysical(virtualIndex);
|
| - this._physicalOffset -= this._physicalSizes[physicalIndex];
|
| - // console.log(' <-', virtualIndex, this._physicalSizes[physicalIndex], this._physicalOffset);
|
| - }
|
| - // Adjust scroll position to home into top when going up
|
| - if (this._scrollTop + this._targetSize < this._viewportSize) {
|
| - this._updateScrollPosition(this._scrollTop);
|
| - }
|
| - }
|
| -
|
| - // Position items
|
| - var divider, upperBound, lowerBound;
|
| - var rowx = 0;
|
| - var x = this._rowMargin;
|
| - var y = this._physicalOffset;
|
| - var lastHeight = 0;
|
| - for (i = 0; i < this._physicalCount; ++i) {
|
| - // Calculate indices
|
| - virtualIndex = this._virtualStart + i;
|
| - physicalIndex = this._virtualToPhysical(virtualIndex);
|
| - physicalItem = this._physicalItems[physicalIndex];
|
| - // Position divider
|
| - if (physicalItem._isDivider) {
|
| - if (rowx !== 0) {
|
| - y += lastHeight;
|
| - rowx = 0;
|
| - }
|
| - divider = this._physicalDividers[physicalIndex];
|
| - x = this._rowMargin;
|
| - if (divider && (divider._translateX != x || divider._translateY != y)) {
|
| - divider.style.opacity = 1;
|
| - if (this.grid) {
|
| - divider.style.width = this.width * this._rowFactor + 'px';
|
| - }
|
| - divider.style.transform = divider.style.webkitTransform =
|
| - 'translate3d(' + x + 'px,' + y + 'px,0)';
|
| - divider._translateX = x;
|
| - divider._translateY = y;
|
| - }
|
| - y += this._dividerSizes[physicalIndex];
|
| - }
|
| - // Position item
|
| - if (physicalItem._translateX != x || physicalItem._translateY != y) {
|
| - physicalItem.style.opacity = 1;
|
| - physicalItem.style.transform = physicalItem.style.webkitTransform =
|
| - 'translate3d(' + x + 'px,' + y + 'px,0)';
|
| - physicalItem._translateX = x;
|
| - physicalItem._translateY = y;
|
| - }
|
| - // Increment offsets
|
| - lastHeight = this._itemSizes[physicalIndex];
|
| - if (this.grid) {
|
| - rowx++;
|
| - if (rowx >= this._rowFactor) {
|
| - rowx = 0;
|
| - y += lastHeight;
|
| - }
|
| - x = this._rowMargin + rowx * this.width;
|
| - } else {
|
| - y += lastHeight;
|
| - }
|
| - }
|
| -
|
| - if (this._scrollTop >= 0) {
|
| - this._updateViewportHeight();
|
| - }
|
| - },
|
| -
|
| - _updateViewportHeight: function() {
|
| - var remaining = Math.max(this._virtualCount - this._virtualStart - this._physicalCount, 0);
|
| - remaining = Math.ceil(remaining / this._rowFactor);
|
| - var vs = this._physicalOffset + this._physicalSize + remaining * this._physicalAverage;
|
| - if (this._viewportSize != vs) {
|
| - // console.log(this._scrollTop, 'adjusting viewport height', vs - this._viewportSize, vs);
|
| - this._viewportSize = vs;
|
| - this.$.viewport.style.height = this._viewportSize + 'px';
|
| - this.syncScroller();
|
| - }
|
| - },
|
| -
|
| - _updateScrollPosition: function(scrollTop) {
|
| - var deltaHeight = this._virtualStart === 0 ? this._physicalOffset :
|
| - Math.min(scrollTop + this._physicalOffset, 0);
|
| - if (deltaHeight) {
|
| - // console.log(scrollTop, 'adjusting scroll pos', this._virtualStart, -deltaHeight, scrollTop - deltaHeight);
|
| - if (this.adjustPositionAllowed) {
|
| - this._scrollTop = this.setScrollTop(scrollTop - deltaHeight);
|
| - }
|
| - this._physicalOffset -= deltaHeight;
|
| - }
|
| - },
|
| -
|
| - // list selection
|
| - tapHandler: function(e) {
|
| - var n = e.target;
|
| - var p = e.path;
|
| - if (!this.selectionEnabled || (n === this)) {
|
| - return;
|
| - }
|
| - requestAnimationFrame(function() {
|
| - // Gambit: only select the item if the tap wasn't on a focusable child
|
| - // of the list (since anything with its own action should be focusable
|
| - // and not result in result in list selection). To check this, we
|
| - // asynchronously check that shadowRoot.activeElement is null, which
|
| - // means the tapped item wasn't focusable. On polyfill where
|
| - // activeElement doesn't follow the data-hinding part of the spec, we
|
| - // can check that document.activeElement is the list itself, which will
|
| - // catch focus in lieu of the tapped item being focusable, as we make
|
| - // the list focusable (tabindex="-1") for this purpose. Note we also
|
| - // allow the list items themselves to be focusable if desired, so those
|
| - // are excluded as well.
|
| - var active = window.ShadowDOMPolyfill ?
|
| - wrap(document.activeElement) : this.shadowRoot.activeElement;
|
| - if (active && (active != this) && (active.parentElement != this) &&
|
| - (document.activeElement != document.body)) {
|
| - return;
|
| - }
|
| - // Unfortunately, Safari does not focus certain form controls via mouse,
|
| - // so we also blacklist input, button, & select
|
| - // (https://bugs.webkit.org/show_bug.cgi?id=118043)
|
| - if ((p[0].localName == 'input') ||
|
| - (p[0].localName == 'button') ||
|
| - (p[0].localName == 'select')) {
|
| - return;
|
| - }
|
| -
|
| - var model = n.templateInstance && n.templateInstance.model;
|
| - if (model) {
|
| - var data = this.dataForIndex(model.index, model.groupIndex, model.groupItemIndex);
|
| - var item = this._physicalItems[model.physicalIndex];
|
| - if (!this.multi && data == this.selection) {
|
| - this.$.selection.select(null);
|
| - } else {
|
| - this.$.selection.select(data);
|
| - }
|
| - this.asyncFire('core-activate', {data: data, item: item});
|
| - }
|
| - }.bind(this));
|
| - },
|
| -
|
| - selectedHandler: function(e, detail) {
|
| - this.selection = this.$.selection.getSelection();
|
| - var id = this.indexesForData(detail.item);
|
| - // TODO(sorvell): we should be relying on selection to store the
|
| - // selected data but we want to optimize for lookup.
|
| - this._selectedData.set(detail.item, detail.isSelected);
|
| - if (id.physical >= 0 && id.virtual >= 0) {
|
| - this.refresh();
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * Select the list item at the given index.
|
| - *
|
| - * @method selectItem
|
| - * @param {number} index
|
| - */
|
| - selectItem: function(index) {
|
| - if (!this.selectionEnabled) {
|
| - return;
|
| - }
|
| - var data = this.data[index];
|
| - if (data) {
|
| - this.$.selection.select(data);
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * Set the selected state of the list item at the given index.
|
| - *
|
| - * @method setItemSelected
|
| - * @param {number} index
|
| - * @param {boolean} isSelected
|
| - */
|
| - setItemSelected: function(index, isSelected) {
|
| - var data = this.data[index];
|
| - if (data) {
|
| - this.$.selection.setItemSelected(data, isSelected);
|
| - }
|
| - },
|
| -
|
| - indexesForData: function(data) {
|
| - var virtual = -1;
|
| - var groupsLen = 0;
|
| - if (this._nestedGroups) {
|
| - for (var i=0; i<this.groups.length; i++) {
|
| - virtual = this.data[i].indexOf(data);
|
| - if (virtual < 0) {
|
| - groupsLen += this.data[i].length;
|
| - } else {
|
| - virtual += groupsLen;
|
| - break;
|
| - }
|
| - }
|
| - } else {
|
| - virtual = this.data.indexOf(data);
|
| - }
|
| - var physical = this.virtualToPhysicalIndex(virtual);
|
| - return { virtual: virtual, physical: physical };
|
| - },
|
| -
|
| - virtualToPhysicalIndex: function(index) {
|
| - for (var i=0, l=this._physicalData.length; i<l; i++) {
|
| - if (this._physicalData[i].index === index) {
|
| - return i;
|
| - }
|
| - }
|
| - return -1;
|
| - },
|
| -
|
| - /**
|
| - * Clears the current selection state of the list.
|
| - *
|
| - * @method clearSelection
|
| - */
|
| - clearSelection: function() {
|
| - this._clearSelection();
|
| - this.refresh();
|
| - },
|
| -
|
| - _clearSelection: function() {
|
| - this._selectedData = new WeakMap();
|
| - this.$.selection.clear();
|
| - this.selection = this.$.selection.getSelection();
|
| - },
|
| -
|
| - _getFirstVisibleIndex: function() {
|
| - for (var i=0; i<this._physicalCount; i++) {
|
| - var virtualIndex = this._virtualStart + i;
|
| - var physicalIndex = this._virtualToPhysical(virtualIndex);
|
| - var item = this._physicalItems[physicalIndex];
|
| - if (!item.hidden && item._translateY >= this._scrollTop - this._aboveSize) {
|
| - return virtualIndex;
|
| - }
|
| - }
|
| - },
|
| -
|
| - _resetIndex: function(index) {
|
| - index = Math.min(index, this._virtualCount-1);
|
| - index = Math.max(index, 0);
|
| - this.changeStartIndex(index - this._virtualStart);
|
| - this._scrollTop = this.setScrollTop(this._aboveSize + (index / this._rowFactor) * this._physicalAverage);
|
| - this._physicalOffset = this._scrollTop - this._aboveSize;
|
| - this._dir = 0;
|
| - },
|
| -
|
| - /**
|
| - * Scroll to an item.
|
| - *
|
| - * Note, when grouping is used, the index is based on the
|
| - * total flattened number of items. For scrolling to an item
|
| - * within a group, use the `scrollToGroupItem` API.
|
| - *
|
| - * @method scrollToItem
|
| - * @param {number} index
|
| - */
|
| - scrollToItem: function(index) {
|
| - this.scrollToGroupItem(null, index);
|
| - },
|
| -
|
| - /**
|
| - * Scroll to a group.
|
| - *
|
| - * @method scrollToGroup
|
| - * @param {number} group
|
| - */
|
| - scrollToGroup: function(group) {
|
| - this.scrollToGroupItem(group, 0);
|
| - },
|
| -
|
| - /**
|
| - * Scroll to an item within a group.
|
| - *
|
| - * @method scrollToGroupItem
|
| - * @param {number} group
|
| - * @param {number} index
|
| - */
|
| - scrollToGroupItem: function(group, index) {
|
| - if (group != null) {
|
| - index = this.virtualIndexForGroup(group, index);
|
| - }
|
| - this._resetIndex(index);
|
| - this.refresh();
|
| - }
|
| -
|
| - }, Polymer.CoreResizable));
|
| -
|
| -})();
|
| -</script>
|
| -</polymer-element>
|
|
|