diff --git a/app/assets/javascripts/modules/global-bar.js b/app/assets/javascripts/modules/global-bar.js new file mode 100644 index 000000000..5161afc3d --- /dev/null +++ b/app/assets/javascripts/modules/global-bar.js @@ -0,0 +1,58 @@ +/* + Global bar + + Manages count of how many times a global bar has been seen + using cookies. +*/ +(function(Modules) { + "use strict"; + + Modules.GlobalBar = function() { + this.start = function($el) { + var GLOBAL_BAR_SEEN_COOKIE = "global_bar_seen", + count = viewCount(); + + $el.on('click', '.dismiss', hide); + + if ($el.is(':visible')) { + incrementViewCount(count); + track('Viewed'); + } + + function hide(evt) { + $el.hide(); + GOVUK.setCookie(GLOBAL_BAR_SEEN_COOKIE, 999, {days: 84}); + track('Manually dismissed'); + $('html').removeClass('show-global-bar'); + evt.preventDefault(); + } + + function incrementViewCount(count) { + count = count + 1; + GOVUK.setCookie(GLOBAL_BAR_SEEN_COOKIE, count, {days: 84}); + + if (count == 2) { + track('Automatically dismissed'); + } + } + + function viewCount() { + var viewCountCookie = GOVUK.getCookie(GLOBAL_BAR_SEEN_COOKIE), + viewCount = parseInt(viewCountCookie, 10); + + if (isNaN(viewCount)) { + viewCount = 0; + } + + return viewCount; + } + + function track(action) { + if (GOVUK.analytics && typeof GOVUK.analytics.trackEvent === "function") { + GOVUK.analytics.trackEvent('Global bar', action, {nonInteraction: 1}); + } + } + }; + }; + +})(window.GOVUK.Modules); diff --git a/app/assets/javascripts/start-modules.js b/app/assets/javascripts/start-modules.js index e84262083..7a7f499d9 100644 --- a/app/assets/javascripts/start-modules.js +++ b/app/assets/javascripts/start-modules.js @@ -1,4 +1,5 @@ // = require govuk/modules +// = require modules/global-bar // = require modules/sticky-element-container // = require modules/toggle // = require modules/track-click diff --git a/app/assets/javascripts/surveys.js b/app/assets/javascripts/surveys.js index 674c69d8b..bca06e06f 100644 --- a/app/assets/javascripts/surveys.js +++ b/app/assets/javascripts/surveys.js @@ -158,6 +158,7 @@ if (userSurveys.canShowAnySurvey()) { var activeSurvey = userSurveys.getActiveSurvey(userSurveys.defaultSurvey, userSurveys.smallSurveys) if (activeSurvey !== undefined) { + $('#global-bar').hide(); // Hide global bar if one is showing userSurveys.displaySurvey(activeSurvey) } } diff --git a/app/assets/stylesheets/helpers/_header.scss b/app/assets/stylesheets/helpers/_header.scss index 508ad60ff..80c987c9f 100644 --- a/app/assets/stylesheets/helpers/_header.scss +++ b/app/assets/stylesheets/helpers/_header.scss @@ -341,3 +341,48 @@ margin-right: .5em; } } + + +.show-global-bar #global-header-bar { + display: none; +} + +.global-bar { + background-color: #BFE3E0; + display: none; + margin-bottom: 15px; + padding: 15px 0; + + .show-global-bar & { + display: block; + } + + .global-bar-message-container { + @include core-19; + @extend %site-width-container; + position: relative; + + @include media(tablet) { + .dismiss { + position: absolute; + right: 0; + top: 0; + } + } + } + + .global-bar-message { + margin-bottom: 0; + margin-top: 0; + + @include media(tablet) { + max-width: 66.67%; + } + + .global-bar-title { + display: block; + font-weight: 700; + margin-right: 10px; + } + } +} diff --git a/app/views/notifications/_global_bar.html.erb b/app/views/notifications/_global_bar.html.erb new file mode 100644 index 000000000..989cc3207 --- /dev/null +++ b/app/views/notifications/_global_bar.html.erb @@ -0,0 +1,29 @@ +<% + show_global_bar ||= false # Toggles the appearance of the global bar + title = "The title" + information = "Some information about something" + link_href = "https://www.gov.uk/" + link_text = %Q(More information about this).html_safe +-%> +<% if show_global_bar %> + <% content_for :head do %> + + + + <% end %> + +
+
+

+ <%= title %> + <%= information %> + <%= link_to(link_text, link_href, rel: "external noreferrer") %> +

+ Hide message +
+
+ +<% end %> diff --git a/app/views/root/_base.html.erb b/app/views/root/_base.html.erb index ea50754ad..9f1be6750 100644 --- a/app/views/root/_base.html.erb +++ b/app/views/root/_base.html.erb @@ -30,6 +30,8 @@ <% end %> <% content_for :content do %> + <%= render "notifications/global_bar" %> +
<%= yield :wrapper_content %>
diff --git a/doc/global-banner.md b/doc/global-banner.md new file mode 100644 index 000000000..2ea979fd0 --- /dev/null +++ b/doc/global-banner.md @@ -0,0 +1,16 @@ +## Global banner + +A site-wide banner can be activated to convey important information on GOV.UK which is not deemed emergency level information. +The file `app/views/notifications/_global_bar.html.erb` contains the necessary minified JS and markup to activate and render the banner. + +### Activating the global banner + +In `app/views/notifications/_global_bar.html.erb` + +1. Update the variables `title`, `information`, `link_href` and `link_text` with the relevant info. +2. Update the `show_global_bar` variable to `true` +3. Deploy static + +The usual rules apply with static template caching. + +![screenshot](/doc/global-banner.png?raw=true) diff --git a/doc/global-banner.png b/doc/global-banner.png new file mode 100644 index 000000000..e3a38b987 Binary files /dev/null and b/doc/global-banner.png differ diff --git a/spec/javascripts/global-bar-class-toggle.spec.js b/spec/javascripts/global-bar-class-toggle.spec.js new file mode 100644 index 000000000..7dbe76132 --- /dev/null +++ b/spec/javascripts/global-bar-class-toggle.spec.js @@ -0,0 +1,133 @@ +describe("toggling a global bar HTML class based on cookie", function () { + var root = window; + + /** + * The global bar needs to be activated early in page loading to prevent + * a flash of unstyled content, to do this we need to minify and inline + * the activation logic into the page head. + * This spec runs tests against both the full and minified sources of the + * activation JS because minification is not automated. + */ + function globalBarSource(fakeWindow) { + var window = fakeWindow || root; + + /* begin minify */ + + (function (document) { + "use strict" + var documentElement = document.documentElement; + if (urlPermitsShow() && viewCountPermitsShow()) { + documentElement.className = documentElement.className.concat(' show-global-bar'); + } + + function urlPermitsShow() { + return !/^\/register-to-vote|^\/done/.test(window.location.pathname); + } + + function viewCountPermitsShow() { + var c = document.cookie.match('(?:^|[ ;])global_bar_seen=([0-9]+)'); + if (!c) { + return true; + } + + return parseInt(c.pop(), 10) < 3; + } + })(document); + + /* end minify */ + } + + + /** + * This is the minified version of the function above 'globalBarSource', + * when developing and testing updates and features, + * changes should be mirrored here manually. + * Only the code between the 'begin/end minify' comments should be copied. + */ + function globalBarMinified(fakeWindow) { + var window = fakeWindow || root; + + /* begin minify */ + !function(t){"use strict";function e(){return!/^\/register-to-vote|^\/done/.test(window.location.pathname)}function n(){var e=t.cookie.match("(?:^|[ ;])global_bar_seen=([0-9]+)");return e?parseInt(e.pop(),10)<3:!0}var o=t.documentElement;e()&&n()&&(o.className=o.className.concat(" show-global-bar"))}(document); + /* end minify */ + } + + afterEach(function() { + $('html').removeClass('show-global-bar'); + deleteAllCookies(); + + function deleteAllCookies() { + var cookies = document.cookie.split(";"); + + for (var i = 0; i < cookies.length; i++) { + var cookie = cookies[i]; + var eqPos = cookie.indexOf("="); + var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; + document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"; + } + } + }); + + describe('when running the full source', function() { + runTests(globalBarSource); + }); + + describe('when running the minified source', function() { + runTests(globalBarMinified); + }); + + function runTests(globalBarFn) { + it("shows when no cookie is set", function() { + expectGlobalBarToBeHidden(); + globalBarFn(); + expectGlobalBarToShow(); + }); + + it("does not show when bar has been seen 3 times", function() { + GOVUK.setCookie('global_bar_seen', 3); + expectGlobalBarToBeHidden(); + globalBarFn(); + expectGlobalBarToBeHidden(); + }); + + it("shows when the bar has been seen 2 times", function() { + GOVUK.setCookie('global_bar_seen', '2'); + globalBarFn(); + expectGlobalBarToShow(); + }); + + it("shows when the bar has been seen 2 times and there are lots of cookies", function() { + GOVUK.setCookie('global_bar_thing', '10'); + GOVUK.setCookie('seen_cookie_message', 'true'); + GOVUK.setCookie('global_bar_seen', '2'); + GOVUK.setCookie('is_global_bar_seen', '8'); + GOVUK.setCookie('_ua', '1234873487'); + globalBarFn(); + expectGlobalBarToShow(); + }); + + it("shows when the cookie value is not a parseable number", function() { + GOVUK.setCookie('global_bar_seen', 'foo_bar2'); + globalBarFn(); + expectGlobalBarToShow(); + }); + + it("does not show on register to vote pages", function() { + globalBarFn({location: {pathname: '/register-to-vote'}}); + expectGlobalBarToBeHidden(); + }); + + it("does not show on done pages", function() { + globalBarFn({location: {pathname: '/done'}}); + expectGlobalBarToBeHidden(); + }); + } + + function expectGlobalBarToShow() { + expect($('html').is('.show-global-bar')).toBe(true); + } + + function expectGlobalBarToBeHidden() { + expect($('html').is('.show-global-bar')).toBe(false); + } +});