mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-11 10:28:41 -04:00
Merge pull request #2702 from alphagov/fix-bugs-with-sticky-overflow-code
Fix bugs with sticky overflow code
This commit is contained in:
@@ -140,7 +140,16 @@
|
|||||||
// Object collecting together methods for treating sticky elements as if they
|
// Object collecting together methods for treating sticky elements as if they
|
||||||
// were wrapped by a dialog component
|
// were wrapped by a dialog component
|
||||||
var dialog = {
|
var dialog = {
|
||||||
_hasResized: false,
|
hasResized: false,
|
||||||
|
// we add padding of 20px around each sticky to isolate it from the rest of the page
|
||||||
|
// it shouldn't apply between stickys when stacked
|
||||||
|
_getPaddingBetweenEls: function (els) {
|
||||||
|
var spaceBetween = 40;
|
||||||
|
|
||||||
|
if (els.length < 2) { return 0; }
|
||||||
|
|
||||||
|
return (els.length - 1) * spaceBetween;
|
||||||
|
},
|
||||||
_getTotalHeight: function (els) {
|
_getTotalHeight: function (els) {
|
||||||
var reducer = function (accumulator, currentValue) {
|
var reducer = function (accumulator, currentValue) {
|
||||||
return accumulator + currentValue;
|
return accumulator + currentValue;
|
||||||
@@ -152,6 +161,7 @@
|
|||||||
},
|
},
|
||||||
getOffsetFromEdge: function (el, sticky) {
|
getOffsetFromEdge: function (el, sticky) {
|
||||||
var els = this._elsThatCanBeStuck(sticky._els).slice();
|
var els = this._elsThatCanBeStuck(sticky._els).slice();
|
||||||
|
var elsBetween;
|
||||||
var elIdx;
|
var elIdx;
|
||||||
|
|
||||||
// els must be arranged furtherest from window edge is stuck to first
|
// els must be arranged furtherest from window edge is stuck to first
|
||||||
@@ -165,10 +175,12 @@
|
|||||||
// if next to window edge the dialog is stuck to, no offset
|
// if next to window edge the dialog is stuck to, no offset
|
||||||
if (elIdx === (els.length - 1)) { return 0; }
|
if (elIdx === (els.length - 1)) { return 0; }
|
||||||
|
|
||||||
|
// make els all those from this one to the window edge
|
||||||
|
els = els.slice(elIdx);
|
||||||
// get all els between this one and the window edge
|
// get all els between this one and the window edge
|
||||||
els = els.slice(elIdx + 1);
|
elsBetween = els.slice(1);
|
||||||
|
|
||||||
return this._getTotalHeight(els);
|
return this._getTotalHeight(elsBetween) - this._getPaddingBetweenEls(els);
|
||||||
},
|
},
|
||||||
getOffsetFromEnd: function (el, sticky) {
|
getOffsetFromEnd: function (el, sticky) {
|
||||||
var els = this._elsThatCanBeStuck(sticky._els).slice();
|
var els = this._elsThatCanBeStuck(sticky._els).slice();
|
||||||
@@ -218,10 +230,8 @@
|
|||||||
sticky.reset(currentEl);
|
sticky.reset(currentEl);
|
||||||
currentEl.canBeStuck(false);
|
currentEl.canBeStuck(false);
|
||||||
|
|
||||||
if (!sticky._hasResized) { sticky._hasResized = true; }
|
if (!self.hasResized) { self.hasResized = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._getTotalHeight(els);
|
|
||||||
},
|
},
|
||||||
getElementAtStickyEdge: function (sticky) {
|
getElementAtStickyEdge: function (sticky) {
|
||||||
var els = this._elsThatCanBeStuck(sticky._els);
|
var els = this._elsThatCanBeStuck(sticky._els);
|
||||||
@@ -251,7 +261,7 @@
|
|||||||
$(window).scrollTop(this.getInPageEdgePosition(sticky) - windowHeight);
|
$(window).scrollTop(this.getInPageEdgePosition(sticky) - windowHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
sticky._hasResized = false;
|
self.hasResized = false;
|
||||||
},
|
},
|
||||||
releaseEl: function (el, sticky) {
|
releaseEl: function (el, sticky) {
|
||||||
el.$fixedEl.css(sticky.edge, '');
|
el.$fixedEl.css(sticky.edge, '');
|
||||||
@@ -263,7 +273,7 @@
|
|||||||
var Sticky = function (selector) {
|
var Sticky = function (selector) {
|
||||||
this._hasScrolled = false;
|
this._hasScrolled = false;
|
||||||
this._scrollTimeout = false;
|
this._scrollTimeout = false;
|
||||||
this._hasResized = false;
|
this._windowHasResized = false;
|
||||||
this._resizeTimeout = false;
|
this._resizeTimeout = false;
|
||||||
this._elsLoaded = false;
|
this._elsLoaded = false;
|
||||||
this._initialPositionsSet = false;
|
this._initialPositionsSet = false;
|
||||||
@@ -272,6 +282,9 @@
|
|||||||
this.CSS_SELECTOR = selector;
|
this.CSS_SELECTOR = selector;
|
||||||
this.STOP_PADDING = 10;
|
this.STOP_PADDING = 10;
|
||||||
};
|
};
|
||||||
|
Sticky.prototype.setMode = function (mode) {
|
||||||
|
_mode = mode;
|
||||||
|
};
|
||||||
Sticky.prototype.getWindowDimensions = function () {
|
Sticky.prototype.getWindowDimensions = function () {
|
||||||
return {
|
return {
|
||||||
height: $(global).height(),
|
height: $(global).height(),
|
||||||
@@ -360,19 +373,19 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Recalculate stored dimensions for all sticky elements
|
// Recalculate stored dimensions for all sticky elements
|
||||||
Sticky.prototype.recalculate = function (opts) {
|
Sticky.prototype.recalculate = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
var onSyncComplete = function () {
|
var onSyncComplete = function () {
|
||||||
self.setEvents();
|
self.setEvents();
|
||||||
if (_mode === 'dialog') {
|
if (_mode === 'dialog') {
|
||||||
dialog.fitToHeight(self);
|
dialog.fitToHeight(self);
|
||||||
dialog.adjustForResize(self);
|
if (dialog.hasResized) {
|
||||||
|
dialog.adjustForResize(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.setElementPositions();
|
self.setElementPositions();
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((opts !== undefined) && ('mode' in opts)) { _mode = opts.mode; }
|
|
||||||
|
|
||||||
this.syncWithDOM(onSyncComplete);
|
this.syncWithDOM(onSyncComplete);
|
||||||
};
|
};
|
||||||
Sticky.prototype.setElWidth = function (el) {
|
Sticky.prototype.setElWidth = function (el) {
|
||||||
@@ -413,30 +426,38 @@
|
|||||||
Sticky.prototype.allElementsLoaded = function (totalEls) {
|
Sticky.prototype.allElementsLoaded = function (totalEls) {
|
||||||
return this._els.length === totalEls;
|
return this._els.length === totalEls;
|
||||||
};
|
};
|
||||||
Sticky.prototype.hasEl = function (node) {
|
Sticky.prototype.getElForNode = function (node) {
|
||||||
return !!$.grep(this._els, function (el) { return el.$fixedEl.is(node); }).length;
|
var matches = $.grep(this._els, function (el) { return el.$fixedEl.is(node); });
|
||||||
|
|
||||||
|
return !!matches.length ? matches[0] : false;
|
||||||
};
|
};
|
||||||
Sticky.prototype.add = function (el, setPositions, cb) {
|
Sticky.prototype.add = function (el, setPositions, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var $el = $(el);
|
var $el = $(el);
|
||||||
var onDimensionsSet;
|
var onDimensionsSet;
|
||||||
var elObj;
|
var elObj = this.getElForNode(el);
|
||||||
|
var exists = !!elObj;
|
||||||
// guard against adding elements already stored
|
|
||||||
if (this.hasEl(el)) { return; }
|
|
||||||
|
|
||||||
onDimensionsSet = function () {
|
onDimensionsSet = function () {
|
||||||
elObj.hasLoaded(true);
|
elObj.hasLoaded(true);
|
||||||
self._els.push(elObj);
|
|
||||||
|
// guard against adding elements already stored
|
||||||
|
if (!exists) {
|
||||||
|
self._els.push(elObj);
|
||||||
|
}
|
||||||
|
|
||||||
if (setPositions) {
|
if (setPositions) {
|
||||||
self.setElementPositions();
|
self.setElementPositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb !== undefined) {
|
if (cb !== undefined) {
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
elObj = new StickyElement($el, self);
|
if (!exists) {
|
||||||
|
elObj = new StickyElement($el, self);
|
||||||
|
}
|
||||||
|
|
||||||
self.setElementDimensions(elObj, onDimensionsSet);
|
self.setElementDimensions(elObj, onDimensionsSet);
|
||||||
};
|
};
|
||||||
@@ -485,8 +506,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Sticky.prototype.init = function (opts) {
|
Sticky.prototype.init = function () {
|
||||||
this.recalculate(opts);
|
this.recalculate();
|
||||||
};
|
};
|
||||||
Sticky.prototype.setEvents = function () {
|
Sticky.prototype.setEvents = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -511,7 +532,7 @@
|
|||||||
this._hasScrolled = true;
|
this._hasScrolled = true;
|
||||||
};
|
};
|
||||||
Sticky.prototype.onResize = function () {
|
Sticky.prototype.onResize = function () {
|
||||||
this._hasResized = true;
|
this._windowHasResized = true;
|
||||||
};
|
};
|
||||||
Sticky.prototype.checkScroll = function () {
|
Sticky.prototype.checkScroll = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -525,8 +546,8 @@
|
|||||||
var self = this,
|
var self = this,
|
||||||
windowWidth = self.getWindowDimensions().width;
|
windowWidth = self.getWindowDimensions().width;
|
||||||
|
|
||||||
if (self._hasResized === true) {
|
if (self._windowHasResized === true) {
|
||||||
self._hasResized = false;
|
self._windowHasResized = false;
|
||||||
|
|
||||||
$.each(self._els, function (i, el) {
|
$.each(self._els, function (i, el) {
|
||||||
if (!self.viewportIsWideEnough(windowWidth)) {
|
if (!self.viewportIsWideEnough(windowWidth)) {
|
||||||
@@ -539,7 +560,9 @@
|
|||||||
if (self.viewportIsWideEnough(windowWidth)) {
|
if (self.viewportIsWideEnough(windowWidth)) {
|
||||||
if (_mode === 'dialog') {
|
if (_mode === 'dialog') {
|
||||||
dialog.fitToHeight(self);
|
dialog.fitToHeight(self);
|
||||||
dialog.adjustForResize(self);
|
if (dialog.hasResized) {
|
||||||
|
dialog.adjustForResize(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.setElementPositions();
|
self.setElementPositions();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,14 +139,20 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.render = function() {
|
this.render = function() {
|
||||||
|
var mode = 'default';
|
||||||
|
|
||||||
// detach everything, unless they are the currentState
|
// detach everything, unless they are the currentState
|
||||||
this.states.forEach(
|
this.states.forEach(
|
||||||
state => (state.key === this.currentState ? this.$stickyBottom.append(state.$el) : state.$el.detach())
|
state => (state.key === this.currentState ? this.$stickyBottom.append(state.$el) : state.$el.detach())
|
||||||
);
|
);
|
||||||
|
|
||||||
// make sticky JS recalculate its cache of the element's position
|
|
||||||
// use dialog mode for states which contain more than one form control
|
// use dialog mode for states which contain more than one form control
|
||||||
GOVUK.stickAtBottomWhenScrolling.recalculate({ 'mode': 'dialog' });
|
if (['move-to-existing-folder', 'add-new-template'].includes(this.currentState)) {
|
||||||
|
mode = 'dialog';
|
||||||
|
}
|
||||||
|
GOVUK.stickAtBottomWhenScrolling.setMode(mode);
|
||||||
|
// make sticky JS recalculate its cache of the element's position
|
||||||
|
GOVUK.stickAtBottomWhenScrolling.recalculate();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.nothingSelectedButtons = $(`
|
this.nothingSelectedButtons = $(`
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
padding: $vertical-padding 0 $vertical-padding $gutter-half;
|
padding: $vertical-padding 0 $vertical-padding $gutter-half;
|
||||||
margin-top: -$vertical-padding;
|
margin-top: -$vertical-padding;
|
||||||
|
|
||||||
|
& + .js-stick-at-bottom-when-scrolling {
|
||||||
|
margin-top: ($vertical-padding * 2) * -1;
|
||||||
|
}
|
||||||
|
|
||||||
.page-footer {
|
.page-footer {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
|
|||||||
Reference in New Issue
Block a user