@ministryofjustice/frontend 4.0.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/govuk-prototype-kit.config.json +19 -4
- package/moj/_base.scss +2 -0
- package/moj/_base.scss.map +1 -0
- package/moj/all.bundle.js +2523 -0
- package/moj/all.bundle.js.map +1 -0
- package/moj/all.bundle.mjs +2502 -0
- package/moj/all.bundle.mjs.map +1 -0
- package/moj/all.mjs +59 -69
- package/moj/all.mjs.map +1 -1
- package/moj/all.scss +2 -0
- package/moj/all.scss.map +1 -0
- package/moj/components/_all.scss +2 -0
- package/moj/components/_all.scss.map +1 -0
- package/moj/components/action-bar/_action-bar.scss +2 -0
- package/moj/components/action-bar/_action-bar.scss.map +1 -0
- package/moj/components/add-another/_add-another.scss +2 -0
- package/moj/components/add-another/_add-another.scss.map +1 -0
- package/moj/components/add-another/add-another.bundle.js +128 -0
- package/moj/components/add-another/add-another.bundle.js.map +1 -0
- package/moj/components/add-another/add-another.bundle.mjs +120 -0
- package/moj/components/add-another/add-another.bundle.mjs.map +1 -0
- package/moj/components/add-another/add-another.mjs +112 -99
- package/moj/components/add-another/add-another.mjs.map +1 -1
- package/moj/components/alert/_alert.scss +4 -0
- package/moj/components/alert/_alert.scss.map +1 -0
- package/moj/components/alert/alert.bundle.js +330 -0
- package/moj/components/alert/alert.bundle.js.map +1 -0
- package/moj/components/alert/alert.bundle.mjs +322 -0
- package/moj/components/alert/alert.bundle.mjs.map +1 -0
- package/moj/components/alert/alert.mjs +181 -217
- package/moj/components/alert/alert.mjs.map +1 -1
- package/moj/components/alert/{alert.spec.helper.js → alert.spec.helper.bundle.js} +1 -1
- package/moj/components/alert/alert.spec.helper.bundle.js.map +1 -0
- package/moj/components/alert/alert.spec.helper.bundle.mjs +67 -0
- package/moj/components/alert/alert.spec.helper.bundle.mjs.map +1 -0
- package/moj/components/alert/alert.spec.helper.mjs.map +1 -1
- package/moj/components/badge/_badge.scss +2 -0
- package/moj/components/badge/_badge.scss.map +1 -0
- package/moj/components/banner/_banner.scss +2 -0
- package/moj/components/banner/_banner.scss.map +1 -0
- package/moj/components/button-menu/README.md +10 -6
- package/moj/components/button-menu/_button-menu.scss +4 -1
- package/moj/components/button-menu/_button-menu.scss.map +1 -0
- package/moj/components/button-menu/button-menu.bundle.js +299 -0
- package/moj/components/button-menu/button-menu.bundle.js.map +1 -0
- package/moj/components/button-menu/{button-menu.js → button-menu.bundle.mjs} +74 -121
- package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -0
- package/moj/components/button-menu/button-menu.mjs +246 -285
- package/moj/components/button-menu/button-menu.mjs.map +1 -1
- package/moj/components/cookie-banner/_cookie-banner.scss +2 -0
- package/moj/components/cookie-banner/_cookie-banner.scss.map +1 -0
- package/moj/components/currency-input/_currency-input.scss +2 -0
- package/moj/components/currency-input/_currency-input.scss.map +1 -0
- package/moj/components/date-picker/_date-picker.scss +2 -0
- package/moj/components/date-picker/_date-picker.scss.map +1 -0
- package/moj/components/date-picker/date-picker.bundle.js +784 -0
- package/moj/components/date-picker/date-picker.bundle.js.map +1 -0
- package/moj/components/date-picker/{date-picker.js → date-picker.bundle.mjs} +245 -439
- package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -0
- package/moj/components/date-picker/date-picker.mjs +654 -840
- package/moj/components/date-picker/date-picker.mjs.map +1 -1
- package/moj/components/filter/_filter.scss +2 -0
- package/moj/components/filter/_filter.scss.map +1 -0
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +96 -0
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -0
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +88 -0
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -0
- package/moj/components/filter-toggle-button/filter-toggle-button.mjs +78 -84
- package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
- package/moj/components/form-validator/form-validator.bundle.js +198 -0
- package/moj/components/form-validator/form-validator.bundle.js.map +1 -0
- package/moj/components/form-validator/form-validator.bundle.mjs +190 -0
- package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -0
- package/moj/components/form-validator/form-validator.mjs +149 -152
- package/moj/components/form-validator/form-validator.mjs.map +1 -1
- package/moj/components/header/_header.scss +2 -0
- package/moj/components/header/_header.scss.map +1 -0
- package/moj/components/identity-bar/_identity-bar.scss +2 -0
- package/moj/components/identity-bar/_identity-bar.scss.map +1 -0
- package/moj/components/interruption-card/_interruption-card.scss +2 -0
- package/moj/components/interruption-card/_interruption-card.scss.map +1 -0
- package/moj/components/messages/_messages.scss +2 -0
- package/moj/components/messages/_messages.scss.map +1 -0
- package/moj/components/multi-file-upload/_multi-file-upload.scss +2 -0
- package/moj/components/multi-file-upload/_multi-file-upload.scss.map +1 -0
- package/moj/components/multi-file-upload/multi-file-upload.bundle.js +223 -0
- package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -0
- package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +215 -0
- package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -0
- package/moj/components/multi-file-upload/multi-file-upload.mjs +193 -209
- package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
- package/moj/components/multi-select/_multi-select.scss +2 -0
- package/moj/components/multi-select/_multi-select.scss.map +1 -0
- package/moj/components/multi-select/multi-select.bundle.js +78 -0
- package/moj/components/multi-select/multi-select.bundle.js.map +1 -0
- package/moj/components/multi-select/multi-select.bundle.mjs +70 -0
- package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -0
- package/moj/components/multi-select/multi-select.mjs +59 -67
- package/moj/components/multi-select/multi-select.mjs.map +1 -1
- package/moj/components/notification-badge/_notification-badge.scss +2 -0
- package/moj/components/notification-badge/_notification-badge.scss.map +1 -0
- package/moj/components/organisation-switcher/_organisation-switcher.scss +2 -0
- package/moj/components/organisation-switcher/_organisation-switcher.scss.map +1 -0
- package/moj/components/page-header-actions/_page-header-actions.scss +2 -0
- package/moj/components/page-header-actions/_page-header-actions.scss.map +1 -0
- package/moj/components/pagination/_pagination.scss +2 -2
- package/moj/components/pagination/_pagination.scss.map +1 -0
- package/moj/components/password-reveal/_password-reveal.scss +2 -0
- package/moj/components/password-reveal/_password-reveal.scss.map +1 -0
- package/moj/components/password-reveal/password-reveal.bundle.js +49 -0
- package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -0
- package/moj/components/password-reveal/password-reveal.bundle.mjs +41 -0
- package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -0
- package/moj/components/password-reveal/password-reveal.mjs +36 -31
- package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
- package/moj/components/primary-navigation/_primary-navigation.scss +2 -0
- package/moj/components/primary-navigation/_primary-navigation.scss.map +1 -0
- package/moj/components/progress-bar/_progress-bar.scss +2 -0
- package/moj/components/progress-bar/_progress-bar.scss.map +1 -0
- package/moj/components/rich-text-editor/README.md +15 -9
- package/moj/components/rich-text-editor/_rich-text-editor.scss +2 -0
- package/moj/components/rich-text-editor/_rich-text-editor.scss.map +1 -0
- package/moj/components/rich-text-editor/rich-text-editor.bundle.js +145 -0
- package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -0
- package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +137 -0
- package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -0
- package/moj/components/rich-text-editor/rich-text-editor.mjs +124 -145
- package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
- package/moj/components/search/_search.scss +2 -0
- package/moj/components/search/_search.scss.map +1 -0
- package/moj/components/search-toggle/{search-toggle.scss → _search-toggle.scss} +2 -0
- package/moj/components/search-toggle/_search-toggle.scss.map +1 -0
- package/moj/components/search-toggle/search-toggle.bundle.js +54 -0
- package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -0
- package/moj/components/search-toggle/search-toggle.bundle.mjs +46 -0
- package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -0
- package/moj/components/search-toggle/search-toggle.mjs +40 -49
- package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
- package/moj/components/side-navigation/_side-navigation.scss +2 -0
- package/moj/components/side-navigation/_side-navigation.scss.map +1 -0
- package/moj/components/sortable-table/_sortable-table.scss +2 -2
- package/moj/components/sortable-table/_sortable-table.scss.map +1 -0
- package/moj/components/sortable-table/sortable-table.bundle.js +134 -0
- package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -0
- package/moj/components/sortable-table/sortable-table.bundle.mjs +126 -0
- package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -0
- package/moj/components/sortable-table/sortable-table.mjs +117 -130
- package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
- package/moj/components/sub-navigation/_sub-navigation.scss +2 -0
- package/moj/components/sub-navigation/_sub-navigation.scss.map +1 -0
- package/moj/components/tag/_tag.scss +2 -0
- package/moj/components/tag/_tag.scss.map +1 -0
- package/moj/components/task-list/_task-list.scss +2 -0
- package/moj/components/task-list/_task-list.scss.map +1 -0
- package/moj/components/ticket-panel/_ticket-panel.scss +2 -0
- package/moj/components/ticket-panel/_ticket-panel.scss.map +1 -0
- package/moj/components/timeline/_timeline.scss +2 -0
- package/moj/components/timeline/_timeline.scss.map +1 -0
- package/moj/filters/all.js +44 -22
- package/moj/helpers/_all.scss +2 -0
- package/moj/helpers/_all.scss.map +1 -0
- package/moj/helpers/_hidden.scss +2 -0
- package/moj/helpers/_hidden.scss.map +1 -0
- package/moj/helpers/_links.scss +2 -0
- package/moj/helpers/_links.scss.map +1 -0
- package/moj/{helpers.js → helpers.bundle.js} +37 -42
- package/moj/helpers.bundle.js.map +1 -0
- package/moj/helpers.bundle.mjs +179 -0
- package/moj/helpers.bundle.mjs.map +1 -0
- package/moj/helpers.mjs +52 -28
- package/moj/helpers.mjs.map +1 -1
- package/moj/init.js +11 -2
- package/moj/moj-frontend.min.css +1 -1
- package/moj/moj-frontend.min.css.map +1 -1
- package/moj/moj-frontend.min.js +1 -1
- package/moj/moj-frontend.min.js.map +1 -1
- package/moj/objects/_all.scss +2 -0
- package/moj/objects/_all.scss.map +1 -0
- package/moj/objects/_button-group.scss +2 -0
- package/moj/objects/_button-group.scss.map +1 -0
- package/moj/objects/_filter-layout.scss +2 -0
- package/moj/objects/_filter-layout.scss.map +1 -0
- package/moj/objects/_scrollable-pane.scss +2 -0
- package/moj/objects/_scrollable-pane.scss.map +1 -0
- package/moj/objects/_width-container.scss +2 -0
- package/moj/objects/_width-container.scss.map +1 -0
- package/moj/settings/_all.scss +2 -0
- package/moj/settings/_all.scss.map +1 -0
- package/moj/settings/_assets.scss +2 -0
- package/moj/settings/_assets.scss.map +1 -0
- package/moj/settings/_colours.scss +2 -0
- package/moj/settings/_colours.scss.map +1 -0
- package/moj/settings/_measurements.scss +2 -0
- package/moj/settings/_measurements.scss.map +1 -0
- package/moj/settings/_typography.scss +2 -0
- package/moj/settings/_typography.scss.map +1 -0
- package/moj/template.njk +13 -0
- package/moj/utilities/_all.scss +2 -0
- package/moj/utilities/_all.scss.map +1 -0
- package/moj/utilities/_hidden.scss +2 -0
- package/moj/utilities/_hidden.scss.map +1 -0
- package/moj/utilities/_width-container.scss +2 -0
- package/moj/utilities/_width-container.scss.map +1 -0
- package/moj/vendor/govuk-frontend/_base.scss +2 -0
- package/moj/vendor/govuk-frontend/_base.scss.map +1 -0
- package/moj/vendor/govuk-frontend/_index.scss +2 -0
- package/moj/vendor/govuk-frontend/_index.scss.map +1 -0
- package/moj/{version.js → version.bundle.js} +1 -1
- package/moj/version.bundle.js.map +1 -0
- package/moj/version.bundle.mjs +4 -0
- package/moj/version.bundle.mjs.map +1 -0
- package/moj/version.mjs.map +1 -1
- package/package.json +5 -6
- package/moj/all.jquery.min.js +0 -1
- package/moj/all.jquery.min.js.map +0 -1
- package/moj/all.js +0 -2662
- package/moj/all.js.map +0 -1
- package/moj/components/add-another/add-another.js +0 -115
- package/moj/components/add-another/add-another.js.map +0 -1
- package/moj/components/alert/alert.js +0 -356
- package/moj/components/alert/alert.js.map +0 -1
- package/moj/components/alert/alert.spec.helper.js.map +0 -1
- package/moj/components/button-menu/button-menu.js.map +0 -1
- package/moj/components/date-picker/date-picker.js.map +0 -1
- package/moj/components/filter-toggle-button/filter-toggle-button.js +0 -102
- package/moj/components/filter-toggle-button/filter-toggle-button.js.map +0 -1
- package/moj/components/form-validator/form-validator.js +0 -205
- package/moj/components/form-validator/form-validator.js.map +0 -1
- package/moj/components/multi-file-upload/multi-file-upload.js +0 -241
- package/moj/components/multi-file-upload/multi-file-upload.js.map +0 -1
- package/moj/components/multi-select/multi-select.js +0 -86
- package/moj/components/multi-select/multi-select.js.map +0 -1
- package/moj/components/password-reveal/password-reveal.js +0 -44
- package/moj/components/password-reveal/password-reveal.js.map +0 -1
- package/moj/components/rich-text-editor/rich-text-editor.js +0 -166
- package/moj/components/rich-text-editor/rich-text-editor.js.map +0 -1
- package/moj/components/search-toggle/search-toggle.js +0 -63
- package/moj/components/search-toggle/search-toggle.js.map +0 -1
- package/moj/components/sortable-table/sortable-table.js +0 -147
- package/moj/components/sortable-table/sortable-table.js.map +0 -1
- package/moj/helpers.js.map +0 -1
- package/moj/vendor/html5shiv.js +0 -326
- package/moj/vendor/jquery.js +0 -9300
- package/moj/version.js.map +0 -1
|
@@ -4,13 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
## Example
|
|
6
6
|
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
toolbar: { 'bold': true, 'italic': true, 'underline': true, 'bullets': true, 'numbers': true }
|
|
12
|
-
})
|
|
13
|
-
</script>
|
|
14
|
-
```
|
|
7
|
+
```mjs
|
|
8
|
+
import { RichTextEditor } from '@ministryofjustice/frontend'
|
|
9
|
+
|
|
10
|
+
const $richTextEditor = document.querySelector('.app-rich-text-editor')
|
|
15
11
|
|
|
16
|
-
|
|
12
|
+
new RichTextEditor({
|
|
13
|
+
textarea: $richTextEditor,
|
|
14
|
+
toolbar: {
|
|
15
|
+
bold: true,
|
|
16
|
+
italic: true,
|
|
17
|
+
underline: true,
|
|
18
|
+
bullets: true,
|
|
19
|
+
numbers: true
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/moj/components/rich-text-editor/_rich-text-editor.scss"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,uCAAuC;;AAEvC;;+EAE+E;;AAE/E;EACE,uBAAuB;EACvB,+BAA+B;AACjC;;AAEA;EACE,WAAW;EACX,YAAY;EACZ,iBAAiB;EACjB,WAAW;EACX,uCAAuC;EACvC,UAAU;EACV,4BAA4B;EAC5B,uCAAuC;EACvC,4BAA4B;EAC5B,4BAA4B;EAC5B,0BAA0B;EAC1B,qBAAqB;EACrB,mBAAmB;EACnB,eAAe;;EAEf;IACE,cAAc;EAChB;;EAEA,wCAAwC;EACxC;IACE,UAAU;IACV,SAAS;EACX;;EAEA;IACE,kBAAkB;IAClB,UAAU;IACV,aAAa;IACb,+BAA+B;IAC/B,qCAAqC;IACrC;;oCAEgC;EAClC;AACF;;AAEA;EACE,+DAA+D;AACjE;;AAEA;EACE,iEAAiE;AACnE;;AAEA;EACE,oEAAoE;AACtE;;AAEA;EACE,6BAA6B;EAC7B,yEAAyE;AAC3E;;AAEA;EACE,uEAAuE;AACzE;;AAEA;EACE,iBAAiB;EACjB,cAAc;EACd,gBAAgB;EAChB,aAAa;AACf","file":"_rich-text-editor.scss","sourcesContent":["@use \"../../settings/assets\" as *;\n@use \"../../vendor/govuk-frontend\" as *;\n\n/* ==========================================================================\n #RICH TEXT EDITOR\n ========================================================================== */\n\n.moj-rich-text-editor__toolbar {\n @include govuk-clearfix;\n margin-bottom: govuk-spacing(2);\n}\n\n.moj-rich-text-editor__toolbar-button {\n width: 40px;\n height: 40px;\n margin-left: -2px;\n float: left;\n border: 2px solid govuk-colour(\"black\");\n outline: 0;\n color: govuk-colour(\"black\");\n background-color: govuk-colour(\"white\");\n background-repeat: no-repeat;\n background-position: 50% 50%;\n background-size: 40px 40px;\n text-decoration: none;\n vertical-align: top;\n cursor: pointer;\n\n &:first-child {\n margin-left: 0;\n }\n\n // Fix unwanted button padding in Firefox\n &::-moz-focus-inner {\n padding: 0;\n border: 0;\n }\n\n &:focus {\n position: relative;\n z-index: 2;\n outline: none;\n color: $govuk-focus-text-colour;\n background-color: $govuk-focus-colour;\n box-shadow:\n 0 -2px $govuk-focus-colour,\n 0 4px $govuk-focus-text-colour;\n }\n}\n\n.moj-rich-text-editor__toolbar-button--bold {\n background-image: url(#{$moj-images-path}icon-wysiwyg-bold.svg);\n}\n\n.moj-rich-text-editor__toolbar-button--italic {\n background-image: url(#{$moj-images-path}icon-wysiwyg-italic.svg);\n}\n\n.moj-rich-text-editor__toolbar-button--underline {\n background-image: url(#{$moj-images-path}icon-wysiwyg-underline.svg);\n}\n\n.moj-rich-text-editor__toolbar-button--unordered-list {\n margin-left: govuk-spacing(2);\n background-image: url(#{$moj-images-path}icon-wysiwyg-unordered-list.svg);\n}\n\n.moj-rich-text-editor__toolbar-button--ordered-list {\n background-image: url(#{$moj-images-path}icon-wysiwyg-ordered-list.svg);\n}\n\n.moj-rich-text-editor__content {\n min-height: 130px;\n overflow: auto;\n resize: vertical;\n outline: none;\n}\n"]}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}));
|
|
5
|
+
})(this, (function (exports) { 'use strict';
|
|
6
|
+
|
|
7
|
+
class RichTextEditor {
|
|
8
|
+
/**
|
|
9
|
+
* @param {RichTextEditorConfig} options
|
|
10
|
+
*/
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
const {
|
|
13
|
+
textarea
|
|
14
|
+
} = options;
|
|
15
|
+
if (!textarea || !textarea.parentElement || !(textarea instanceof HTMLTextAreaElement) || !('contentEditable' in document.documentElement)) {
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
options.toolbar = options.toolbar || {
|
|
19
|
+
bold: false,
|
|
20
|
+
italic: false,
|
|
21
|
+
underline: false,
|
|
22
|
+
bullets: true,
|
|
23
|
+
numbers: true
|
|
24
|
+
};
|
|
25
|
+
this.textarea = textarea;
|
|
26
|
+
this.container = this.textarea.parentElement;
|
|
27
|
+
this.options = options;
|
|
28
|
+
if (this.container.hasAttribute('data-rich-text-editor-init')) {
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
this.container.setAttribute('data-rich-text-editor-init', '');
|
|
32
|
+
this.createToolbar();
|
|
33
|
+
this.hideDefault();
|
|
34
|
+
this.configureToolbar();
|
|
35
|
+
this.keys = {
|
|
36
|
+
left: 37,
|
|
37
|
+
right: 39,
|
|
38
|
+
up: 38,
|
|
39
|
+
down: 40
|
|
40
|
+
};
|
|
41
|
+
this.content.addEventListener('input', this.onEditorInput.bind(this));
|
|
42
|
+
this.container.querySelector('label').addEventListener('click', this.onLabelClick.bind(this));
|
|
43
|
+
this.toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this));
|
|
44
|
+
}
|
|
45
|
+
onToolbarKeydown(event) {
|
|
46
|
+
let focusableButton;
|
|
47
|
+
switch (event.keyCode) {
|
|
48
|
+
case this.keys.right:
|
|
49
|
+
case this.keys.down:
|
|
50
|
+
{
|
|
51
|
+
focusableButton = this.buttons.find(button => button.getAttribute('tabindex') === '0');
|
|
52
|
+
const nextButton = focusableButton.nextElementSibling;
|
|
53
|
+
if (nextButton instanceof HTMLButtonElement) {
|
|
54
|
+
nextButton.focus();
|
|
55
|
+
focusableButton.setAttribute('tabindex', '-1');
|
|
56
|
+
nextButton.setAttribute('tabindex', '0');
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case this.keys.left:
|
|
61
|
+
case this.keys.up:
|
|
62
|
+
{
|
|
63
|
+
focusableButton = this.buttons.find(button => button.getAttribute('tabindex') === '0');
|
|
64
|
+
const previousButton = focusableButton.previousElementSibling;
|
|
65
|
+
if (previousButton instanceof HTMLButtonElement) {
|
|
66
|
+
previousButton.focus();
|
|
67
|
+
focusableButton.setAttribute('tabindex', '-1');
|
|
68
|
+
previousButton.setAttribute('tabindex', '0');
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
getToolbarHtml() {
|
|
75
|
+
let html = '';
|
|
76
|
+
html += '<div class="moj-rich-text-editor__toolbar" role="toolbar">';
|
|
77
|
+
if (this.options.toolbar.bold) {
|
|
78
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold" type="button" data-command="bold"><span class="govuk-visually-hidden">Bold</span></button>';
|
|
79
|
+
}
|
|
80
|
+
if (this.options.toolbar.italic) {
|
|
81
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic" type="button" data-command="italic"><span class="govuk-visually-hidden">Italic</span></button>';
|
|
82
|
+
}
|
|
83
|
+
if (this.options.toolbar.underline) {
|
|
84
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline" type="button" data-command="underline"><span class="govuk-visually-hidden">Underline</span></button>';
|
|
85
|
+
}
|
|
86
|
+
if (this.options.toolbar.bullets) {
|
|
87
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list" type="button" data-command="insertUnorderedList"><span class="govuk-visually-hidden">Unordered list</span></button>';
|
|
88
|
+
}
|
|
89
|
+
if (this.options.toolbar.numbers) {
|
|
90
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list" type="button" data-command="insertOrderedList"><span class="govuk-visually-hidden">Ordered list</span></button>';
|
|
91
|
+
}
|
|
92
|
+
html += '</div>';
|
|
93
|
+
return html;
|
|
94
|
+
}
|
|
95
|
+
getEnhancedHtml() {
|
|
96
|
+
return `${this.getToolbarHtml()}<div class="govuk-textarea moj-rich-text-editor__content" contenteditable="true" spellcheck="false"></div>`;
|
|
97
|
+
}
|
|
98
|
+
hideDefault() {
|
|
99
|
+
this.textarea.classList.add('govuk-visually-hidden');
|
|
100
|
+
this.textarea.setAttribute('aria-hidden', 'true');
|
|
101
|
+
this.textarea.setAttribute('tabindex', '-1');
|
|
102
|
+
}
|
|
103
|
+
createToolbar() {
|
|
104
|
+
this.toolbar = document.createElement('div');
|
|
105
|
+
this.toolbar.className = 'moj-rich-text-editor';
|
|
106
|
+
this.toolbar.innerHTML = this.getEnhancedHtml();
|
|
107
|
+
this.container.append(this.toolbar);
|
|
108
|
+
this.content = /** @type {HTMLDivElement} */
|
|
109
|
+
this.container.querySelector('.moj-rich-text-editor__content');
|
|
110
|
+
this.content.innerHTML = this.$textarea.value;
|
|
111
|
+
}
|
|
112
|
+
configureToolbar() {
|
|
113
|
+
this.buttons = Array.from(/** @type {NodeListOf<HTMLButtonElement>} */
|
|
114
|
+
this.container.querySelectorAll('.moj-rich-text-editor__toolbar-button'));
|
|
115
|
+
this.buttons.forEach((button, index) => {
|
|
116
|
+
button.setAttribute('tabindex', !index ? '0' : '-1');
|
|
117
|
+
button.addEventListener('click', this.onButtonClick.bind(this));
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
onButtonClick(event) {
|
|
121
|
+
if (!(event.currentTarget instanceof HTMLElement)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
document.execCommand(event.currentTarget.getAttribute('data-command'), false, undefined);
|
|
125
|
+
}
|
|
126
|
+
getContent() {
|
|
127
|
+
return this.content.innerHTML;
|
|
128
|
+
}
|
|
129
|
+
onEditorInput() {
|
|
130
|
+
this.updateTextarea();
|
|
131
|
+
}
|
|
132
|
+
updateTextarea() {
|
|
133
|
+
document.execCommand('defaultParagraphSeparator', false, 'p');
|
|
134
|
+
this.textarea.value = this.getContent();
|
|
135
|
+
}
|
|
136
|
+
onLabelClick(event) {
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
this.content.focus();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
exports.RichTextEditor = RichTextEditor;
|
|
143
|
+
|
|
144
|
+
}));
|
|
145
|
+
//# sourceMappingURL=rich-text-editor.bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text-editor.bundle.js","sources":["../../../../src/moj/components/rich-text-editor/rich-text-editor.mjs"],"sourcesContent":["export class RichTextEditor {\n /**\n * @param {RichTextEditorConfig} options\n */\n constructor(options = {}) {\n const { textarea } = options\n\n if (\n !textarea ||\n !textarea.parentElement ||\n !(textarea instanceof HTMLTextAreaElement) ||\n !('contentEditable' in document.documentElement)\n ) {\n return this\n }\n\n options.toolbar = options.toolbar || {\n bold: false,\n italic: false,\n underline: false,\n bullets: true,\n numbers: true\n }\n\n this.textarea = textarea\n this.container = this.textarea.parentElement\n this.options = options\n\n if (this.container.hasAttribute('data-rich-text-editor-init')) {\n return this\n }\n\n this.container.setAttribute('data-rich-text-editor-init', '')\n\n this.createToolbar()\n this.hideDefault()\n this.configureToolbar()\n\n this.keys = {\n left: 37,\n right: 39,\n up: 38,\n down: 40\n }\n\n this.content.addEventListener('input', this.onEditorInput.bind(this))\n\n this.container\n .querySelector('label')\n .addEventListener('click', this.onLabelClick.bind(this))\n\n this.toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this))\n }\n\n onToolbarKeydown(event) {\n let focusableButton\n switch (event.keyCode) {\n case this.keys.right:\n case this.keys.down: {\n focusableButton = this.buttons.find(\n (button) => button.getAttribute('tabindex') === '0'\n )\n const nextButton = focusableButton.nextElementSibling\n if (nextButton instanceof HTMLButtonElement) {\n nextButton.focus()\n focusableButton.setAttribute('tabindex', '-1')\n nextButton.setAttribute('tabindex', '0')\n }\n break\n }\n case this.keys.left:\n case this.keys.up: {\n focusableButton = this.buttons.find(\n (button) => button.getAttribute('tabindex') === '0'\n )\n const previousButton = focusableButton.previousElementSibling\n if (previousButton instanceof HTMLButtonElement) {\n previousButton.focus()\n focusableButton.setAttribute('tabindex', '-1')\n previousButton.setAttribute('tabindex', '0')\n }\n break\n }\n }\n }\n\n getToolbarHtml() {\n let html = ''\n\n html += '<div class=\"moj-rich-text-editor__toolbar\" role=\"toolbar\">'\n\n if (this.options.toolbar.bold) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold\" type=\"button\" data-command=\"bold\"><span class=\"govuk-visually-hidden\">Bold</span></button>'\n }\n\n if (this.options.toolbar.italic) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic\" type=\"button\" data-command=\"italic\"><span class=\"govuk-visually-hidden\">Italic</span></button>'\n }\n\n if (this.options.toolbar.underline) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline\" type=\"button\" data-command=\"underline\"><span class=\"govuk-visually-hidden\">Underline</span></button>'\n }\n\n if (this.options.toolbar.bullets) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list\" type=\"button\" data-command=\"insertUnorderedList\"><span class=\"govuk-visually-hidden\">Unordered list</span></button>'\n }\n\n if (this.options.toolbar.numbers) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list\" type=\"button\" data-command=\"insertOrderedList\"><span class=\"govuk-visually-hidden\">Ordered list</span></button>'\n }\n\n html += '</div>'\n return html\n }\n\n getEnhancedHtml() {\n return `${this.getToolbarHtml()}<div class=\"govuk-textarea moj-rich-text-editor__content\" contenteditable=\"true\" spellcheck=\"false\"></div>`\n }\n\n hideDefault() {\n this.textarea.classList.add('govuk-visually-hidden')\n this.textarea.setAttribute('aria-hidden', 'true')\n this.textarea.setAttribute('tabindex', '-1')\n }\n\n createToolbar() {\n this.toolbar = document.createElement('div')\n this.toolbar.className = 'moj-rich-text-editor'\n this.toolbar.innerHTML = this.getEnhancedHtml()\n this.container.append(this.toolbar)\n\n this.content = /** @type {HTMLDivElement} */ (\n this.container.querySelector('.moj-rich-text-editor__content')\n )\n\n this.content.innerHTML = this.$textarea.value\n }\n\n configureToolbar() {\n this.buttons = Array.from(\n /** @type {NodeListOf<HTMLButtonElement>} */\n (this.container.querySelectorAll('.moj-rich-text-editor__toolbar-button'))\n )\n\n this.buttons.forEach((button, index) => {\n button.setAttribute('tabindex', !index ? '0' : '-1')\n button.addEventListener('click', this.onButtonClick.bind(this))\n })\n }\n\n onButtonClick(event) {\n if (!(event.currentTarget instanceof HTMLElement)) {\n return\n }\n\n document.execCommand(\n event.currentTarget.getAttribute('data-command'),\n false,\n undefined\n )\n }\n\n getContent() {\n return this.content.innerHTML\n }\n\n onEditorInput() {\n this.updateTextarea()\n }\n\n updateTextarea() {\n document.execCommand('defaultParagraphSeparator', false, 'p')\n this.textarea.value = this.getContent()\n }\n\n onLabelClick(event) {\n event.preventDefault()\n this.content.focus()\n }\n}\n"],"names":["RichTextEditor","constructor","options","textarea","parentElement","HTMLTextAreaElement","document","documentElement","toolbar","bold","italic","underline","bullets","numbers","container","hasAttribute","setAttribute","createToolbar","hideDefault","configureToolbar","keys","left","right","up","down","content","addEventListener","onEditorInput","bind","querySelector","onLabelClick","onToolbarKeydown","event","focusableButton","keyCode","buttons","find","button","getAttribute","nextButton","nextElementSibling","HTMLButtonElement","focus","previousButton","previousElementSibling","getToolbarHtml","html","getEnhancedHtml","classList","add","createElement","className","innerHTML","append","$textarea","value","Array","from","querySelectorAll","forEach","index","onButtonClick","currentTarget","HTMLElement","execCommand","undefined","getContent","updateTextarea","preventDefault"],"mappings":";;;;;;EAAO,MAAMA,cAAc,CAAC;EAC1B;EACF;EACA;EACEC,EAAAA,WAAWA,CAACC,OAAO,GAAG,EAAE,EAAE;MACxB,MAAM;EAAEC,MAAAA;EAAS,KAAC,GAAGD,OAAO;MAE5B,IACE,CAACC,QAAQ,IACT,CAACA,QAAQ,CAACC,aAAa,IACvB,EAAED,QAAQ,YAAYE,mBAAmB,CAAC,IAC1C,EAAE,iBAAiB,IAAIC,QAAQ,CAACC,eAAe,CAAC,EAChD;EACA,MAAA,OAAO,IAAI;EACb;EAEAL,IAAAA,OAAO,CAACM,OAAO,GAAGN,OAAO,CAACM,OAAO,IAAI;EACnCC,MAAAA,IAAI,EAAE,KAAK;EACXC,MAAAA,MAAM,EAAE,KAAK;EACbC,MAAAA,SAAS,EAAE,KAAK;EAChBC,MAAAA,OAAO,EAAE,IAAI;EACbC,MAAAA,OAAO,EAAE;OACV;MAED,IAAI,CAACV,QAAQ,GAAGA,QAAQ;EACxB,IAAA,IAAI,CAACW,SAAS,GAAG,IAAI,CAACX,QAAQ,CAACC,aAAa;MAC5C,IAAI,CAACF,OAAO,GAAGA,OAAO;MAEtB,IAAI,IAAI,CAACY,SAAS,CAACC,YAAY,CAAC,4BAA4B,CAAC,EAAE;EAC7D,MAAA,OAAO,IAAI;EACb;MAEA,IAAI,CAACD,SAAS,CAACE,YAAY,CAAC,4BAA4B,EAAE,EAAE,CAAC;MAE7D,IAAI,CAACC,aAAa,EAAE;MACpB,IAAI,CAACC,WAAW,EAAE;MAClB,IAAI,CAACC,gBAAgB,EAAE;MAEvB,IAAI,CAACC,IAAI,GAAG;EACVC,MAAAA,IAAI,EAAE,EAAE;EACRC,MAAAA,KAAK,EAAE,EAAE;EACTC,MAAAA,EAAE,EAAE,EAAE;EACNC,MAAAA,IAAI,EAAE;OACP;EAED,IAAA,IAAI,CAACC,OAAO,CAACC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACC,aAAa,CAACC,IAAI,CAAC,IAAI,CAAC,CAAC;MAErE,IAAI,CAACd,SAAS,CACXe,aAAa,CAAC,OAAO,CAAC,CACtBH,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACI,YAAY,CAACF,IAAI,CAAC,IAAI,CAAC,CAAC;EAE1D,IAAA,IAAI,CAACpB,OAAO,CAACkB,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAACK,gBAAgB,CAACH,IAAI,CAAC,IAAI,CAAC,CAAC;EAC5E;IAEAG,gBAAgBA,CAACC,KAAK,EAAE;EACtB,IAAA,IAAIC,eAAe;MACnB,QAAQD,KAAK,CAACE,OAAO;EACnB,MAAA,KAAK,IAAI,CAACd,IAAI,CAACE,KAAK;EACpB,MAAA,KAAK,IAAI,CAACF,IAAI,CAACI,IAAI;EAAE,QAAA;EACnBS,UAAAA,eAAe,GAAG,IAAI,CAACE,OAAO,CAACC,IAAI,CAChCC,MAAM,IAAKA,MAAM,CAACC,YAAY,CAAC,UAAU,CAAC,KAAK,GAClD,CAAC;EACD,UAAA,MAAMC,UAAU,GAAGN,eAAe,CAACO,kBAAkB;YACrD,IAAID,UAAU,YAAYE,iBAAiB,EAAE;cAC3CF,UAAU,CAACG,KAAK,EAAE;EAClBT,YAAAA,eAAe,CAACjB,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;EAC9CuB,YAAAA,UAAU,CAACvB,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC;EAC1C;EACA,UAAA;EACF;EACA,MAAA,KAAK,IAAI,CAACI,IAAI,CAACC,IAAI;EACnB,MAAA,KAAK,IAAI,CAACD,IAAI,CAACG,EAAE;EAAE,QAAA;EACjBU,UAAAA,eAAe,GAAG,IAAI,CAACE,OAAO,CAACC,IAAI,CAChCC,MAAM,IAAKA,MAAM,CAACC,YAAY,CAAC,UAAU,CAAC,KAAK,GAClD,CAAC;EACD,UAAA,MAAMK,cAAc,GAAGV,eAAe,CAACW,sBAAsB;YAC7D,IAAID,cAAc,YAAYF,iBAAiB,EAAE;cAC/CE,cAAc,CAACD,KAAK,EAAE;EACtBT,YAAAA,eAAe,CAACjB,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;EAC9C2B,YAAAA,cAAc,CAAC3B,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC;EAC9C;EACA,UAAA;EACF;EACF;EACF;EAEA6B,EAAAA,cAAcA,GAAG;MACf,IAAIC,IAAI,GAAG,EAAE;EAEbA,IAAAA,IAAI,IAAI,4DAA4D;EAEpE,IAAA,IAAI,IAAI,CAAC5C,OAAO,CAACM,OAAO,CAACC,IAAI,EAAE;EAC7BqC,MAAAA,IAAI,IACF,4LAA4L;EAChM;EAEA,IAAA,IAAI,IAAI,CAAC5C,OAAO,CAACM,OAAO,CAACE,MAAM,EAAE;EAC/BoC,MAAAA,IAAI,IACF,kMAAkM;EACtM;EAEA,IAAA,IAAI,IAAI,CAAC5C,OAAO,CAACM,OAAO,CAACG,SAAS,EAAE;EAClCmC,MAAAA,IAAI,IACF,2MAA2M;EAC/M;EAEA,IAAA,IAAI,IAAI,CAAC5C,OAAO,CAACM,OAAO,CAACI,OAAO,EAAE;EAChCkC,MAAAA,IAAI,IACF,+NAA+N;EACnO;EAEA,IAAA,IAAI,IAAI,CAAC5C,OAAO,CAACM,OAAO,CAACK,OAAO,EAAE;EAChCiC,MAAAA,IAAI,IACF,yNAAyN;EAC7N;EAEAA,IAAAA,IAAI,IAAI,QAAQ;EAChB,IAAA,OAAOA,IAAI;EACb;EAEAC,EAAAA,eAAeA,GAAG;EAChB,IAAA,OAAO,GAAG,IAAI,CAACF,cAAc,EAAE,CAA4G,0GAAA,CAAA;EAC7I;EAEA3B,EAAAA,WAAWA,GAAG;MACZ,IAAI,CAACf,QAAQ,CAAC6C,SAAS,CAACC,GAAG,CAAC,uBAAuB,CAAC;MACpD,IAAI,CAAC9C,QAAQ,CAACa,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC;MACjD,IAAI,CAACb,QAAQ,CAACa,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;EAC9C;EAEAC,EAAAA,aAAaA,GAAG;MACd,IAAI,CAACT,OAAO,GAAGF,QAAQ,CAAC4C,aAAa,CAAC,KAAK,CAAC;EAC5C,IAAA,IAAI,CAAC1C,OAAO,CAAC2C,SAAS,GAAG,sBAAsB;MAC/C,IAAI,CAAC3C,OAAO,CAAC4C,SAAS,GAAG,IAAI,CAACL,eAAe,EAAE;MAC/C,IAAI,CAACjC,SAAS,CAACuC,MAAM,CAAC,IAAI,CAAC7C,OAAO,CAAC;MAEnC,IAAI,CAACiB,OAAO;EACV,IAAA,IAAI,CAACX,SAAS,CAACe,aAAa,CAAC,gCAAgC,CAC9D;MAED,IAAI,CAACJ,OAAO,CAAC2B,SAAS,GAAG,IAAI,CAACE,SAAS,CAACC,KAAK;EAC/C;EAEApC,EAAAA,gBAAgBA,GAAG;EACjB,IAAA,IAAI,CAACgB,OAAO,GAAGqB,KAAK,CAACC,IAAI;EAEtB,IAAA,IAAI,CAAC3C,SAAS,CAAC4C,gBAAgB,CAAC,uCAAuC,CAC1E,CAAC;MAED,IAAI,CAACvB,OAAO,CAACwB,OAAO,CAAC,CAACtB,MAAM,EAAEuB,KAAK,KAAK;QACtCvB,MAAM,CAACrB,YAAY,CAAC,UAAU,EAAE,CAAC4C,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC;EACpDvB,MAAAA,MAAM,CAACX,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACmC,aAAa,CAACjC,IAAI,CAAC,IAAI,CAAC,CAAC;EACjE,KAAC,CAAC;EACJ;IAEAiC,aAAaA,CAAC7B,KAAK,EAAE;EACnB,IAAA,IAAI,EAAEA,KAAK,CAAC8B,aAAa,YAAYC,WAAW,CAAC,EAAE;EACjD,MAAA;EACF;EAEAzD,IAAAA,QAAQ,CAAC0D,WAAW,CAClBhC,KAAK,CAAC8B,aAAa,CAACxB,YAAY,CAAC,cAAc,CAAC,EAChD,KAAK,EACL2B,SACF,CAAC;EACH;EAEAC,EAAAA,UAAUA,GAAG;EACX,IAAA,OAAO,IAAI,CAACzC,OAAO,CAAC2B,SAAS;EAC/B;EAEAzB,EAAAA,aAAaA,GAAG;MACd,IAAI,CAACwC,cAAc,EAAE;EACvB;EAEAA,EAAAA,cAAcA,GAAG;MACf7D,QAAQ,CAAC0D,WAAW,CAAC,2BAA2B,EAAE,KAAK,EAAE,GAAG,CAAC;MAC7D,IAAI,CAAC7D,QAAQ,CAACoD,KAAK,GAAG,IAAI,CAACW,UAAU,EAAE;EACzC;IAEApC,YAAYA,CAACE,KAAK,EAAE;MAClBA,KAAK,CAACoC,cAAc,EAAE;EACtB,IAAA,IAAI,CAAC3C,OAAO,CAACiB,KAAK,EAAE;EACtB;EACF;;;;;;;;"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
class RichTextEditor {
|
|
2
|
+
/**
|
|
3
|
+
* @param {RichTextEditorConfig} options
|
|
4
|
+
*/
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
const {
|
|
7
|
+
textarea
|
|
8
|
+
} = options;
|
|
9
|
+
if (!textarea || !textarea.parentElement || !(textarea instanceof HTMLTextAreaElement) || !('contentEditable' in document.documentElement)) {
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
options.toolbar = options.toolbar || {
|
|
13
|
+
bold: false,
|
|
14
|
+
italic: false,
|
|
15
|
+
underline: false,
|
|
16
|
+
bullets: true,
|
|
17
|
+
numbers: true
|
|
18
|
+
};
|
|
19
|
+
this.textarea = textarea;
|
|
20
|
+
this.container = this.textarea.parentElement;
|
|
21
|
+
this.options = options;
|
|
22
|
+
if (this.container.hasAttribute('data-rich-text-editor-init')) {
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
this.container.setAttribute('data-rich-text-editor-init', '');
|
|
26
|
+
this.createToolbar();
|
|
27
|
+
this.hideDefault();
|
|
28
|
+
this.configureToolbar();
|
|
29
|
+
this.keys = {
|
|
30
|
+
left: 37,
|
|
31
|
+
right: 39,
|
|
32
|
+
up: 38,
|
|
33
|
+
down: 40
|
|
34
|
+
};
|
|
35
|
+
this.content.addEventListener('input', this.onEditorInput.bind(this));
|
|
36
|
+
this.container.querySelector('label').addEventListener('click', this.onLabelClick.bind(this));
|
|
37
|
+
this.toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this));
|
|
38
|
+
}
|
|
39
|
+
onToolbarKeydown(event) {
|
|
40
|
+
let focusableButton;
|
|
41
|
+
switch (event.keyCode) {
|
|
42
|
+
case this.keys.right:
|
|
43
|
+
case this.keys.down:
|
|
44
|
+
{
|
|
45
|
+
focusableButton = this.buttons.find(button => button.getAttribute('tabindex') === '0');
|
|
46
|
+
const nextButton = focusableButton.nextElementSibling;
|
|
47
|
+
if (nextButton instanceof HTMLButtonElement) {
|
|
48
|
+
nextButton.focus();
|
|
49
|
+
focusableButton.setAttribute('tabindex', '-1');
|
|
50
|
+
nextButton.setAttribute('tabindex', '0');
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case this.keys.left:
|
|
55
|
+
case this.keys.up:
|
|
56
|
+
{
|
|
57
|
+
focusableButton = this.buttons.find(button => button.getAttribute('tabindex') === '0');
|
|
58
|
+
const previousButton = focusableButton.previousElementSibling;
|
|
59
|
+
if (previousButton instanceof HTMLButtonElement) {
|
|
60
|
+
previousButton.focus();
|
|
61
|
+
focusableButton.setAttribute('tabindex', '-1');
|
|
62
|
+
previousButton.setAttribute('tabindex', '0');
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
getToolbarHtml() {
|
|
69
|
+
let html = '';
|
|
70
|
+
html += '<div class="moj-rich-text-editor__toolbar" role="toolbar">';
|
|
71
|
+
if (this.options.toolbar.bold) {
|
|
72
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold" type="button" data-command="bold"><span class="govuk-visually-hidden">Bold</span></button>';
|
|
73
|
+
}
|
|
74
|
+
if (this.options.toolbar.italic) {
|
|
75
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic" type="button" data-command="italic"><span class="govuk-visually-hidden">Italic</span></button>';
|
|
76
|
+
}
|
|
77
|
+
if (this.options.toolbar.underline) {
|
|
78
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline" type="button" data-command="underline"><span class="govuk-visually-hidden">Underline</span></button>';
|
|
79
|
+
}
|
|
80
|
+
if (this.options.toolbar.bullets) {
|
|
81
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list" type="button" data-command="insertUnorderedList"><span class="govuk-visually-hidden">Unordered list</span></button>';
|
|
82
|
+
}
|
|
83
|
+
if (this.options.toolbar.numbers) {
|
|
84
|
+
html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list" type="button" data-command="insertOrderedList"><span class="govuk-visually-hidden">Ordered list</span></button>';
|
|
85
|
+
}
|
|
86
|
+
html += '</div>';
|
|
87
|
+
return html;
|
|
88
|
+
}
|
|
89
|
+
getEnhancedHtml() {
|
|
90
|
+
return `${this.getToolbarHtml()}<div class="govuk-textarea moj-rich-text-editor__content" contenteditable="true" spellcheck="false"></div>`;
|
|
91
|
+
}
|
|
92
|
+
hideDefault() {
|
|
93
|
+
this.textarea.classList.add('govuk-visually-hidden');
|
|
94
|
+
this.textarea.setAttribute('aria-hidden', 'true');
|
|
95
|
+
this.textarea.setAttribute('tabindex', '-1');
|
|
96
|
+
}
|
|
97
|
+
createToolbar() {
|
|
98
|
+
this.toolbar = document.createElement('div');
|
|
99
|
+
this.toolbar.className = 'moj-rich-text-editor';
|
|
100
|
+
this.toolbar.innerHTML = this.getEnhancedHtml();
|
|
101
|
+
this.container.append(this.toolbar);
|
|
102
|
+
this.content = /** @type {HTMLDivElement} */
|
|
103
|
+
this.container.querySelector('.moj-rich-text-editor__content');
|
|
104
|
+
this.content.innerHTML = this.$textarea.value;
|
|
105
|
+
}
|
|
106
|
+
configureToolbar() {
|
|
107
|
+
this.buttons = Array.from(/** @type {NodeListOf<HTMLButtonElement>} */
|
|
108
|
+
this.container.querySelectorAll('.moj-rich-text-editor__toolbar-button'));
|
|
109
|
+
this.buttons.forEach((button, index) => {
|
|
110
|
+
button.setAttribute('tabindex', !index ? '0' : '-1');
|
|
111
|
+
button.addEventListener('click', this.onButtonClick.bind(this));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
onButtonClick(event) {
|
|
115
|
+
if (!(event.currentTarget instanceof HTMLElement)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
document.execCommand(event.currentTarget.getAttribute('data-command'), false, undefined);
|
|
119
|
+
}
|
|
120
|
+
getContent() {
|
|
121
|
+
return this.content.innerHTML;
|
|
122
|
+
}
|
|
123
|
+
onEditorInput() {
|
|
124
|
+
this.updateTextarea();
|
|
125
|
+
}
|
|
126
|
+
updateTextarea() {
|
|
127
|
+
document.execCommand('defaultParagraphSeparator', false, 'p');
|
|
128
|
+
this.textarea.value = this.getContent();
|
|
129
|
+
}
|
|
130
|
+
onLabelClick(event) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
this.content.focus();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { RichTextEditor };
|
|
137
|
+
//# sourceMappingURL=rich-text-editor.bundle.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text-editor.bundle.mjs","sources":["../../../../src/moj/components/rich-text-editor/rich-text-editor.mjs"],"sourcesContent":["export class RichTextEditor {\n /**\n * @param {RichTextEditorConfig} options\n */\n constructor(options = {}) {\n const { textarea } = options\n\n if (\n !textarea ||\n !textarea.parentElement ||\n !(textarea instanceof HTMLTextAreaElement) ||\n !('contentEditable' in document.documentElement)\n ) {\n return this\n }\n\n options.toolbar = options.toolbar || {\n bold: false,\n italic: false,\n underline: false,\n bullets: true,\n numbers: true\n }\n\n this.textarea = textarea\n this.container = this.textarea.parentElement\n this.options = options\n\n if (this.container.hasAttribute('data-rich-text-editor-init')) {\n return this\n }\n\n this.container.setAttribute('data-rich-text-editor-init', '')\n\n this.createToolbar()\n this.hideDefault()\n this.configureToolbar()\n\n this.keys = {\n left: 37,\n right: 39,\n up: 38,\n down: 40\n }\n\n this.content.addEventListener('input', this.onEditorInput.bind(this))\n\n this.container\n .querySelector('label')\n .addEventListener('click', this.onLabelClick.bind(this))\n\n this.toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this))\n }\n\n onToolbarKeydown(event) {\n let focusableButton\n switch (event.keyCode) {\n case this.keys.right:\n case this.keys.down: {\n focusableButton = this.buttons.find(\n (button) => button.getAttribute('tabindex') === '0'\n )\n const nextButton = focusableButton.nextElementSibling\n if (nextButton instanceof HTMLButtonElement) {\n nextButton.focus()\n focusableButton.setAttribute('tabindex', '-1')\n nextButton.setAttribute('tabindex', '0')\n }\n break\n }\n case this.keys.left:\n case this.keys.up: {\n focusableButton = this.buttons.find(\n (button) => button.getAttribute('tabindex') === '0'\n )\n const previousButton = focusableButton.previousElementSibling\n if (previousButton instanceof HTMLButtonElement) {\n previousButton.focus()\n focusableButton.setAttribute('tabindex', '-1')\n previousButton.setAttribute('tabindex', '0')\n }\n break\n }\n }\n }\n\n getToolbarHtml() {\n let html = ''\n\n html += '<div class=\"moj-rich-text-editor__toolbar\" role=\"toolbar\">'\n\n if (this.options.toolbar.bold) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold\" type=\"button\" data-command=\"bold\"><span class=\"govuk-visually-hidden\">Bold</span></button>'\n }\n\n if (this.options.toolbar.italic) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic\" type=\"button\" data-command=\"italic\"><span class=\"govuk-visually-hidden\">Italic</span></button>'\n }\n\n if (this.options.toolbar.underline) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline\" type=\"button\" data-command=\"underline\"><span class=\"govuk-visually-hidden\">Underline</span></button>'\n }\n\n if (this.options.toolbar.bullets) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list\" type=\"button\" data-command=\"insertUnorderedList\"><span class=\"govuk-visually-hidden\">Unordered list</span></button>'\n }\n\n if (this.options.toolbar.numbers) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list\" type=\"button\" data-command=\"insertOrderedList\"><span class=\"govuk-visually-hidden\">Ordered list</span></button>'\n }\n\n html += '</div>'\n return html\n }\n\n getEnhancedHtml() {\n return `${this.getToolbarHtml()}<div class=\"govuk-textarea moj-rich-text-editor__content\" contenteditable=\"true\" spellcheck=\"false\"></div>`\n }\n\n hideDefault() {\n this.textarea.classList.add('govuk-visually-hidden')\n this.textarea.setAttribute('aria-hidden', 'true')\n this.textarea.setAttribute('tabindex', '-1')\n }\n\n createToolbar() {\n this.toolbar = document.createElement('div')\n this.toolbar.className = 'moj-rich-text-editor'\n this.toolbar.innerHTML = this.getEnhancedHtml()\n this.container.append(this.toolbar)\n\n this.content = /** @type {HTMLDivElement} */ (\n this.container.querySelector('.moj-rich-text-editor__content')\n )\n\n this.content.innerHTML = this.$textarea.value\n }\n\n configureToolbar() {\n this.buttons = Array.from(\n /** @type {NodeListOf<HTMLButtonElement>} */\n (this.container.querySelectorAll('.moj-rich-text-editor__toolbar-button'))\n )\n\n this.buttons.forEach((button, index) => {\n button.setAttribute('tabindex', !index ? '0' : '-1')\n button.addEventListener('click', this.onButtonClick.bind(this))\n })\n }\n\n onButtonClick(event) {\n if (!(event.currentTarget instanceof HTMLElement)) {\n return\n }\n\n document.execCommand(\n event.currentTarget.getAttribute('data-command'),\n false,\n undefined\n )\n }\n\n getContent() {\n return this.content.innerHTML\n }\n\n onEditorInput() {\n this.updateTextarea()\n }\n\n updateTextarea() {\n document.execCommand('defaultParagraphSeparator', false, 'p')\n this.textarea.value = this.getContent()\n }\n\n onLabelClick(event) {\n event.preventDefault()\n this.content.focus()\n }\n}\n"],"names":["RichTextEditor","constructor","options","textarea","parentElement","HTMLTextAreaElement","document","documentElement","toolbar","bold","italic","underline","bullets","numbers","container","hasAttribute","setAttribute","createToolbar","hideDefault","configureToolbar","keys","left","right","up","down","content","addEventListener","onEditorInput","bind","querySelector","onLabelClick","onToolbarKeydown","event","focusableButton","keyCode","buttons","find","button","getAttribute","nextButton","nextElementSibling","HTMLButtonElement","focus","previousButton","previousElementSibling","getToolbarHtml","html","getEnhancedHtml","classList","add","createElement","className","innerHTML","append","$textarea","value","Array","from","querySelectorAll","forEach","index","onButtonClick","currentTarget","HTMLElement","execCommand","undefined","getContent","updateTextarea","preventDefault"],"mappings":"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"}
|