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 class="errorMoreInfo">[[_lastError.moreInfo]]</div>
</div> </div>
</main> </main>
<gr-fixed-panel <gr-fixed-panel id="footer">
ready-for-measure="false">
<footer r="contentinfo"> <footer r="contentinfo">
<div> <div>
Powered by <a href="https://www.gerritcodereview.com/" rel="noopener" Powered by <a href="https://www.gerritcodereview.com/" rel="noopener"

View File

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

View File

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

View File

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

View File

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