Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: polymer_1.0.4/bower_components/iron-list/iron-list.html

Issue 1264073002: Update polymer 1.0 install to pick up newly added elements. (Closed) Base URL: https://chromium.googlesource.com/infra/third_party/npm_modules.git@master
Patch Set: Update bower file to match actual versions. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!--
2 @license
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt
9 -->
10
11 <link rel="import" href="../polymer/polymer.html">
12 <link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html ">
13
14 <!--
15
16 `iron-list` displays a virtual, 'infinite' list. The template inside
17 the iron-list element represents the DOM to create for each list item.
18 The `items` property specifies an array of list item data.
19
20 For performance reasons, not every item in the list is rendered at once;
21 instead a small subset of actual template elements *(enough to fill the viewport )*
22 are rendered and reused as the user scrolls. As such, it is important that all
23 state of the list template be bound to the model driving it, since the view may
24 be reused with a new model at any time. Particularly, any state that may change
25 as the result of a user interaction with the list item must be bound to the mode l
26 to avoid view state inconsistency.
27
28 __Important:__ `iron-list` must ether be explicitly sized, or delegate scrolling to an
29 explicitly sized parent. By "explicitly sized", we mean it either has an explici t
30 CSS `height` property set via a class or inline style, or else is sized by other
31 layout means (e.g. the `flex` or `fit` classes).
32
33 ### Template model
34
35 List item templates should bind to template models of the following structure:
36
37 {
38 index: 0, // data index for this item
39 item: { // user data corresponding to items[index]
40 /* user item data */
41 }
42 }
43
44 Alternatively, you can change the property name used as data index by changing t he
45 `indexAs` property. The `as` property defines the name of the variable to add to the binding
46 scope for the array.
47
48 For example, given the following `data` array:
49
50 ##### data.json
51
52 [
53 {"name": "Bob"},
54 {"name": "Tim"},
55 {"name": "Mike"}
56 ]
57
58 The following code would render the list (note the name and checked properties a re
59 bound from the model object provided to the template scope):
60
61 <template is="dom-bind">
62 <iron-ajax url="data.json" last-response="{{data}}" auto></iron-ajax>
63 <iron-list items="[[data]]" as="item">
64 <template>
65 <div>
66 Name: <span>[[item.name]]</span>
67 </div>
68 </template>
69 </iron-list>
70 </template>
71
72
73 @group Iron Element
74 @element iron-list
75 @demo demo/index.html
76 -->
77
78 <dom-module id="iron-list">
79 <style>
80
81 :host {
82 display: block;
83 will-change: transform;
84 }
85
86 :host(.has-scroller) {
87 overflow: auto;
88 }
89
90 #items {
91 position: relative;
92 }
93
94 #items > ::content > * {
95 width: 100%;
96 box-sizing: border-box;
97 position: absolute;
98 top: 0;
99 }
100
101 </style>
102 <template>
103 <div id="items">
104 <content></content>
105 </div>
106 </template>
107 </dom-module>
108
109 <script>
110
111 (function() {
112
113 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
114 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
115 var DEFAULT_PHYSICAL_COUNT = 20;
116 var MAX_PHYSICAL_COUNT = 500;
117
118 Polymer({
119
120 is: 'iron-list',
121
122 properties: {
123
124 /**
125 * An array containing items determining how many instances of the templat e
126 * to stamp and that that each template instance should bind to.
127 */
128 items: {
129 type: Array
130 },
131
132 /**
133 * The name of the variable to add to the binding scope for the array
134 * element associated with a given template instance.
135 */
136 as: {
137 type: String,
138 value: 'item'
139 },
140
141 /**
142 * The name of the variable to add to the binding scope with the index
143 * for the row. If `sort` is provided, the index will reflect the
144 * sorted order (rather than the original array order).
145 */
146 indexAs: {
147 type: String,
148 value: 'index'
149 }
150
151 },
152
153 observers: [
154 '_itemsChanged(items.*)'
155 ],
156
157 behaviors: [
158 Polymer.Templatizer,
159 Polymer.IronResizableBehavior
160 ],
161
162 listeners: {
163 'iron-resize': '_resizeHandler'
164 },
165
166 /**
167 * The ratio of hidden tiles that should remain in the scroll direction.
168 * Recommended value ≈ 0.5, so it will distribute tiles evely in both direct ions.
169 */
170 _ratio: 0.5,
171
172 /**
173 * The element that controls the scroll
174 */
175 _scroller: null,
176
177 /**
178 * The padding-top value of the `scroller` element
179 */
180 _scrollerPaddingTop: 0,
181
182 /**
183 * This value is the same as `scrollTop`.
184 */
185 _scrollPosition: 0,
186
187 /**
188 * The number of tiles in the DOM.
189 */
190 _physicalCount: DEFAULT_PHYSICAL_COUNT,
191
192 /**
193 * The k-th tile that is at the top of the scrolling list.
194 */
195 _physicalStart: 0,
196
197 /**
198 * The k-th tile that is at the bottom of the scrolling list.
199 */
200 _physicalEnd: 0,
201
202 /**
203 * The sum of the heights of all the tiles in the DOM.
204 */
205 _physicalSize: 0,
206
207 /**
208 * The average `offsetHeight` of the tiles observed till now.
209 */
210 _physicalAverage: 0,
211
212 /**
213 * The number of tiles which `offsetHeight` > 0 observed until now.
214 */
215 _physicalAverageCount: 0,
216
217 /**
218 * The Y position of the item rendered in the `_physicalStart`
219 * tile relative to the scrolling list.
220 */
221 _physicalTop: 0,
222
223 /**
224 * The number of items in the list.
225 */
226 _virtualCount: 0,
227
228 /**
229 * The n-th item rendered in the `_physicalStart` tile.
230 */
231 _virtualStartVal: 0,
232
233 /**
234 * A map between an item key and its physical item index
235 */
236 _physicalIndexForKey: {},
237
238 /**
239 * The average scroll size
240 */
241 _scrollSize: 0,
242
243 /**
244 * The size of the viewport
245 */
246 _viewportSize: 0,
247
248 /**
249 * An array of DOM nodes that are currently in the tree
250 */
251 _physicalItems: null,
252
253 /**
254 * An array of heights for each item in `_physicalItems`
255 */
256 _physicalSizes: null,
257
258 /**
259 * A cached value for the visible index.
260 * See `firstVisibleIndex`
261 */
262 _firstVisibleIndexVal: null,
263
264 /**
265 * A Polymer collection for the items.
266 */
267 _collection: null,
268
269 /**
270 * True if the current item list was rendered for the first time
271 * after attached.
272 */
273 _initRendered: false,
274
275 /**
276 * The bottom of the physical content.
277 */
278 get _physicalBottom() {
279 return this._physicalTop + this._physicalSize;
280 },
281
282 /**
283 * The n-th item rendered in the last physical item.
284 */
285 get _virtualEnd() {
286 return this._virtualStartVal + this._physicalCount - 1;
287 },
288
289 /**
290 * The lowest n-th value for an item such that it can be rendered in `_physi calStart`.
291 */
292 _minVirtualStart: 0,
293
294 /**
295 * The largest n-th value for an item such that it can be rendered in `_phys icalStart`.
296 */
297 get _maxVirtualStart() {
298 return this._virtualCount < this._physicalCount ?
299 this._virtualCount : this._virtualCount - this._physicalCount;
300 },
301
302 /**
303 * The height of the physical content that isn't on the screen.
304 */
305 get _hiddenContentSize() {
306 return this._physicalSize - this._viewportSize;
307 },
308
309 /**
310 * The maximum scroll top value.
311 */
312 get _maxScrollTop() {
313 return this._scrollSize - this._viewportSize;
314 },
315
316 /**
317 * Sets the n-th item rendered in `_physicalStart`
318 */
319 set _virtualStart(val) {
320 // clamp the value so that _minVirtualStart <= val <= _maxVirtualStart
321 this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._min VirtualStart, val));
322 this._physicalStart = this._virtualStartVal % this._physicalCount;
323 this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this ._physicalCount;
324 },
325
326 /**
327 * Gets the n-th item rendered in `_physicalStart`
328 */
329 get _virtualStart() {
330 return this._virtualStartVal;
331 },
332
333 /**
334 * An optimal physical size such that we will have enough physical items
335 * to fill up the viewport and recycle when the user scrolls.
336 *
337 * This default value assumes that we will at least have the equivalent
338 * to a viewport of physical items above and below the user's viewport.
339 */
340 get _optPhysicalSize() {
341 return this._viewportSize * 3;
342 },
343
344 /**
345 * Gets the first visible item in the viewport.
346 *
347 * @property firstVisibleIndex
348 */
349 get firstVisibleIndex() {
350 var physicalOffset;
351
352 if (this._firstVisibleIndexVal === null) {
353 physicalOffset = this._physicalTop;
354
355 this._firstVisibleIndexVal = this._iterateItems(
356 function(pidx, vidx) {
357 physicalOffset += this._physicalSizes[pidx];
358
359 if (physicalOffset > this._scrollPosition) {
360 return vidx;
361 }
362 }) || 0;
363 }
364
365 return this._firstVisibleIndexVal;
366 },
367
368 /**
369 * When the element has been attached to the DOM tree.
370 */
371 attached: function() {
372 // delegate to the parent's scroller
373 // e.g. paper-scroll-header-panel
374 var el = Polymer.dom(this);
375
376 if (el.parentNode && el.parentNode.scroller) {
377 this._scroller = el.parentNode.scroller;
378 } else {
379 this._scroller = this;
380 this.classList.add('has-scroller');
381 }
382
383 this.updateViewportBoundaries();
384
385 if (IOS_TOUCH_SCROLLING) {
386 this._scroller.style.webkitOverflowScrolling = 'touch';
387
388 this._scroller.addEventListener('scroll', function() {
389 requestAnimationFrame(this._scrollHandler.bind(this));
390 }.bind(this));
391 } else {
392 this._scroller.addEventListener('scroll', this._scrollHandler.bind(this) );
393 }
394
395 // render the list of items if we haven't rendered them yet
396 this._render();
397 },
398
399 /**
400 * When the element has been removed from the DOM tree.
401 */
402 detached: function() {
403 this._initRendered = false;
404 },
405
406 /**
407 * Invoke this method if you dynamically update the viewport's
408 * size or CSS padding.
409 *
410 * @method updateViewportBoundaries
411 */
412 updateViewportBoundaries: function() {
413 var scrollerStyle = window.getComputedStyle(this._scroller);
414 this._scrollerPaddingTop = parseInt(scrollerStyle['padding-top']);
415 this._viewportSize = this._scroller.offsetHeight;
416 },
417
418 /**
419 * Update the models, the position of the
420 * items in the viewport and recycle tiles as needed.
421 */
422 _refresh: function() {
423 var SCROLL_DIRECTION_UP = -1;
424 var SCROLL_DIRECTION_DOWN = 1;
425 var SCROLL_DIRECTION_NONE = 0;
426
427 // clamp the `scrollTop` value
428 // IE 10|11 scrollTop may go above `_maxScrollTop`
429 // iOS `scrollTop` may go below 0 and above `_maxScrollTop`
430 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scroller.sc rollTop));
431
432 var tileHeight, kth, recycledTileSet;
433 var ratio = this._ratio;
434 var delta = scrollTop - this._scrollPosition;
435 var direction = SCROLL_DIRECTION_NONE;
436 var recycledTiles = 0;
437 var hiddenContentSize = this._hiddenContentSize;
438 var currentRatio = ratio;
439 var movingUp = [];
440
441 // track the last `scrollTop`
442 this._scrollPosition = scrollTop;
443
444 // clear cached visible index
445 this._firstVisibleIndexVal = null;
446
447 // random access
448 if (Math.abs(delta) > this._physicalSize) {
449 this._physicalTop += delta;
450 direction = SCROLL_DIRECTION_NONE;
451 recycledTiles = Math.round(delta / this._physicalAverage);
452 }
453 // scroll up
454 else if (delta < 0) {
455 var topSpace = scrollTop - this._physicalTop;
456 var virtualStart = this._virtualStart;
457
458 direction = SCROLL_DIRECTION_UP;
459 recycledTileSet = [];
460
461 kth = this._physicalEnd;
462 currentRatio = topSpace / hiddenContentSize;
463
464 // move tiles from bottom to top
465 while (
466 // approximate `currentRatio` to `ratio`
467 currentRatio < ratio &&
468 // recycle less physical items than the total
469 recycledTiles < this._physicalCount &&
470 // ensure that these recycled tiles are needed
471 virtualStart - recycledTiles > 0
472 ) {
473
474 tileHeight = this._physicalSizes[kth] || this._physicalAverage;
475 currentRatio += tileHeight / hiddenContentSize;
476
477 recycledTileSet.push(kth);
478 recycledTiles++;
479 kth = (kth === 0) ? this._physicalCount - 1 : kth - 1;
480 }
481
482 movingUp = recycledTileSet;
483 recycledTiles = -recycledTiles;
484
485 }
486 // scroll down
487 else if (delta > 0) {
488 var bottomSpace = this._physicalBottom - (scrollTop + this._viewportSize );
489 var virtualEnd = this._virtualEnd;
490 var lastVirtualItemIndex = this._virtualCount-1;
491
492 direction = SCROLL_DIRECTION_DOWN;
493 recycledTileSet = [];
494
495 kth = this._physicalStart;
496 currentRatio = bottomSpace / hiddenContentSize;
497
498 // move tiles from top to bottom
499 while (
500 // approximate `currentRatio` to `ratio`
501 currentRatio < ratio &&
502 // recycle less physical items than the total
503 recycledTiles < this._physicalCount &&
504 // ensure that these recycled tiles are needed
505 virtualEnd + recycledTiles < lastVirtualItemIndex
506 ) {
507
508 tileHeight = this._physicalSizes[kth] || this._physicalAverage;
509 currentRatio += tileHeight / hiddenContentSize;
510
511 this._physicalTop += tileHeight;
512 recycledTileSet.push(kth);
513 recycledTiles++;
514 kth = (kth + 1) % this._physicalCount;
515 }
516 }
517
518 if (recycledTiles !== 0) {
519 this._virtualStart = this._virtualStart + recycledTiles;
520 this._update(recycledTileSet, movingUp);
521 }
522 },
523
524 /**
525 * Update the list of items, starting from the `_virtualStartVal` item.
526 */
527 _update: function(itemSet, movingUp) {
528 // update models
529 this._assignModels(itemSet);
530
531 // measure heights
532 // TODO(blasten) pass `recycledTileSet`
533 this._updateMetrics();
534
535 // adjust offset after measuring
536 if (movingUp) {
537 while (movingUp.length) {
538 this._physicalTop -= this._physicalSizes[movingUp.pop()];
539 }
540 }
541
542 // update the position of the items
543 this._positionItems();
544
545 // set the scroller size
546 this._updateScrollerSize();
547
548 // increase the pool of physical items if needed
549 if (itemSet = this._increasePoolIfNeeded()) {
550 // set models to the new items
551 this.async(this._update.bind(this, itemSet));
552 }
553 },
554
555 /**
556 * Creates a pool of DOM elements and attaches them to the local dom.
557 */
558 _createPool: function(size) {
559 var physicalItems = new Array(size);
560
561 this._ensureTemplatized();
562
563 for (var i = 0; i < size; i++) {
564 var inst = this.stamp(null);
565
566 // First element child is item; Safari doesn't support children[0]
567 // on a doc fragment
568 physicalItems[i] = inst.root.querySelector('*');
569 Polymer.dom(this).appendChild(inst.root);
570 }
571
572 return physicalItems;
573 },
574
575 /**
576 * Increases the pool size. That is, the physical items in the DOM.
577 * This function will allocate additional physical items
578 * (limited by `MAX_PHYSICAL_COUNT`) if the content size is shorter than
579 * `_optPhysicalSize`
580 *
581 * @return Array
582 */
583 _increasePoolIfNeeded: function() {
584 if (this._physicalSize > this._optPhysicalSize) {
585 return null;
586 }
587
588 // the estimated number of physical items that we will need to reach
589 // the cap established by `_optPhysicalSize`.
590 var missingItems = Math.round(
591 (this._optPhysicalSize - this._physicalSize) * 1.2 / this._physicalAve rage
592 );
593
594 // limit the size
595 var nextPhysicalCount = Math.min(
596 this._physicalCount + missingItems,
597 this._virtualCount,
598 MAX_PHYSICAL_COUNT
599 );
600
601 var prevPhysicalCount = this._physicalCount;
602 var delta = nextPhysicalCount - prevPhysicalCount;
603
604 if (delta <= 0) {
605 return null;
606 }
607
608 var newPhysicalItems = this._createPool(delta);
609 var emptyArray = new Array(delta);
610
611 [].push.apply(this._physicalItems, newPhysicalItems);
612 [].push.apply(this._physicalSizes, emptyArray);
613
614 this._physicalCount = prevPhysicalCount + delta;
615
616 // fill the array with the new item pos
617 while (delta > 0) {
618 emptyArray[--delta] = prevPhysicalCount + delta;
619 }
620
621 return emptyArray;
622 },
623
624 /**
625 * Render a new list of items. This method does exactly the same as `update` ,
626 * but it also ensures that only one `update` cycle is created.
627 */
628 _render: function() {
629 if (this.isAttached && !this._initRendered && this.items) {
630 // polymer/issues/2039
631 if (window.CustomElements) {
632 window.CustomElements.takeRecords();
633 }
634 this._update();
635 this._initRendered = true;
636 }
637 },
638
639 /**
640 * Templetizes the user template.
641 */
642 _ensureTemplatized: function() {
643 if (!this.ctor) {
644 // Template instance props that should be excluded from forwarding
645 this._instanceProps = {
646 __key__: true
647 };
648 this._instanceProps[this.as] = true;
649 this._instanceProps[this.indexAs] = true;
650 this._userTemplate = Polymer.dom(this).querySelector('template');
651 if (this._userTemplate) {
652 this.templatize(this._userTemplate);
653 } else {
654 console.warn('iron-list requires a template to be provided in light-do m');
655 }
656 }
657 },
658
659 /**
660 * Implements extension point from Templatizer mixin.
661 */
662 _getStampedChildren: function() {
663 return this._physicalItems;
664 },
665
666 /**
667 * Implements extension point from Templatizer
668 * Called as a side effect of a template instance path change, responsible
669 * for notifying items.<key-for-instance>.<path> change up to host.
670 */
671 _forwardInstancePath: function(inst, path, value) {
672 if (path.indexOf(this.as + '.') === 0) {
673 this.notifyPath('items.' + inst.__key__ + '.' +
674 path.slice(this.as.length + 1), value);
675 }
676 },
677
678 /**
679 * Implements extension point from Templatizer mixin
680 * Called as side-effect of a host property change, responsible for
681 * notifying parent path change on each row.
682 */
683 _forwardParentProp: function(prop, value) {
684 if (this._physicalItems) {
685 this._physicalItems.forEach(function(item) {
686 item._templateInstance[prop] = value;
687 }, this);
688 }
689 },
690
691 /**
692 * Implements extension point from Templatizer
693 * Called as side-effect of a host path change, responsible for
694 * notifying parent.<path> path change on each row.
695 */
696 _forwardParentPath: function(path, value) {
697 if (this._physicalItems) {
698 this._physicalItems.forEach(function(item) {
699 item._templateInstance.notifyPath(path, value, true);
700 }, this);
701 }
702 },
703
704 /**
705 * Called as a side effect of a host items.<key>.<path> path change,
706 * responsible for notifying item.<path> changes to row for key.
707 */
708 _forwardItemPath: function(path, value) {
709 if (this._physicalIndexForKey) {
710 var dot = path.indexOf('.');
711 var key = path.substring(0, dot < 0 ? path.length : dot);
712 var idx = this._physicalIndexForKey[key];
713 var row = this._physicalItems[idx];
714 if (row) {
715 var inst = row._templateInstance;
716 if (dot >= 0) {
717 path = this.as + '.' + path.substring(dot+1);
718 inst.notifyPath(path, value, true);
719 } else {
720 inst[this.as] = value;
721 }
722 }
723 }
724 },
725
726 _itemsChanged: function(change) {
727 if (change.path === 'items') {
728 // render the new set
729 this._initRendered = false;
730
731 // update the whole set
732 this._virtualStartVal = 0;
733 this._physicalTop = 0;
734 this._virtualCount = this.items ? this.items.length : 0;
735 this._collection = this.items ? Polymer.Collection.get(this.items) : nul l;
736
737 // scroll to the top
738 this._resetScrollPosition(0);
739
740 // create the initial physical items
741 if (!this._physicalItems) {
742 this._physicalItems = this._createPool(this._physicalCount);
743 this._physicalSizes = new Array(this._physicalCount);
744 }
745
746 this.debounce('refresh', this._render);
747
748 } else if (change.path === 'items.splices') {
749 // render the new set
750 this._initRendered = false;
751
752 this._adjustVirtualIndex(change.value.indexSplices);
753 this._virtualCount = this.items ? this.items.length : 0;
754
755 this.debounce('refresh', this._render);
756
757 } else {
758 // update a single item
759 this._forwardItemPath(change.path.split('.').slice(1).join('.'), change. value);
760 }
761 },
762
763 _adjustVirtualIndex: function(splices) {
764 for (var i = 0; i < splices.length; i++) {
765 var splice = splices[i];
766 var idx = splice.index;
767 // We only need to care about changes happening above the current positi on
768 if (idx >= this._virtualStartVal) {
769 break;
770 }
771
772 this._virtualStart = this._virtualStart +
773 Math.max(splice.addedCount - splice.removed.length, idx - this._virt ualStartVal);
774 }
775 },
776
777 _scrollHandler: function() {
778 this._refresh();
779 },
780
781 _iterateItems: function(fn, itemSet) {
782 var pidx, vidx, rtn, i;
783
784 if (arguments.length === 2 && itemSet) {
785 for (i = 0; i < itemSet.length; i++) {
786 pidx = itemSet[i];
787 if (pidx >= this._physicalStart) {
788 vidx = this._virtualStartVal + (pidx - this._physicalStart);
789 } else {
790 vidx = this._virtualStartVal + (this._physicalCount - this._physical Start) + pidx;
791 }
792 if ((rtn = fn.call(this, pidx, vidx)) != null) {
793 return rtn;
794 }
795 }
796 } else {
797 pidx = this._physicalStart;
798 vidx = this._virtualStartVal;
799
800 for (; pidx < this._physicalCount; pidx++, vidx++) {
801 if ((rtn = fn.call(this, pidx, vidx)) != null) {
802 return rtn;
803 }
804 }
805
806 pidx = 0;
807
808 for (; pidx < this._physicalStart; pidx++, vidx++) {
809 if ((rtn = fn.call(this, pidx, vidx)) != null) {
810 return rtn;
811 }
812 }
813 }
814 },
815
816 _assignModels: function(itemSet) {
817 this._iterateItems(function(pidx, vidx) {
818 var el = this._physicalItems[pidx];
819 var inst = el._templateInstance;
820 var item = this.items && this.items[vidx];
821
822 if (item) {
823 inst[this.as] = item;
824 inst.__key__ = this._collection.getKey(item);
825 inst[this.indexAs] = vidx;
826 el.removeAttribute('hidden');
827 this._physicalIndexForKey[inst.__key__] = pidx;
828 } else {
829 inst.__key__ = null;
830 el.setAttribute('hidden', '');
831 }
832
833 }, itemSet);
834 },
835
836 _updateMetrics: function() {
837 var total = 0;
838 var prevAvgCount = this._physicalAverageCount;
839 var prevPhysicalAvg = this._physicalAverage;
840
841 for (var i = 0; i < this._physicalCount; i++) {
842 this._physicalSizes[i] = this._physicalItems[i].offsetHeight;
843 total += this._physicalSizes[i];
844 this._physicalAverageCount += this._physicalSizes[i] ? 1 : 0;
845 }
846
847 this._physicalSize = total;
848 this._viewportSize = this._scroller.offsetHeight;
849
850 if (this._physicalAverageCount !== prevAvgCount) {
851 this._physicalAverage = Math.round(
852 ((prevPhysicalAvg * prevAvgCount) + total) /
853 this._physicalAverageCount);
854 }
855 },
856
857 _positionItems: function(itemSet) {
858 this._adjustScrollPosition();
859
860 var y = this._physicalTop;
861
862 this._iterateItems(function(pidx) {
863
864 this.transform('translate3d(0, ' + y + 'px, 0)', this._physicalItems[pid x]);
865 y += this._physicalSizes[pidx];
866
867 }, itemSet);
868 },
869
870 _adjustScrollPosition: function() {
871 var deltaHeight = this._virtualStartVal === 0 ? this._physicalTop :
872 Math.min(this._scrollPosition + this._physicalTop, 0);
873
874 if (deltaHeight) {
875 this._physicalTop = this._physicalTop - deltaHeight;
876
877 // juking scroll position during interial scrolling on iOS is no bueno
878 if (!IOS_TOUCH_SCROLLING) {
879 this._resetScrollPosition(this._scroller.scrollTop - deltaHeight);
880 }
881 }
882 },
883
884 _resetScrollPosition: function(pos) {
885 if (this._scroller) {
886 this._scroller.scrollTop = pos;
887 this._scrollPosition = this._scroller.scrollTop;
888 }
889 },
890
891 _updateScrollerSize: function() {
892 this._scrollSize = (this._physicalBottom +
893 Math.max(this._virtualCount - this._physicalCount - this._virtualStart Val, 0) * this._physicalAverage);
894
895 this.$.items.style.height = this._scrollSize + 'px';
896 },
897
898 /**
899 * Scroll to a specific item in the virtual list regardless
900 * of the physical items in the DOM tree.
901 *
902 * @method scrollToIndex
903 */
904 scrollToIndex: function(idx) {
905 if (typeof idx !== 'number') {
906 return;
907 }
908
909 var firstVisible = this.firstVisibleIndex;
910
911 idx = Math.min(Math.max(idx, 0), this._virtualCount-1);
912
913 // start at the previous virtual item
914 // so we have a item above the first visible item
915 this._virtualStart = idx - 1;
916
917 // assign new models
918 this._assignModels();
919
920 // measure the new sizes
921 this._updateMetrics();
922
923 // estimate new physical offset
924 this._physicalTop = this._virtualStart * this._physicalAverage;
925
926 var currentTopItem = this._physicalStart;
927 var currentVirtualItem = this._virtualStart;
928 var targetOffsetTop = 0;
929 var hiddenContentSize = this._hiddenContentSize;
930
931 // scroll to the item as much as we can
932 while (currentVirtualItem !== idx && targetOffsetTop < hiddenContentSize) {
933 targetOffsetTop = targetOffsetTop + this._physicalSizes[currentTopItem];
934 currentTopItem = (currentTopItem + 1) % this._physicalCount;
935 currentVirtualItem++;
936 }
937
938 // update the scroller size
939 this._updateScrollerSize();
940
941 // update the position of the items
942 this._positionItems();
943
944 // set the new scroll position
945 this._resetScrollPosition(this._physicalTop + targetOffsetTop + 1);
946
947 // clear cached visible index
948 this._firstVisibleIndexVal = null;
949 },
950
951 _resetAverage: function() {
952 this._physicalAverage = 0;
953 this._physicalAverageCount = 0;
954 },
955
956 _resizeHandler: function() {
957 if (this._physicalItems) {
958 this.debounce('resize', function() {
959 this._resetAverage();
960 this.updateViewportBoundaries();
961 this.scrollToIndex(this.firstVisibleIndex);
962 });
963 }
964 }
965 });
966
967 })();
968
969 </script>
OLDNEW
« no previous file with comments | « polymer_1.0.4/bower_components/iron-list/index.html ('k') | polymer_1.0.4/bower_components/iron-list/test/basic.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698