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. | 5 // Fast out, slow in. |
| 6 var EASING_FUNCTION = 'cubic-bezier(0.4, 0, 0.2, 1)'; | 6 var EASING_FUNCTION = 'cubic-bezier(0.4, 0, 0.2, 1)'; |
| 7 var EXPAND_DURATION = 350; | 7 var EXPAND_DURATION = 350; |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Provides animations to expand and collapse individual sections in a page. | 10 * Provides animations to expand and collapse individual sections in a page. |
| 11 * Expanded sections take up the full height of the container. At most one | 11 * Expanded sections take up the full height of the container. At most one |
| 12 * section should be expanded at any given time. | 12 * section should be expanded at any given time. |
| 13 * @polymerBehavior Polymer.MainPageBehavior | 13 * @polymerBehavior Polymer.MainPageBehavior |
| 14 */ | 14 */ |
| 15 var MainPageBehaviorImpl = { | 15 var MainPageBehaviorImpl = { |
| 16 /** | 16 /** |
| 17 * @type {string} Selector to get the sections. Derived elements | 17 * @type {string} Selector to get the sections. Derived elements |
| 18 * must override. | 18 * must override. |
| 19 */ | 19 */ |
| 20 sectionSelector: '', | 20 sectionSelector: '', |
| 21 | 21 |
| 22 /** @type {?Element} The scrolling container. Elements must set this. */ | 22 /** @type {?Element} The scrolling container. Elements must set this. */ |
| 23 scroller: null, | 23 scroller: null, |
| 24 | 24 |
| 25 | |
| 26 /** @override */ | |
| 27 attached: function() { | |
| 28 this.scroller = (this.parentNode.$ && this.parentNode.$.mainContainer) || | |
|
michaelpg
2016/06/13 21:11:22
This is a symptom of using this behavior for heter
dschuyler
2016/06/13 21:44:50
Done.
| |
| 29 (this.domHost && this.domHost.parentNode.$.mainContainer); | |
| 30 }, | |
| 31 | |
| 25 /** | 32 /** |
| 26 * Hides or unhides the sections not being expanded. | 33 * Hides or unhides the sections not being expanded. |
| 27 * @param {string} sectionName The section to keep visible. | 34 * @param {string} sectionName The section to keep visible. |
| 28 * @param {boolean} hidden Whether the sections should be hidden. | 35 * @param {boolean} hidden Whether the sections should be hidden. |
| 29 * @private | 36 * @private |
| 30 */ | 37 */ |
| 31 toggleOtherSectionsHidden_: function(sectionName, hidden) { | 38 toggleOtherSectionsHidden_: function(sectionName, hidden) { |
| 32 var sections = Polymer.dom(this.root).querySelectorAll( | 39 var sections = Polymer.dom(this.root).querySelectorAll( |
| 33 this.sectionSelector + ':not([section=' + sectionName + '])'); | 40 this.sectionSelector + ':not([section=' + sectionName + '])'); |
| 34 for (var section of sections) | 41 for (var section of sections) |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 /** | 212 /** |
| 206 * Expands the card in |section| to fill the page. | 213 * Expands the card in |section| to fill the page. |
| 207 * @param {!SettingsSectionElement} section | 214 * @param {!SettingsSectionElement} section |
| 208 * @return {!Promise} | 215 * @return {!Promise} |
| 209 * @private | 216 * @private |
| 210 */ | 217 */ |
| 211 playExpandSection_: function(section) { | 218 playExpandSection_: function(section) { |
| 212 var card = section.$.card; | 219 var card = section.$.card; |
| 213 | 220 |
| 214 // The card should start at the top of the page. | 221 // The card should start at the top of the page. |
| 215 var targetTop = this.parentElement.getBoundingClientRect().top; | 222 var targetTop = this.scroller.getBoundingClientRect().top; |
| 216 | 223 |
| 217 section.classList.add('expanding'); | 224 section.classList.add('expanding'); |
| 218 | 225 |
| 219 // Expand the card, using minHeight. (The card must span the container's | 226 // Expand the card, using minHeight. (The card must span the container's |
| 220 // client height, so it must be at least 100% in case the card is too short. | 227 // client height, so it must be at least 100% in case the card is too short. |
| 221 // If the card is already taller than the container's client height, we | 228 // If the card is already taller than the container's client height, we |
| 222 // don't want to shrink the card to 100% or the content will overflow, so | 229 // don't want to shrink the card to 100% or the content will overflow, so |
| 223 // we can't use height, and animating height wouldn't look right anyway.) | 230 // we can't use height, and animating height wouldn't look right anyway.) |
| 224 var keyframes = [{ | 231 var keyframes = [{ |
| 225 top: card.style.top, | 232 top: card.style.top, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 * @param {!SettingsSectionElement} section | 269 * @param {!SettingsSectionElement} section |
| 263 * @return {!Promise} | 270 * @return {!Promise} |
| 264 * @private | 271 * @private |
| 265 */ | 272 */ |
| 266 playCollapseSection_: function(section) { | 273 playCollapseSection_: function(section) { |
| 267 var card = section.$.card; | 274 var card = section.$.card; |
| 268 | 275 |
| 269 this.style.margin = ''; | 276 this.style.margin = ''; |
| 270 section.$.header.hidden = false; | 277 section.$.header.hidden = false; |
| 271 | 278 |
| 272 var startingTop = this.parentElement.getBoundingClientRect().top; | 279 var startingTop = this.scroller.getBoundingClientRect().top; |
| 273 | 280 |
| 274 var cardHeightStart = card.clientHeight; | 281 var cardHeightStart = card.clientHeight; |
| 275 var cardWidthStart = card.clientWidth; | 282 var cardWidthStart = card.clientWidth; |
| 276 | 283 |
| 277 section.classList.add('collapsing'); | 284 section.classList.add('collapsing'); |
| 278 section.classList.remove('expanding', 'expanded'); | 285 section.classList.remove('expanding', 'expanded'); |
| 279 | 286 |
| 280 // If we navigated here directly, we don't know the original height of the | 287 // If we navigated here directly, we don't know the original height of the |
| 281 // section, so we skip the animation. | 288 // section, so we skip the animation. |
| 282 // TODO(michaelpg): remove this condition once sliding is implemented. | 289 // TODO(michaelpg): remove this condition once sliding is implemented. |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 312 duration: EXPAND_DURATION | 319 duration: EXPAND_DURATION |
| 313 }); | 320 }); |
| 314 | 321 |
| 315 card.style.width = cardWidthStart + 'px'; | 322 card.style.width = cardWidthStart + 'px'; |
| 316 var promise = this.animateElement('section', card, keyframes, options); | 323 var promise = this.animateElement('section', card, keyframes, options); |
| 317 promise.then(function() { | 324 promise.then(function() { |
| 318 card.style.width = ''; | 325 card.style.width = ''; |
| 319 }); | 326 }); |
| 320 return promise; | 327 return promise; |
| 321 }, | 328 }, |
| 329 | |
| 330 scrollWhenReady: function(containerCallback, elementCallback) { | |
| 331 // TODO(dschuyler): Determine whether this setTimeout can be removed. | |
| 332 // See also: https://github.com/Polymer/polymer/issues/3629 | |
| 333 setTimeout(function pollForScrollHeight() { | |
| 334 var container = containerCallback(); | |
| 335 if (!container || container.scrollHeight == 0) { | |
| 336 setTimeout(pollForScrollHeight.bind(this), 10); | |
| 337 return; | |
| 338 } | |
| 339 | |
| 340 elementCallback().scrollIntoView(); | |
| 341 }.bind(this)); | |
| 342 }, | |
| 322 }; | 343 }; |
| 323 | 344 |
| 324 | 345 |
| 325 /** @polymerBehavior */ | 346 /** @polymerBehavior */ |
| 326 var MainPageBehavior = [ | 347 var MainPageBehavior = [ |
| 327 TransitionBehavior, | 348 TransitionBehavior, |
| 328 MainPageBehaviorImpl | 349 MainPageBehaviorImpl |
| 329 ]; | 350 ]; |
| 330 | 351 |
| 331 | 352 |
| 332 /** | 353 /** |
| 333 * TODO(michaelpg): integrate slide animations. | 354 * TODO(michaelpg): integrate slide animations. |
| 334 * @polymerBehavior RoutableBehavior | 355 * @polymerBehavior RoutableBehavior |
| 335 */ | 356 */ |
| 336 var RoutableBehaviorImpl = { | 357 var RoutableBehaviorImpl = { |
| 337 properties: { | 358 properties: { |
| 338 /** Contains the current route. */ | 359 /** Contains the current route. */ |
| 339 currentRoute: { | 360 currentRoute: { |
| 340 type: Object, | 361 type: Object, |
| 341 notify: true, | 362 notify: true, |
| 342 observer: 'currentRouteChanged_', | 363 observer: 'currentRouteChanged_', |
| 343 }, | 364 }, |
| 344 }, | 365 }, |
| 345 | 366 |
| 346 /** @private */ | 367 /** @private */ |
| 347 scrollToSection_: function() { | 368 scrollToSection_: function() { |
| 348 // TODO(dschuyler): Determine whether this setTimeout can be removed. | 369 this.scrollWhenReady( |
| 349 // See also: https://github.com/Polymer/polymer/issues/3629 | 370 function() { |
| 350 setTimeout(function pollForScrollHeight() { | 371 return this; |
| 351 // If the current section changes while we are waiting for the page to be | 372 }.bind(this), |
| 352 // ready, scroll to the newest requested section. | 373 function() { |
| 353 var element = this.getSection_(this.currentRoute.section); | 374 // If the current section changes while we are waiting for the page to |
| 354 if (!element) | 375 // be ready, scroll to the newest requested section. |
| 355 return; | 376 return this.getSection_(this.currentRoute.section); |
| 356 | 377 }.bind(this)); |
| 357 var host = findAncestor(element, function(n) { return n.host; }).host; | |
| 358 if (host.scrollHeight == 0) { | |
| 359 setTimeout(pollForScrollHeight.bind(this), 100); | |
| 360 return; | |
| 361 } | |
| 362 | |
| 363 // TODO(michaelpg): due to the workaround for crbug.com/617827 in | |
| 364 // settings_page_css.html, we have to use element.offsetTop instead of | |
| 365 // relying on element.scrollIntoView() so the margin is included. | |
| 366 host.scroller.scrollTop = element.offsetTop; | |
| 367 }.bind(this)); | |
| 368 }, | 378 }, |
| 369 | 379 |
| 370 /** @private */ | 380 /** @private */ |
| 371 currentRouteChanged_: function(newRoute, oldRoute) { | 381 currentRouteChanged_: function(newRoute, oldRoute) { |
| 372 var newRouteIsSubpage = newRoute && newRoute.subpage.length; | 382 var newRouteIsSubpage = newRoute && newRoute.subpage.length; |
| 373 var oldRouteIsSubpage = oldRoute && oldRoute.subpage.length; | 383 var oldRouteIsSubpage = oldRoute && oldRoute.subpage.length; |
| 374 | 384 |
| 375 if (!oldRoute && newRouteIsSubpage) { | 385 if (!oldRoute && newRouteIsSubpage) { |
| 376 // Allow the page to load before expanding the section. TODO(michaelpg): | 386 // Allow the page to load before expanding the section. TODO(michaelpg): |
| 377 // Time this better when refactoring settings-animated-pages. | 387 // Time this better when refactoring settings-animated-pages. |
| 378 setTimeout(function() { | 388 setTimeout(function() { |
| 379 var section = this.getSection_(newRoute.section); | 389 var section = this.getSection_(newRoute.section); |
| 380 if (section) | 390 if (section) |
| 381 this.expandSection(section); | 391 this.expandSection(section); |
| 382 }.bind(this)); | 392 }.bind(this)); |
| 383 return; | 393 return; |
| 384 } | 394 } |
| 385 | 395 |
| 386 if (!newRouteIsSubpage && oldRouteIsSubpage) { | 396 if (!newRouteIsSubpage && oldRouteIsSubpage) { |
| 387 var section = this.getSection_(oldRoute.section); | 397 var section = this.getSection_(oldRoute.section); |
| 388 if (section) | 398 if (section) |
| 389 this.collapseSection(section); | 399 this.collapseSection(section); |
| 390 } else if (newRouteIsSubpage && | 400 } else if (newRouteIsSubpage && |
| 391 (!oldRouteIsSubpage || newRoute.section != oldRoute.section)) { | 401 (!oldRouteIsSubpage || newRoute.section != oldRoute.section)) { |
| 392 var section = this.getSection_(newRoute.section); | 402 var section = this.getSection_(newRoute.section); |
| 393 if (section) | 403 if (section) |
| 394 this.expandSection(section); | 404 this.expandSection(section); |
| 395 } else if (newRoute && newRoute.section) { | 405 } else if (newRoute && newRoute.section && |
| 406 this.$$('[data-page=' + newRoute.page + ']')) { | |
| 396 this.scrollToSection_(); | 407 this.scrollToSection_(); |
| 397 } | 408 } |
| 398 }, | 409 }, |
| 399 | 410 |
| 400 /** | 411 /** |
| 401 * Helper function to get a section from the local DOM. | 412 * Helper function to get a section from the local DOM. |
| 402 * @param {string} section Section name of the element to get. | 413 * @param {string} section Section name of the element to get. |
| 403 * @return {?SettingsSectionElement} | 414 * @return {?SettingsSectionElement} |
| 404 * @private | 415 * @private |
| 405 */ | 416 */ |
| 406 getSection_: function(section) { | 417 getSection_: function(section) { |
| 407 return /** @type {?SettingsSectionElement} */( | 418 return /** @type {?SettingsSectionElement} */( |
| 408 this.$$('[section=' + section + ']')); | 419 this.$$('[section=' + section + ']')); |
| 409 }, | 420 }, |
| 410 }; | 421 }; |
| 411 | 422 |
| 412 | 423 |
| 413 /** @polymerBehavior */ | 424 /** @polymerBehavior */ |
| 414 var RoutableBehavior = [ | 425 var RoutableBehavior = [ |
| 415 MainPageBehavior, | 426 MainPageBehavior, |
| 416 RoutableBehaviorImpl | 427 RoutableBehaviorImpl |
| 417 ]; | 428 ]; |
| OLD | NEW |