Skip to content

Commit

Permalink
Merge pull request #5 from hmrc/JRSC-3
Browse files Browse the repository at this point in the history
Scaffold init
  • Loading branch information
jordanrowe authored Apr 10, 2020
2 parents 791eceb + ec998f7 commit 30fbe43
Show file tree
Hide file tree
Showing 147 changed files with 6,772 additions and 451 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,3 @@
# coronavirus-jrs-calculator-frontend

This is a placeholder README.md for a new repository

### License

This code is open source software licensed under the [Apache 2.0 License]("http://www.apache.org/licenses/LICENSE-2.0.html").
54 changes: 54 additions & 0 deletions app/assets/javascripts/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
$(document).ready(function() {

// =====================================================
// Handle number inputs
// =====================================================
numberInputs();

// =====================================================
// Back link mimics browser back functionality
// =====================================================

// prevent resubmit warning
if (window.history && window.history.replaceState && typeof window.history.replaceState === 'function') {
window.history.replaceState(null, null, window.location.href);
}
// back click handle, dependent upon presence of referrer & no host change
$('#back-link[href="#"]').on('click', function(e){
e.preventDefault();
window.history.back();
});

});

function numberInputs() {
// =====================================================
// Set currency fields to number inputs on touch devices
// this ensures on-screen keyboards display the correct style
// don't do this for FF as it has issues with trailing zeroes
// =====================================================
if($('html.touchevents').length > 0 && window.navigator.userAgent.indexOf("Firefox") == -1){
$('[data-type="currency"] > input[type="text"], [data-type="percentage"] > input[type="text"]').each(function(){
$(this).attr('type', 'number');
$(this).attr('step', 'any');
$(this).attr('min', '0');
});
}

// =====================================================
// Disable mouse wheel and arrow keys (38,40) for number inputs to prevent mis-entry
// also disable commas (188) as they will silently invalidate entry on Safari 10.0.3 and IE11
// =====================================================
$("form").on("focus", "input[type=number]", function(e) {
$(this).on('wheel', function(e) {
e.preventDefault();
});
});
$("form").on("blur", "input[type=number]", function(e) {
$(this).off('wheel');
});
$("form").on("keydown", "input[type=number]", function(e) {
if ( e.which == 38 || e.which == 40 || e.which == 188 )
e.preventDefault();
});
}
2 changes: 2 additions & 0 deletions app/assets/javascripts/jquery.min.js

Large diffs are not rendered by default.

289 changes: 289 additions & 0 deletions app/assets/javascripts/timeoutDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
/**
* TAKEN FROM ASSETS_FRONTEND as currentlly not supported in GDS Design System
* https://github.com/hmrc/assets-frontend/tree/master/assets/patterns/help-users-when-we-time-them-out-of-a-service
* */

function displayDialog(elementToDisplay) {
var $dialog = $('<div id="timeout-dialog" tabindex="-1" role="dialog" class="timeout-dialog">')
.append(elementToDisplay)
var $overlay = $('<div id="timeout-overlay" class="timeout-overlay">')
var resetElementsFunctionList = []
var closeCallbacks = []

if (!$('html').hasClass('noScroll')) {
$('html').addClass('noScroll')
resetElementsFunctionList.push(function () {
$('html').removeClass('noScroll')
})
}
$('body').append($dialog).append($overlay)

resetElementsFunctionList.push(function () {
$dialog.remove()
$overlay.remove()
})

// disable the non-dialog page to prevent confusion for VoiceOver users
$('#skiplink-container, body>header, #global-cookie-message, body>main, body>footer').each(function () {
var value = $(this).attr('aria-hidden')
var $elem = $(this)
resetElementsFunctionList.push(function () {
if (value) {
$elem.attr('aria-hidden', value)
} else {
$elem.removeAttr('aria-hidden')
}
})
}).attr('aria-hidden', 'true')

setupFocusHandlerAndFocusDialog()
setupKeydownHandler()
preventMobileScrollWhileAllowingPinchZoom()

function close() {
while (resetElementsFunctionList.length > 0) {
var fn = resetElementsFunctionList.shift()
fn()
}
}

function closeAndInform() {
$.each(closeCallbacks, function () {
var fn = this
fn()
})
close()
}

function setupFocusHandlerAndFocusDialog() {
function keepFocus(event) {
var modalFocus = document.getElementById('timeout-dialog')
if (modalFocus) {
if (event.target !== modalFocus && !modalFocus.contains(event.target)) {
event.stopPropagation()
modalFocus.focus()
}
}
}

var elemToFocusOnReset = document.activeElement
$dialog.focus()

$(document).on('focus', '*', keepFocus)

resetElementsFunctionList.push(function () {
$(document).off('focus', '*', keepFocus)
$(elemToFocusOnReset).focus()
})
}

function setupKeydownHandler() {
function keydownListener(e) {
if (e.keyCode === 27) {
closeAndInform()
}
}

$(document).on('keydown', keydownListener)

resetElementsFunctionList.push(function () {
$(document).off('keydown', keydownListener)
})
}

function preventMobileScrollWhileAllowingPinchZoom() {
function handleTouch(e) {
var touches = e.originalEvent.touches || e.originalEvent.changedTouches || []

if (touches.length === 1) {
e.preventDefault()
}
}

$(document).on('touchmove', handleTouch)

resetElementsFunctionList.push(function () {
$(document).off('touchmove', handleTouch)
})
}

function createSetterFunctionForAttributeOfDialog(attributeName) {
return function (value) {
if (value) {
$dialog.attr(attributeName, value)
} else {
$dialog.removeAttr(attributeName)
}
}
}

return {
closeDialog: function () {
close()
},
setAriaLive: createSetterFunctionForAttributeOfDialog('aria-live'),
setAriaLabelledBy: createSetterFunctionForAttributeOfDialog('aria-labelledby'),
addCloseHandler: function (closeHandler) {
closeCallbacks.push(closeHandler)
}
}
}

function timeoutDialog(options) {

validateInput(options)

var cleanupFunctions = []
var localisedDefaults = readCookie('PLAY_LANG') && readCookie('PLAY_LANG') === 'cy' && {
title: undefined,
message: 'Er eich diogelwch, byddwn yn eich allgofnodi cyn pen',
keepAliveButtonText: 'Parhau i fod wedi’ch mewngofnodi',
signOutButtonText: 'Allgofnodi',
properties: {
minutes: 'funud',
minute: 'funud',
seconds: 'eiliad',
second: 'eiliad'
}
} || {
title: undefined,
message: 'For your security, we will sign you out in',
keepAliveButtonText: 'Stay signed in',
signOutButtonText: 'Sign out',
properties: {
minutes: 'minutes',
minute: 'minute',
seconds: 'seconds',
second: 'second'
}
}

var settings = mergeOptionsWithDefaults(options, localisedDefaults)

setupDialogTimer()

function validateInput(config) {
var requiredConfig = ['timeout', 'countdown', 'keepAliveUrl', 'signOutUrl']
var missingRequiredConfig = []

$.each(requiredConfig, function () {
if (!config.hasOwnProperty(this)) {
missingRequiredConfig.push(this)
}
})

if (missingRequiredConfig.length > 0) {
throw new Error('Missing config item(s): [' + missingRequiredConfig.join(', ') + ']')
}
}

function mergeOptionsWithDefaults(options, localisedDefaults) {
return $.extend({}, localisedDefaults, options)
}

function setupDialogTimer() {
settings.signout_time = getDateNow() + settings.timeout * 1000

var timeout = window.setTimeout(function () {
setupDialog()
}, ((settings.timeout) - (settings.countdown)) * 1000)

cleanupFunctions.push(function () {
window.clearTimeout(timeout)
})
}

function setupDialog() {
var $countdownElement = $('<span id="timeout-countdown" class="countdown">');
var $element = $('<div>')
.append(settings.title ? $('<h1 class="govuk-heading-m push--top">').text(settings.title) : '')
.append($('<p class="govuk-body" id="timeout-message" role="text">').text(settings.message + ' ')
.append($countdownElement)
.append('.'))
.append($('<button id="timeout-keep-signin-btn" class="govuk-button govuk-!-margin-right-1">').text(settings.keepAliveButtonText))
.append($('<button id="timeout-sign-out-btn" class="govuk-button govuk-button--secondary">').text(settings.signOutButtonText))

$element.find('#timeout-keep-signin-btn').on('click', keepAliveAndClose)
$element.find('#timeout-sign-out-btn').on('click', signOut)

var dialogControl = displayDialog($element)

cleanupFunctions.push(function () {
dialogControl.closeDialog()
})

dialogControl.addCloseHandler(keepAliveAndClose)

dialogControl.setAriaLabelledBy('timeout-message')
if (getSecondsRemaining() > 60) {
dialogControl.setAriaLive('polite')
}

startCountdown($countdownElement, dialogControl)
}

function getSecondsRemaining() {
return Math.floor((settings.signout_time - getDateNow()) / 1000)
}

function startCountdown($countdownElement, dialogControl) {
function updateCountdown(counter, $countdownElement) {
var message
if (counter === 60) {
dialogControl.setAriaLive()
}
if (counter < 60) {
message = counter + ' ' + settings.properties[counter === 1 ? 'second' : 'seconds']
} else {
var minutes = Math.ceil(counter / 60)
message = minutes + ' ' + settings.properties[minutes === 1 ? 'minute' : 'minutes']
}
$countdownElement.text(message)
}

function runUpdate() {
var counter = getSecondsRemaining()
updateCountdown(counter, $countdownElement)
if (counter <= 0) {
signOut()
}
}

var countdown = window.setInterval(runUpdate, 1000)
cleanupFunctions.push(function () {
window.clearInterval(countdown)
})
runUpdate()
}

function keepAliveAndClose() {
cleanup()
setupDialogTimer()
$.get(settings.keepAliveUrl, function () {
})
}

function getDateNow() {
return Date.now() || +new Date()
}

function signOut() {
window.location.href = settings.signOutUrl
}

function cleanup() {
while (cleanupFunctions.length > 0) {
var fn = cleanupFunctions.shift()
fn()
}
}

function readCookie(cookieName) { // From http://www.javascripter.net/faq/readingacookie.htm
var re = new RegExp('[; ]'+cookieName+'=([^\\s;]*)');
var sMatch = (' '+document.cookie).match(re);
if (cookieName && sMatch) return unescape(sMatch[1]);
return '';
}

return {cleanup: cleanup}
}
35 changes: 35 additions & 0 deletions app/assets/stylesheets/_language-selection.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Language switcher
.lang {

display: inline-block;
float: right;

&::after {
content: "";
display: table;
clear: both;
}

ul {
float: right;
font-size: 0.8em;
margin-top: 1em;
text-align: right;

// seems we need to be specific with the fonts here
li {
display: inline-block;
font-family: "GDS Transport", Arial, sans-serif;
font-size: 16px;

&:first-child::after {
content: "|";
}
}

a,
[aria-current] {
padding: 0.25em;
}
}
}
Loading

0 comments on commit 30fbe43

Please sign in to comment.