OLD | NEW |
(Empty) | |
| 1 <!-- |
| 2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
| 4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| 5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
| 6 Code distributed by Google as part of the polymer project is also |
| 7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
| 8 --> |
| 9 |
| 10 <!-- |
| 11 `core-scroll-threshold` is a utility element that listens for `scroll` events fr
om a |
| 12 scrollable region and fires events to indicate when the scroller has reached a p
re-defined |
| 13 limit, specified in pixels from the upper and lower bounds of the scrollable reg
ion. |
| 14 |
| 15 This element may wrap a scrollable region and will listen for `scroll` events bu
bbling |
| 16 through it from its children. In this case, care should be taken that only one
scrollable |
| 17 region with the same orientation as this element is contained within. Alternati
vely, |
| 18 the `scrollTarget` property can be set/bound to a non-child scrollable region, f
rom which |
| 19 it will listen for events. |
| 20 |
| 21 Once a threshold has been reached, a `lower-threshold` or `upper-threshold` even
t will |
| 22 be fired, at which point the user may perform actions such as lazily-loading mor
e data |
| 23 to be displayed. After any work is done, the user must then clear the threshold
by |
| 24 calling the `clearUpper` or `clearLower` methods on this element, after which it
will |
| 25 begin listening again for the scroll position to reach the threshold again (assu
ming |
| 26 the content in the) scrollable region has grown. If the user no longer wishes t
o receive |
| 27 events (e.g. all data has been exhausted), the |
| 28 |
| 29 Example: |
| 30 |
| 31 <core-scroll-threshold id="threshold" lowerThreshold="500" |
| 32 on-lower-triggered="{{loadMore}}" lowerTriggered="{{spinnerShouldShow}}"> |
| 33 </scroll-threshold> |
| 34 |
| 35 ... |
| 36 |
| 37 loadMore: function() { |
| 38 this.asyncLoadStuffThen(function() { |
| 39 this.$.threshold.clearLower(); |
| 40 }.bind(this)); |
| 41 } |
| 42 |
| 43 @group Polymer Core Elements |
| 44 @element core-scroll-threshold |
| 45 @homepage github.io |
| 46 --> |
| 47 |
| 48 <link rel="import" href="../polymer/polymer.html"> |
| 49 |
| 50 <polymer-element name="core-scroll-threshold"> |
| 51 |
| 52 <script> |
| 53 |
| 54 Polymer({ |
| 55 |
| 56 publish: { |
| 57 |
| 58 /** |
| 59 * When set, the given element is observed for scroll position. When unde
fined, |
| 60 * children can be placed inside and element itself can be used as the scr
ollable |
| 61 * element. |
| 62 * |
| 63 * @attribute scrollTarget |
| 64 * @type string |
| 65 * @default null |
| 66 */ |
| 67 scrollTarget: null, |
| 68 |
| 69 /** |
| 70 * Orientation of the scroller to be observed (`v` for vertical, `h` for h
orizontal) |
| 71 * |
| 72 * @attribute orient |
| 73 * @type boolean |
| 74 * @default 'v' |
| 75 */ |
| 76 orient: 'v', |
| 77 |
| 78 /** |
| 79 * Distance from the top (or left, for horizontal) bound of the scroller |
| 80 * where the "upper trigger" will fire. |
| 81 * |
| 82 * @attribute upperThreshold |
| 83 * @type integer |
| 84 * @default null |
| 85 */ |
| 86 upperThreshold: null, |
| 87 |
| 88 /** |
| 89 * Distance from the bottom (or right, for horizontal) bound of the scroll
er |
| 90 * where the "lower trigger" will fire. |
| 91 * |
| 92 * @attribute lowerThreshold |
| 93 * @type integer |
| 94 * @default false |
| 95 */ |
| 96 lowerThreshold: null, |
| 97 |
| 98 /** |
| 99 * Read-only value that tracks the triggered state of the upper threshold |
| 100 * |
| 101 * @attribute upperTriggered |
| 102 * @type boolean |
| 103 * @default false |
| 104 */ |
| 105 upperTriggered: false, |
| 106 |
| 107 /** |
| 108 * Read-only value that tracks the triggered state of the lower threshold |
| 109 * |
| 110 * @attribute lowerTriggered |
| 111 * @type boolean |
| 112 * @default false |
| 113 */ |
| 114 lowerTriggered: false |
| 115 |
| 116 }, |
| 117 |
| 118 observe: { |
| 119 'upperThreshold lowerThreshold scrollTarget orient': 'setup' |
| 120 }, |
| 121 |
| 122 ready: function() { |
| 123 this._boundScrollHandler = this.checkThreshold.bind(this); |
| 124 }, |
| 125 |
| 126 setup: function() { |
| 127 // Remove listener for any previous scroll target |
| 128 if (this._scrollTarget && (this._scrollTarget != this.target)) { |
| 129 this._scrollTarget.removeEventListener(this._boundScrollHandler); |
| 130 } |
| 131 |
| 132 // Add listener for new scroll target |
| 133 var target = this.scrollTarget || this; |
| 134 if (target) { |
| 135 this._scrollTarget = target; |
| 136 this._scrollTarget.addEventListener('scroll', this._boundScrollHandler); |
| 137 } |
| 138 |
| 139 // If we're listening on ourself, make us auto in case someone put |
| 140 // content inside |
| 141 this.style.overflow = (target == this) ? 'auto' : null; |
| 142 |
| 143 // Setup extents based on orientation |
| 144 this.scrollPosition = (this.orient == 'v') ? 'scrollTop' : 'scrollLeft'; |
| 145 this.sizeExtent = (this.orient == 'v') ? 'offsetHeight' : 'offsetWidth'; |
| 146 this.scrollExtent = (this.orient == 'v') ? 'scrollHeight' : 'scrollWidth'; |
| 147 |
| 148 // Clear trigger state if user has cleared the threshold |
| 149 if (!this.upperThreshold) { |
| 150 this.upperTriggered = false; |
| 151 } |
| 152 if (!this.lowerThreshold) { |
| 153 this.lowerTriggered = false; |
| 154 } |
| 155 }, |
| 156 |
| 157 checkThreshold: function(e) { |
| 158 var top = this._scrollTarget[this.scrollPosition]; |
| 159 if (!this.upperTriggered && this.upperThreshold != null) { |
| 160 if (top < this.upperThreshold) { |
| 161 this.upperTriggered = true; |
| 162 this.fire('upper-trigger'); |
| 163 } |
| 164 } |
| 165 if (this.lowerThreshold != null) { |
| 166 var bottom = top + this._scrollTarget[this.sizeExtent]; |
| 167 var size = this._scrollTarget[this.scrollExtent]; |
| 168 if (!this.lowerTriggered && (size - bottom) < this.lowerThreshold) { |
| 169 this.lowerTriggered = true; |
| 170 this.fire('lower-trigger'); |
| 171 } |
| 172 } |
| 173 }, |
| 174 |
| 175 /** |
| 176 * Clear the upper threshold, following an `upper-trigger` event. |
| 177 * |
| 178 * @method clearUpper |
| 179 */ |
| 180 clearUpper: function(waitForMutation) { |
| 181 if (waitForMutation) { |
| 182 this._waitForMutation(function() { |
| 183 this.clearUpper(); |
| 184 }.bind(this)); |
| 185 } else { |
| 186 requestAnimationFrame(function() { |
| 187 this.upperTriggered = false; |
| 188 }.bind(this)); |
| 189 } |
| 190 }, |
| 191 |
| 192 /** |
| 193 * Clear the lower threshold, following a `lower-trigger` event. |
| 194 * |
| 195 * @method clearLower |
| 196 */ |
| 197 clearLower: function(waitForMutation) { |
| 198 if (waitForMutation) { |
| 199 this._waitForMutation(function() { |
| 200 this.clearLower(); |
| 201 }.bind(this)); |
| 202 } else { |
| 203 requestAnimationFrame(function() { |
| 204 this.lowerTriggered = false; |
| 205 }.bind(this)); |
| 206 } |
| 207 }, |
| 208 |
| 209 _waitForMutation: function(listener) { |
| 210 var observer = new MutationObserver(function(mutations) { |
| 211 listener.call(this, observer, mutations); |
| 212 observer.disconnect(); |
| 213 }.bind(this)); |
| 214 observer.observe(this._scrollTarget, {attributes:true, childList: true, su
btree: true}); |
| 215 } |
| 216 |
| 217 }); |
| 218 |
| 219 </script> |
| 220 </polymer-element> |
OLD | NEW |