Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2062)

Unified Diff: chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js

Issue 1962643005: [Media Router WebUI] Fix search input positioning when list scrolls. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: CSS attribute instead of JS binding Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
index c3af59def0a63d4c78f4df1776562746284d1618..bcf1b5da57765b497e2c992534f60320c6d37339 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -294,6 +294,17 @@ Polymer({
},
/**
+ * Whether the search input should be padded as if it were at the bottom of
+ * the dialog.
+ * @type {boolean}
+ */
+ searchUseBottomPadding: {
+ type: Boolean,
+ reflectToAttribute: true,
+ value: true,
+ },
+
+ /**
* Whether to show the user domain of sinks associated with identity.
* @type {boolean|undefined}
*/
@@ -748,6 +759,18 @@ Polymer({
},
/**
+ * @param {?Element} element Element to compute padding for.
+ * @return {number} Computes the amount of vertical padding (top + bottom) on
+ * |element|.
+ * @private
+ */
+ computeElementVerticalPadding_: function(element) {
+ var paddingBottom, paddingTop;
+ [paddingBottom, paddingTop] = this.getElementVerticalPadding_(element);
+ return paddingBottom + paddingTop;
+ },
+
+ /**
* Computes an array of substring indices that mark where substrings of
* |searchString| occur in |sinkName|.
*
@@ -983,18 +1006,21 @@ Polymer({
* Computes the height of the sink list view element when search results are
* being shown.
*
+ * @param {?Element} deviceMissing No devices message element.
* @param {?Element} noMatches No search matches element.
* @param {?Element} results Search results list element.
- * @param {?Element} search Search input container element.
+ * @param {number} searchOffsetHeight Search input container element height.
* @param {number} maxHeight Max height of the list elements.
* @return {number} The height of the sink list view when search results are
* being shown.
* @private
*/
- computeTotalSearchHeight_: function(noMatches, results, search, maxHeight) {
- var contentHeight = (noMatches.hasAttribute('hidden')) ?
- results.offsetHeight : noMatches.offsetHeight;
- return Math.min(contentHeight, maxHeight) + search.offsetHeight;
+ computeTotalSearchHeight_: function(
+ deviceMissing, noMatches, results, searchOffsetHeight, maxHeight) {
+ var contentHeight = deviceMissing.offsetHeight +
+ ((noMatches.hasAttribute('hidden')) ?
+ results.offsetHeight : noMatches.offsetHeight);
+ return Math.min(contentHeight, maxHeight) + searchOffsetHeight;
},
/**
@@ -1083,6 +1109,18 @@ Polymer({
},
/**
+ * @param {?Element} element Element to compute padding for.
+ * @return {!Array<number>} Array containing the element's bottom padding
+ * value and the element's top padding value, in that order.
+ * @private
+ */
+ getElementVerticalPadding_: function(element) {
+ var style = window.getComputedStyle(element);
+ return [parseInt(style.getPropertyValue('padding-bottom'), 10) || 0,
+ parseInt(style.getPropertyValue('padding-top'), 10) || 0];
+ },
+
+ /**
* Retrieves the first run flow cloud preferences text, if it exists. On
* non-officially branded builds, the string is not defined.
*
@@ -1255,11 +1293,24 @@ Polymer({
var view = this.$['sink-list-view'];
var hasList = this.hasConditionalElement_(list);
- // Same reason for omission of |search.offsetHeight| as above.
- var initialHeight = resultsContainer.offsetHeight;
- // Force the view height to be max height.
+ var initialHeight = view.offsetHeight;
+ // Force the view height to be max dialog height.
view.style['overflow'] = 'hidden';
+ var searchInitialOffsetHeight = search.offsetHeight;
+ var searchInitialPaddingBottom, searchInitialPaddingTop;
+ [searchInitialPaddingBottom, searchInitialPaddingTop] =
+ this.getElementVerticalPadding_(search);
+ var searchPadding = searchInitialPaddingBottom + searchInitialPaddingTop;
+ var searchHeight = search.offsetHeight - searchPadding;
+ this.searchUseBottomPadding = true;
+ var searchFinalPaddingBottom, searchFinalPaddingTop;
+ [searchFinalPaddingBottom, searchFinalPaddingTop] =
+ this.getElementVerticalPadding_(search);
+ var searchFinalOffsetHeight =
+ searchHeight + searchFinalPaddingBottom + searchFinalPaddingTop;
+
+ var resultsInitialTop = 0;
var finalHeight = 0;
// Get final view height ahead of animation.
if (hasList) {
@@ -1268,6 +1319,10 @@ Polymer({
this.hideSinkListForAnimation_ = false;
finalHeight += list.offsetHeight;
list.style['position'] = 'relative';
+ } else {
+ resultsInitialTop +=
+ deviceMissing.offsetHeight + searchInitialOffsetHeight;
+ finalHeight += deviceMissing.offsetHeight;
}
var searchInitialTop = hasList ? 0 : deviceMissing.offsetHeight;
@@ -1278,27 +1333,39 @@ Polymer({
var duration =
this.computeAnimationDuration_(searchFinalTop - searchInitialTop);
+ var timing = {duration: duration, easing: 'ease-in-out', fill: 'forwards'};
// This GroupEffect does the reverse of |moveSearchToTop_|. It fades the
// sink list in while sliding the search input and search results list down.
// The dialog height is also adjusted smoothly to the sink list height.
+ var deviceMissingEffect = new KeyframeEffect(deviceMissing,
+ [{'marginBottom': searchInitialOffsetHeight},
+ {'marginBottom': searchFinalOffsetHeight}],
+ timing);
var listEffect = new KeyframeEffect(list,
[{'opacity': '0'}, {'opacity': '1'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ timing);
var resultsEffect = new KeyframeEffect(resultsContainer,
- [{'top': '0px', 'paddingTop': resultsContainer.style['padding-top']},
+ [{'top': resultsInitialTop + 'px',
+ 'paddingTop': resultsContainer.style['padding-top']},
{'top': '100%', 'paddingTop': '0px'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ timing);
var searchEffect = new KeyframeEffect(search,
- [{'top': searchInitialTop + 'px', 'marginTop': '0px'},
- {'top': '100%', 'marginTop': '-' + (search.offsetHeight + 16) + 'px'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ [{'top': searchInitialTop + 'px', 'marginTop': '0px',
+ 'paddingBottom': searchInitialPaddingBottom + 'px',
+ 'paddingTop': searchInitialPaddingTop + 'px'},
+ {'top': '100%', 'marginTop': '-' + searchFinalOffsetHeight + 'px',
+ 'paddingBottom': searchFinalPaddingBottom + 'px',
+ 'paddingTop': searchFinalPaddingTop + 'px'}],
+ timing);
var viewEffect = new KeyframeEffect(view,
- [{'height': initialHeight + 'px'}, {'height': finalHeight + 'px'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ [{'height': initialHeight + 'px', 'paddingBottom': '0px'},
+ {'height': finalHeight + 'px',
+ 'paddingBottom': searchFinalOffsetHeight + 'px'}],
+ timing);
var player = document.timeline.play(new GroupEffect(hasList ?
[listEffect, resultsEffect, searchEffect, viewEffect] :
- [resultsEffect, searchEffect, viewEffect]));
+ [deviceMissingEffect, resultsEffect, searchEffect, viewEffect]));
var that = this;
var finalizeAnimation = function() {
@@ -1337,48 +1404,71 @@ Polymer({
// Saves current search container |offsetHeight| which includes bottom
// padding.
- var searchOffsetHeight = search.offsetHeight;
+ var searchInitialOffsetHeight = search.offsetHeight;
var hasList = this.hasConditionalElement_(list);
- var searchInitialTop = hasList ? list.offsetHeight - searchOffsetHeight :
- deviceMissing.offsetHeight;
+ var searchInitialTop = hasList ?
+ list.offsetHeight - searchInitialOffsetHeight :
+ deviceMissing.offsetHeight;
var searchFinalTop = hasList ? 0 : deviceMissing.offsetHeight;
- resultsContainer.style['max-height'] = this.sinkListMaxHeight_ + 'px';
-
- // Omitting |search.offsetHeight| because |list| is padded with
- // |search.offsetHeight| and |offsetHeight| includes padding.
- var initialHeight = hasList ?
- list.offsetHeight :
- deviceMissing.offsetHeight + searchOffsetHeight;
+ var searchInitialPaddingBottom, searchInitialPaddingTop;
+ [searchInitialPaddingBottom, searchInitialPaddingTop] =
+ this.getElementVerticalPadding_(search);
+ var searchPadding = searchInitialPaddingBottom + searchInitialPaddingTop;
+ var searchHeight = search.offsetHeight - searchPadding;
+ this.searchUseBottomPadding =
+ this.shouldSearchUseBottomPadding_(deviceMissing);
+ var searchFinalPaddingBottom, searchFinalPaddingTop;
+ [searchFinalPaddingBottom, searchFinalPaddingTop] =
+ this.getElementVerticalPadding_(search);
+ var searchFinalOffsetHeight =
+ searchHeight + searchFinalPaddingBottom + searchFinalPaddingTop;
+
+ // Omitting |search.offsetHeight| because it is handled by view animation
+ // separately.
+ var initialHeight =
+ hasList ? list.offsetHeight : deviceMissing.offsetHeight;
view.style['overflow'] = 'hidden';
- search.className = '';
- var finalHeight = this.computeTotalSearchHeight_(noMatches, results, search,
- this.sinkListMaxHeight_);
+ var resultsPadding = this.computeElementVerticalPadding_(results);
+ var finalHeight = this.computeTotalSearchHeight_(
+ deviceMissing, noMatches, results, searchFinalOffsetHeight,
+ this.sinkListMaxHeight_ + resultsPadding);
var duration =
this.computeAnimationDuration_(searchFinalTop - searchInitialTop);
+ var timing = {duration: duration, easing: 'ease-in-out', fill: 'forwards'};
// This GroupEffect will cause the sink list to fade out while the search
// input and search results list slide up. The dialog will also resize
// smoothly to the new search result list height.
+ var deviceMissingEffect = new KeyframeEffect(deviceMissing,
+ [{'marginBottom': searchInitialOffsetHeight},
+ {'marginBottom': searchFinalOffsetHeight}],
+ timing);
var listEffect = new KeyframeEffect(list,
[{'opacity': '1'}, {'opacity': '0'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ timing);
var resultsEffect = new KeyframeEffect(resultsContainer,
[{'top': '100%', 'paddingTop': '0px'},
{'top': searchFinalTop + 'px',
- 'paddingTop': search.offsetHeight + 'px'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ 'paddingTop': searchFinalOffsetHeight + 'px'}],
+ timing);
var searchEffect = new KeyframeEffect(search,
- [{'top': '100%', 'marginTop': '-' + searchOffsetHeight + 'px'},
- {'top': searchFinalTop + 'px', 'marginTop': '0px'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ [{'top': '100%', 'marginTop': '-' + searchInitialOffsetHeight + 'px',
+ 'paddingBottom': searchInitialPaddingBottom + 'px',
+ 'paddingTop': searchInitialPaddingTop + 'px'},
+ {'top': searchFinalTop + 'px', 'marginTop': '0px',
+ 'paddingBottom': searchFinalPaddingBottom + 'px',
+ 'paddingTop': searchFinalPaddingTop + 'px'}],
+ timing);
var viewEffect = new KeyframeEffect(view,
- [{'height': initialHeight + 'px'}, {'height': finalHeight + 'px'}],
- {duration: duration, easing: 'ease-in-out', fill: 'forwards'});
+ [{'height': initialHeight + 'px',
+ 'paddingBottom': searchInitialOffsetHeight + 'px'},
+ {'height': finalHeight + 'px', 'paddingBottom': '0px'}],
+ timing);
var player = document.timeline.play(new GroupEffect(hasList ?
[listEffect, resultsEffect, searchEffect, viewEffect] :
- [resultsEffect, searchEffect, viewEffect]));
+ [deviceMissingEffect, resultsEffect, searchEffect, viewEffect]));
var that = this;
var finalizeAnimation = function() {
@@ -1620,7 +1710,8 @@ Polymer({
var list = this.$$('#sink-list');
var resultsContainer = this.$$('#search-results-container');
var search = this.$['sink-search'];
- search.className = 'bottom';
+ var view = this.$['sink-list-view'];
+ this.searchUseBottomPadding = true;
search.style['top'] = '';
if (resultsContainer) {
resultsContainer.style['position'] = '';
@@ -1631,7 +1722,7 @@ Polymer({
var hasList = this.hasConditionalElement_(list);
if (hasList) {
search.style['margin-top'] = '-' + search.offsetHeight + 'px';
- list.style['padding-bottom'] = search.offsetHeight + 'px';
+ view.style['padding-bottom'] = search.offsetHeight + 'px';
list.style['opacity'] = '';
} else {
deviceMissing.style['margin-bottom'] = search.offsetHeight + 'px';
@@ -1665,8 +1756,9 @@ Polymer({
// If there is a height mismatch between where the animation calculated the
// height should be and where it is now because the search results changed
// during the animation, correct it with... another animation.
- var finalHeight = this.computeTotalSearchHeight_(noMatches, results, search,
- this.sinkListMaxHeight_);
+ var resultsPadding = this.computeElementVerticalPadding_(results);
+ var finalHeight = this.computeTotalSearchHeight_(deviceMissing, noMatches,
+ results, search.offsetHeight, this.sinkListMaxHeight_ + resultsPadding);
if (finalHeight != view.offsetHeight) {
var viewEffect = new KeyframeEffect(view,
[{'height': view.offsetHeight + 'px'},
@@ -1674,7 +1766,6 @@ Polymer({
{duration:
this.computeAnimationDuration_(finalHeight - view.offsetHeight),
easing: 'ease-in-out', fill: 'forwards'});
- var that = this;
var player = document.timeline.play(viewEffect);
if (this.heightAdjustmentPlayer_) {
this.heightAdjustmentPlayer_.cancel();
@@ -1686,6 +1777,7 @@ Polymer({
var hasList = this.hasConditionalElement_(list);
search.style['margin-top'] = '';
+ deviceMissing.style['margin-bottom'] = search.offsetHeight + 'px';
var searchFinalTop = hasList ? 0 : deviceMissing.offsetHeight;
var resultsPaddingTop = hasList ? search.offsetHeight + 'px' : '0px';
search.style['top'] = searchFinalTop + 'px';
@@ -1696,6 +1788,7 @@ Polymer({
resultsContainer.style['overflow-y'] = 'auto';
view.style['overflow'] = '';
+ view.style['padding-bottom'] = '';
if (this.filterTransitionPlayer_) {
this.filterTransitionPlayer_.cancel();
this.filterTransitionPlayer_ = null;
@@ -1966,6 +2059,16 @@ Polymer({
},
/**
+ * @param {?Element} deviceMissing Device missing message element.
+ * @return {boolean} Whether the search input should use vertical padding as
+ * if it were the lowest (at the very bottom) item in the dialog.
+ * @private
+ */
+ shouldSearchUseBottomPadding_: function(deviceMissing) {
+ return !deviceMissing.hasAttribute('hidden');
+ },
+
+ /**
* Shows the cast mode list.
*
* @private
@@ -2056,8 +2159,11 @@ Polymer({
showSinkList_: function() {
if (this.currentView_ == media_router.MediaRouterView.FILTER) {
this.queueMoveSearchToBottom_();
+ this.currentView_ = media_router.MediaRouterView.SINK_LIST;
+ } else {
+ this.currentView_ = media_router.MediaRouterView.SINK_LIST;
+ this.putSearchAtBottom_();
}
- this.currentView_ = media_router.MediaRouterView.SINK_LIST;
},
/**
@@ -2104,20 +2210,27 @@ Polymer({
var issueHeight = this.$$('#issue-banner') &&
this.$$('#issue-banner').style.display != 'none' ?
this.$$('#issue-banner').offsetHeight : 0;
- var searchHeight = this.$$('#sink-search').offsetHeight;
+ var search = this.$['sink-search'];
+ var searchHeight = search.offsetHeight;
this.$['container-header'].style.marginTop = firstRunFlowHeight + 'px';
this.$['content'].style.marginTop =
firstRunFlowHeight + headerHeight + 'px';
- this.sinkListMaxHeight_ = this.dialogHeight_ - headerHeight -
- firstRunFlowHeight - issueHeight - searchHeight;
var sinkList = this.$$('#sink-list');
+ var sinkListPadding =
+ sinkList ? this.computeElementVerticalPadding_(sinkList) : 0;
+ var searchPadding = this.computeElementVerticalPadding_(search);
+
+ var sinkListMaxHeight = this.dialogHeight_ - headerHeight -
+ firstRunFlowHeight - issueHeight - searchHeight + searchPadding -
+ sinkListPadding;
+ this.sinkListMaxHeight_ = sinkListMaxHeight;
if (sinkList) {
sinkList.style.maxHeight = this.sinkListMaxHeight_ + 'px';
var searchResults = this.$$('#search-results');
if (searchResults)
- searchResults.style.maxHeight = sinkList.style.maxHeight;
+ searchResults.style.maxHeight = this.sinkListMaxHeight_ + 'px';
}
});
},

Powered by Google App Engine
This is Rietveld 408576698