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 // Fast out, slow in. | |
| 6 var EASING_FUNCTION = 'cubic-bezier(0.4, 0, 0.2, 1)'; | |
| 7 var EXPAND_DURATION = 350; | |
| 8 | |
| 9 /** | 5 /** |
| 10 * Calls |readyTest| repeatedly until it returns true, then calls | 6 * Calls |readyTest| repeatedly until it returns true, then calls |
| 11 * |readyCallback|. | 7 * |readyCallback|. |
| 12 * @param {function():boolean} readyTest | 8 * @param {function():boolean} readyTest |
| 13 * @param {!Function} readyCallback | 9 * @param {!Function} readyCallback |
| 14 */ | 10 */ |
| 15 function doWhenReady(readyTest, readyCallback) { | 11 function doWhenReady(readyTest, readyCallback) { |
| 16 // TODO(dschuyler): Determine whether this hack can be removed. | 12 // TODO(dschuyler): Determine whether this hack can be removed. |
| 17 // See also: https://github.com/Polymer/polymer/issues/3629 | 13 // See also: https://github.com/Polymer/polymer/issues/3629 |
| 18 var intervalId = setInterval(function() { | 14 var intervalId = setInterval(function() { |
| 19 if (readyTest()) { | 15 if (readyTest()) { |
| 20 clearInterval(intervalId); | 16 clearInterval(intervalId); |
| 21 readyCallback(); | 17 readyCallback(); |
| 22 } | 18 } |
| 23 }, 10); | 19 }, 10); |
| 24 } | 20 } |
| 25 | 21 |
| 26 /** | 22 /** |
| 27 * Provides animations to expand and collapse individual sections in a page. | 23 * Responds to route changes by expanding, collapsing, and scrolling to |
| 28 * Expanded sections take up the full height of the container. At most one | 24 * sections. Expanded sections take up the full height of the container. At |
| 29 * section should be expanded at any given time. | 25 * most one section should be expanded at any given time. |
| 26 * TODO(michaelpg): Combine with RoutableBehaviorImpl. | |
| 30 * @polymerBehavior Polymer.MainPageBehavior | 27 * @polymerBehavior Polymer.MainPageBehavior |
| 31 */ | 28 */ |
| 32 var MainPageBehaviorImpl = { | 29 var MainPageBehaviorImpl = { |
| 33 /** @type {?Element} The scrolling container. */ | |
| 34 scroller: null, | |
| 35 | |
| 36 /** @override */ | 30 /** @override */ |
| 37 attached: function() { | 31 attached: function() { |
| 38 if (this.domHost && this.domHost.parentNode.tagName == 'PAPER-HEADER-PANEL') | 32 /** @type {!HTMLElement} */ |
|
Dan Beam
2016/08/05 00:18:05
indent off
| |
| 39 this.scroller = this.domHost.parentNode.$.mainContainer; | 33 this.scroller = (this.domHost && this.domHost.parentNode.tagName == |
|
Dan Beam
2016/08/05 00:18:05
what's the functional difference here? why are yo
| |
| 40 else | 34 'PAPER-HEADER-PANEL') ? |
| 41 this.scroller = document.body; // Used in unit tests. | 35 this.domHost.parentNode.$.mainContainer : |
|
Dan Beam
2016/08/05 00:18:05
yeppppppp this'll trigger that presubmit
| |
| 36 document.body; // Used in unit tests. | |
| 42 }, | 37 }, |
| 43 | 38 |
| 44 /** | 39 /** |
| 45 * Hides or unhides the sections not being expanded. | 40 * Hides or unhides the sections not being expanded. |
| 46 * @param {string} sectionName The section to keep visible. | 41 * @param {string} sectionName The section to keep visible. |
| 47 * @param {boolean} hidden Whether the sections should be hidden. | 42 * @param {boolean} hidden Whether the sections should be hidden. |
| 48 * @private | 43 * @private |
| 49 */ | 44 */ |
| 50 toggleOtherSectionsHidden_: function(sectionName, hidden) { | 45 toggleOtherSectionsHidden_: function(sectionName, hidden) { |
| 51 var sections = Polymer.dom(this.root).querySelectorAll( | 46 var sections = Polymer.dom(this.root).querySelectorAll( |
| 52 'settings-section'); | 47 'settings-section'); |
| 53 for (var section of sections) | 48 for (var section of sections) |
| 54 section.hidden = hidden && (section.section != sectionName); | 49 section.hidden = hidden && (section.section != sectionName); |
| 55 }, | 50 }, |
| 56 | 51 |
| 57 /** | 52 /** |
| 53 * Transistions to the current route if the |deferredTransition_| flag is set. | |
|
Dan Beam
2016/08/05 00:47:07
Transitions
| |
| 54 * @private | |
| 55 */ | |
| 56 runDeferredTransition_: function() { | |
|
Dan Beam
2016/08/05 00:47:06
this makes it seem as if "deferredTransition_" is
| |
| 57 // TODO(michaelpg): Manage transition lifetime better. crbug.com/624145 | |
| 58 if (!this.deferredTransition_) | |
| 59 return; | |
| 60 this.deferredTransition_ = false; | |
| 61 this.transitionToRoute_(); | |
| 62 }, | |
| 63 | |
| 64 /** | |
| 65 * Transitions to the current route based on the state of the current page | |
| 66 * (i.e., expands and collapses sections as necessary). Must only be called | |
| 67 * when no other transition is running or pending. | |
| 68 * @private | |
| 69 */ | |
| 70 transitionToRoute_: function() { | |
| 71 assert(!this.currentSectionTransition_); | |
| 72 | |
| 73 var expandedSection = /** @type {?SettingsSectionElement} */( | |
| 74 this.$$('settings-section.expanded')); | |
| 75 if (expandedSection) { | |
| 76 if (expandedSection.section == this.currentRoute.section && | |
| 77 this.currentRoute.subpage.length > 0) { | |
| 78 // settings-animated-pages controls visibility of subpages in sections. | |
|
Dan Beam
2016/08/05 00:47:06
can you describe this in a different, more high-le
| |
| 79 return; | |
| 80 } | |
| 81 | |
| 82 // Collapse this section (and check for a deferred transition when | |
| 83 // finished). | |
| 84 this.collapseSection(expandedSection).then( | |
| 85 this.runDeferredTransition_.bind(this)); | |
| 86 | |
| 87 // If the new route is a sub-page, we'll have to expand that next. | |
| 88 this.deferredTransition_ = this.currentRoute.subpage.length > 0; | |
| 89 return; | |
| 90 } | |
| 91 | |
| 92 if (this.currentRoute.section.length == 0) | |
|
Dan Beam
2016/08/05 00:47:06
nit: can you just use truthiness for section or ot
| |
| 93 return; | |
| 94 | |
| 95 var section = this.getSection_(this.currentRoute.section); | |
| 96 if (!section) | |
| 97 return; | |
| 98 | |
| 99 // Expand the section if the route is a subpage (and check for a deferred | |
| 100 // transition when finished). | |
| 101 if (this.currentRoute.subpage.length > 0) { | |
| 102 this.expandSection(section).then(this.runDeferredTransition_.bind(this)); | |
| 103 return; | |
| 104 } | |
| 105 | |
|
Dan Beam
2016/08/05 00:47:06
can you put a comment saying which cases actually
| |
| 106 this.scrollToSection_(); | |
| 107 }, | |
| 108 | |
| 109 /** | |
| 58 * Animates the card in |section|, expanding it to fill the page. | 110 * Animates the card in |section|, expanding it to fill the page. |
| 59 * @param {!SettingsSectionElement} section | 111 * @param {!SettingsSectionElement} section |
| 112 * @return {!Promise} Promise when the transition finishes or cancels. | |
| 60 */ | 113 */ |
| 61 expandSection: function(section) { | 114 expandSection: function(section) { |
| 62 // If another section's card is expanding, cancel that animation first. | 115 assert(!this.currentSectionTransition_); |
| 63 var expanding = this.$$('.expanding'); | |
| 64 if (expanding) { | |
| 65 if (expanding == section) | |
| 66 return; | |
| 67 | 116 |
| 68 if (this.animations['section']) { | 117 // The overscroll must not shrink during the transition. |
| 69 // Cancel the animation, then call startExpandSection_. | 118 this.fire('overscroll-suppress'); |
| 70 this.cancelAnimation('section', function() { | |
| 71 this.startExpandSection_(section); | |
| 72 }.bind(this)); | |
| 73 } else { | |
| 74 // The animation must have finished but its promise hasn't resolved yet. | |
| 75 // When it resolves, collapse that section's card before expanding | |
| 76 // this one. | |
| 77 setTimeout(function() { | |
| 78 this.collapseSection( | |
| 79 /** @type {!SettingsSectionElement} */(expanding)); | |
| 80 this.finishAnimation('section', function() { | |
| 81 this.startExpandSection_(section); | |
| 82 }.bind(this)); | |
| 83 }.bind(this)); | |
| 84 } | |
| 85 | 119 |
| 86 return; | 120 // Prevent additional scrolling and keep the expanding section clipped. |
| 87 } | 121 this.scroller.style.overflow = ''; |
| 122 var scrollerWidth = this.scroller.clientWidth; | |
| 123 this.mainScrollTop_ = this.scroller.scrollTop; | |
| 124 this.scroller.style.overflow = 'hidden'; | |
| 88 | 125 |
| 89 if (this.$$('.collapsing') && this.animations['section']) { | 126 // Set the width to account for the missing scrollbar. |
| 90 // Finish the collapse animation before expanding. | |
| 91 this.finishAnimation('section', function() { | |
| 92 this.startExpandSection_(section); | |
| 93 }.bind(this)); | |
| 94 return; | |
| 95 } | |
| 96 | |
| 97 this.startExpandSection_(section); | |
| 98 }, | |
| 99 | |
| 100 /** | |
| 101 * Helper function to set up and start the expand animation. | |
| 102 * @param {!SettingsSectionElement} section | |
| 103 */ | |
| 104 startExpandSection_: function(section) { | |
| 105 if (section.classList.contains('expanded')) | |
| 106 return; | |
| 107 | |
| 108 // Freeze the scroller and save its position. | |
| 109 this.listScrollTop_ = this.scroller.scrollTop; | |
| 110 | |
| 111 var scrollerWidth = this.scroller.clientWidth; | |
| 112 this.scroller.style.overflow = 'hidden'; | |
| 113 // Adjust width to compensate for scroller. | |
| 114 var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; | 127 var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; |
| 115 this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; | 128 this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; |
| 116 | 129 |
| 117 // Freezes the section's height so its card can be removed from the flow. | 130 this.currentSectionTransition_ = |
| 118 this.freezeSection_(section); | 131 new settings.OpenSectionTransition(section, this.scroller); |
| 119 | 132 |
| 120 // Expand the section's card to fill the parent. | 133 return this.currentSectionTransition_.play().then(function(success) { |
| 121 var animationPromise = this.playExpandSection_(section); | 134 this.currentSectionTransition_ = null; |
| 135 if (success) { | |
| 136 // Hide other sections and scroll to the top of the subpage. | |
| 137 this.classList.add('showing-subpage'); | |
| 138 this.toggleOtherSectionsHidden_(section.section, true); | |
| 139 this.scroller.scrollTop = 0; | |
| 140 // Notify that the page is fully expanded. | |
| 141 this.fire('subpage-expand'); | |
| 142 } else { | |
| 143 // The open transition cancelled, so scroll back to our old location. | |
| 144 this.scroller.scrollTop = this.mainScrollTop_; | |
| 145 } | |
| 122 | 146 |
| 123 animationPromise.then(function() { | 147 // Overscroll can now be recalculated. |
| 124 this.scroller.scrollTop = 0; | 148 this.fire('overscroll-recalc'); |
| 125 this.toggleOtherSectionsHidden_(section.section, true); | 149 |
| 126 }.bind(this), function() { | 150 // Restore the scrollbar. |
| 127 // Animation was canceled; restore the section. | 151 this.scroller.style.width = ''; |
| 128 this.unfreezeSection_(section); | |
| 129 }.bind(this)).then(function() { | |
| 130 this.scroller.style.overflow = ''; | 152 this.scroller.style.overflow = ''; |
| 131 this.scroller.style.width = ''; | |
| 132 }.bind(this)); | 153 }.bind(this)); |
| 133 }, | 154 }, |
| 134 | 155 |
| 135 /** | 156 /** |
| 136 * Animates the card in |section|, collapsing it back into its section. | 157 * Animates the card in |section|, collapsing it back into its section. |
| 137 * @param {!SettingsSectionElement} section | 158 * @param {!SettingsSectionElement} section |
| 159 * @return {!Promise} Promise when the transition finishes or cancels. | |
| 138 */ | 160 */ |
| 139 collapseSection: function(section) { | 161 collapseSection: function(section) { |
| 140 // If the section's card is still expanding, cancel the expand animation. | 162 assert(!this.currentSectionTransition_); |
| 141 if (section.classList.contains('expanding')) { | 163 assert(section.classList.contains('expanded')); |
| 142 if (this.animations['section']) { | |
| 143 this.cancelAnimation('section'); | |
| 144 } else { | |
| 145 // The animation must have finished but its promise hasn't finished | |
| 146 // resolving; try again asynchronously. | |
| 147 this.async(function() { | |
| 148 this.collapseSection(section); | |
| 149 }); | |
| 150 } | |
| 151 return; | |
| 152 } | |
| 153 | 164 |
| 154 if (!section.classList.contains('expanded')) | 165 // TODO(michaelpg): Minimize horizontal motion when scrollbar changes for |
| 155 return; | 166 // the common cases. |
| 167 this.scroller.style.overflow = 'hidden'; | |
| 168 | |
| 169 // Set up the close transition first, which takes the section out of the | |
| 170 // flow, before showing everything. | |
| 171 this.currentSectionTransition_ = | |
| 172 new settings.CloseSectionTransition(section, this.scroller); | |
| 173 this.currentSectionTransition_.setUp(); | |
| 156 | 174 |
| 157 this.toggleOtherSectionsHidden_(section.section, false); | 175 this.toggleOtherSectionsHidden_(section.section, false); |
| 176 this.classList.remove('showing-subpage'); | |
| 177 this.fire('overscroll-recalc'); | |
| 158 | 178 |
| 159 var scrollerWidth = this.scroller.clientWidth; | 179 return new Promise(function(resolve, reject) { |
| 160 this.scroller.style.overflow = 'hidden'; | 180 // Wait for the other sections to show up so we can scroll properly. |
| 161 // Adjust width to compensate for scroller. | 181 setTimeout(function() { |
| 162 var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; | 182 // Allow overscroll adjustment so it changes now rather than after the |
| 163 this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; | 183 // transition has begun. |
| 164 | 184 |
| 165 this.playCollapseSection_(section).then(function() { | 185 var newSection = this.currentRoute.section && |
| 166 this.unfreezeSection_(section); | 186 this.getSection_(this.currentRoute.section); |
| 167 this.scroller.style.overflow = ''; | 187 |
| 168 this.scroller.style.width = ''; | 188 // Scroll to the section if indicated by the route. TODO(dschuyler): Is |
| 169 section.classList.remove('collapsing'); | 189 // this the right behavior, or should we return to the previous scroll |
| 190 // position? | |
| 191 if (newSection) | |
| 192 newSection.scrollIntoView(); | |
| 193 else | |
| 194 this.scroller.scrollTop = this.mainScrollTop_; | |
| 195 | |
| 196 this.currentSectionTransition_.play().then(function(success) { | |
| 197 this.currentSectionTransition_ = null; | |
| 198 if (!success) { | |
| 199 // The collapse was canceled, so ensure the page is still set up for | |
| 200 // a full-height section. | |
| 201 this.fire('subpage-expand'); | |
| 202 } | |
| 203 | |
| 204 // Restore the scrollbar. | |
| 205 this.scroller.style.overflow = ''; | |
| 206 this.scroller.style.width = ''; | |
|
Dan Beam
2016/08/05 00:47:06
marginally useful: make a lockScrolling_() and unl
| |
| 207 resolve(); | |
| 208 }.bind(this)); | |
| 209 }.bind(this)); | |
| 170 }.bind(this)); | 210 }.bind(this)); |
| 171 }, | 211 }, |
| 172 | |
| 173 /** | |
| 174 * Freezes a section's height so its card can be removed from the flow without | |
| 175 * affecting the layout of the surrounding sections. | |
| 176 * @param {!SettingsSectionElement} section | |
| 177 * @private | |
| 178 */ | |
| 179 freezeSection_: function(section) { | |
| 180 var card = section.$.card; | |
| 181 section.style.height = section.clientHeight + 'px'; | |
| 182 | |
| 183 var cardHeight = card.offsetHeight; | |
| 184 var cardWidth = card.offsetWidth; | |
| 185 // If the section is not displayed yet (e.g., navigated directly to a | |
| 186 // sub-page), cardHeight and cardWidth are 0, so do not set the height or | |
| 187 // width explicitly. | |
| 188 // TODO(michaelpg): Improve this logic when refactoring | |
| 189 // settings-animated-pages. | |
| 190 if (cardHeight && cardWidth) { | |
| 191 // TODO(michaelpg): Temporary hack to store the height the section should | |
| 192 // collapse to when it closes. | |
| 193 card.origHeight_ = cardHeight; | |
| 194 | |
| 195 card.style.height = cardHeight + 'px'; | |
| 196 card.style.width = cardWidth + 'px'; | |
| 197 } else { | |
| 198 // Set an invalid value so we don't try to use it later. | |
| 199 card.origHeight_ = NaN; | |
| 200 } | |
| 201 | |
| 202 // Place the section's card at its current position but removed from the | |
| 203 // flow. | |
| 204 card.style.top = card.getBoundingClientRect().top + 'px'; | |
| 205 section.classList.add('frozen'); | |
| 206 }, | |
| 207 | |
| 208 /** | |
| 209 * After freezeSection_, restores the section to its normal height. | |
| 210 * @param {!SettingsSectionElement} section | |
| 211 * @private | |
| 212 */ | |
| 213 unfreezeSection_: function(section) { | |
| 214 if (!section.classList.contains('frozen')) | |
| 215 return; | |
| 216 var card = section.$.card; | |
| 217 section.classList.remove('frozen'); | |
| 218 card.style.top = ''; | |
| 219 card.style.height = ''; | |
| 220 card.style.width = ''; | |
| 221 section.style.height = ''; | |
| 222 }, | |
| 223 | |
| 224 /** | |
| 225 * Expands the card in |section| to fill the page. | |
| 226 * @param {!SettingsSectionElement} section | |
| 227 * @return {!Promise} | |
| 228 * @private | |
| 229 */ | |
| 230 playExpandSection_: function(section) { | |
| 231 var card = section.$.card; | |
| 232 | |
| 233 // The card should start at the top of the page. | |
| 234 var targetTop = this.scroller.getBoundingClientRect().top; | |
| 235 | |
| 236 section.classList.add('expanding'); | |
| 237 | |
| 238 // Expand the card, using minHeight. (The card must span the container's | |
| 239 // client height, so it must be at least 100% in case the card is too short. | |
| 240 // If the card is already taller than the container's client height, we | |
| 241 // don't want to shrink the card to 100% or the content will overflow, so | |
| 242 // we can't use height, and animating height wouldn't look right anyway.) | |
| 243 var keyframes = [{ | |
| 244 top: card.style.top, | |
| 245 minHeight: card.style.height, | |
| 246 easing: EASING_FUNCTION, | |
| 247 }, { | |
| 248 top: targetTop + 'px', | |
| 249 minHeight: 'calc(100% - ' + targetTop + 'px)', | |
| 250 }]; | |
| 251 var options = /** @type {!KeyframeEffectOptions} */({ | |
| 252 duration: EXPAND_DURATION | |
| 253 }); | |
| 254 // TODO(michaelpg): Change elevation of sections. | |
| 255 var promise; | |
| 256 if (keyframes[0].top && keyframes[0].minHeight) | |
| 257 promise = this.animateElement('section', card, keyframes, options); | |
| 258 else | |
| 259 promise = Promise.resolve(); | |
| 260 | |
| 261 promise.then(function() { | |
| 262 section.classList.add('expanded'); | |
| 263 card.style.top = ''; | |
| 264 this.style.margin = 'auto'; | |
| 265 section.$.header.hidden = true; | |
| 266 section.style.height = ''; | |
| 267 }.bind(this), function() { | |
| 268 // The animation was canceled; catch the error and continue. | |
| 269 }).then(function() { | |
| 270 // Whether finished or canceled, clean up the animation. | |
| 271 section.classList.remove('expanding'); | |
| 272 card.style.height = ''; | |
| 273 card.style.width = ''; | |
| 274 }); | |
| 275 | |
| 276 return promise; | |
| 277 }, | |
| 278 | |
| 279 /** | |
| 280 * Collapses the card in |section| back to its normal position. | |
| 281 * @param {!SettingsSectionElement} section | |
| 282 * @return {!Promise} | |
| 283 * @private | |
| 284 */ | |
| 285 playCollapseSection_: function(section) { | |
| 286 var card = section.$.card; | |
| 287 | |
| 288 this.style.margin = ''; | |
| 289 section.$.header.hidden = false; | |
| 290 | |
| 291 var startingTop = this.scroller.getBoundingClientRect().top; | |
| 292 | |
| 293 var cardHeightStart = card.clientHeight; | |
| 294 var cardWidthStart = card.clientWidth; | |
| 295 | |
| 296 section.classList.add('collapsing'); | |
| 297 section.classList.remove('expanding', 'expanded'); | |
| 298 | |
| 299 // If we navigated here directly, we don't know the original height of the | |
| 300 // section, so we skip the animation. | |
| 301 // TODO(michaelpg): remove this condition once sliding is implemented. | |
| 302 if (isNaN(card.origHeight_)) | |
| 303 return Promise.resolve(); | |
| 304 | |
| 305 // Restore the section to its proper height to make room for the card. | |
| 306 section.style.height = section.clientHeight + card.origHeight_ + 'px'; | |
| 307 | |
| 308 // TODO(michaelpg): this should be in collapseSection(), but we need to wait | |
| 309 // until the full page height is available (setting the section height). | |
| 310 this.scroller.scrollTop = this.listScrollTop_; | |
| 311 | |
| 312 // The card is unpositioned, so use its position as the ending state, | |
| 313 // but account for scroll. | |
| 314 var targetTop = card.getBoundingClientRect().top - this.scroller.scrollTop; | |
| 315 | |
| 316 // Account for the section header. | |
| 317 var headerStyle = getComputedStyle(section.$.header); | |
| 318 targetTop += section.$.header.offsetHeight + | |
| 319 parseInt(headerStyle.marginBottom, 10) + | |
| 320 parseInt(headerStyle.marginTop, 10); | |
| 321 | |
| 322 var keyframes = [{ | |
| 323 top: startingTop + 'px', | |
| 324 minHeight: cardHeightStart + 'px', | |
| 325 easing: EASING_FUNCTION, | |
| 326 }, { | |
| 327 top: targetTop + 'px', | |
| 328 minHeight: card.origHeight_ + 'px', | |
| 329 }]; | |
| 330 var options = /** @type {!KeyframeEffectOptions} */({ | |
| 331 duration: EXPAND_DURATION | |
| 332 }); | |
| 333 | |
| 334 card.style.width = cardWidthStart + 'px'; | |
| 335 var promise = this.animateElement('section', card, keyframes, options); | |
| 336 promise.then(function() { | |
| 337 card.style.width = ''; | |
| 338 }); | |
| 339 return promise; | |
| 340 }, | |
| 341 }; | 212 }; |
| 342 | 213 |
| 343 | 214 |
| 344 /** @polymerBehavior */ | 215 /** @polymerBehavior */ |
| 345 var MainPageBehavior = [ | 216 var MainPageBehavior = [ |
| 346 TransitionBehavior, | |
| 347 MainPageBehaviorImpl | 217 MainPageBehaviorImpl |
| 348 ]; | 218 ]; |
| 349 | 219 |
| 350 | 220 |
| 351 /** | 221 /** |
| 352 * TODO(michaelpg): integrate slide animations. | 222 * TODO(michaelpg): integrate slide animations. |
| 353 * @polymerBehavior RoutableBehavior | 223 * @polymerBehavior RoutableBehavior |
| 354 */ | 224 */ |
| 355 var RoutableBehaviorImpl = { | 225 var RoutableBehaviorImpl = { |
| 356 properties: { | 226 properties: { |
| 357 /** Contains the current route. */ | 227 /** Contains the current route. */ |
| 358 currentRoute: { | 228 currentRoute: { |
| 359 type: Object, | 229 type: Object, |
| 360 notify: true, | 230 notify: true, |
| 361 observer: 'currentRouteChanged_', | 231 observer: 'currentRouteChanged_', |
| 362 }, | 232 }, |
| 363 }, | 233 }, |
| 364 | 234 |
| 365 /** @private */ | 235 /** @private */ |
| 366 scrollToSection_: function() { | 236 scrollToSection_: function() { |
| 367 doWhenReady( | 237 doWhenReady( |
| 368 function() { | 238 function() { |
| 369 return this.scrollHeight > 0; | 239 return this.scrollHeight > 0; |
| 370 }.bind(this), | 240 }.bind(this), |
| 371 function() { | 241 function() { |
| 372 // If the current section changes while we are waiting for the page to | 242 // If the current section changes while we are waiting for the page to |
| 373 // be ready, scroll to the newest requested section. | 243 // be ready, scroll to the newest requested section. |
| 374 this.getSection_(this.currentRoute.section).scrollIntoView(); | 244 var section = this.getSection_(this.currentRoute.section); |
| 245 if (section) | |
| 246 section.scrollIntoView(); | |
| 375 }.bind(this)); | 247 }.bind(this)); |
| 376 }, | 248 }, |
| 377 | 249 |
| 378 /** @private */ | 250 /** |
| 251 * @param {?settings.Route} newRoute | |
| 252 * @param {?settings.Route} oldRoute | |
| 253 * @private | |
| 254 */ | |
| 379 currentRouteChanged_: function(newRoute, oldRoute) { | 255 currentRouteChanged_: function(newRoute, oldRoute) { |
| 380 var newRouteIsSubpage = newRoute && newRoute.subpage.length; | 256 if (!oldRoute && newRoute && newRoute.subpage.length > 0) { |
| 381 var oldRouteIsSubpage = oldRoute && oldRoute.subpage.length; | |
| 382 | |
| 383 if (!oldRoute && newRouteIsSubpage) { | |
| 384 // Allow the page to load before expanding the section. TODO(michaelpg): | 257 // Allow the page to load before expanding the section. TODO(michaelpg): |
| 385 // Time this better when refactoring settings-animated-pages. | 258 // Time this better when refactoring settings-animated-pages. |
| 386 setTimeout(function() { | 259 this.deferredTransition_ = true; |
| 387 var section = this.getSection_(newRoute.section); | 260 setTimeout(this.runDeferredTransition_.bind(this)); |
| 388 if (section) | |
| 389 this.expandSection(section); | |
| 390 }.bind(this)); | |
| 391 return; | 261 return; |
| 392 } | 262 } |
| 393 | 263 |
| 394 if (newRouteIsSubpage) { | 264 if (this.currentSectionTransition_) { |
| 395 if (!oldRouteIsSubpage || newRoute.section != oldRoute.section) { | 265 // Transition to the current route when the current one finishes. |
| 396 var section = this.getSection_(newRoute.section); | 266 this.deferredTransition_ = true; |
| 397 if (section) | 267 |
| 398 this.expandSection(section); | 268 // If the current transition is opening a section we want to close, cancel |
| 269 // that transition immediately. | |
| 270 if (this.currentSectionTransition_ instanceof | |
| 271 settings.OpenSectionTransition && | |
| 272 (this.currentSectionTransition_.section != newRoute.section || | |
| 273 newRoute.subpage.length == 0)) { | |
|
Dan Beam
2016/08/05 00:47:07
can you use some temporary variables for this?
| |
| 274 this.currentSectionTransition_.cancel(); | |
| 399 } | 275 } |
| 400 } else { | 276 return; |
| 401 if (oldRouteIsSubpage) { | 277 } |
| 402 var section = this.getSection_(oldRoute.section); | |
| 403 if (section) | |
| 404 this.collapseSection(section); | |
| 405 } | |
| 406 | 278 |
| 407 // Scrolls to the section if this main page contains the route's section. | 279 this.transitionToRoute_(); |
| 408 if (newRoute && newRoute.section && this.getSection_(newRoute.section)) | |
| 409 this.scrollToSection_(); | |
| 410 } | |
| 411 }, | 280 }, |
| 412 | 281 |
| 413 /** | 282 /** |
| 414 * Helper function to get a section from the local DOM. | 283 * Helper function to get a section from the local DOM. |
| 415 * @param {string} section Section name of the element to get. | 284 * @param {string} section Section name of the element to get. |
| 416 * @return {?SettingsSectionElement} | 285 * @return {?SettingsSectionElement} |
| 417 * @private | 286 * @private |
| 418 */ | 287 */ |
| 419 getSection_: function(section) { | 288 getSection_: function(section) { |
| 420 return /** @type {?SettingsSectionElement} */( | 289 return /** @type {?SettingsSectionElement} */( |
| 421 this.$$('[section=' + section + ']')); | 290 this.$$('[section=' + section + ']')); |
| 422 }, | 291 }, |
| 423 }; | 292 }; |
| 424 | 293 |
| 425 | 294 |
| 426 /** @polymerBehavior */ | 295 /** @polymerBehavior */ |
| 427 var RoutableBehavior = [ | 296 var RoutableBehavior = [ |
| 428 MainPageBehavior, | 297 MainPageBehavior, |
| 429 RoutableBehaviorImpl | 298 RoutableBehaviorImpl |
| 430 ]; | 299 ]; |
| OLD | NEW |