73bcce88
luigser
COMPONENTS
|
1
2
3
4
5
6
7
8
9
10
11
12
|
<!--
@license
Copyright (c) 2015 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
-->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
|
a53fbbed
Renato De Donato
select-dataset ne...
|
13
14
|
<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
<link rel="import" href="../iron-scroll-target-behavior/iron-scroll-target-behavior.html">
|
73bcce88
luigser
COMPONENTS
|
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<!--
`iron-list` displays a virtual, 'infinite' list. The template inside
the iron-list element represents the DOM to create for each list item.
The `items` 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.
|
a53fbbed
Renato De Donato
select-dataset ne...
|
30
|
__Important:__ `iron-list` must either be explicitly sized, or delegate scrolling to an
|
73bcce88
luigser
COMPONENTS
|
31
32
33
34
35
36
37
38
|
explicitly sized parent. By "explicitly sized", we mean it either has an explicit
CSS `height` property set via a class or inline style, or else is sized by other
layout means (e.g. the `flex` or `fit` classes).
### Template model
List item templates should bind to template models of the following structure:
|
a53fbbed
Renato De Donato
select-dataset ne...
|
39
40
41
42
43
44
45
46
|
```js
{
index: 0, // index in the item array
selected: false, // true if the current item is selected
tabIndex: -1, // a dynamically generated tabIndex for focus management
item: {} // user data corresponding to items[index]
}
```
|
73bcce88
luigser
COMPONENTS
|
47
48
49
50
51
52
53
54
55
|
Alternatively, you can change the property name used as data index by changing the
`indexAs` property. The `as` property defines the name of the variable to add to the binding
scope for the array.
For example, given the following `data` array:
##### data.json
|
a53fbbed
Renato De Donato
select-dataset ne...
|
56
57
58
59
60
61
62
|
```js
[
{"name": "Bob"},
{"name": "Tim"},
{"name": "Mike"}
]
```
|
73bcce88
luigser
COMPONENTS
|
63
64
65
66
|
The following code would render the list (note the name and checked properties are
bound from the model object provided to the template scope):
|
a53fbbed
Renato De Donato
select-dataset ne...
|
67
68
69
70
71
72
73
74
|
```html
<template is="dom-bind">
<iron-ajax url="data.json" last-response="{{data}}" auto></iron-ajax>
<iron-list items="[[data]]" as="item">
<template>
<div>
Name: [[item.name]]
</div>
|
73bcce88
luigser
COMPONENTS
|
75
|
</template>
|
a53fbbed
Renato De Donato
select-dataset ne...
|
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
</iron-list>
</template>
```
### Accessibility
`iron-list` automatically manages the focus state for the items. It also provides
a `tabIndex` property within the template scope that can be used for keyboard navigation.
For example, users can press the up and down keys to move to previous and next
items in the list:
```html
<iron-list items="[[data]]" as="item">
<template>
<div tabindex$="[[tabIndex]]">
Name: [[item.name]]
</div>
</template>
</iron-list>
```
|
73bcce88
luigser
COMPONENTS
|
96
|
|
eb240478
Luigi Serra
public room cards...
|
97
98
|
### Styling
|
a53fbbed
Renato De Donato
select-dataset ne...
|
99
|
You can use the `--iron-list-items-container` mixin to style the container of items:
|
eb240478
Luigi Serra
public room cards...
|
100
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
101
102
103
104
105
106
107
|
```css
iron-list {
--iron-list-items-container: {
margin: auto;
};
}
```
|
eb240478
Luigi Serra
public room cards...
|
108
|
|
e619a3b0
Luigi Serra
Controllet cross ...
|
109
110
|
### Resizing
|
a53fbbed
Renato De Donato
select-dataset ne...
|
111
|
`iron-list` lays out the items when it receives a notification via the `iron-resize` event.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
112
113
114
115
116
|
This event is fired by any element that implements `IronResizableBehavior`.
By default, elements such as `iron-pages`, `paper-tabs` or `paper-dialog` will trigger
this event automatically. If you hide the list manually (e.g. you use `display: none`)
you might want to implement `IronResizableBehavior` or fire this event manually right
|
a53fbbed
Renato De Donato
select-dataset ne...
|
117
|
after the list became visible again. For example:
|
e619a3b0
Luigi Serra
Controllet cross ...
|
118
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
119
120
121
|
```js
document.querySelector('iron-list').fire('iron-resize');
```
|
e619a3b0
Luigi Serra
Controllet cross ...
|
122
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
123
124
125
126
127
128
129
130
131
132
133
|
### When should `<iron-list>` be used?
`iron-list` should be used when a page has significantly more DOM nodes than the ones
visible on the screen. e.g. the page has 500 nodes, but only 20 are visible at the time.
This is why we refer to it as a `virtual` list. In this case, a `dom-repeat` will still
create 500 nodes which could slow down the web app, but `iron-list` will only create 20.
However, having an `iron-list` does not mean that you can load all the data at once.
Say, you have a million records in the database, you want to split the data into pages
so you can bring a page at the time. The page could contain 500 items, and iron-list
will only render 20.
|
73bcce88
luigser
COMPONENTS
|
134
135
136
|
@group Iron Element
@element iron-list
|
a53fbbed
Renato De Donato
select-dataset ne...
|
137
138
|
@demo demo/index.html List of cards
@demo demo/selection.html Items selection
|
eb240478
Luigi Serra
public room cards...
|
139
|
@demo demo/collapse.html Collapsable items
|
a53fbbed
Renato De Donato
select-dataset ne...
|
140
141
142
|
@demo demo/scroll-threshold.html Scroll thesholds
@demo demo/basic.html Basic list
|
73bcce88
luigser
COMPONENTS
|
143
144
145
|
-->
<dom-module id="iron-list">
|
eb240478
Luigi Serra
public room cards...
|
146
147
148
149
|
<template>
<style>
:host {
display: block;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
150
|
position: relative;
|
eb240478
Luigi Serra
public room cards...
|
151
|
}
|
73bcce88
luigser
COMPONENTS
|
152
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
153
154
155
156
|
@media only screen and (-webkit-max-device-pixel-ratio: 1) {
:host {
will-change: transform;
}
|
eb240478
Luigi Serra
public room cards...
|
157
|
}
|
73bcce88
luigser
COMPONENTS
|
158
|
|
eb240478
Luigi Serra
public room cards...
|
159
160
161
162
|
#items {
@apply(--iron-list-items-container);
position: relative;
}
|
73bcce88
luigser
COMPONENTS
|
163
|
|
eb240478
Luigi Serra
public room cards...
|
164
165
166
167
168
169
170
171
|
#items > ::content > * {
width: 100%;
box-sizing: border-box;
position: absolute;
top: 0;
will-change: transform;
}
</style>
|
e619a3b0
Luigi Serra
Controllet cross ...
|
172
173
|
<array-selector id="selector" items="{{items}}"
|
eb240478
Luigi Serra
public room cards...
|
174
|
selected="{{selectedItems}}" selected-item="{{selectedItem}}">
|
e619a3b0
Luigi Serra
Controllet cross ...
|
175
176
|
</array-selector>
|
73bcce88
luigser
COMPONENTS
|
177
178
179
|
<div id="items">
<content></content>
</div>
|
e619a3b0
Luigi Serra
Controllet cross ...
|
180
|
|
73bcce88
luigser
COMPONENTS
|
181
182
183
184
185
186
187
188
189
|
</template>
</dom-module>
<script>
(function() {
var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
190
|
var DEFAULT_PHYSICAL_COUNT = 3;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
191
|
var MAX_PHYSICAL_COUNT = 500;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
192
|
var HIDDEN_Y = '-10000px';
|
73bcce88
luigser
COMPONENTS
|
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
Polymer({
is: 'iron-list',
properties: {
/**
* An array containing items determining how many instances of the template
* to stamp and that that each template instance should bind to.
*/
items: {
type: Array
},
/**
* The name of the variable to add to the binding scope for the array
* element associated with a given template instance.
*/
as: {
type: String,
value: 'item'
},
/**
* The name of the variable to add to the binding scope with the index
|
eb240478
Luigi Serra
public room cards...
|
219
|
* for the row.
|
73bcce88
luigser
COMPONENTS
|
220
221
222
223
|
*/
indexAs: {
type: String,
value: 'index'
|
e619a3b0
Luigi Serra
Controllet cross ...
|
224
|
},
|
73bcce88
luigser
COMPONENTS
|
225
|
|
e619a3b0
Luigi Serra
Controllet cross ...
|
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
|
/**
* The name of the variable to add to the binding scope to indicate
* if the row is selected.
*/
selectedAs: {
type: String,
value: 'selected'
},
/**
* 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.
*/
selectionEnabled: {
type: Boolean,
value: false
},
/**
* When `multiSelection` is false, this is the currently selected item, or `null`
* if no item is selected.
*/
selectedItem: {
type: Object,
notify: true
},
/**
* When `multiSelection` is true, this is an array that contains the selected items.
*/
selectedItems: {
type: Object,
notify: true
},
/**
* When `true`, multiple items may be selected at once (in this case,
* `selected` is an array of currently selected items). When `false`,
* only one item may be selected at a time.
*/
multiSelection: {
type: Boolean,
value: false
}
|
73bcce88
luigser
COMPONENTS
|
273
274
275
|
},
observers: [
|
e619a3b0
Luigi Serra
Controllet cross ...
|
276
277
|
'_itemsChanged(items.*)',
'_selectionEnabledChanged(selectionEnabled)',
|
a53fbbed
Renato De Donato
select-dataset ne...
|
278
279
|
'_multiSelectionChanged(multiSelection)',
'_setOverflow(scrollTarget)'
|
73bcce88
luigser
COMPONENTS
|
280
281
282
283
|
],
behaviors: [
Polymer.Templatizer,
|
a53fbbed
Renato De Donato
select-dataset ne...
|
284
285
286
|
Polymer.IronResizableBehavior,
Polymer.IronA11yKeysBehavior,
Polymer.IronScrollTargetBehavior
|
73bcce88
luigser
COMPONENTS
|
287
288
|
],
|
a53fbbed
Renato De Donato
select-dataset ne...
|
289
290
291
292
|
keyBindings: {
'up': '_didMoveUp',
'down': '_didMoveDown',
'enter': '_didEnter'
|
73bcce88
luigser
COMPONENTS
|
293
294
295
296
|
},
/**
* The ratio of hidden tiles that should remain in the scroll direction.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
297
|
* Recommended value ~0.5, so it will distribute tiles evely in both directions.
|
73bcce88
luigser
COMPONENTS
|
298
299
300
301
|
*/
_ratio: 0.5,
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
302
|
* The padding-top value for the list.
|
73bcce88
luigser
COMPONENTS
|
303
304
305
306
307
308
309
310
311
|
*/
_scrollerPaddingTop: 0,
/**
* This value is the same as `scrollTop`.
*/
_scrollPosition: 0,
/**
|
73bcce88
luigser
COMPONENTS
|
312
313
314
315
316
|
* The sum of the heights of all the tiles in the DOM.
*/
_physicalSize: 0,
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
317
|
* The average `F` of the tiles observed till now.
|
73bcce88
luigser
COMPONENTS
|
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
|
*/
_physicalAverage: 0,
/**
* The number of tiles which `offsetHeight` > 0 observed until now.
*/
_physicalAverageCount: 0,
/**
* The Y position of the item rendered in the `_physicalStart`
* tile relative to the scrolling list.
*/
_physicalTop: 0,
/**
* The number of items in the list.
*/
_virtualCount: 0,
/**
|
73bcce88
luigser
COMPONENTS
|
338
339
|
* A map between an item key and its physical item index
*/
|
e619a3b0
Luigi Serra
Controllet cross ...
|
340
341
342
343
344
345
|
_physicalIndexForKey: null,
/**
* The estimated scroll height based on `_physicalAverage`
*/
_estScrollHeight: 0,
|
73bcce88
luigser
COMPONENTS
|
346
347
|
/**
|
e619a3b0
Luigi Serra
Controllet cross ...
|
348
|
* The scroll height of the dom node
|
73bcce88
luigser
COMPONENTS
|
349
|
*/
|
e619a3b0
Luigi Serra
Controllet cross ...
|
350
|
_scrollHeight: 0,
|
73bcce88
luigser
COMPONENTS
|
351
352
|
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
353
|
* The height of the list. This is referred as the viewport in the context of list.
|
73bcce88
luigser
COMPONENTS
|
354
355
356
357
358
|
*/
_viewportSize: 0,
/**
* An array of DOM nodes that are currently in the tree
|
e619a3b0
Luigi Serra
Controllet cross ...
|
359
|
* @type {?Array<!TemplatizerNode>}
|
73bcce88
luigser
COMPONENTS
|
360
361
362
363
364
|
*/
_physicalItems: null,
/**
* An array of heights for each item in `_physicalItems`
|
e619a3b0
Luigi Serra
Controllet cross ...
|
365
|
* @type {?Array<number>}
|
73bcce88
luigser
COMPONENTS
|
366
367
368
369
|
*/
_physicalSizes: null,
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
370
|
* A cached value for the first visible index.
|
73bcce88
luigser
COMPONENTS
|
371
|
* See `firstVisibleIndex`
|
e619a3b0
Luigi Serra
Controllet cross ...
|
372
|
* @type {?number}
|
73bcce88
luigser
COMPONENTS
|
373
374
375
376
|
*/
_firstVisibleIndexVal: null,
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
377
378
379
380
381
382
383
|
* A cached value for the last visible index.
* See `lastVisibleIndex`
* @type {?number}
*/
_lastVisibleIndexVal: null,
/**
|
73bcce88
luigser
COMPONENTS
|
384
|
* A Polymer collection for the items.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
385
|
* @type {?Polymer.Collection}
|
73bcce88
luigser
COMPONENTS
|
386
387
388
|
*/
_collection: null,
|
e619a3b0
Luigi Serra
Controllet cross ...
|
389
390
391
392
393
394
395
|
/**
* True if the current item list was rendered for the first time
* after attached.
*/
_itemsRendered: false,
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
|
* The page that is currently rendered.
*/
_lastPage: null,
/**
* The max number of pages to render. One page is equivalent to the height of the list.
*/
_maxPages: 3,
/**
* The currently focused physical item.
*/
_focusedItem: null,
/**
* The index of the `_focusedItem`.
*/
_focusedIndex: -1,
/**
* The the item that is focused if it is moved offscreen.
* @private {?TemplatizerNode}
*/
_offscreenFocusedItem: null,
/**
* The item that backfills the `_offscreenFocusedItem` in the physical items
* list when that item is moved offscreen.
*/
_focusBackfillItem: null,
/**
|
e619a3b0
Luigi Serra
Controllet cross ...
|
428
429
|
* The bottom of the physical content.
*/
|
73bcce88
luigser
COMPONENTS
|
430
431
432
433
|
get _physicalBottom() {
return this._physicalTop + this._physicalSize;
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
434
|
/**
|
f748e9cf
Luigi Serra
new controllet an...
|
435
436
437
438
439
440
441
|
* The bottom of the scroll.
*/
get _scrollBottom() {
return this._scrollPosition + this._viewportSize;
},
/**
|
e619a3b0
Luigi Serra
Controllet cross ...
|
442
443
|
* The n-th item rendered in the last physical item.
*/
|
73bcce88
luigser
COMPONENTS
|
444
|
get _virtualEnd() {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
|
return this._virtualStart + this._physicalCount - 1;
},
/**
* The height of the physical content that isn't on the screen.
*/
get _hiddenContentSize() {
return this._physicalSize - this._viewportSize;
},
/**
* The maximum scroll top value.
*/
get _maxScrollTop() {
return this._estScrollHeight - this._viewportSize + this._scrollerPaddingTop;
|
73bcce88
luigser
COMPONENTS
|
460
461
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
462
463
464
465
466
467
468
469
|
/**
* The lowest n-th value for an item such that it can be rendered in `_physicalStart`.
*/
_minVirtualStart: 0,
/**
* The largest n-th value for an item such that it can be rendered in `_physicalStart`.
*/
|
73bcce88
luigser
COMPONENTS
|
470
|
get _maxVirtualStart() {
|
eb240478
Luigi Serra
public room cards...
|
471
|
return Math.max(0, this._virtualCount - this._physicalCount);
|
73bcce88
luigser
COMPONENTS
|
472
473
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
474
|
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
475
|
* The n-th item rendered in the `_physicalStart` tile.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
476
|
*/
|
a53fbbed
Renato De Donato
select-dataset ne...
|
477
478
479
480
481
482
483
484
|
_virtualStartVal: 0,
set _virtualStart(val) {
this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
},
get _virtualStart() {
return this._virtualStartVal || 0;
|
73bcce88
luigser
COMPONENTS
|
485
486
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
487
|
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
488
|
* The k-th tile that is at the top of the scrolling list.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
489
|
*/
|
a53fbbed
Renato De Donato
select-dataset ne...
|
490
491
492
493
494
495
496
497
498
499
500
501
|
_physicalStartVal: 0,
set _physicalStart(val) {
this._physicalStartVal = val % this._physicalCount;
if (this._physicalStartVal < 0) {
this._physicalStartVal = this._physicalCount + this._physicalStartVal;
}
this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
},
get _physicalStart() {
return this._physicalStartVal || 0;
|
73bcce88
luigser
COMPONENTS
|
502
503
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
504
|
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
505
|
* The number of tiles in the DOM.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
506
|
*/
|
a53fbbed
Renato De Donato
select-dataset ne...
|
507
508
509
510
|
_physicalCountVal: 0,
set _physicalCount(val) {
this._physicalCountVal = val;
|
73bcce88
luigser
COMPONENTS
|
511
512
513
|
this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
},
|
a53fbbed
Renato De Donato
select-dataset ne...
|
514
515
516
517
|
get _physicalCount() {
return this._physicalCountVal;
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
518
|
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
519
|
* The k-th tile that is at the bottom of the scrolling list.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
520
|
*/
|
a53fbbed
Renato De Donato
select-dataset ne...
|
521
|
_physicalEnd: 0,
|
73bcce88
luigser
COMPONENTS
|
522
523
|
/**
|
e619a3b0
Luigi Serra
Controllet cross ...
|
524
525
526
527
528
529
530
|
* An optimal physical size such that we will have enough physical items
* to fill up the viewport and recycle when the user scrolls.
*
* This default value assumes that we will at least have the equivalent
* to a viewport of physical items above and below the user's viewport.
*/
get _optPhysicalSize() {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
531
|
return this._viewportSize * this._maxPages;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
532
533
534
535
536
537
|
},
/**
* True if the current list is visible.
*/
get _isVisible() {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
538
|
return this.scrollTarget && Boolean(this.scrollTarget.offsetWidth || this.scrollTarget.offsetHeight);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
539
540
541
|
},
/**
|
eb240478
Luigi Serra
public room cards...
|
542
|
* Gets the index of the first visible item in the viewport.
|
73bcce88
luigser
COMPONENTS
|
543
|
*
|
eb240478
Luigi Serra
public room cards...
|
544
|
* @type {number}
|
73bcce88
luigser
COMPONENTS
|
545
546
|
*/
get firstVisibleIndex() {
|
e619a3b0
Luigi Serra
Controllet cross ...
|
547
|
if (this._firstVisibleIndexVal === null) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
548
|
var physicalOffset = this._physicalTop + this._scrollerPaddingTop;
|
73bcce88
luigser
COMPONENTS
|
549
550
551
552
|
this._firstVisibleIndexVal = this._iterateItems(
function(pidx, vidx) {
physicalOffset += this._physicalSizes[pidx];
|
73bcce88
luigser
COMPONENTS
|
553
554
555
556
557
|
if (physicalOffset > this._scrollPosition) {
return vidx;
}
}) || 0;
}
|
73bcce88
luigser
COMPONENTS
|
558
559
560
|
return this._firstVisibleIndexVal;
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
561
|
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
562
563
564
|
* Gets the index of the last visible item in the viewport.
*
* @type {number}
|
e619a3b0
Luigi Serra
Controllet cross ...
|
565
|
*/
|
a53fbbed
Renato De Donato
select-dataset ne...
|
566
567
568
|
get lastVisibleIndex() {
if (this._lastVisibleIndexVal === null) {
var physicalOffset = this._physicalTop;
|
73bcce88
luigser
COMPONENTS
|
569
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
570
571
|
this._iterateItems(function(pidx, vidx) {
physicalOffset += this._physicalSizes[pidx];
|
73bcce88
luigser
COMPONENTS
|
572
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
573
574
575
576
|
if (physicalOffset <= this._scrollBottom) {
this._lastVisibleIndexVal = vidx;
}
});
|
e619a3b0
Luigi Serra
Controllet cross ...
|
577
|
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
578
579
580
581
582
583
|
return this._lastVisibleIndexVal;
},
get _defaultScrollTarget() {
return this;
},
|
73bcce88
luigser
COMPONENTS
|
584
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
585
586
587
|
ready: function() {
this.addEventListener('focus', this._didFocus.bind(this), true);
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
588
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
589
|
attached: function() {
|
e619a3b0
Luigi Serra
Controllet cross ...
|
590
591
|
this.updateViewportBoundaries();
this._render();
|
a53fbbed
Renato De Donato
select-dataset ne...
|
592
593
594
|
// `iron-resize` is fired when the list is attached if the event is added
// before attached causing unnecessary work.
this.listen(this, 'iron-resize', '_resizeHandler');
|
e619a3b0
Luigi Serra
Controllet cross ...
|
595
596
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
597
598
|
detached: function() {
this._itemsRendered = false;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
599
600
601
602
603
604
605
606
607
|
this.unlisten(this, 'iron-resize', '_resizeHandler');
},
/**
* Set the overflow property if this element has its own scrolling region
*/
_setOverflow: function(scrollTarget) {
this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
this.style.overflow = scrollTarget === this ? 'auto' : '';
|
73bcce88
luigser
COMPONENTS
|
608
609
610
611
612
613
614
615
616
|
},
/**
* Invoke this method if you dynamically update the viewport's
* size or CSS padding.
*
* @method updateViewportBoundaries
*/
updateViewportBoundaries: function() {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
617
618
619
620
|
this._scrollerPaddingTop = this.scrollTarget === this ? 0 :
parseInt(window.getComputedStyle(this)['padding-top'], 10);
this._viewportSize = this._scrollTargetHeight;
|
73bcce88
luigser
COMPONENTS
|
621
622
623
624
625
626
|
},
/**
* Update the models, the position of the
* items in the viewport and recycle tiles as needed.
*/
|
a53fbbed
Renato De Donato
select-dataset ne...
|
627
|
_scrollHandler: function() {
|
73bcce88
luigser
COMPONENTS
|
628
|
// clamp the `scrollTop` value
|
a53fbbed
Renato De Donato
select-dataset ne...
|
629
|
var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
|
73bcce88
luigser
COMPONENTS
|
630
|
var delta = scrollTop - this._scrollPosition;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
631
632
|
var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
var ratio = this._ratio;
|
73bcce88
luigser
COMPONENTS
|
633
634
635
636
637
638
639
640
|
var recycledTiles = 0;
var hiddenContentSize = this._hiddenContentSize;
var currentRatio = ratio;
var movingUp = [];
// track the last `scrollTop`
this._scrollPosition = scrollTop;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
641
|
// clear cached visible indexes
|
73bcce88
luigser
COMPONENTS
|
642
|
this._firstVisibleIndexVal = null;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
643
|
this._lastVisibleIndexVal = null;
|
73bcce88
luigser
COMPONENTS
|
644
|
|
f748e9cf
Luigi Serra
new controllet an...
|
645
|
scrollBottom = this._scrollBottom;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
646
|
physicalBottom = this._physicalBottom;
|
f748e9cf
Luigi Serra
new controllet an...
|
647
|
|
73bcce88
luigser
COMPONENTS
|
648
|
// random access
|
e619a3b0
Luigi Serra
Controllet cross ...
|
649
|
if (Math.abs(delta) > this._physicalSize) {
|
73bcce88
luigser
COMPONENTS
|
650
|
this._physicalTop += delta;
|
73bcce88
luigser
COMPONENTS
|
651
652
653
654
655
656
|
recycledTiles = Math.round(delta / this._physicalAverage);
}
// scroll up
else if (delta < 0) {
var topSpace = scrollTop - this._physicalTop;
var virtualStart = this._virtualStart;
|
73bcce88
luigser
COMPONENTS
|
657
|
|
73bcce88
luigser
COMPONENTS
|
658
659
660
661
662
663
664
665
666
667
668
669
|
recycledTileSet = [];
kth = this._physicalEnd;
currentRatio = topSpace / hiddenContentSize;
// move tiles from bottom to top
while (
// approximate `currentRatio` to `ratio`
currentRatio < ratio &&
// recycle less physical items than the total
recycledTiles < this._physicalCount &&
// ensure that these recycled tiles are needed
|
f748e9cf
Luigi Serra
new controllet an...
|
670
671
672
|
virtualStart - recycledTiles > 0 &&
// ensure that the tile is not visible
physicalBottom - this._physicalSizes[kth] > scrollBottom
|
73bcce88
luigser
COMPONENTS
|
673
674
|
) {
|
f748e9cf
Luigi Serra
new controllet an...
|
675
|
tileHeight = this._physicalSizes[kth];
|
73bcce88
luigser
COMPONENTS
|
676
|
currentRatio += tileHeight / hiddenContentSize;
|
f748e9cf
Luigi Serra
new controllet an...
|
677
|
physicalBottom -= tileHeight;
|
73bcce88
luigser
COMPONENTS
|
678
679
680
681
682
683
684
|
recycledTileSet.push(kth);
recycledTiles++;
kth = (kth === 0) ? this._physicalCount - 1 : kth - 1;
}
movingUp = recycledTileSet;
recycledTiles = -recycledTiles;
|
73bcce88
luigser
COMPONENTS
|
685
686
687
|
}
// scroll down
else if (delta > 0) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
688
|
var bottomSpace = physicalBottom - scrollBottom;
|
73bcce88
luigser
COMPONENTS
|
689
690
691
|
var virtualEnd = this._virtualEnd;
var lastVirtualItemIndex = this._virtualCount-1;
|
73bcce88
luigser
COMPONENTS
|
692
693
694
695
696
697
698
699
700
701
702
703
|
recycledTileSet = [];
kth = this._physicalStart;
currentRatio = bottomSpace / hiddenContentSize;
// move tiles from top to bottom
while (
// approximate `currentRatio` to `ratio`
currentRatio < ratio &&
// recycle less physical items than the total
recycledTiles < this._physicalCount &&
// ensure that these recycled tiles are needed
|
f748e9cf
Luigi Serra
new controllet an...
|
704
705
706
|
virtualEnd + recycledTiles < lastVirtualItemIndex &&
// ensure that the tile is not visible
this._physicalTop + this._physicalSizes[kth] < scrollTop
|
73bcce88
luigser
COMPONENTS
|
707
708
|
) {
|
f748e9cf
Luigi Serra
new controllet an...
|
709
|
tileHeight = this._physicalSizes[kth];
|
73bcce88
luigser
COMPONENTS
|
710
711
712
713
714
715
716
717
718
|
currentRatio += tileHeight / hiddenContentSize;
this._physicalTop += tileHeight;
recycledTileSet.push(kth);
recycledTiles++;
kth = (kth + 1) % this._physicalCount;
}
}
|
f748e9cf
Luigi Serra
new controllet an...
|
719
|
if (recycledTiles === 0) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
720
721
722
|
// Try to increase the pool if the list's client height isn't filled up with physical items
if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
this._increasePoolIfNeeded();
|
f748e9cf
Luigi Serra
new controllet an...
|
723
724
|
}
} else {
|
73bcce88
luigser
COMPONENTS
|
725
|
this._virtualStart = this._virtualStart + recycledTiles;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
726
|
this._physicalStart = this._physicalStart + recycledTiles;
|
73bcce88
luigser
COMPONENTS
|
727
728
729
730
|
this._update(recycledTileSet, movingUp);
}
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
731
|
/**
|
a53fbbed
Renato De Donato
select-dataset ne...
|
732
|
* Update the list of items, starting from the `_virtualStart` item.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
733
734
735
736
|
* @param {!Array<number>=} itemSet
* @param {!Array<number>=} movingUp
*/
_update: function(itemSet, movingUp) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
737
738
|
// manage focus
this._manageFocus();
|
73bcce88
luigser
COMPONENTS
|
739
|
// update models
|
e619a3b0
Luigi Serra
Controllet cross ...
|
740
|
this._assignModels(itemSet);
|
73bcce88
luigser
COMPONENTS
|
741
|
// measure heights
|
eb240478
Luigi Serra
public room cards...
|
742
|
this._updateMetrics(itemSet);
|
73bcce88
luigser
COMPONENTS
|
743
744
745
746
747
748
|
// adjust offset after measuring
if (movingUp) {
while (movingUp.length) {
this._physicalTop -= this._physicalSizes[movingUp.pop()];
}
}
|
e619a3b0
Luigi Serra
Controllet cross ...
|
749
|
// update the position of the items
|
73bcce88
luigser
COMPONENTS
|
750
|
this._positionItems();
|
73bcce88
luigser
COMPONENTS
|
751
752
|
// set the scroller size
this._updateScrollerSize();
|
a53fbbed
Renato De Donato
select-dataset ne...
|
753
754
|
// increase the pool of physical items
this._increasePoolIfNeeded();
|
73bcce88
luigser
COMPONENTS
|
755
756
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
757
758
759
760
761
762
763
764
765
766
|
/**
* Creates a pool of DOM elements and attaches them to the local dom.
*/
_createPool: function(size) {
var physicalItems = new Array(size);
this._ensureTemplatized();
for (var i = 0; i < size; i++) {
var inst = this.stamp(null);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
767
768
769
770
771
|
// First element child is item; Safari doesn't support children[0]
// on a doc fragment
physicalItems[i] = inst.root.querySelector('*');
Polymer.dom(this).appendChild(inst.root);
}
|
e619a3b0
Luigi Serra
Controllet cross ...
|
772
773
774
775
|
return physicalItems;
},
/**
|
f748e9cf
Luigi Serra
new controllet an...
|
776
|
* Increases the pool of physical items only if needed.
|
c5169e0e
Renato De Donato
a new hope
|
777
|
*
|
a53fbbed
Renato De Donato
select-dataset ne...
|
778
|
* @return {boolean} True if the pool was increased.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
779
780
|
*/
_increasePoolIfNeeded: function() {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
781
782
|
// Base case 1: the list has no size.
if (this._viewportSize === 0) {
|
c5169e0e
Renato De Donato
a new hope
|
783
784
|
return false;
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
785
786
787
788
789
|
// Base case 2: If the physical size is optimal and the list's client height is full
// with physical items, don't increase the pool.
var isClientHeightFull = this._physicalBottom >= this._scrollBottom && this._physicalTop <= this._scrollPosition;
if (this._physicalSize >= this._optPhysicalSize && isClientHeightFull) {
return false;
|
c5169e0e
Renato De Donato
a new hope
|
790
|
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
791
792
793
794
795
796
797
798
799
800
801
802
803
|
// this value should range between [0 <= `currentPage` <= `_maxPages`]
var currentPage = Math.floor(this._physicalSize / this._viewportSize);
if (currentPage === 0) {
// fill the first page
this._debounceTemplate(this._increasePool.bind(this, Math.round(this._physicalCount * 0.5)));
} else if (this._lastPage !== currentPage && isClientHeightFull) {
// paint the page and defer the next increase
// wait 16ms which is rough enough to get paint cycle.
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increasePool.bind(this, 1), 16));
} else {
// fill the rest of the pages
this._debounceTemplate(this._increasePool.bind(this, 1));
|
f748e9cf
Luigi Serra
new controllet an...
|
804
|
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
805
806
807
808
|
this._lastPage = currentPage;
return true;
|
f748e9cf
Luigi Serra
new controllet an...
|
809
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
810
|
|
f748e9cf
Luigi Serra
new controllet an...
|
811
812
813
814
|
/**
* Increases the pool size.
*/
_increasePool: function(missingItems) {
|
e619a3b0
Luigi Serra
Controllet cross ...
|
815
816
|
var nextPhysicalCount = Math.min(
this._physicalCount + missingItems,
|
a53fbbed
Renato De Donato
select-dataset ne...
|
817
|
this._virtualCount - this._virtualStart,
|
e619a3b0
Luigi Serra
Controllet cross ...
|
818
819
|
MAX_PHYSICAL_COUNT
);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
820
821
822
|
var prevPhysicalCount = this._physicalCount;
var delta = nextPhysicalCount - prevPhysicalCount;
|
c5169e0e
Renato De Donato
a new hope
|
823
|
if (delta <= 0) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
824
|
return;
|
a1a3bc73
Luigi Serra
graphs updates
|
825
|
}
|
c5169e0e
Renato De Donato
a new hope
|
826
827
828
829
830
831
|
[].push.apply(this._physicalItems, this._createPool(delta));
[].push.apply(this._physicalSizes, new Array(delta));
this._physicalCount = prevPhysicalCount + delta;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
832
833
834
835
836
837
838
839
840
|
// update the physical start if we need to preserve the model of the focused item.
// In this situation, the focused item is currently rendered and its model would
// have changed after increasing the pool if the physical start remained unchanged.
if (this._physicalStart > this._physicalEnd &&
this._isIndexRendered(this._focusedIndex) &&
this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
this._physicalStart = this._physicalStart + delta;
}
this._update();
|
73bcce88
luigser
COMPONENTS
|
841
842
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
843
844
845
846
847
848
849
|
/**
* Render a new list of items. This method does exactly the same as `update`,
* but it also ensures that only one `update` cycle is created.
*/
_render: function() {
var requiresUpdate = this._virtualCount > 0 || this._physicalCount > 0;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
850
851
|
if (this.isAttached && !this._itemsRendered && this._isVisible && requiresUpdate) {
this._lastPage = 0;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
852
853
854
855
856
857
858
859
|
this._update();
this._itemsRendered = true;
}
},
/**
* Templetizes the user template.
*/
|
73bcce88
luigser
COMPONENTS
|
860
861
862
|
_ensureTemplatized: function() {
if (!this.ctor) {
// Template instance props that should be excluded from forwarding
|
e619a3b0
Luigi Serra
Controllet cross ...
|
863
|
var props = {};
|
e619a3b0
Luigi Serra
Controllet cross ...
|
864
865
866
867
|
props.__key__ = true;
props[this.as] = true;
props[this.indexAs] = true;
props[this.selectedAs] = true;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
868
|
props.tabIndex = true;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
869
870
|
this._instanceProps = props;
|
73bcce88
luigser
COMPONENTS
|
871
|
this._userTemplate = Polymer.dom(this).querySelector('template');
|
e619a3b0
Luigi Serra
Controllet cross ...
|
872
|
|
73bcce88
luigser
COMPONENTS
|
873
874
875
|
if (this._userTemplate) {
this.templatize(this._userTemplate);
} else {
|
e619a3b0
Luigi Serra
Controllet cross ...
|
876
|
console.warn('iron-list requires a template to be provided in light-dom');
|
73bcce88
luigser
COMPONENTS
|
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
|
}
}
},
/**
* Implements extension point from Templatizer mixin.
*/
_getStampedChildren: function() {
return this._physicalItems;
},
/**
* Implements extension point from Templatizer
* Called as a side effect of a template instance path change, responsible
* for notifying items.<key-for-instance>.<path> change up to host.
*/
_forwardInstancePath: function(inst, path, value) {
if (path.indexOf(this.as + '.') === 0) {
this.notifyPath('items.' + inst.__key__ + '.' +
path.slice(this.as.length + 1), value);
}
},
/**
* Implements extension point from Templatizer mixin
* Called as side-effect of a host property change, responsible for
* notifying parent path change on each row.
*/
_forwardParentProp: function(prop, value) {
if (this._physicalItems) {
this._physicalItems.forEach(function(item) {
item._templateInstance[prop] = value;
}, this);
}
},
/**
* Implements extension point from Templatizer
* Called as side-effect of a host path change, responsible for
* notifying parent.<path> path change on each row.
*/
_forwardParentPath: function(path, value) {
if (this._physicalItems) {
this._physicalItems.forEach(function(item) {
item._templateInstance.notifyPath(path, value, true);
}, this);
}
},
/**
* Called as a side effect of a host items.<key>.<path> path change,
|
a53fbbed
Renato De Donato
select-dataset ne...
|
928
|
* responsible for notifying item.<path> changes.
|
73bcce88
luigser
COMPONENTS
|
929
930
|
*/
_forwardItemPath: function(path, value) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
|
if (!this._physicalIndexForKey) {
return;
}
var inst;
var dot = path.indexOf('.');
var key = path.substring(0, dot < 0 ? path.length : dot);
var idx = this._physicalIndexForKey[key];
var el = this._physicalItems[idx];
if (idx === this._focusedIndex && this._offscreenFocusedItem) {
el = this._offscreenFocusedItem;
}
if (!el) {
return;
}
inst = el._templateInstance;
if (inst.__key__ !== key) {
return;
}
if (dot >= 0) {
path = this.as + '.' + path.substring(dot+1);
inst.notifyPath(path, value, true);
} else {
inst[this.as] = value;
|
73bcce88
luigser
COMPONENTS
|
958
959
960
|
}
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
961
962
963
964
|
/**
* Called when the items have changed. That is, ressignments
* to `items`, splices or updates to a single item.
*/
|
73bcce88
luigser
COMPONENTS
|
965
966
|
_itemsChanged: function(change) {
if (change.path === 'items') {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
967
968
|
// reset items
this._virtualStart = 0;
|
73bcce88
luigser
COMPONENTS
|
969
970
|
this._physicalTop = 0;
this._virtualCount = this.items ? this.items.length : 0;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
971
972
|
this._collection = this.items ? Polymer.Collection.get(this.items) : null;
this._physicalIndexForKey = {};
|
73bcce88
luigser
COMPONENTS
|
973
|
|
e619a3b0
Luigi Serra
Controllet cross ...
|
974
|
this._resetScrollPosition(0);
|
a53fbbed
Renato De Donato
select-dataset ne...
|
975
|
this._removeFocusedItem();
|
73bcce88
luigser
COMPONENTS
|
976
|
|
e619a3b0
Luigi Serra
Controllet cross ...
|
977
978
979
980
981
|
// create the initial physical items
if (!this._physicalItems) {
this._physicalCount = Math.max(1, Math.min(DEFAULT_PHYSICAL_COUNT, this._virtualCount));
this._physicalItems = this._createPool(this._physicalCount);
this._physicalSizes = new Array(this._physicalCount);
|
73bcce88
luigser
COMPONENTS
|
982
983
|
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
984
|
this._physicalStart = 0;
|
73bcce88
luigser
COMPONENTS
|
985
986
|
} else if (change.path === 'items.splices') {
|
73bcce88
luigser
COMPONENTS
|
987
988
989
|
this._adjustVirtualIndex(change.value.indexSplices);
this._virtualCount = this.items ? this.items.length : 0;
|
73bcce88
luigser
COMPONENTS
|
990
991
992
|
} else {
// update a single item
this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
|
a53fbbed
Renato De Donato
select-dataset ne...
|
993
|
return;
|
73bcce88
luigser
COMPONENTS
|
994
|
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
995
996
997
|
this._itemsRendered = false;
this._debounceTemplate(this._render);
|
73bcce88
luigser
COMPONENTS
|
998
999
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1000
1001
1002
|
/**
* @param {!Array<!PolymerSplice>} splices
*/
|
73bcce88
luigser
COMPONENTS
|
1003
|
_adjustVirtualIndex: function(splices) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1004
|
splices.forEach(function(splice) {
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1005
|
// deselect removed items
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1006
|
splice.removed.forEach(this._removeItem, this);
|
73bcce88
luigser
COMPONENTS
|
1007
|
// We only need to care about changes happening above the current position
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1008
1009
1010
1011
|
if (splice.index < this._virtualStart) {
var delta = Math.max(
splice.addedCount - splice.removed.length,
splice.index - this._virtualStart);
|
73bcce88
luigser
COMPONENTS
|
1012
|
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1013
1014
1015
1016
1017
1018
1019
|
this._virtualStart = this._virtualStart + delta;
if (this._focusedIndex >= 0) {
this._focusedIndex = this._focusedIndex + delta;
}
}
}, this);
|
73bcce88
luigser
COMPONENTS
|
1020
1021
|
},
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1022
1023
1024
1025
1026
1027
|
_removeItem: function(item) {
this.$.selector.deselect(item);
// remove the current focused item
if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
this._removeFocusedItem();
}
|
73bcce88
luigser
COMPONENTS
|
1028
1029
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1030
1031
1032
|
/**
* Executes a provided function per every physical index in `itemSet`
* `itemSet` default value is equivalent to the entire set of physical indexes.
|
eb240478
Luigi Serra
public room cards...
|
1033
|
*
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1034
1035
1036
|
* @param {!function(number, number)} fn
* @param {!Array<number>=} itemSet
*/
|
73bcce88
luigser
COMPONENTS
|
1037
1038
1039
1040
1041
1042
1043
|
_iterateItems: function(fn, itemSet) {
var pidx, vidx, rtn, i;
if (arguments.length === 2 && itemSet) {
for (i = 0; i < itemSet.length; i++) {
pidx = itemSet[i];
if (pidx >= this._physicalStart) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1044
|
vidx = this._virtualStart + (pidx - this._physicalStart);
|
73bcce88
luigser
COMPONENTS
|
1045
|
} else {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1046
|
vidx = this._virtualStart + (this._physicalCount - this._physicalStart) + pidx;
|
73bcce88
luigser
COMPONENTS
|
1047
1048
1049
1050
1051
1052
1053
|
}
if ((rtn = fn.call(this, pidx, vidx)) != null) {
return rtn;
}
}
} else {
pidx = this._physicalStart;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1054
|
vidx = this._virtualStart;
|
73bcce88
luigser
COMPONENTS
|
1055
1056
1057
1058
1059
1060
|
for (; pidx < this._physicalCount; pidx++, vidx++) {
if ((rtn = fn.call(this, pidx, vidx)) != null) {
return rtn;
}
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1061
|
for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) {
|
73bcce88
luigser
COMPONENTS
|
1062
1063
1064
1065
1066
1067
1068
|
if ((rtn = fn.call(this, pidx, vidx)) != null) {
return rtn;
}
}
}
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1069
1070
1071
1072
|
/**
* Assigns the data models to a given set of items.
* @param {!Array<number>=} itemSet
*/
|
73bcce88
luigser
COMPONENTS
|
1073
1074
1075
1076
1077
1078
|
_assignModels: function(itemSet) {
this._iterateItems(function(pidx, vidx) {
var el = this._physicalItems[pidx];
var inst = el._templateInstance;
var item = this.items && this.items[vidx];
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1079
|
if (item != null) {
|
73bcce88
luigser
COMPONENTS
|
1080
1081
|
inst[this.as] = item;
inst.__key__ = this._collection.getKey(item);
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1082
|
inst[this.selectedAs] = /** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item);
|
73bcce88
luigser
COMPONENTS
|
1083
|
inst[this.indexAs] = vidx;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1084
|
inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
|
73bcce88
luigser
COMPONENTS
|
1085
|
this._physicalIndexForKey[inst.__key__] = pidx;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1086
|
el.removeAttribute('hidden');
|
73bcce88
luigser
COMPONENTS
|
1087
1088
1089
1090
|
} else {
inst.__key__ = null;
el.setAttribute('hidden', '');
}
|
73bcce88
luigser
COMPONENTS
|
1091
1092
1093
|
}, itemSet);
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1094
1095
|
/**
* Updates the height for a given set of items.
|
eb240478
Luigi Serra
public room cards...
|
1096
1097
|
*
* @param {!Array<number>=} itemSet
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1098
|
*/
|
eb240478
Luigi Serra
public room cards...
|
1099
|
_updateMetrics: function(itemSet) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1100
1101
1102
1103
|
// Make sure we distributed all the physical items
// so we can measure them
Polymer.dom.flush();
|
eb240478
Luigi Serra
public room cards...
|
1104
1105
|
var newPhysicalSize = 0;
var oldPhysicalSize = 0;
|
73bcce88
luigser
COMPONENTS
|
1106
1107
|
var prevAvgCount = this._physicalAverageCount;
var prevPhysicalAvg = this._physicalAverage;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1108
|
|
eb240478
Luigi Serra
public room cards...
|
1109
|
this._iterateItems(function(pidx, vidx) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1110
|
|
eb240478
Luigi Serra
public room cards...
|
1111
1112
1113
1114
|
oldPhysicalSize += this._physicalSizes[pidx] || 0;
this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight;
newPhysicalSize += this._physicalSizes[pidx];
this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1115
|
|
eb240478
Luigi Serra
public room cards...
|
1116
|
}, itemSet);
|
73bcce88
luigser
COMPONENTS
|
1117
|
|
eb240478
Luigi Serra
public room cards...
|
1118
|
this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1119
|
this._viewportSize = this._scrollTargetHeight;
|
73bcce88
luigser
COMPONENTS
|
1120
|
|
eb240478
Luigi Serra
public room cards...
|
1121
|
// update the average if we measured something
|
73bcce88
luigser
COMPONENTS
|
1122
1123
|
if (this._physicalAverageCount !== prevAvgCount) {
this._physicalAverage = Math.round(
|
eb240478
Luigi Serra
public room cards...
|
1124
|
((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) /
|
73bcce88
luigser
COMPONENTS
|
1125
1126
1127
1128
|
this._physicalAverageCount);
}
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1129
1130
1131
1132
|
/**
* Updates the position of the physical items.
*/
_positionItems: function() {
|
73bcce88
luigser
COMPONENTS
|
1133
1134
1135
1136
1137
|
this._adjustScrollPosition();
var y = this._physicalTop;
this._iterateItems(function(pidx) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1138
|
this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
|
73bcce88
luigser
COMPONENTS
|
1139
|
y += this._physicalSizes[pidx];
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1140
|
});
|
73bcce88
luigser
COMPONENTS
|
1141
1142
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1143
1144
1145
|
/**
* Adjusts the scroll position when it was overestimated.
*/
|
73bcce88
luigser
COMPONENTS
|
1146
|
_adjustScrollPosition: function() {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1147
|
var deltaHeight = this._virtualStart === 0 ? this._physicalTop :
|
73bcce88
luigser
COMPONENTS
|
1148
1149
1150
1151
|
Math.min(this._scrollPosition + this._physicalTop, 0);
if (deltaHeight) {
this._physicalTop = this._physicalTop - deltaHeight;
|
73bcce88
luigser
COMPONENTS
|
1152
1153
|
// juking scroll position during interial scrolling on iOS is no bueno
if (!IOS_TOUCH_SCROLLING) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1154
|
this._resetScrollPosition(this._scrollTop - deltaHeight);
|
73bcce88
luigser
COMPONENTS
|
1155
1156
1157
1158
|
}
}
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1159
1160
1161
|
/**
* Sets the position of the scroll.
*/
|
73bcce88
luigser
COMPONENTS
|
1162
|
_resetScrollPosition: function(pos) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1163
1164
1165
|
if (this.scrollTarget) {
this._scrollTop = pos;
this._scrollPosition = this._scrollTop;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1166
|
}
|
73bcce88
luigser
COMPONENTS
|
1167
1168
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1169
1170
|
/**
* Sets the scroll height, that's the height of the content,
|
eb240478
Luigi Serra
public room cards...
|
1171
1172
|
*
* @param {boolean=} forceUpdate If true, updates the height no matter what.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1173
1174
1175
|
*/
_updateScrollerSize: function(forceUpdate) {
this._estScrollHeight = (this._physicalBottom +
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1176
|
Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage);
|
73bcce88
luigser
COMPONENTS
|
1177
|
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1178
1179
1180
1181
1182
1183
1184
1185
|
forceUpdate = forceUpdate || this._scrollHeight === 0;
forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
// amortize height adjustment, so it won't trigger repaints very often
if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._optPhysicalSize) {
this.$.items.style.height = this._estScrollHeight + 'px';
this._scrollHeight = this._estScrollHeight;
}
|
73bcce88
luigser
COMPONENTS
|
1186
|
},
|
73bcce88
luigser
COMPONENTS
|
1187
1188
1189
1190
1191
|
/**
* Scroll to a specific item in the virtual list regardless
* of the physical items in the DOM tree.
*
* @method scrollToIndex
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1192
|
* @param {number} idx The index of the item
|
73bcce88
luigser
COMPONENTS
|
1193
1194
1195
1196
1197
1198
|
*/
scrollToIndex: function(idx) {
if (typeof idx !== 'number') {
return;
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1199
|
Polymer.dom.flush();
|
73bcce88
luigser
COMPONENTS
|
1200
1201
|
idx = Math.min(Math.max(idx, 0), this._virtualCount-1);
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1202
1203
1204
1205
1206
1207
|
// update the virtual start only when needed
if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
this._virtualStart = idx - 1;
}
// manage focus
this._manageFocus();
|
73bcce88
luigser
COMPONENTS
|
1208
1209
|
// assign new models
this._assignModels();
|
73bcce88
luigser
COMPONENTS
|
1210
1211
|
// measure the new sizes
this._updateMetrics();
|
73bcce88
luigser
COMPONENTS
|
1212
1213
1214
1215
1216
1217
1218
1219
1220
|
// estimate new physical offset
this._physicalTop = this._virtualStart * this._physicalAverage;
var currentTopItem = this._physicalStart;
var currentVirtualItem = this._virtualStart;
var targetOffsetTop = 0;
var hiddenContentSize = this._hiddenContentSize;
// scroll to the item as much as we can
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1221
|
while (currentVirtualItem < idx && targetOffsetTop < hiddenContentSize) {
|
73bcce88
luigser
COMPONENTS
|
1222
1223
1224
1225
|
targetOffsetTop = targetOffsetTop + this._physicalSizes[currentTopItem];
currentTopItem = (currentTopItem + 1) % this._physicalCount;
currentVirtualItem++;
}
|
73bcce88
luigser
COMPONENTS
|
1226
|
// update the scroller size
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1227
|
this._updateScrollerSize(true);
|
73bcce88
luigser
COMPONENTS
|
1228
1229
|
// update the position of the items
this._positionItems();
|
73bcce88
luigser
COMPONENTS
|
1230
|
// set the new scroll position
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1231
|
this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + targetOffsetTop);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1232
|
// increase the pool of physical items if needed
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1233
|
this._increasePoolIfNeeded();
|
73bcce88
luigser
COMPONENTS
|
1234
1235
|
// clear cached visible index
this._firstVisibleIndexVal = null;
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1236
|
this._lastVisibleIndexVal = null;
|
73bcce88
luigser
COMPONENTS
|
1237
1238
|
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1239
1240
1241
|
/**
* Reset the physical average and the average count.
*/
|
73bcce88
luigser
COMPONENTS
|
1242
1243
1244
1245
1246
|
_resetAverage: function() {
this._physicalAverage = 0;
this._physicalAverageCount = 0;
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1247
|
/**
|
eb240478
Luigi Serra
public room cards...
|
1248
|
* A handler for the `iron-resize` event triggered by `IronResizableBehavior`
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1249
1250
|
* when the element is resized.
*/
|
73bcce88
luigser
COMPONENTS
|
1251
|
_resizeHandler: function() {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
|
// iOS fires the resize event when the address bar slides up
if (IOS && Math.abs(this._viewportSize - this._scrollTargetHeight) < 100) {
return;
}
// In Desktop Safari 9.0.3, if the scroll bars are always shown,
// changing the scroll position from a resize handler would result in
// the scroll position being reset. Waiting 1ms fixes the issue.
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate',
function() {
this._render();
if (this._itemsRendered && this._physicalItems && this._isVisible) {
this._resetAverage();
this.updateViewportBoundaries();
this.scrollToIndex(this.firstVisibleIndex);
}
}.bind(this), 1));
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1269
1270
1271
1272
1273
1274
|
},
_getModelFromItem: function(item) {
var key = this._collection.getKey(item);
var pidx = this._physicalIndexForKey[key];
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1275
|
if (pidx != null) {
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1276
|
return this._physicalItems[pidx]._templateInstance;
|
73bcce88
luigser
COMPONENTS
|
1277
|
}
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1278
1279
1280
1281
|
return null;
},
/**
|
eb240478
Luigi Serra
public room cards...
|
1282
|
* Gets a valid item instance from its index or the object value.
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1283
|
*
|
eb240478
Luigi Serra
public room cards...
|
1284
|
* @param {(Object|number)} item The item object or its index
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1285
|
*/
|
eb240478
Luigi Serra
public room cards...
|
1286
|
_getNormalizedItem: function(item) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1287
1288
1289
1290
1291
1292
1293
|
if (this._collection.getKey(item) === undefined) {
if (typeof item === 'number') {
item = this.items[item];
if (!item) {
throw new RangeError('<item> not found');
}
return item;
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1294
|
}
|
eb240478
Luigi Serra
public room cards...
|
1295
|
throw new TypeError('<item> should be a valid item');
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1296
|
}
|
eb240478
Luigi Serra
public room cards...
|
1297
1298
|
return item;
},
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1299
|
|
eb240478
Luigi Serra
public room cards...
|
1300
1301
1302
1303
1304
1305
1306
1307
|
/**
* Select the list item at the given index.
*
* @method selectItem
* @param {(Object|number)} item The item object or its index
*/
selectItem: function(item) {
item = this._getNormalizedItem(item);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1308
1309
1310
1311
1312
1313
1314
1315
1316
|
var model = this._getModelFromItem(item);
if (!this.multiSelection && this.selectedItem) {
this.deselectItem(this.selectedItem);
}
if (model) {
model[this.selectedAs] = true;
}
this.$.selector.select(item);
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1317
|
this.updateSizeForItem(item);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1318
1319
1320
1321
1322
|
},
/**
* Deselects the given item list if it is already selected.
*
|
eb240478
Luigi Serra
public room cards...
|
1323
|
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1324
|
* @method deselect
|
eb240478
Luigi Serra
public room cards...
|
1325
|
* @param {(Object|number)} item The item object or its index
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1326
1327
|
*/
deselectItem: function(item) {
|
eb240478
Luigi Serra
public room cards...
|
1328
|
item = this._getNormalizedItem(item);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1329
1330
1331
1332
1333
1334
|
var model = this._getModelFromItem(item);
if (model) {
model[this.selectedAs] = false;
}
this.$.selector.deselect(item);
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1335
|
this.updateSizeForItem(item);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1336
1337
1338
1339
1340
1341
1342
|
},
/**
* Select or deselect a given item depending on whether the item
* has already been selected.
*
* @method toggleSelectionForItem
|
eb240478
Luigi Serra
public room cards...
|
1343
|
* @param {(Object|number)} item The item object or its index
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1344
1345
|
*/
toggleSelectionForItem: function(item) {
|
eb240478
Luigi Serra
public room cards...
|
1346
|
item = this._getNormalizedItem(item);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
|
if (/** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item)) {
this.deselectItem(item);
} else {
this.selectItem(item);
}
},
/**
* Clears the current selection state of the list.
*
* @method clearSelection
*/
clearSelection: function() {
function unselect(item) {
var model = this._getModelFromItem(item);
if (model) {
model[this.selectedAs] = false;
}
}
if (Array.isArray(this.selectedItems)) {
this.selectedItems.forEach(unselect, this);
} else if (this.selectedItem) {
unselect.call(this, this.selectedItem);
}
/** @type {!ArraySelectorElement} */ (this.$.selector).clearSelection();
},
/**
* Add an event listener to `tap` if `selectionEnabled` is true,
* it will remove the listener otherwise.
*/
_selectionEnabledChanged: function(selectionEnabled) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1381
1382
|
var handler = selectionEnabled ? this.listen : this.unlisten;
handler.call(this, this, 'tap', '_selectionHandler');
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1383
1384
1385
1386
1387
1388
|
},
/**
* Select an item from an event object.
*/
_selectionHandler: function(e) {
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1389
|
if (this.selectionEnabled) {
|
eb240478
Luigi Serra
public room cards...
|
1390
|
var model = this.modelForElement(e.target);
|
e619a3b0
Luigi Serra
Controllet cross ...
|
1391
1392
1393
1394
1395
1396
1397
1398
1399
|
if (model) {
this.toggleSelectionForItem(model[this.as]);
}
}
},
_multiSelectionChanged: function(multiSelection) {
this.clearSelection();
this.$.selector.multi = multiSelection;
|
eb240478
Luigi Serra
public room cards...
|
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
|
},
/**
* Updates the size of an item.
*
* @method updateSizeForItem
* @param {(Object|number)} item The item object or its index
*/
updateSizeForItem: function(item) {
item = this._getNormalizedItem(item);
var key = this._collection.getKey(item);
var pidx = this._physicalIndexForKey[key];
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1413
|
if (pidx != null) {
|
eb240478
Luigi Serra
public room cards...
|
1414
1415
1416
|
this._updateMetrics([pidx]);
this._positionItems();
}
|
a53fbbed
Renato De Donato
select-dataset ne...
|
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
|
},
/**
* Creates a temporary backfill item in the rendered pool of physical items
* to replace the main focused item. The focused item has tabIndex = 0
* and might be currently focused by the user.
*
* This dynamic replacement helps to preserve the focus state.
*/
_manageFocus: function() {
var fidx = this._focusedIndex;
if (fidx >= 0 && fidx < this._virtualCount) {
// if it's a valid index, check if that index is rendered
// in a physical item.
if (this._isIndexRendered(fidx)) {
this._restoreFocusedItem();
} else {
this._createFocusBackfillItem();
}
} else if (this._virtualCount > 0 && this._physicalCount > 0) {
// otherwise, assign the initial focused index.
this._focusedIndex = this._virtualStart;
this._focusedItem = this._physicalItems[this._physicalStart];
}
},
_isIndexRendered: function(idx) {
return idx >= this._virtualStart && idx <= this._virtualEnd;
},
_isIndexVisible: function(idx) {
return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
},
_getPhysicalIndex: function(idx) {
return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))];
},
_focusPhysicalItem: function(idx) {
if (idx < 0 || idx >= this._virtualCount) {
return;
}
this._restoreFocusedItem();
// scroll to index to make sure it's rendered
if (!this._isIndexRendered(idx)) {
this.scrollToIndex(idx);
}
var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
var SECRET = ~(Math.random() * 100);
var model = physicalItem._templateInstance;
var focusable;
// set a secret tab index
model.tabIndex = SECRET;
// check if focusable element is the physical item
if (physicalItem.tabIndex === SECRET) {
focusable = physicalItem;
}
// search for the element which tabindex is bound to the secret tab index
if (!focusable) {
focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET + '"]');
}
// restore the tab index
model.tabIndex = 0;
// focus the focusable element
this._focusedIndex = idx;
focusable && focusable.focus();
},
_removeFocusedItem: function() {
if (this._offscreenFocusedItem) {
Polymer.dom(this).removeChild(this._offscreenFocusedItem);
}
this._offscreenFocusedItem = null;
this._focusBackfillItem = null;
this._focusedItem = null;
this._focusedIndex = -1;
},
_createFocusBackfillItem: function() {
var pidx, fidx = this._focusedIndex;
if (this._offscreenFocusedItem || fidx < 0) {
return;
}
if (!this._focusBackfillItem) {
// create a physical item, so that it backfills the focused item.
var stampedTemplate = this.stamp(null);
this._focusBackfillItem = stampedTemplate.root.querySelector('*');
Polymer.dom(this).appendChild(stampedTemplate.root);
}
// get the physical index for the focused index
pidx = this._getPhysicalIndex(fidx);
if (pidx != null) {
// set the offcreen focused physical item
this._offscreenFocusedItem = this._physicalItems[pidx];
// backfill the focused physical item
this._physicalItems[pidx] = this._focusBackfillItem;
// hide the focused physical
this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
}
},
_restoreFocusedItem: function() {
var pidx, fidx = this._focusedIndex;
if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
return;
}
// assign models to the focused index
this._assignModels();
// get the new physical index for the focused index
pidx = this._getPhysicalIndex(fidx);
if (pidx != null) {
// flip the focus backfill
this._focusBackfillItem = this._physicalItems[pidx];
// restore the focused physical item
this._physicalItems[pidx] = this._offscreenFocusedItem;
// reset the offscreen focused item
this._offscreenFocusedItem = null;
// hide the physical item that backfills
this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem);
}
},
_didFocus: function(e) {
var targetModel = this.modelForElement(e.target);
var focusedModel = this._focusedItem ? this._focusedItem._templateInstance : null;
var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null;
var fidx = this._focusedIndex;
if (!targetModel || !focusedModel) {
return;
}
if (focusedModel === targetModel) {
// if the user focused the same item, then bring it into view if it's not visible
if (!this._isIndexVisible(fidx)) {
this.scrollToIndex(fidx);
}
} else {
this._restoreFocusedItem();
// restore tabIndex for the currently focused item
focusedModel.tabIndex = -1;
// set the tabIndex for the next focused item
targetModel.tabIndex = 0;
fidx = targetModel[this.indexAs];
this._focusedIndex = fidx;
this._focusedItem = this._physicalItems[this._getPhysicalIndex(fidx)];
if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) {
this._update();
}
}
},
_didMoveUp: function() {
this._focusPhysicalItem(this._focusedIndex - 1);
},
_didMoveDown: function() {
this._focusPhysicalItem(this._focusedIndex + 1);
},
_didEnter: function(e) {
this._focusPhysicalItem(this._focusedIndex);
this._selectionHandler(e.detail.keyboardEvent);
|
73bcce88
luigser
COMPONENTS
|
1586
1587
1588
1589
1590
1591
|
}
});
})();
</script>
|