Chromium Code Reviews| 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 * Calls |readyTest| repeatedly until it returns true, then calls | 6 * Calls |readyTest| repeatedly until it returns true, then calls |
| 7 * |readyCallback|. | 7 * |readyCallback|. |
| 8 * @param {function():boolean} readyTest | 8 * @param {function():boolean} readyTest |
| 9 * @param {!Function} readyCallback | 9 * @param {!Function} readyCallback |
| 10 */ | 10 */ |
| 11 function doWhenReady(readyTest, readyCallback) { | 11 function doWhenReady(readyTest, readyCallback) { |
| 12 // TODO(dschuyler): Determine whether this hack can be removed. | 12 // TODO(dschuyler): Determine whether this hack can be removed. |
| 13 // See also: https://github.com/Polymer/polymer/issues/3629 | 13 // See also: https://github.com/Polymer/polymer/issues/3629 |
| 14 var intervalId = setInterval(function() { | 14 var intervalId = setInterval(function() { |
| 15 if (readyTest()) { | 15 if (readyTest()) { |
| 16 clearInterval(intervalId); | 16 clearInterval(intervalId); |
| 17 readyCallback(); | 17 readyCallback(); |
| 18 } | 18 } |
| 19 }, 10); | 19 }, 10); |
| 20 } | 20 } |
| 21 | 21 |
| 22 /** | 22 /** |
| 23 * Provides animations to expand and collapse individual sections in a page. | 23 * Responds to route changes by expanding, collapsing, or scrolling to sections |
| 24 * Expanded sections take up the full height of the container. At most one | 24 * on the page. Expanded sections take up the full height of the container. At |
| 25 * section should be expanded at any given time. | 25 * most one section should be expanded at any given time. |
| 26 * @polymerBehavior Polymer.MainPageBehavior | 26 * @polymerBehavior MainPageBehavior |
| 27 */ | 27 */ |
| 28 var MainPageBehaviorImpl = { | 28 var MainPageBehaviorImpl = { |
| 29 /** @type {?HTMLElement} The scrolling container. */ | 29 /** @type {?HTMLElement} The scrolling container. */ |
| 30 scroller: null, | 30 scroller: null, |
| 31 | 31 |
| 32 /** @override */ | 32 /** @override */ |
| 33 attached: function() { | 33 attached: function() { |
| 34 if (this.domHost && this.domHost.parentNode.tagName == 'PAPER-HEADER-PANEL') | 34 if (this.domHost && this.domHost.parentNode.tagName == 'PAPER-HEADER-PANEL') |
| 35 this.scroller = this.domHost.parentNode.scroller; | 35 this.scroller = this.domHost.parentNode.scroller; |
| 36 else | 36 else |
| 37 this.scroller = document.body; // Used in unit tests. | 37 this.scroller = document.body; // Used in unit tests. |
| 38 }, | 38 }, |
| 39 | 39 |
| 40 /** | 40 /** |
| 41 * Hides or unhides the sections not being expanded. | 41 * @param {!settings.Route} newRoute |
| 42 * @param {string} sectionName The section to keep visible. | 42 * @param {!settings.Route} oldRoute |
| 43 * @param {boolean} hidden Whether the sections should be hidden. | |
| 44 * @private | |
| 45 */ | 43 */ |
| 46 toggleOtherSectionsHidden_: function(sectionName, hidden) { | 44 currentRouteChanged: function(newRoute, oldRoute) { |
|
michaelpg
2016/08/06 03:20:37
Same code, just moved up to the other public funct
| |
| 47 var sections = Polymer.dom(this.root).querySelectorAll( | 45 var newRouteIsSubpage = newRoute && newRoute.subpage.length; |
| 48 'settings-section'); | 46 var oldRouteIsSubpage = oldRoute && oldRoute.subpage.length; |
| 49 for (var section of sections) | 47 |
| 50 section.hidden = hidden && (section.section != sectionName); | 48 if (!oldRoute && newRouteIsSubpage) { |
| 49 // Allow the page to load before expanding the section. TODO(michaelpg): | |
| 50 // Time this better when refactoring settings-animated-pages. | |
| 51 setTimeout(function() { | |
| 52 var section = this.getSection_(newRoute.section); | |
| 53 if (section) | |
| 54 this.expandSection_(section); | |
| 55 }.bind(this)); | |
| 56 return; | |
| 57 } | |
| 58 | |
| 59 if (newRouteIsSubpage) { | |
| 60 if (!oldRouteIsSubpage || newRoute.section != oldRoute.section) { | |
| 61 var section = this.getSection_(newRoute.section); | |
| 62 if (section) | |
| 63 this.expandSection_(section); | |
| 64 } | |
| 65 } else { | |
| 66 if (oldRouteIsSubpage) { | |
| 67 var section = this.getSection_(oldRoute.section); | |
| 68 if (section) | |
| 69 this.collapseSection_(section); | |
| 70 } | |
| 71 | |
| 72 // Scrolls to the section if this main page contains the route's section. | |
| 73 if (newRoute && newRoute.section && this.getSection_(newRoute.section)) | |
| 74 this.scrollToSection_(); | |
| 75 } | |
| 51 }, | 76 }, |
| 52 | 77 |
| 53 /** | 78 /** |
| 54 * Animates the card in |section|, expanding it to fill the page. | 79 * Animates the card in |section|, expanding it to fill the page. |
| 55 * @param {!SettingsSectionElement} section | 80 * @param {!SettingsSectionElement} section |
| 81 * @private | |
| 56 */ | 82 */ |
| 57 expandSection: function(section) { | 83 expandSection_: function(section) { |
| 58 // If another section's card is expanding, cancel that animation first. | 84 // If another section's card is expanding, cancel that animation first. |
| 59 var expanding = this.$$('.expanding'); | 85 var expanding = this.$$('.expanding'); |
| 60 if (expanding) { | 86 if (expanding) { |
| 61 if (expanding == section) | 87 if (expanding == section) |
| 62 return; | 88 return; |
| 63 | 89 |
| 64 if (this.animations['section']) { | 90 if (this.animations['section']) { |
| 65 // Cancel the animation, then call startExpandSection_. | 91 // Cancel the animation, then call startExpandSection_. |
| 66 this.cancelAnimation('section', function() { | 92 this.cancelAnimation('section', function() { |
| 67 this.startExpandSection_(section); | 93 this.startExpandSection_(section); |
| 68 }.bind(this)); | 94 }.bind(this)); |
| 69 } else { | 95 } else { |
| 70 // The animation must have finished but its promise hasn't resolved yet. | 96 // The animation must have finished but its promise hasn't resolved yet. |
| 71 // When it resolves, collapse that section's card before expanding | 97 // When it resolves, collapse that section's card before expanding |
| 72 // this one. | 98 // this one. |
| 73 setTimeout(function() { | 99 setTimeout(function() { |
| 74 this.collapseSection( | 100 this.collapseSection_( |
| 75 /** @type {!SettingsSectionElement} */(expanding)); | 101 /** @type {!SettingsSectionElement} */(expanding)); |
| 76 this.finishAnimation('section', function() { | 102 this.finishAnimation('section', function() { |
| 77 this.startExpandSection_(section); | 103 this.startExpandSection_(section); |
| 78 }.bind(this)); | 104 }.bind(this)); |
| 79 }.bind(this)); | 105 }.bind(this)); |
| 80 } | 106 } |
| 81 | 107 |
| 82 return; | 108 return; |
| 83 } | 109 } |
| 84 | 110 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 }.bind(this), function() { | 148 }.bind(this), function() { |
| 123 // Animation was canceled; restore the section. | 149 // Animation was canceled; restore the section. |
| 124 section.setFrozen(false); | 150 section.setFrozen(false); |
| 125 }.bind(this)).then(function() { | 151 }.bind(this)).then(function() { |
| 126 this.scroller.style.overflow = ''; | 152 this.scroller.style.overflow = ''; |
| 127 this.scroller.style.width = ''; | 153 this.scroller.style.width = ''; |
| 128 }.bind(this)); | 154 }.bind(this)); |
| 129 }, | 155 }, |
| 130 | 156 |
| 131 /** | 157 /** |
| 158 * Expands the card in |section| to fill the page. | |
| 159 * @param {!SettingsSectionElement} section | |
| 160 * @return {!Promise} | |
| 161 * @private | |
| 162 */ | |
| 163 playExpandSection_: function(section) { | |
|
michaelpg
2016/08/06 03:20:37
Exact same code, just moved up one.
| |
| 164 // We must be attached. | |
| 165 assert(this.scroller); | |
| 166 | |
| 167 var promise; | |
| 168 var animationConfig = section.animateExpand(this.scroller); | |
| 169 if (animationConfig) { | |
| 170 promise = this.animateElement('section', animationConfig.card, | |
| 171 animationConfig.keyframes, animationConfig.options); | |
| 172 } else { | |
| 173 promise = Promise.resolve(); | |
| 174 } | |
| 175 | |
| 176 var finished; | |
| 177 promise.then(function() { | |
| 178 finished = true; | |
| 179 this.style.margin = 'auto'; | |
| 180 }.bind(this), function() { | |
| 181 // The animation was canceled; catch the error and continue. | |
| 182 finished = false; | |
| 183 }).then(function() { | |
| 184 section.cleanUpAnimateExpand(finished); | |
| 185 }); | |
| 186 | |
| 187 return promise; | |
| 188 }, | |
| 189 | |
| 190 /** | |
| 132 * Animates the card in |section|, collapsing it back into its section. | 191 * Animates the card in |section|, collapsing it back into its section. |
| 133 * @param {!SettingsSectionElement} section | 192 * @param {!SettingsSectionElement} section |
| 193 * @private | |
| 134 */ | 194 */ |
| 135 collapseSection: function(section) { | 195 collapseSection_: function(section) { |
| 136 // If the section's card is still expanding, cancel the expand animation. | 196 // If the section's card is still expanding, cancel the expand animation. |
| 137 if (section.classList.contains('expanding')) { | 197 if (section.classList.contains('expanding')) { |
| 138 if (this.animations['section']) { | 198 if (this.animations['section']) { |
| 139 this.cancelAnimation('section'); | 199 this.cancelAnimation('section'); |
| 140 } else { | 200 } else { |
| 141 // The animation must have finished but its promise hasn't finished | 201 // The animation must have finished but its promise hasn't finished |
| 142 // resolving; try again asynchronously. | 202 // resolving; try again asynchronously. |
| 143 this.async(function() { | 203 this.async(function() { |
| 144 this.collapseSection(section); | 204 this.collapseSection_(section); |
| 145 }); | 205 }); |
| 146 } | 206 } |
| 147 return; | 207 return; |
| 148 } | 208 } |
| 149 | 209 |
| 150 if (!section.canAnimateCollapse()) | 210 if (!section.canAnimateCollapse()) |
| 151 return; | 211 return; |
| 152 | 212 |
| 153 this.toggleOtherSectionsHidden_(section.section, false); | 213 this.toggleOtherSectionsHidden_(section.section, false); |
| 154 | 214 |
| 155 var scrollerWidth = this.scroller.clientWidth; | 215 var scrollerWidth = this.scroller.clientWidth; |
| 156 this.scroller.style.overflow = 'hidden'; | 216 this.scroller.style.overflow = 'hidden'; |
| 157 // Adjust width to compensate for scroller. | 217 // Adjust width to compensate for scroller. |
| 158 var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; | 218 var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; |
| 159 this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; | 219 this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; |
| 160 | 220 |
| 161 this.playCollapseSection_(section).then(function() { | 221 this.playCollapseSection_(section).then(function() { |
| 162 section.setFrozen(false); | 222 section.setFrozen(false); |
| 163 this.scroller.style.overflow = ''; | 223 this.scroller.style.overflow = ''; |
| 164 this.scroller.style.width = ''; | 224 this.scroller.style.width = ''; |
| 165 section.classList.remove('collapsing'); | 225 section.classList.remove('collapsing'); |
| 166 }.bind(this)); | 226 }.bind(this)); |
| 167 }, | 227 }, |
| 168 | 228 |
| 169 /** | 229 /** |
| 170 * Expands the card in |section| to fill the page. | |
| 171 * @param {!SettingsSectionElement} section | |
| 172 * @return {!Promise} | |
| 173 * @private | |
| 174 */ | |
| 175 playExpandSection_: function(section) { | |
| 176 // We must be attached. | |
| 177 assert(this.scroller); | |
| 178 | |
| 179 var promise; | |
| 180 var animationConfig = section.animateExpand(this.scroller); | |
| 181 if (animationConfig) { | |
| 182 promise = this.animateElement('section', animationConfig.card, | |
| 183 animationConfig.keyframes, animationConfig.options); | |
| 184 } else { | |
| 185 promise = Promise.resolve(); | |
| 186 } | |
| 187 | |
| 188 var finished; | |
| 189 promise.then(function() { | |
| 190 finished = true; | |
| 191 this.style.margin = 'auto'; | |
| 192 }.bind(this), function() { | |
| 193 // The animation was canceled; catch the error and continue. | |
| 194 finished = false; | |
| 195 }).then(function() { | |
| 196 section.cleanUpAnimateExpand(finished); | |
| 197 }); | |
| 198 | |
| 199 return promise; | |
| 200 }, | |
| 201 | |
| 202 /** | |
| 203 * Collapses the card in |section| back to its normal position. | 230 * Collapses the card in |section| back to its normal position. |
| 204 * @param {!SettingsSectionElement} section | 231 * @param {!SettingsSectionElement} section |
| 205 * @return {!Promise} | 232 * @return {!Promise} |
| 206 * @private | 233 * @private |
| 207 */ | 234 */ |
| 208 playCollapseSection_: function(section) { | 235 playCollapseSection_: function(section) { |
| 209 // We must be attached. | 236 // We must be attached. |
| 210 assert(this.scroller); | 237 assert(this.scroller); |
| 211 | 238 |
| 212 this.style.margin = ''; | 239 this.style.margin = ''; |
| 213 | 240 |
| 214 var promise; | 241 var promise; |
| 215 var animationConfig = | 242 var animationConfig = |
| 216 section.animateCollapse(this.scroller, this.listScrollTop_); | 243 section.animateCollapse(this.scroller, this.listScrollTop_); |
| 217 if (animationConfig) { | 244 if (animationConfig) { |
| 218 promise = this.animateElement('section', animationConfig.card, | 245 promise = this.animateElement('section', animationConfig.card, |
| 219 animationConfig.keyframes, animationConfig.options); | 246 animationConfig.keyframes, animationConfig.options); |
| 220 } else { | 247 } else { |
| 221 promise = Promise.resolve(); | 248 promise = Promise.resolve(); |
| 222 } | 249 } |
| 223 | 250 |
| 224 promise.then(function() { | 251 promise.then(function() { |
| 225 section.cleanUpAnimateCollapse(true); | 252 section.cleanUpAnimateCollapse(true); |
| 226 }, function() { | 253 }, function() { |
| 227 section.cleanUpAnimateCollapse(false); | 254 section.cleanUpAnimateCollapse(false); |
| 228 }); | 255 }); |
| 229 return promise; | 256 return promise; |
| 230 }, | 257 }, |
| 231 }; | |
| 232 | 258 |
| 233 | |
| 234 /** @polymerBehavior */ | |
| 235 var MainPageBehavior = [ | |
| 236 TransitionBehavior, | |
| 237 MainPageBehaviorImpl | |
| 238 ]; | |
| 239 | |
| 240 | |
| 241 /** | |
| 242 * TODO(michaelpg): integrate slide animations. | |
| 243 * @polymerBehavior RoutableBehavior | |
| 244 */ | |
| 245 var RoutableBehaviorImpl = { | |
| 246 /** @private */ | 259 /** @private */ |
| 247 scrollToSection_: function() { | 260 scrollToSection_: function() { |
| 248 doWhenReady( | 261 doWhenReady( |
| 249 function() { | 262 function() { |
| 250 return this.scrollHeight > 0; | 263 return this.scrollHeight > 0; |
| 251 }.bind(this), | 264 }.bind(this), |
| 252 function() { | 265 function() { |
| 253 // If the current section changes while we are waiting for the page to | 266 // If the current section changes while we are waiting for the page to |
| 254 // be ready, scroll to the newest requested section. | 267 // be ready, scroll to the newest requested section. |
| 255 this.getSection_(settings.getCurrentRoute().section).scrollIntoView(); | 268 this.getSection_(settings.getCurrentRoute().section).scrollIntoView(); |
| 256 }.bind(this)); | 269 }.bind(this)); |
| 257 }, | 270 }, |
| 258 | 271 |
| 259 /** @private */ | 272 /** |
| 260 currentRouteChanged: function(newRoute, oldRoute) { | 273 * Hides or unhides the sections not being expanded. |
| 261 var newRouteIsSubpage = newRoute && newRoute.subpage.length; | 274 * @param {string} sectionName The section to keep visible. |
| 262 var oldRouteIsSubpage = oldRoute && oldRoute.subpage.length; | 275 * @param {boolean} hidden Whether the sections should be hidden. |
| 263 | 276 * @private |
| 264 if (!oldRoute && newRouteIsSubpage) { | 277 */ |
| 265 // Allow the page to load before expanding the section. TODO(michaelpg): | 278 toggleOtherSectionsHidden_: function(sectionName, hidden) { |
|
michaelpg
2016/08/06 03:20:37
Again, exact same code from the top, just put down
| |
| 266 // Time this better when refactoring settings-animated-pages. | 279 var sections = Polymer.dom(this.root).querySelectorAll( |
| 267 setTimeout(function() { | 280 'settings-section'); |
| 268 var section = this.getSection_(newRoute.section); | 281 for (var section of sections) |
| 269 if (section) | 282 section.hidden = hidden && (section.section != sectionName); |
| 270 this.expandSection(section); | |
| 271 }.bind(this)); | |
| 272 return; | |
| 273 } | |
| 274 | |
| 275 if (newRouteIsSubpage) { | |
| 276 if (!oldRouteIsSubpage || newRoute.section != oldRoute.section) { | |
| 277 var section = this.getSection_(newRoute.section); | |
| 278 if (section) | |
| 279 this.expandSection(section); | |
| 280 } | |
| 281 } else { | |
| 282 if (oldRouteIsSubpage) { | |
| 283 var section = this.getSection_(oldRoute.section); | |
| 284 if (section) | |
| 285 this.collapseSection(section); | |
| 286 } | |
| 287 | |
| 288 // Scrolls to the section if this main page contains the route's section. | |
| 289 if (newRoute && newRoute.section && this.getSection_(newRoute.section)) | |
| 290 this.scrollToSection_(); | |
| 291 } | |
| 292 }, | 283 }, |
| 293 | 284 |
| 294 /** | 285 /** |
| 295 * Helper function to get a section from the local DOM. | 286 * Helper function to get a section from the local DOM. |
| 296 * @param {string} section Section name of the element to get. | 287 * @param {string} section Section name of the element to get. |
| 297 * @return {?SettingsSectionElement} | 288 * @return {?SettingsSectionElement} |
| 298 * @private | 289 * @private |
| 299 */ | 290 */ |
| 300 getSection_: function(section) { | 291 getSection_: function(section) { |
| 301 return /** @type {?SettingsSectionElement} */( | 292 return /** @type {?SettingsSectionElement} */( |
| 302 this.$$('[section=' + section + ']')); | 293 this.$$('[section=' + section + ']')); |
| 303 }, | 294 }, |
| 304 }; | 295 }; |
| 305 | 296 |
| 306 | |
| 307 /** @polymerBehavior */ | 297 /** @polymerBehavior */ |
| 308 var RoutableBehavior = [ | 298 var MainPageBehavior = [ |
| 309 MainPageBehavior, | |
| 310 settings.RouteObserverBehavior, | 299 settings.RouteObserverBehavior, |
| 311 RoutableBehaviorImpl | 300 TransitionBehavior, |
| 301 MainPageBehaviorImpl, | |
| 312 ]; | 302 ]; |
| OLD | NEW |