From 91ccbf7c84bca091f3ff1ddf4c5d99fe9d9849a6 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Fri, 7 Feb 2025 07:53:00 +0000 Subject: [PATCH] feat: migrate to exported modules --- docs/assets/javascript/application.mjs | 2 +- src/moj/all.js | 89 +++++++++++++---- src/moj/all.spec.js | 14 +-- src/moj/components/add-another/add-another.js | 22 +++-- .../add-another/add-another.spec.js | 4 +- src/moj/components/button-menu/button-menu.js | 32 ++++--- .../button-menu/button-menu.spec.js | 18 ++-- src/moj/components/date-picker/date-picker.js | 96 +++++++++---------- .../date-picker/date-picker.spec.js | 64 ++++++------- .../filter-toggle-button.js | 28 +++--- .../filter-toggle-button.spec.js | 28 +++--- .../form-validator/form-validator.js | 42 ++++---- .../multi-file-upload/multi-file-upload.js | 52 +++++----- .../multi-file-upload.spec.js | 5 +- .../components/multi-select/multi-select.js | 14 +-- .../multi-select/multi-select.spec.js | 4 +- .../password-reveal/password-reveal.js | 8 +- .../password-reveal/password-reveal.spec.js | 4 +- .../rich-text-editor/rich-text-editor.js | 26 ++--- .../components/search-toggle/search-toggle.js | 12 ++- .../search-toggle/search-toggle.spec.js | 4 +- .../sortable-table/sortable-table.js | 38 +++----- .../sortable-table/sortable-table.spec.js | 22 ++--- src/moj/helpers.js | 21 ++-- src/moj/version.js | 4 +- 25 files changed, 365 insertions(+), 288 deletions(-) diff --git a/docs/assets/javascript/application.mjs b/docs/assets/javascript/application.mjs index e1694764..9e1dbda3 100644 --- a/docs/assets/javascript/application.mjs +++ b/docs/assets/javascript/application.mjs @@ -2,7 +2,7 @@ import * as GOVUKFrontend from 'govuk-frontend' -import MOJFrontend from '../../../package/moj/all.js' +import * as MOJFrontend from '../../../src/moj/all.js' import CollapsibleNav from './collapsible-nav.mjs' import Cookies from './cookies.mjs' diff --git a/src/moj/all.js b/src/moj/all.js index fd95bd2b..24d64429 100644 --- a/src/moj/all.js +++ b/src/moj/all.js @@ -1,6 +1,29 @@ /* eslint-disable no-new */ -MOJFrontend.initAll = function (options) { +const { AddAnother } = require('./components/add-another/add-another.js') +const { ButtonMenu } = require('./components/button-menu/button-menu.js') +const { DatePicker } = require('./components/date-picker/date-picker.js') +const { + FilterToggleButton +} = require('./components/filter-toggle-button/filter-toggle-button.js') +const { + MultiFileUpload +} = require('./components/multi-file-upload/multi-file-upload.js') +const { MultiSelect } = require('./components/multi-select/multi-select.js') +const { + PasswordReveal +} = require('./components/password-reveal/password-reveal.js') +const { + RichTextEditor +} = require('./components/rich-text-editor/rich-text-editor.js') +const { SearchToggle } = require('./components/search-toggle/search-toggle.js') +const { + SortableTable +} = require('./components/sortable-table/sortable-table.js') +const { nodeListForEach } = require('./helpers.js') +const { version } = require('./version.js') + +function initAll(options) { // Set the options to an empty object by default if no options are passed. options = typeof options !== 'undefined' ? options : {} @@ -9,15 +32,17 @@ MOJFrontend.initAll = function (options) { const scope = typeof options.scope !== 'undefined' ? options.scope : document const $addAnothers = scope.querySelectorAll('[data-module="moj-add-another"]') - MOJFrontend.nodeListForEach($addAnothers, function ($addAnother) { - new MOJFrontend.AddAnother($addAnother) + + nodeListForEach($addAnothers, function ($addAnother) { + new AddAnother($addAnother) }) const $multiSelects = scope.querySelectorAll( '[data-module="moj-multi-select"]' ) - MOJFrontend.nodeListForEach($multiSelects, function ($multiSelect) { - new MOJFrontend.MultiSelect({ + + nodeListForEach($multiSelects, function ($multiSelect) { + new MultiSelect({ container: $multiSelect.querySelector( $multiSelect.getAttribute('data-multi-select-checkbox') ), @@ -31,14 +56,16 @@ MOJFrontend.initAll = function (options) { const $passwordReveals = scope.querySelectorAll( '[data-module="moj-password-reveal"]' ) - MOJFrontend.nodeListForEach($passwordReveals, function ($passwordReveal) { - new MOJFrontend.PasswordReveal($passwordReveal) + + nodeListForEach($passwordReveals, function ($passwordReveal) { + new PasswordReveal($passwordReveal) }) const $richTextEditors = scope.querySelectorAll( '[data-module="moj-rich-text-editor"]' ) - MOJFrontend.nodeListForEach($richTextEditors, function ($richTextEditor) { + + nodeListForEach($richTextEditors, function ($richTextEditor) { const options = { textarea: $($richTextEditor) } @@ -46,20 +73,26 @@ MOJFrontend.initAll = function (options) { const toolbarAttr = $richTextEditor.getAttribute( 'data-moj-rich-text-editor-toolbar' ) + if (toolbarAttr) { const toolbar = toolbarAttr.split(',') + options.toolbar = {} - for (const item in toolbar) options.toolbar[toolbar[item]] = true + + for (const item in toolbar) { + options.toolbar[toolbar[item]] = true + } } - new MOJFrontend.RichTextEditor(options) + new RichTextEditor(options) }) const $searchToggles = scope.querySelectorAll( '[data-module="moj-search-toggle"]' ) - MOJFrontend.nodeListForEach($searchToggles, function ($searchToggle) { - new MOJFrontend.SearchToggle({ + + nodeListForEach($searchToggles, function ($searchToggle) { + new SearchToggle({ toggleButton: { container: $($searchToggle.querySelector('.moj-search-toggle__toggle')), text: $searchToggle.getAttribute('data-moj-search-toggle-text') @@ -73,19 +106,39 @@ MOJFrontend.initAll = function (options) { const $sortableTables = scope.querySelectorAll( '[data-module="moj-sortable-table"]' ) - MOJFrontend.nodeListForEach($sortableTables, function ($table) { - new MOJFrontend.SortableTable({ + + nodeListForEach($sortableTables, function ($table) { + new SortableTable({ table: $table }) }) const $datepickers = scope.querySelectorAll('[data-module="moj-date-picker"]') - MOJFrontend.nodeListForEach($datepickers, function ($datepicker) { - new MOJFrontend.DatePicker($datepicker, {}).init() + + nodeListForEach($datepickers, function ($datepicker) { + new DatePicker($datepicker, {}).init() }) const $buttonMenus = scope.querySelectorAll('[data-module="moj-button-menu"]') - MOJFrontend.nodeListForEach($buttonMenus, function ($buttonmenu) { - new MOJFrontend.ButtonMenu($buttonmenu, {}).init() + + nodeListForEach($buttonMenus, function ($buttonmenu) { + new ButtonMenu($buttonmenu, {}).init() }) } + +module.exports = { + initAll, + version, + + // Components + AddAnother, + ButtonMenu, + DatePicker, + FilterToggleButton, + MultiFileUpload, + MultiSelect, + PasswordReveal, + RichTextEditor, + SearchToggle, + SortableTable +} diff --git a/src/moj/all.spec.js b/src/moj/all.spec.js index b0790010..bc049e81 100644 --- a/src/moj/all.spec.js +++ b/src/moj/all.spec.js @@ -2,22 +2,24 @@ const { getByTestId } = require('@testing-library/dom') -require('./helpers') -require('./all.js') +const { initAll } = require('./all.js') +const { + PasswordReveal +} = require('./components/password-reveal/password-reveal.js') + +jest.mock('./components/password-reveal/password-reveal.js') describe('initAll', () => { test('initialises container', () => { - MOJFrontend.PasswordReveal = jest.fn() - const container = document.createElement('div') container.innerHTML = ` ` - MOJFrontend.initAll({ scope: container }) + initAll({ scope: container }) - expect(MOJFrontend.PasswordReveal).toHaveBeenCalledWith( + expect(PasswordReveal).toHaveBeenCalledWith( getByTestId(container, 'password-reveal') ) }) diff --git a/src/moj/components/add-another/add-another.js b/src/moj/components/add-another/add-another.js index 7bae56ce..5ac2ee9a 100755 --- a/src/moj/components/add-another/add-another.js +++ b/src/moj/components/add-another/add-another.js @@ -1,4 +1,4 @@ -MOJFrontend.AddAnother = function (container) { +function AddAnother(container) { this.container = $(container) if (this.container.data('moj-add-another-initialised')) { @@ -22,7 +22,7 @@ MOJFrontend.AddAnother = function (container) { .prop('type', 'button') } -MOJFrontend.AddAnother.prototype.onAddButtonClick = function (e) { +AddAnother.prototype.onAddButtonClick = function (e) { const item = this.getNewItem() this.updateAttributes(this.getItems().length, item) this.resetItem(item) @@ -34,15 +34,15 @@ MOJFrontend.AddAnother.prototype.onAddButtonClick = function (e) { item.find('input, textarea, select').first().focus() } -MOJFrontend.AddAnother.prototype.hasRemoveButton = function (item) { +AddAnother.prototype.hasRemoveButton = function (item) { return item.find('.moj-add-another__remove-button').length } -MOJFrontend.AddAnother.prototype.getItems = function () { +AddAnother.prototype.getItems = function () { return this.container.find('.moj-add-another__item') } -MOJFrontend.AddAnother.prototype.getNewItem = function () { +AddAnother.prototype.getNewItem = function () { const item = this.getItems().first().clone() if (!this.hasRemoveButton(item)) { this.createRemoveButton(item) @@ -50,7 +50,7 @@ MOJFrontend.AddAnother.prototype.getNewItem = function () { return item } -MOJFrontend.AddAnother.prototype.updateAttributes = function (index, item) { +AddAnother.prototype.updateAttributes = function (index, item) { item.find('[data-name]').each(function (i, el) { const originalId = el.id @@ -69,13 +69,13 @@ MOJFrontend.AddAnother.prototype.updateAttributes = function (index, item) { }) } -MOJFrontend.AddAnother.prototype.createRemoveButton = function (item) { +AddAnother.prototype.createRemoveButton = function (item) { item.append( '' ) } -MOJFrontend.AddAnother.prototype.resetItem = function (item) { +AddAnother.prototype.resetItem = function (item) { item.find('[data-name], [data-id]').each(function (index, el) { if (el.type === 'checkbox' || el.type === 'radio') { el.checked = false @@ -85,7 +85,7 @@ MOJFrontend.AddAnother.prototype.resetItem = function (item) { }) } -MOJFrontend.AddAnother.prototype.onRemoveButtonClick = function (e) { +AddAnother.prototype.onRemoveButtonClick = function (e) { $(e.currentTarget).parents('.moj-add-another__item').remove() const items = this.getItems() if (items.length === 1) { @@ -99,6 +99,8 @@ MOJFrontend.AddAnother.prototype.onRemoveButtonClick = function (e) { this.focusHeading() } -MOJFrontend.AddAnother.prototype.focusHeading = function () { +AddAnother.prototype.focusHeading = function () { this.container.find('.moj-add-another__heading').get(0).focus() } + +module.exports = { AddAnother } diff --git a/src/moj/components/add-another/add-another.spec.js b/src/moj/components/add-another/add-another.spec.js index 609c1e59..cf0f63df 100644 --- a/src/moj/components/add-another/add-another.spec.js +++ b/src/moj/components/add-another/add-another.spec.js @@ -7,7 +7,7 @@ const { } = require('@testing-library/dom') const { userEvent } = require('@testing-library/user-event') -require('./add-another.js') +const { AddAnother } = require('./add-another.js') const user = userEvent.setup() @@ -41,7 +41,7 @@ describe('Add Another component', () => { beforeEach(() => { component = createComponent() - new MOJFrontend.AddAnother(component) + new AddAnother(component) addButton = getByRole(component, 'button', { name: 'Add another person' }) }) diff --git a/src/moj/components/button-menu/button-menu.js b/src/moj/components/button-menu/button-menu.js index bc71fa19..7101d1c1 100644 --- a/src/moj/components/button-menu/button-menu.js +++ b/src/moj/components/button-menu/button-menu.js @@ -10,7 +10,7 @@ * @param {ButtonMenuConfig} config * @class */ -MOJFrontend.ButtonMenu = function ($module, config = {}) { +function ButtonMenu($module, config = {}) { if (!$module) { return this } @@ -38,7 +38,7 @@ MOJFrontend.ButtonMenu = function ($module, config = {}) { this.$module = $module } -MOJFrontend.ButtonMenu.prototype.init = function () { +ButtonMenu.prototype.init = function () { // If only one button is provided, don't initiate a menu and toggle button // if classes have been provided for the toggleButton, apply them to the single item if (this.$module.children.length === 1) { @@ -59,7 +59,7 @@ MOJFrontend.ButtonMenu.prototype.init = function () { } } -MOJFrontend.ButtonMenu.prototype.initMenu = function () { +ButtonMenu.prototype.initMenu = function () { this.$menu = this.createMenu() this.$module.insertAdjacentHTML('afterbegin', this.toggleTemplate()) this.setupMenuItems() @@ -82,7 +82,7 @@ MOJFrontend.ButtonMenu.prototype.initMenu = function () { }) } -MOJFrontend.ButtonMenu.prototype.createMenu = function () { +ButtonMenu.prototype.createMenu = function () { const $menu = document.createElement('ul') $menu.setAttribute('role', 'list') $menu.hidden = true @@ -99,7 +99,7 @@ MOJFrontend.ButtonMenu.prototype.createMenu = function () { return $menu } -MOJFrontend.ButtonMenu.prototype.setupMenuItems = function () { +ButtonMenu.prototype.setupMenuItems = function () { Array.from(this.$menu.children).forEach((item) => { // wrap item in li tag const listItem = document.createElement('li') @@ -127,7 +127,7 @@ MOJFrontend.ButtonMenu.prototype.setupMenuItems = function () { }) } -MOJFrontend.ButtonMenu.prototype.toggleTemplate = function () { +ButtonMenu.prototype.toggleTemplate = function () { return ` ` ) @@ -25,7 +25,7 @@ MOJFrontend.FilterToggleButton.prototype.createToggleButton = function () { this.container.append(this.menuButton) } -MOJFrontend.FilterToggleButton.prototype.checkMode = function (mq) { +FilterToggleButton.prototype.checkMode = function (mq) { if (mq.matches) { this.enableBigMode() } else { @@ -33,17 +33,17 @@ MOJFrontend.FilterToggleButton.prototype.checkMode = function (mq) { } } -MOJFrontend.FilterToggleButton.prototype.enableBigMode = function () { +FilterToggleButton.prototype.enableBigMode = function () { this.showMenu() this.removeCloseButton() } -MOJFrontend.FilterToggleButton.prototype.enableSmallMode = function () { +FilterToggleButton.prototype.enableSmallMode = function () { this.hideMenu() this.addCloseButton() } -MOJFrontend.FilterToggleButton.prototype.addCloseButton = function () { +FilterToggleButton.prototype.addCloseButton = function () { if (this.options.closeButton) { this.closeButton = $( `` @@ -53,35 +53,35 @@ MOJFrontend.FilterToggleButton.prototype.addCloseButton = function () { } } -MOJFrontend.FilterToggleButton.prototype.onCloseClick = function () { +FilterToggleButton.prototype.onCloseClick = function () { this.hideMenu() this.menuButton.focus() } -MOJFrontend.FilterToggleButton.prototype.removeCloseButton = function () { +FilterToggleButton.prototype.removeCloseButton = function () { if (this.closeButton) { this.closeButton.remove() this.closeButton = null } } -MOJFrontend.FilterToggleButton.prototype.hideMenu = function () { +FilterToggleButton.prototype.hideMenu = function () { this.menuButton.attr('aria-expanded', 'false') this.filterContainer.addClass('moj-js-hidden') this.menuButton.text(this.options.toggleButton.showText) } -MOJFrontend.FilterToggleButton.prototype.showMenu = function () { +FilterToggleButton.prototype.showMenu = function () { this.menuButton.attr('aria-expanded', 'true') this.filterContainer.removeClass('moj-js-hidden') this.menuButton.text(this.options.toggleButton.hideText) } -MOJFrontend.FilterToggleButton.prototype.onMenuButtonClick = function () { +FilterToggleButton.prototype.onMenuButtonClick = function () { this.toggle() } -MOJFrontend.FilterToggleButton.prototype.toggle = function () { +FilterToggleButton.prototype.toggle = function () { if (this.menuButton.attr('aria-expanded') === 'false') { this.showMenu() this.filterContainer.get(0).focus() @@ -89,3 +89,5 @@ MOJFrontend.FilterToggleButton.prototype.toggle = function () { this.hideMenu() } } + +module.exports = { FilterToggleButton } diff --git a/src/moj/components/filter-toggle-button/filter-toggle-button.spec.js b/src/moj/components/filter-toggle-button/filter-toggle-button.spec.js index 4ca577eb..4855e61a 100644 --- a/src/moj/components/filter-toggle-button/filter-toggle-button.spec.js +++ b/src/moj/components/filter-toggle-button/filter-toggle-button.spec.js @@ -6,7 +6,7 @@ const { configureAxe } = require('jest-axe') const merge = require('lodash/merge') const { setMedia } = require('mock-match-media') -require('./filter-toggle-button.js') +const { FilterToggleButton } = require('./filter-toggle-button.js') const user = userEvent.setup() const axe = configureAxe({ @@ -91,7 +91,7 @@ describe('Filter toggle in big mode', () => { }) test('creates toggle button', () => { - new MOJFrontend.FilterToggleButton(defaultConfig) + new FilterToggleButton(defaultConfig) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton).toBeInTheDocument() @@ -104,7 +104,7 @@ describe('Filter toggle in big mode', () => { }) test('toggle button reveals filters', async () => { - new MOJFrontend.FilterToggleButton(defaultConfig) + new FilterToggleButton(defaultConfig) const toggleButton = queryByRole(buttonContainer, 'button') expect(filterContainer).toHaveAttribute('tabindex', '-1') @@ -128,7 +128,7 @@ describe('Filter toggle in big mode', () => { test('start visible', () => { const config = merge(defaultConfig, { startHidden: false }) - new MOJFrontend.FilterToggleButton(config) + new FilterToggleButton(config) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton.innerHTML).toBe('Hide filter') @@ -139,7 +139,7 @@ describe('Filter toggle in big mode', () => { const config = merge(defaultConfig, { toggleButton: { showText: 'Custom label', hideText: 'Hide me' } }) - new MOJFrontend.FilterToggleButton(config) + new FilterToggleButton(config) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton.innerHTML).toBe('Custom label') @@ -151,7 +151,7 @@ describe('Filter toggle in big mode', () => { const config = merge(defaultConfig, { toggleButton: { classes: 'classname-1 classname-2' } }) - new MOJFrontend.FilterToggleButton(config) + new FilterToggleButton(config) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton).toHaveClass('classname-1 classname-2') @@ -159,7 +159,7 @@ describe('Filter toggle in big mode', () => { describe('accessibility', () => { test('component has no wcag violations', async () => { - new MOJFrontend.FilterToggleButton(defaultConfig) + new FilterToggleButton(defaultConfig) const toggleButton = queryByRole(buttonContainer, 'button') expect(await axe(document.body)).toHaveNoViolations() await user.click(toggleButton) @@ -193,7 +193,7 @@ describe('Filter toggle in small mode', () => { }) test('creates toggle button', () => { - new MOJFrontend.FilterToggleButton(defaultConfig) + new FilterToggleButton(defaultConfig) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton).toBeInTheDocument() @@ -206,7 +206,7 @@ describe('Filter toggle in small mode', () => { }) test('toggle button reveals filters', async () => { - new MOJFrontend.FilterToggleButton(defaultConfig) + new FilterToggleButton(defaultConfig) const toggleButton = queryByRole(buttonContainer, 'button') expect(filterContainer).toHaveAttribute('tabindex', '-1') @@ -230,7 +230,7 @@ describe('Filter toggle in small mode', () => { test('start visible is ignored', () => { const config = merge(defaultConfig, { startHidden: false }) - new MOJFrontend.FilterToggleButton(config) + new FilterToggleButton(config) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton.innerHTML).toBe('Show filter') @@ -239,7 +239,7 @@ describe('Filter toggle in small mode', () => { test('adds a close button', async () => { const config = merge(defaultConfig, { startHidden: false }) - new MOJFrontend.FilterToggleButton(config) + new FilterToggleButton(config) const toggleButton = queryByRole(buttonContainer, 'button') await user.click(toggleButton) @@ -256,7 +256,7 @@ describe('Filter toggle in small mode', () => { }) const config = merge(defaultConfig, { startHidden: false }) - new MOJFrontend.FilterToggleButton(config) + new FilterToggleButton(config) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton.innerHTML).toBe('Hide filter') @@ -276,7 +276,7 @@ describe('Filter toggle in small mode', () => { }) const config = merge(defaultConfig) - new MOJFrontend.FilterToggleButton(config) + new FilterToggleButton(config) const toggleButton = queryByRole(buttonContainer, 'button') expect(toggleButton.innerHTML).toBe('Show filter') @@ -292,7 +292,7 @@ describe('Filter toggle in small mode', () => { describe('accessibility', () => { test('component has no wcag violations', async () => { - new MOJFrontend.FilterToggleButton(defaultConfig) + new FilterToggleButton(defaultConfig) const toggleButton = queryByRole(buttonContainer, 'button') expect(await axe(document.body)).toHaveNoViolations() await user.click(toggleButton) diff --git a/src/moj/components/form-validator/form-validator.js b/src/moj/components/form-validator/form-validator.js index 6bad6bad..9c9c4960 100755 --- a/src/moj/components/form-validator/form-validator.js +++ b/src/moj/components/form-validator/form-validator.js @@ -1,4 +1,6 @@ -MOJFrontend.FormValidator = function (form, options) { +const { addAttributeValue, removeAttributeValue } = require('../../helpers.js') + +function FormValidator(form, options) { this.form = form this.errors = [] this.validators = [] @@ -8,7 +10,7 @@ MOJFrontend.FormValidator = function (form, options) { this.originalTitle = document.title } -MOJFrontend.FormValidator.entityMap = { +FormValidator.entityMap = { '&': '&', '<': '<', '>': '>', @@ -19,28 +21,28 @@ MOJFrontend.FormValidator.entityMap = { '=': '=' } -MOJFrontend.FormValidator.prototype.escapeHtml = function (string) { +FormValidator.prototype.escapeHtml = function (string) { return String(string).replace(/[&<>"'`=/]/g, function fromEntityMap(s) { - return MOJFrontend.FormValidator.entityMap[s] + return FormValidator.entityMap[s] }) } -MOJFrontend.FormValidator.prototype.resetTitle = function () { +FormValidator.prototype.resetTitle = function () { document.title = this.originalTitle } -MOJFrontend.FormValidator.prototype.updateTitle = function () { +FormValidator.prototype.updateTitle = function () { document.title = `${this.errors.length} errors - ${document.title}` } -MOJFrontend.FormValidator.prototype.showSummary = function () { +FormValidator.prototype.showSummary = function () { this.summary.html(this.getSummaryHtml()) this.summary.removeClass('moj-hidden') this.summary.attr('aria-labelledby', 'errorSummary-heading') this.summary.focus() } -MOJFrontend.FormValidator.prototype.getSummaryHtml = function () { +FormValidator.prototype.getSummaryHtml = function () { let html = '

There is a problem

' html += '
' @@ -58,12 +60,12 @@ MOJFrontend.FormValidator.prototype.getSummaryHtml = function () { return html } -MOJFrontend.FormValidator.prototype.hideSummary = function () { +FormValidator.prototype.hideSummary = function () { this.summary.addClass('moj-hidden') this.summary.removeAttr('aria-labelledby') } -MOJFrontend.FormValidator.prototype.onSubmit = function (e) { +FormValidator.prototype.onSubmit = function (e) { this.removeInlineErrors() this.hideSummary() this.resetTitle() @@ -75,13 +77,13 @@ MOJFrontend.FormValidator.prototype.onSubmit = function (e) { } } -MOJFrontend.FormValidator.prototype.showInlineErrors = function () { +FormValidator.prototype.showInlineErrors = function () { for (let i = 0, j = this.errors.length; i < j; i++) { this.showInlineError(this.errors[i]) } } -MOJFrontend.FormValidator.prototype.showInlineError = function (error) { +FormValidator.prototype.showInlineError = function (error) { const errorSpanId = `${error.fieldName}-error` const errorSpan = `') this.dropzone = this.container.find('.moj-multi-file-upload__dropzone') this.dropzone.on('dragover', $.proxy(this, 'onDragOver')) @@ -46,7 +46,7 @@ MOJFrontend.MultiFileUpload.prototype.setupDropzone = function () { this.dropzone.on('drop', $.proxy(this, 'onDrop')) } -MOJFrontend.MultiFileUpload.prototype.setupLabel = function () { +MultiFileUpload.prototype.setupLabel = function () { this.label = $( `` ) @@ -56,30 +56,30 @@ MOJFrontend.MultiFileUpload.prototype.setupLabel = function () { this.dropzone.append(this.label) } -MOJFrontend.MultiFileUpload.prototype.setupFileInput = function () { +MultiFileUpload.prototype.setupFileInput = function () { this.fileInput = this.container.find('.moj-multi-file-upload__input') this.fileInput.on('change', $.proxy(this, 'onFileChange')) this.fileInput.on('focus', $.proxy(this, 'onFileFocus')) this.fileInput.on('blur', $.proxy(this, 'onFileBlur')) } -MOJFrontend.MultiFileUpload.prototype.setupStatusBox = function () { +MultiFileUpload.prototype.setupStatusBox = function () { this.status = $( '
' ) this.dropzone.append(this.status) } -MOJFrontend.MultiFileUpload.prototype.onDragOver = function (e) { +MultiFileUpload.prototype.onDragOver = function (e) { e.preventDefault() this.dropzone.addClass('moj-multi-file-upload--dragover') } -MOJFrontend.MultiFileUpload.prototype.onDragLeave = function () { +MultiFileUpload.prototype.onDragLeave = function () { this.dropzone.removeClass('moj-multi-file-upload--dragover') } -MOJFrontend.MultiFileUpload.prototype.onDrop = function (e) { +MultiFileUpload.prototype.onDrop = function (e) { e.preventDefault() this.dropzone.removeClass('moj-multi-file-upload--dragover') this.feedbackContainer.removeClass('moj-hidden') @@ -87,13 +87,13 @@ MOJFrontend.MultiFileUpload.prototype.onDrop = function (e) { this.uploadFiles(e.originalEvent.dataTransfer.files) } -MOJFrontend.MultiFileUpload.prototype.uploadFiles = function (files) { +MultiFileUpload.prototype.uploadFiles = function (files) { for (let i = 0; i < files.length; i++) { this.uploadFile(files[i]) } } -MOJFrontend.MultiFileUpload.prototype.onFileChange = function (e) { +MultiFileUpload.prototype.onFileChange = function (e) { this.feedbackContainer.removeClass('moj-hidden') this.status.html(this.params.uploadStatusText) this.uploadFiles(e.currentTarget.files) @@ -102,23 +102,23 @@ MOJFrontend.MultiFileUpload.prototype.onFileChange = function (e) { this.fileInput.get(0).focus() } -MOJFrontend.MultiFileUpload.prototype.onFileFocus = function (e) { +MultiFileUpload.prototype.onFileFocus = function (e) { this.label.addClass('moj-multi-file-upload--focused') } -MOJFrontend.MultiFileUpload.prototype.onFileBlur = function (e) { +MultiFileUpload.prototype.onFileBlur = function (e) { this.label.removeClass('moj-multi-file-upload--focused') } -MOJFrontend.MultiFileUpload.prototype.getSuccessHtml = function (success) { +MultiFileUpload.prototype.getSuccessHtml = function (success) { return ` ${success.messageHtml}` } -MOJFrontend.MultiFileUpload.prototype.getErrorHtml = function (error) { +MultiFileUpload.prototype.getErrorHtml = function (error) { return ` ${error.message}` } -MOJFrontend.MultiFileUpload.prototype.getFileRowHtml = function (file) { +MultiFileUpload.prototype.getFileRowHtml = function (file) { const html = `
;
; @@ -130,13 +130,13 @@ MOJFrontend.MultiFileUpload.prototype.getFileRowHtml = function (file) { return html } -MOJFrontend.MultiFileUpload.prototype.getDeleteButtonHtml = function (file) { +MultiFileUpload.prototype.getDeleteButtonHtml = function (file) { return `` } -MOJFrontend.MultiFileUpload.prototype.uploadFile = function (file) { +MultiFileUpload.prototype.uploadFile = function (file) { this.params.uploadFileEntryHook(this, file) const item = $(this.getFileRowHtml(file)) const formData = new FormData() @@ -195,7 +195,7 @@ MOJFrontend.MultiFileUpload.prototype.uploadFile = function (file) { }) } -MOJFrontend.MultiFileUpload.prototype.onFileDeleteClick = function (e) { +MultiFileUpload.prototype.onFileDeleteClick = function (e) { e.preventDefault() // if user refreshes page and then deletes const button = $(e.currentTarget) const data = {} @@ -221,3 +221,5 @@ MOJFrontend.MultiFileUpload.prototype.onFileDeleteClick = function (e) { }, this) }) } + +module.exports = { MultiFileUpload } diff --git a/src/moj/components/multi-file-upload/multi-file-upload.spec.js b/src/moj/components/multi-file-upload/multi-file-upload.spec.js index eb3d766a..a62e3a59 100644 --- a/src/moj/components/multi-file-upload/multi-file-upload.spec.js +++ b/src/moj/components/multi-file-upload/multi-file-upload.spec.js @@ -9,8 +9,7 @@ const { userEvent } = require('@testing-library/user-event') const { configureAxe } = require('jest-axe') const sinon = require('sinon') -require('../../helpers.js') -require('./multi-file-upload.js') +const { MultiFileUpload } = require('./multi-file-upload.js') const user = userEvent.setup() const axe = configureAxe({ @@ -77,7 +76,7 @@ describe('Multi-file upload', () => { deleteUrl: '/delete' })) - new MOJFrontend.MultiFileUpload(options) + new MultiFileUpload(options) }) afterEach(() => { diff --git a/src/moj/components/multi-select/multi-select.js b/src/moj/components/multi-select/multi-select.js index a94254ce..cb0b0c20 100644 --- a/src/moj/components/multi-select/multi-select.js +++ b/src/moj/components/multi-select/multi-select.js @@ -1,4 +1,4 @@ -MOJFrontend.MultiSelect = function (options) { +function MultiSelect(options) { this.container = $(options.container) if (this.container.data('moj-multi-select-initialised')) { @@ -22,7 +22,7 @@ MOJFrontend.MultiSelect = function (options) { this.checked = options.checked || false } -MOJFrontend.MultiSelect.prototype.getToggleHtml = function (allId) { +MultiSelect.prototype.getToggleHtml = function (allId) { let html = '' html += '
' @@ -34,7 +34,7 @@ MOJFrontend.MultiSelect.prototype.getToggleHtml = function (allId) { return html } -MOJFrontend.MultiSelect.prototype.onButtonClick = function (e) { +MultiSelect.prototype.onButtonClick = function (e) { if (this.checked) { this.uncheckAll() this.toggleButton[0].checked = false @@ -44,7 +44,7 @@ MOJFrontend.MultiSelect.prototype.onButtonClick = function (e) { } } -MOJFrontend.MultiSelect.prototype.checkAll = function () { +MultiSelect.prototype.checkAll = function () { this.checkboxes.each( $.proxy(function (index, el) { el.checked = true @@ -53,7 +53,7 @@ MOJFrontend.MultiSelect.prototype.checkAll = function () { this.checked = true } -MOJFrontend.MultiSelect.prototype.uncheckAll = function () { +MultiSelect.prototype.uncheckAll = function () { this.checkboxes.each( $.proxy(function (index, el) { el.checked = false @@ -62,7 +62,7 @@ MOJFrontend.MultiSelect.prototype.uncheckAll = function () { this.checked = false } -MOJFrontend.MultiSelect.prototype.onCheckboxClick = function (e) { +MultiSelect.prototype.onCheckboxClick = function (e) { if (!e.target.checked) { this.toggleButton[0].checked = false this.checked = false @@ -73,3 +73,5 @@ MOJFrontend.MultiSelect.prototype.onCheckboxClick = function (e) { } } } + +module.exports = { MultiSelect } diff --git a/src/moj/components/multi-select/multi-select.spec.js b/src/moj/components/multi-select/multi-select.spec.js index 029881d1..42461c33 100644 --- a/src/moj/components/multi-select/multi-select.spec.js +++ b/src/moj/components/multi-select/multi-select.spec.js @@ -3,7 +3,7 @@ const { queryByRole, queryAllByRole } = require('@testing-library/dom') const { userEvent } = require('@testing-library/user-event') -require('./multi-select.js') +const { MultiSelect } = require('./multi-select.js') const user = userEvent.setup() @@ -58,7 +58,7 @@ describe('multi select', () => { container = component.querySelector('#multi-select-select-all') checkboxes = component.querySelectorAll('tbody input[type=checkbox]') - new MOJFrontend.MultiSelect({ + new MultiSelect({ container, checkboxes }) diff --git a/src/moj/components/password-reveal/password-reveal.js b/src/moj/components/password-reveal/password-reveal.js index 2cb5af70..d5d3f3d5 100644 --- a/src/moj/components/password-reveal/password-reveal.js +++ b/src/moj/components/password-reveal/password-reveal.js @@ -1,4 +1,4 @@ -MOJFrontend.PasswordReveal = function (element) { +function PasswordReveal(element) { this.el = element const $el = $(this.el) @@ -14,7 +14,7 @@ MOJFrontend.PasswordReveal = function (element) { this.createButton() } -MOJFrontend.PasswordReveal.prototype.createButton = function () { +PasswordReveal.prototype.createButton = function () { this.button = $( '' ) @@ -22,7 +22,7 @@ MOJFrontend.PasswordReveal.prototype.createButton = function () { this.button.on('click', $.proxy(this, 'onButtonClick')) } -MOJFrontend.PasswordReveal.prototype.onButtonClick = function () { +PasswordReveal.prototype.onButtonClick = function () { if (this.el.type === 'password') { this.el.type = 'text' this.button.html('Hide password') @@ -31,3 +31,5 @@ MOJFrontend.PasswordReveal.prototype.onButtonClick = function () { this.button.html('Show password') } } + +module.exports = { PasswordReveal } diff --git a/src/moj/components/password-reveal/password-reveal.spec.js b/src/moj/components/password-reveal/password-reveal.spec.js index 7f8d893c..8be0ed59 100644 --- a/src/moj/components/password-reveal/password-reveal.spec.js +++ b/src/moj/components/password-reveal/password-reveal.spec.js @@ -4,7 +4,7 @@ const { getByDisplayValue, getByText } = require('@testing-library/dom') const { userEvent } = require('@testing-library/user-event') const { configureAxe } = require('jest-axe') -require('./password-reveal.js') +const { PasswordReveal } = require('./password-reveal.js') const user = userEvent.setup() const axe = configureAxe({ @@ -22,7 +22,7 @@ describe('Password reveal', () => { input.type = 'password' input.value = 'password' - new MOJFrontend.PasswordReveal(input) + new PasswordReveal(input) container = input.parentNode }) diff --git a/src/moj/components/rich-text-editor/rich-text-editor.js b/src/moj/components/rich-text-editor/rich-text-editor.js index 4d6a9d86..ff5dd9c7 100755 --- a/src/moj/components/rich-text-editor/rich-text-editor.js +++ b/src/moj/components/rich-text-editor/rich-text-editor.js @@ -1,4 +1,4 @@ -MOJFrontend.RichTextEditor = function (options) { +function RichTextEditor(options) { if (!('contentEditable' in document.documentElement)) { return } @@ -41,7 +41,7 @@ MOJFrontend.RichTextEditor = function (options) { this.toolbar.on('keydown', $.proxy(this, 'onToolbarKeydown')) } -MOJFrontend.RichTextEditor.prototype.onToolbarKeydown = function (e) { +RichTextEditor.prototype.onToolbarKeydown = function (e) { let focusableButton switch (e.keyCode) { case this.keys.right: @@ -69,7 +69,7 @@ MOJFrontend.RichTextEditor.prototype.onToolbarKeydown = function (e) { } } -MOJFrontend.RichTextEditor.prototype.getToolbarHtml = function () { +RichTextEditor.prototype.getToolbarHtml = function () { let html = '' html += '