Large number of gr-fixed-panel bugfixes:

* recalculate position and header dimensions on header contents change
* recalculate footer position on view change
* use min-height instead of height for floating header placeholder for
  correct dimensions calculation
* drop unnecessary contentWrapper
* float panel only if there's horizontal scrolling

Bug: Issue 6382
Change-Id: I2bac228578071273b9dce37e6b41e7b6602db841
This commit is contained in:
Viktar Donich
2017-05-31 17:33:52 -07:00
parent 4d28854369
commit 77e0f8c0e7
5 changed files with 60 additions and 47 deletions

View File

@@ -156,8 +156,7 @@ limitations under the License.
<div class="errorMoreInfo">[[_lastError.moreInfo]]</div>
</div>
</main>
<gr-fixed-panel
ready-for-measure="false">
<gr-fixed-panel id="footer">
<footer r="contentinfo">
<div>
Powered by <a href="https://www.gerritcodereview.com/" rel="noopener"

View File

@@ -134,6 +134,7 @@
if (this.params.justRegistered) {
this.$.registration.open();
}
this.$.footer.update();
},
_loginTapHandler(e) {

View File

@@ -21,12 +21,13 @@ limitations under the License.
<style>
:host {
display: block;
height: var(--header-height);
min-height: var(--header-height);
position: relative;
}
header {
background: inherit;
border: inherit;
display: inline;
height: inherit;
}
.floating {
@@ -37,9 +38,7 @@ limitations under the License.
}
</style>
<header id="header" class$="[[_computeHeaderClass(_headerFloating)]]">
<div class="contentWrapper">
<content></content>
</div>
<content></content>
</header>
</template>
<script src="gr-fixed-panel.js"></script>

View File

@@ -20,7 +20,7 @@
properties: {
readyForMeasure: {
type: Boolean,
observer: '_maybeFloatHeader',
observer: '_readyForMeasureObserver',
},
keepOnScroll: {
type: Boolean,
@@ -37,22 +37,34 @@
type: Boolean,
value: false,
},
_observer: {
type: Object,
value: null,
},
_webComponentsReady: Boolean,
},
attached() {
// Enable content measure unless blocked by param.
this.async(() => {
if (this.readyForMeasure !== false) {
this.readyForMeasure = true;
}
}, 1);
this.listen(window, 'scroll', '_handleScroll');
this.listen(window, 'resize', '_handleResize');
if (this.readyForMeasure !== false) {
this.readyForMeasure = true;
}
this.listen(window, 'resize', 'update');
this.listen(window, 'scroll', '_updateOnScroll');
this._observer = new MutationObserver(this.update.bind(this));
this._observer.observe(this.$.header, {childList: true, subtree: true});
},
detached() {
this.unlisten(window, 'scroll', '_handleScroll');
this.unlisten(window, 'resize', '_handleResize');
this.unlisten(window, 'scroll', '_updateOnScroll');
this.unlisten(window, 'resize', 'update');
this._observer.disconnect();
},
_readyForMeasureObserver(readyForMeasure) {
if (readyForMeasure) {
this.update();
}
},
_computeHeaderClass(headerFloating) {
@@ -63,19 +75,25 @@
return window.scrollY;
},
_handleResize() {
this.debounce('resize', () => {
this._maybeFloatHeader();
this._handleScrollDebounced();
update() {
this.debounce('update', () => {
this._updateDebounced();
}, 100);
},
_handleScroll() {
this._maybeFloatHeader();
this.debounce('scroll', this._handleScrollDebounced);
_updateOnScroll() {
this.debounce('update', () => {
this._updateDebounced();
});
},
_handleScrollDebounced() {
_updateDebounced() {
this._isMeasured = false;
this._maybeFloatHeader();
this._reposition();
},
_reposition() {
if (!this._headerFloating) {
return;
}
@@ -114,38 +132,39 @@
if (rect.height === 0 && rect.width === 0) {
return; // Not ready for measurement yet.
}
const isVisible = (rect.top >= 0) && (rect.bottom <= window.innerHeight);
if (!isVisible) {
return;
}
const top = document.body.scrollTop + rect.top;
this._topInitial = top;
this._topLast = top;
this._headerHeight = rect.height;
this._topInitial =
this.getBoundingClientRect().top + document.body.scrollTop;
this._isMeasured = true;
},
_isFloatingNeeded() {
return this.keepOnScroll ||
document.body.scrollWidth > document.body.clientWidth;
},
_maybeFloatHeader() {
if (!this.readyForMeasure) {
if (!this._isFloatingNeeded()) {
return;
}
this._measure();
if (!this._headerFloating && this._isMeasured) {
if (this._isMeasured) {
this._floatHeader();
}
},
_unfloatHeader() {
this.customStyle['--header-height'] = '';
this._headerFloating = false;
this.customStyle['--header-height'] = '';
this.updateStyles();
},
_floatHeader() {
const rect = this.$.header.getBoundingClientRect();
this._headerHeight = rect.height;
this.customStyle['--header-height'] = rect.height + 'px';
this._headerFloating = true;
this.customStyle['--header-height'] = this._headerHeight + 'px';
this.updateStyles();
this._headerFloating = true;
},
});
})();

View File

@@ -52,20 +52,21 @@ limitations under the License.
assert.equal(element.getBoundingClientRect().height, 100);
});
test('scroll triggers _handleScroll', () => {
sandbox.stub(element, '_handleScroll');
test('scroll triggers _reposition', () => {
sandbox.stub(element, '_reposition');
window.dispatchEvent(new CustomEvent('scroll'));
assert.isTrue(element._handleScroll.called);
element.flushDebouncer('update');
assert.isTrue(element._reposition.called);
});
suite('_handleScroll', () => {
suite('_reposition', () => {
const getHeaderTop = function() {
return element.$.header.style.top;
};
const emulateScrollY = function(distance) {
element._getScrollY.returns(distance);
element._handleScroll();
element._updateDebounced();
element.flushDebouncer('scroll');
};
@@ -74,12 +75,6 @@ limitations under the License.
sandbox.stub(element, '_getScrollY').returns(0);
});
test('is debounced', () => {
sandbox.stub(element, 'debounce');
element._handleScroll();
assert.isTrue(element.debounce.called);
});
test('scrolls header along with document', () => {
emulateScrollY(20);
assert.equal(getHeaderTop(), '-12px');