OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview Behavior for scrollable containers with <iron-list>. | 6 * @fileoverview Behavior for scrollable containers with <iron-list>. |
7 * | 7 * |
8 * Any containers with the 'scrollable' attribute set will have the following | 8 * Any containers with the 'scrollable' attribute set will have the following |
9 * classes toggled appropriately: can-scroll, is-scrolled, scrolled-to-bottom. | 9 * classes toggled appropriately: can-scroll, is-scrolled, scrolled-to-bottom. |
10 * These classes are used to style the container div and list elements | 10 * These classes are used to style the container div and list elements |
(...skipping 23 matching lines...) Expand all Loading... |
34 * will not be sized correctly. | 34 * will not be sized correctly. |
35 */ | 35 */ |
36 | 36 |
37 /** @polymerBehavior */ | 37 /** @polymerBehavior */ |
38 var CrScrollableBehavior = { | 38 var CrScrollableBehavior = { |
39 | 39 |
40 /** @private {number|null} */ | 40 /** @private {number|null} */ |
41 intervalId_: null, | 41 intervalId_: null, |
42 | 42 |
43 ready: function() { | 43 ready: function() { |
44 var scrollableElements = this.root.querySelectorAll('[scrollable]'); | 44 this.requestUpdateScroll(); |
45 | |
46 // Setup the intial scrolling related classes for each scrollable container. | |
47 requestAnimationFrame(function() { | |
48 for (var i = 0; i < scrollableElements.length; i++) | |
49 this.updateScroll_(scrollableElements[i]); | |
50 }.bind(this)); | |
51 | 45 |
52 // Listen to the 'scroll' event for each scrollable container. | 46 // Listen to the 'scroll' event for each scrollable container. |
| 47 var scrollableElements = this.root.querySelectorAll('[scrollable]'); |
53 for (var i = 0; i < scrollableElements.length; i++) { | 48 for (var i = 0; i < scrollableElements.length; i++) { |
54 scrollableElements[i].addEventListener( | 49 scrollableElements[i].addEventListener( |
55 'scroll', this.updateScrollEvent_.bind(this)); | 50 'scroll', this.updateScrollEvent_.bind(this)); |
56 } | 51 } |
57 }, | 52 }, |
58 | 53 |
59 detached: function() { | 54 detached: function() { |
60 if (this.intervalId_ !== null) | 55 if (this.intervalId_ !== null) |
61 clearInterval(this.intervalId_); | 56 clearInterval(this.intervalId_); |
62 }, | 57 }, |
63 | 58 |
64 /** | 59 /** |
65 * Called any time the contents of a scrollable container may have changed. | 60 * Called any time the contents of a scrollable container may have changed. |
66 * This ensures that the <iron-list> contents of dynamically sized | 61 * This ensures that the <iron-list> contents of dynamically sized |
67 * containers are resized correctly. | 62 * containers are resized correctly. |
68 */ | 63 */ |
69 updateScrollableContents: function() { | 64 updateScrollableContents: function() { |
70 if (this.intervalId_ !== null) | 65 if (this.intervalId_ !== null) |
71 return; // notifyResize is arelady in progress. | 66 return; // notifyResize is arelady in progress. |
72 | 67 |
| 68 this.requestUpdateScroll(); |
| 69 |
73 var nodeList = this.root.querySelectorAll('[scrollable] iron-list'); | 70 var nodeList = this.root.querySelectorAll('[scrollable] iron-list'); |
| 71 if (!nodeList.length) |
| 72 return; |
| 73 |
74 // Use setInterval to avoid initial render / sizing issues. | 74 // Use setInterval to avoid initial render / sizing issues. |
75 this.intervalId_ = window.setInterval(function() { | 75 this.intervalId_ = window.setInterval(function() { |
76 var unreadyNodes = []; | 76 var unreadyNodes = []; |
77 for (var i = 0; i < nodeList.length; i++) { | 77 for (var i = 0; i < nodeList.length; i++) { |
78 var node = nodeList[i]; | 78 var node = nodeList[i]; |
79 if (node.parentNode.scrollHeight == 0) { | 79 if (node.parentNode.scrollHeight == 0) { |
80 unreadyNodes.push(node); | 80 unreadyNodes.push(node); |
81 continue; | 81 continue; |
82 } | 82 } |
83 var ironList = /** @type {!IronListElement} */ (node); | 83 var ironList = /** @type {!IronListElement} */ (node); |
84 ironList.notifyResize(); | 84 ironList.notifyResize(); |
85 } | 85 } |
86 if (unreadyNodes.length == 0) { | 86 if (unreadyNodes.length == 0) { |
87 window.clearInterval(this.intervalId_); | 87 window.clearInterval(this.intervalId_); |
88 this.intervalId_ = null; | 88 this.intervalId_ = null; |
89 } else { | 89 } else { |
90 nodeList = unreadyNodes; | 90 nodeList = unreadyNodes; |
91 } | 91 } |
92 }.bind(this), 10); | 92 }.bind(this), 10); |
93 }, | 93 }, |
94 | 94 |
| 95 /** |
| 96 * Setup the intial scrolling related classes for each scrollable container. |
| 97 * Called from ready() and updateScrollableContents(). May also be called |
| 98 * directly when the contents change (e.g. when not using iron-list). |
| 99 */ |
| 100 requestUpdateScroll: function() { |
| 101 requestAnimationFrame(function() { |
| 102 var scrollableElements = this.root.querySelectorAll('[scrollable]'); |
| 103 for (var i = 0; i < scrollableElements.length; i++) |
| 104 this.updateScroll_(/** @type {!HTMLElement} */(scrollableElements[i])); |
| 105 }.bind(this)); |
| 106 }, |
| 107 |
95 /** @param {!IronListElement} list */ | 108 /** @param {!IronListElement} list */ |
96 saveScroll: function(list) { | 109 saveScroll: function(list) { |
97 // Store a FIFO of saved scroll positions so that multiple updates in a | 110 // Store a FIFO of saved scroll positions so that multiple updates in a |
98 // frame are applied correctly. Specifically we need to track when '0' is | 111 // frame are applied correctly. Specifically we need to track when '0' is |
99 // saved (but not apply it), and still handle patterns like [30, 0, 32]. | 112 // saved (but not apply it), and still handle patterns like [30, 0, 32]. |
100 list.savedScrollTops = list.savedScrollTops || []; | 113 list.savedScrollTops = list.savedScrollTops || []; |
101 list.savedScrollTops.push(list.scrollTarget.scrollTop); | 114 list.savedScrollTops.push(list.scrollTarget.scrollTop); |
102 }, | 115 }, |
103 | 116 |
104 /** @param {!IronListElement} list */ | 117 /** @param {!IronListElement} list */ |
(...skipping 24 matching lines...) Expand all Loading... |
129 */ | 142 */ |
130 updateScroll_: function(scrollable) { | 143 updateScroll_: function(scrollable) { |
131 scrollable.classList.toggle( | 144 scrollable.classList.toggle( |
132 'can-scroll', scrollable.clientHeight < scrollable.scrollHeight); | 145 'can-scroll', scrollable.clientHeight < scrollable.scrollHeight); |
133 scrollable.classList.toggle('is-scrolled', scrollable.scrollTop > 0); | 146 scrollable.classList.toggle('is-scrolled', scrollable.scrollTop > 0); |
134 scrollable.classList.toggle( | 147 scrollable.classList.toggle( |
135 'scrolled-to-bottom', scrollable.scrollTop + scrollable.clientHeight >= | 148 'scrolled-to-bottom', scrollable.scrollTop + scrollable.clientHeight >= |
136 scrollable.scrollHeight); | 149 scrollable.scrollHeight); |
137 }, | 150 }, |
138 }; | 151 }; |
OLD | NEW |