diff --git a/app/assets/javascripts/modules/sticky-element-container.js b/app/assets/javascripts/modules/sticky-element-container.js new file mode 100644 index 000000000..970c7fdc5 --- /dev/null +++ b/app/assets/javascripts/modules/sticky-element-container.js @@ -0,0 +1,117 @@ +/* + This module will cause a child in the target element to: + - hide when the top of the target element is visible; + - stick to the bottom of the window while the parent element is in view; + - stick to the bottom of the target when the user scrolls past the bottom. + + Use 'data-module="sticky-element-container"' to instantiate, and add + `[data-sticky-element]` to the child you want to position. +*/ +(function (Modules, root) { + 'use strict' + + var $ = root.$ + var $window = $(root) + + Modules.StickyElementContainer = function () { + var self = this + + self._getWindowDimensions = function _getWindowDimensions () { + return { + height: $window.height(), + width: $window.width() + } + } + + self._getWindowPositions = function _getWindowPositions () { + return { + scrollTop: $window.scrollTop() + } + } + + self.start = function start ($el) { + var $element = $el.find('[data-sticky-element]') + var _hasResized = true + var _hasScrolled = true + var _interval = 50 + var _windowVerticalPosition = 1 + var _startPosition, _stopPosition + + initialise() + + function initialise () { + $window.resize(onResize) + $window.scroll(onScroll) + setInterval(checkResize, _interval) + setInterval(checkScroll, _interval) + checkResize() + checkScroll() + $element.addClass('sticky-element--enabled') + } + + function onResize () { + _hasResized = true + } + + function onScroll () { + _hasScrolled = true + } + + function checkResize () { + if (_hasResized) { + _hasResized = false + _hasScrolled = true + + var windowDimensions = self._getWindowDimensions() + _startPosition = $el.offset().top + _stopPosition = $el.offset().top + $el.height() - windowDimensions.height + } + } + + function checkScroll () { + if (_hasScrolled) { + _hasScrolled = false + + _windowVerticalPosition = self._getWindowPositions().scrollTop + + updateVisibility() + updatePosition() + } + } + + function updateVisibility () { + var isPastStart = _startPosition < _windowVerticalPosition + if (isPastStart) { + show() + } else { + hide() + } + } + + function updatePosition () { + var isPastEnd = _stopPosition < _windowVerticalPosition + if (isPastEnd) { + stickToParent() + } else { + stickToWindow() + } + } + + function stickToWindow () { + $element.addClass('sticky-element--stuck-to-window') + } + + function stickToParent () { + $element.removeClass('sticky-element--stuck-to-window') + } + + function show () { + $element.removeClass('sticky-element--hidden') + } + + function hide () { + $element.addClass('sticky-element--hidden') + } + } + } +})(window.GOVUK.Modules, window) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 991a10aaf..061e71397 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -54,9 +54,10 @@ $govuk-use-legacy-palette: false; @import 'helpers/organisation-logos'; @import 'helpers/parts'; @import 'helpers/add-title-margin'; -@import "helpers/content-bottom-margin"; -@import "helpers/publisher-metadata-with-logo"; -@import "helpers/attachments"; +@import 'helpers/content-bottom-margin'; +@import 'helpers/publisher-metadata-with-logo'; +@import 'helpers/attachments'; +@import 'helpers/sticky-element-container'; // Components from this application @import 'components/*'; diff --git a/app/assets/stylesheets/components/_contents-list-with-body.scss b/app/assets/stylesheets/components/_contents-list-with-body.scss index 41b56f702..de7459f8d 100644 --- a/app/assets/stylesheets/components/_contents-list-with-body.scss +++ b/app/assets/stylesheets/components/_contents-list-with-body.scss @@ -20,7 +20,7 @@ } } -.app-c-contents-list-with-body__link-wrapper.govuk-sticky-element--stuck-to-window { +.app-c-contents-list-with-body__link-wrapper.sticky-element--stuck-to-window { background-color: govuk-colour("light-grey", $legacy: "grey-3"); bottom: -1px; // 'Fix' for anomalous 1px margin which sporadically appears below this element. left: 0; diff --git a/app/assets/stylesheets/helpers/_sticky-element-container.scss b/app/assets/stylesheets/helpers/_sticky-element-container.scss new file mode 100644 index 000000000..5e9f47d85 --- /dev/null +++ b/app/assets/stylesheets/helpers/_sticky-element-container.scss @@ -0,0 +1,23 @@ +.js-enabled .sticky-element { + position: absolute; + bottom: 0; + + &--stuck-to-window { + bottom: 0; + position: fixed; + } + + &--enabled { + transition: opacity, .3s, ease; + opacity: 1; + + @include govuk-media-query($until: tablet) { + position: static; + } + } + + &--hidden { + opacity: 0; + pointer-events: none; + } +} diff --git a/app/assets/stylesheets/views/_html-publication.scss b/app/assets/stylesheets/views/_html-publication.scss index 5b2dd8133..e7390bcbb 100644 --- a/app/assets/stylesheets/views/_html-publication.scss +++ b/app/assets/stylesheets/views/_html-publication.scss @@ -54,14 +54,14 @@ display: none; } - .govuk-sticky-element { - .govuk-sticky-element__print-link { + .sticky-element { + .sticky-element__print-link { margin-left: govuk-spacing(3); } } @include govuk-media-query($until: desktop) { - .govuk-sticky-element--enabled { + .sticky-element--enabled { position: static; } } diff --git a/app/presenters/content_item/brexit_notice.rb b/app/presenters/content_item/brexit_notice.rb index d68284d7d..7df23282d 100644 --- a/app/presenters/content_item/brexit_notice.rb +++ b/app/presenters/content_item/brexit_notice.rb @@ -36,7 +36,7 @@ def brexit_notice_link_intro def brexit_landing_page_cta data_attributes = { - "module": "track-click", + "module": "gem-track-click", "track-category": "no_deal_notice", "track-action": "/transition", "track-label": "Get your personalised list of actions", @@ -56,7 +56,7 @@ def brexit_links title: link["title"], href: link["href"], data_attributes: { - "module": "track-click", + "module": "gem-track-click", "track-category": "no_deal_notice", "track-action": link["href"], "track-label": link["title"], diff --git a/app/views/components/_important-metadata.html.erb b/app/views/components/_important-metadata.html.erb index 21cea1c57..ca50428ba 100644 --- a/app/views/components/_important-metadata.html.erb +++ b/app/views/components/_important-metadata.html.erb @@ -10,7 +10,7 @@ <% if title %>

<%= sanitize title %>

<% end %> -
+
<% items.each do |title, definition| %> diff --git a/app/views/components/_published-dates.html.erb b/app/views/components/_published-dates.html.erb index 7ae6a26b4..63257d8e7 100644 --- a/app/views/components/_published-dates.html.erb +++ b/app/views/components/_published-dates.html.erb @@ -7,7 +7,7 @@ history_class = "app-c-published-dates--history" if history.any? %> <% if published || last_updated %> -
id="history" data-module="toggle"<% end %> lang="en"> +
id="history" data-module="gem-toggle"<% end %> lang="en"> <% if published %> Published <%= published %> <% end %> diff --git a/app/views/components/_publisher-metadata.html.erb b/app/views/components/_publisher-metadata.html.erb index 4a19bf4d1..826d5b443 100644 --- a/app/views/components/_publisher-metadata.html.erb +++ b/app/views/components/_publisher-metadata.html.erb @@ -11,7 +11,7 @@ <%= render 'components/published-dates', published: published, last_updated: last_updated, link_to_history: link_to_history %> <% if other_has_values %>