From 413e3c4e81c54147a57125a2b18aaa48c422afbb Mon Sep 17 00:00:00 2001 From: Tom Byers Date: Tue, 26 May 2020 09:58:41 +0100 Subject: [PATCH] Add scrollToRevealElement method to stickys API When an element is obscured by the sticky nav, this method allows you to scroll the page until it is revealled. The bulk of this code was added in: https://github.com/alphagov/notifications-admin/pull/2843 to ensure elements with focus were in view. This moves that into a public method so, as well as being called by the focus event handler, it can be called directly by other code. These changes include code that adds a 'sticky-scroll-area' class to scroll areas not explicitly marked as such in the base HTML but made to be a scroll area by the sticky JS. --- .../stick-to-window-when-scrolling.js | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/stick-to-window-when-scrolling.js b/app/assets/javascripts/stick-to-window-when-scrolling.js index c75779109..da1129742 100644 --- a/app/assets/javascripts/stick-to-window-when-scrolling.js +++ b/app/assets/javascripts/stick-to-window-when-scrolling.js @@ -10,7 +10,10 @@ var $el = el.$fixedEl; var $scrollArea = $el.closest('.sticky-scroll-area'); - $scrollArea = $scrollArea.length ? $scrollArea : $el.parent(); + if($scrollArea.length === 0) { + $scrollArea = $el.parent(); + $scrollArea.addClass('sticky-scroll-area'); + } this._els = [el]; this.edge = edge; @@ -46,11 +49,11 @@ return focused; }, - forCaret: function (evt) { - var textarea = evt.target; + forCaret: function ($textarea) { + var textarea = $textarea.get(0); var caretCoordinates = window.getCaretCoordinates(textarea, textarea.selectionEnd); var focused = { - 'top': $(textarea).offset().top + caretCoordinates.top, + 'top': $textarea.offset().top + caretCoordinates.top, 'height': caretCoordinates.height, 'type': 'caret' }; @@ -61,21 +64,23 @@ } }; ScrollArea.prototype.focusHandler = function (e) { - var $focusedElement = $(document.activeElement); - var nodeName = $focusedElement.get(0).nodeName.toLowerCase(); + this.scrollToRevealElement($(document.activeElement)); + }; + ScrollArea.prototype.scrollToRevealElement = function ($el) { + var nodeName = $el.get(0).nodeName.toLowerCase(); var endOfFurthestEl = focusOverlap.endOfFurthestEl(this._els, this.edge); var isInSticky = function () { - return $focusedElement.closest(this.selector).length > 0; + return $el.closest(this.selector).length > 0; }.bind(this); var focused; var overlap; // if textarea is focused, we care about checking the caret, not the whole element if (nodeName === 'textarea') { - focused = this.getFocusedDetails.forCaret(e); + focused = this.getFocusedDetails.forCaret($el); } else { if (isInSticky()) { return; } - focused = this.getFocusedDetails.forElement($focusedElement); + focused = this.getFocusedDetails.forElement($el); } overlap = focusOverlap.getOverlap(focused, this.edge, endOfFurthestEl); @@ -586,6 +591,18 @@ this.syncWithDOM(onSyncComplete); }; + // Public method to scroll so an element isn't covered by the sticky nav + Sticky.prototype.scrollToRevealElement = function (el) { + var $el = $(el); + var scrollAreaNode = $el.closest('.sticky-scroll-area').get(0); + var matches = $.grep(scrollAreas._scrollAreas, function (scrollArea) { + return scrollArea.node === scrollAreaNode; + }); + + if (matches.length) { + matches[0].scrollToRevealElement($el); + } + }; Sticky.prototype.setElWidth = function (el) { var $el = el.$fixedEl; var scrollArea = scrollAreas.getAreaByEl(el);