Blame view

bower_components/iron-list/iron-list.html 48.9 KB
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>