@ministryofjustice/frontend 3.3.1 → 3.4.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.
Files changed (87) hide show
  1. package/README.md +4 -10
  2. package/govuk-prototype-kit.config.json +5 -16
  3. package/moj/all.jquery.min.js +77 -3
  4. package/moj/all.js +2021 -1436
  5. package/moj/all.scss +2 -0
  6. package/moj/all.spec.js +15 -13
  7. package/moj/components/_all.scss +1 -0
  8. package/moj/components/action-bar/_action-bar.scss +4 -6
  9. package/moj/components/add-another/_add-another.scss +9 -7
  10. package/moj/components/add-another/add-another.js +90 -69
  11. package/moj/components/add-another/add-another.spec.js +165 -0
  12. package/moj/components/alert/README.md +0 -0
  13. package/moj/components/alert/_alert.scss +142 -0
  14. package/moj/components/alert/alert.js +247 -0
  15. package/moj/components/alert/alert.spec.helper.js +67 -0
  16. package/moj/components/alert/alert.spec.js +229 -0
  17. package/moj/components/alert/macro.njk +3 -0
  18. package/moj/components/alert/template.njk +83 -0
  19. package/moj/components/badge/_badge.scss +3 -4
  20. package/moj/components/banner/_banner.scss +5 -10
  21. package/moj/components/button-menu/_button-menu.scss +10 -9
  22. package/moj/components/button-menu/button-menu.js +139 -136
  23. package/moj/components/button-menu/button-menu.spec.js +295 -296
  24. package/moj/components/cookie-banner/_cookie-banner.scss +6 -5
  25. package/moj/components/currency-input/_currency-input.scss +4 -4
  26. package/moj/components/date-picker/README.md +14 -17
  27. package/moj/components/date-picker/_date-picker.scss +122 -106
  28. package/moj/components/date-picker/date-picker.js +473 -471
  29. package/moj/components/date-picker/date-picker.spec.js +971 -923
  30. package/moj/components/filter/README.md +1 -1
  31. package/moj/components/filter/_filter.scss +53 -75
  32. package/moj/components/filter-toggle-button/filter-toggle-button.js +71 -67
  33. package/moj/components/filter-toggle-button/filter-toggle-button.spec.js +203 -205
  34. package/moj/components/form-validator/form-validator.js +117 -109
  35. package/moj/components/header/_header.scss +17 -19
  36. package/moj/components/identity-bar/_identity-bar.scss +5 -5
  37. package/moj/components/interruption-card/_interruption-card.scss +2 -2
  38. package/moj/components/messages/_messages.scss +12 -19
  39. package/moj/components/multi-file-upload/README.md +1 -1
  40. package/moj/components/multi-file-upload/_multi-file-upload.scss +34 -30
  41. package/moj/components/multi-file-upload/multi-file-upload.js +188 -152
  42. package/moj/components/multi-file-upload/multi-file-upload.spec.js +510 -0
  43. package/moj/components/multi-select/_multi-select.scss +4 -3
  44. package/moj/components/multi-select/multi-select.js +55 -50
  45. package/moj/components/multi-select/multi-select.spec.js +72 -79
  46. package/moj/components/notification-badge/_notification-badge.scss +12 -12
  47. package/moj/components/organisation-switcher/_organisation-switcher.scss +1 -1
  48. package/moj/components/page-header-actions/_page-header-actions.scss +3 -2
  49. package/moj/components/pagination/_pagination.scss +26 -31
  50. package/moj/components/password-reveal/_password-reveal.scss +1 -2
  51. package/moj/components/password-reveal/password-reveal.js +22 -21
  52. package/moj/components/password-reveal/password-reveal.spec.js +39 -37
  53. package/moj/components/primary-navigation/_primary-navigation.scss +26 -29
  54. package/moj/components/progress-bar/_progress-bar.scss +21 -26
  55. package/moj/components/rich-text-editor/_rich-text-editor.scss +17 -16
  56. package/moj/components/rich-text-editor/rich-text-editor.js +117 -103
  57. package/moj/components/search/_search.scss +6 -4
  58. package/moj/components/search-toggle/search-toggle.js +29 -30
  59. package/moj/components/search-toggle/search-toggle.scss +21 -15
  60. package/moj/components/search-toggle/search-toggle.spec.js +65 -70
  61. package/moj/components/side-navigation/_side-navigation.scss +12 -21
  62. package/moj/components/sortable-table/_sortable-table.scss +25 -23
  63. package/moj/components/sortable-table/sortable-table.js +139 -117
  64. package/moj/components/sortable-table/sortable-table.spec.js +362 -0
  65. package/moj/components/sub-navigation/_sub-navigation.scss +24 -28
  66. package/moj/components/tag/_tag.scss +8 -9
  67. package/moj/components/task-list/_task-list.scss +8 -7
  68. package/moj/components/ticket-panel/_ticket-panel.scss +14 -6
  69. package/moj/components/timeline/_timeline.scss +18 -20
  70. package/moj/filters/all.js +28 -30
  71. package/moj/filters/prototype-kit-13-filters.js +2 -1
  72. package/moj/helpers/_all.scss +1 -0
  73. package/moj/helpers/_hidden.scss +1 -1
  74. package/moj/helpers/_links.scss +20 -0
  75. package/moj/helpers.js +160 -31
  76. package/moj/helpers.spec.js +235 -0
  77. package/moj/init.js +2 -2
  78. package/moj/moj-frontend.min.css +2 -2
  79. package/moj/moj-frontend.min.js +77 -3
  80. package/moj/namespace.js +2 -1
  81. package/moj/objects/_filter-layout.scss +11 -10
  82. package/moj/objects/_scrollable-pane.scss +11 -14
  83. package/moj/settings/_colours.scss +5 -0
  84. package/moj/settings/_measurements.scss +0 -2
  85. package/moj/utilities/_hidden.scss +3 -3
  86. package/moj/utilities/_width-container.scss +1 -1
  87. package/package.json +1 -1
@@ -1,20 +1,15 @@
1
- const { queryByRole } = require("@testing-library/dom");
2
- const { userEvent } = require("@testing-library/user-event");
3
- const { configureAxe } = require("jest-axe");
4
- const $ = require("jquery");
1
+ /* eslint-disable no-new */
5
2
 
6
- require("./search-toggle.js");
3
+ const { queryByRole } = require('@testing-library/dom')
4
+ const { userEvent } = require('@testing-library/user-event')
5
+ const $ = require('jquery')
7
6
 
8
- const user = userEvent.setup();
9
- const axe = configureAxe({
10
- rules: {
11
- // disable landmark rules when testing isolated components.
12
- region: { enabled: false },
13
- },
14
- });
7
+ require('./search-toggle.js')
8
+
9
+ const user = userEvent.setup()
15
10
 
16
11
  const createComponent = () => {
17
- html = `
12
+ const html = `
18
13
  <div class="moj-search-toggle" data-module="moj-search-toggle" data-moj-search-toggle-text="Find case">
19
14
  <div class="moj-search-toggle__toggle"></div>
20
15
  <div class="moj-search-toggle__search">
@@ -45,90 +40,90 @@ const createComponent = () => {
45
40
 
46
41
  </div>
47
42
  </div>
48
- <a href="#">link</a>`;
49
- document.body.insertAdjacentHTML("afterbegin", html);
50
- const component = document.querySelector(".moj-search-toggle");
51
- return component;
52
- };
43
+ <a href="#">link</a>`
44
+ document.body.insertAdjacentHTML('afterbegin', html)
45
+ const component = document.querySelector('.moj-search-toggle')
46
+ return component
47
+ }
53
48
 
54
- describe("search toggle", () => {
55
- let component, buttonContainer, searchContainer;
49
+ describe('search toggle', () => {
50
+ let component, buttonContainer, searchContainer
56
51
 
57
52
  beforeEach(() => {
58
- component = createComponent();
59
- searchContainer = component.querySelector(".moj-search");
60
- buttonContainer = component.querySelector(".moj-search-toggle__toggle");
53
+ component = createComponent()
54
+ searchContainer = component.querySelector('.moj-search')
55
+ buttonContainer = component.querySelector('.moj-search-toggle__toggle')
61
56
 
62
57
  new MOJFrontend.SearchToggle({
63
58
  toggleButton: {
64
59
  container: $(buttonContainer),
65
- text: component.getAttribute("data-moj-search-toggle-text"),
60
+ text: component.getAttribute('data-moj-search-toggle-text')
66
61
  },
67
62
  search: {
68
- container: $(searchContainer),
69
- },
70
- });
71
- });
63
+ container: $(searchContainer)
64
+ }
65
+ })
66
+ })
72
67
 
73
68
  afterEach(() => {
74
- document.body.innerHTML = "";
75
- });
69
+ document.body.innerHTML = ''
70
+ })
76
71
 
77
- test("initialises component", () => {
78
- const toggleButton = queryByRole(buttonContainer, "button");
72
+ test('initialises component', () => {
73
+ const toggleButton = queryByRole(buttonContainer, 'button')
79
74
 
80
- expect(toggleButton).not.toBeNull();
81
- expect(toggleButton).toHaveTextContent("Find case");
82
- expect(toggleButton).toHaveAttribute("aria-haspopup", "true");
83
- expect(toggleButton).toHaveAttribute("aria-expanded", "false");
75
+ expect(toggleButton).toBeInTheDocument()
76
+ expect(toggleButton).toHaveTextContent('Find case')
77
+ expect(toggleButton).toHaveAttribute('aria-haspopup', 'true')
78
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
84
79
 
85
- expect(searchContainer).toHaveClass("moj-js-hidden");
86
- });
80
+ expect(searchContainer).toHaveClass('moj-js-hidden')
81
+ })
87
82
 
88
- test("clicking button toggles search container", async () => {
89
- const toggleButton = queryByRole(buttonContainer, "button");
83
+ test('clicking button toggles search container', async () => {
84
+ const toggleButton = queryByRole(buttonContainer, 'button')
90
85
 
91
- await user.click(toggleButton);
86
+ await user.click(toggleButton)
92
87
 
93
- expect(toggleButton).toHaveAttribute("aria-expanded", "true");
94
- expect(searchContainer).not.toHaveClass("moj-js-hidden");
88
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'true')
89
+ expect(searchContainer).not.toHaveClass('moj-js-hidden')
95
90
 
96
- const input = queryByRole(searchContainer, "searchbox");
97
- expect(input).toHaveFocus();
91
+ const input = queryByRole(searchContainer, 'searchbox')
92
+ expect(input).toHaveFocus()
98
93
 
99
- await user.click(toggleButton);
94
+ await user.click(toggleButton)
100
95
 
101
- expect(toggleButton).toHaveAttribute("aria-expanded", "false");
102
- expect(searchContainer).toHaveClass("moj-js-hidden");
103
- expect(toggleButton).toHaveFocus();
104
- });
96
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
97
+ expect(searchContainer).toHaveClass('moj-js-hidden')
98
+ expect(toggleButton).toHaveFocus()
99
+ })
105
100
 
106
- test("clicking outside closes the search container", async () => {
107
- const toggleButton = queryByRole(buttonContainer, "button");
101
+ test('clicking outside closes the search container', async () => {
102
+ const toggleButton = queryByRole(buttonContainer, 'button')
108
103
 
109
- await user.click(toggleButton);
104
+ await user.click(toggleButton)
110
105
 
111
- expect(toggleButton).toHaveAttribute("aria-expanded", "true");
112
- expect(searchContainer).not.toHaveClass("moj-js-hidden");
106
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'true')
107
+ expect(searchContainer).not.toHaveClass('moj-js-hidden')
113
108
 
114
- await user.click(document.body);
109
+ await user.click(document.body)
115
110
 
116
- expect(toggleButton).toHaveAttribute("aria-expanded", "false");
117
- expect(searchContainer).toHaveClass("moj-js-hidden");
118
- });
111
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
112
+ expect(searchContainer).toHaveClass('moj-js-hidden')
113
+ })
119
114
 
120
- test("tabbing closes the search container", async () => {
121
- const toggleButton = queryByRole(buttonContainer, "button");
115
+ test('tabbing closes the search container', async () => {
116
+ const toggleButton = queryByRole(buttonContainer, 'button')
122
117
 
123
- await user.click(toggleButton);
118
+ await user.click(toggleButton)
124
119
 
125
- expect(toggleButton).toHaveAttribute("aria-expanded", "true");
126
- expect(searchContainer).not.toHaveClass("moj-js-hidden");
120
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'true')
121
+ expect(searchContainer).not.toHaveClass('moj-js-hidden')
127
122
 
128
- await user.tab();
129
- await user.tab();
123
+ await user.tab()
124
+ await user.tab()
130
125
 
131
- expect(toggleButton).toHaveAttribute("aria-expanded", "false");
132
- expect(searchContainer).toHaveClass("moj-js-hidden");
133
- });
134
- });
126
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false')
127
+ expect(searchContainer).toHaveClass('moj-js-hidden')
128
+ })
129
+ })
@@ -14,27 +14,25 @@
14
14
  display: block;
15
15
  padding: govuk-spacing(4) 0 0;
16
16
  }
17
-
18
17
  }
19
18
 
20
19
  .moj-side-navigation__title {
21
20
  @include govuk-font($size: 19);
22
- color: govuk-colour("dark-grey");
23
- font-weight: normal;
24
21
  margin: 0;
25
22
  padding: govuk-spacing(2);
26
23
  padding-left: govuk-spacing(2) + 4px;
24
+ color: govuk-colour("dark-grey");
25
+ font-weight: normal;
27
26
 
28
27
  @include govuk-media-query($until: tablet) {
29
28
  display: none;
30
29
  }
31
-
32
30
  }
33
31
 
34
32
  .moj-side-navigation__list {
35
- list-style: none;
36
33
  margin: 0;
37
34
  padding: 0;
35
+ list-style: none;
38
36
 
39
37
  @include govuk-media-query($until: tablet) {
40
38
  display: flex;
@@ -48,7 +46,6 @@
48
46
  }
49
47
 
50
48
  .moj-side-navigation__item {
51
-
52
49
  @include govuk-media-query($until: tablet) {
53
50
  display: flex;
54
51
  }
@@ -56,24 +53,22 @@
56
53
  a,
57
54
  a:link,
58
55
  a:visited {
59
- background-color: inherit;
60
- color: $govuk-link-colour;
61
56
  display: block;
57
+ color: $govuk-link-colour;
58
+ background-color: inherit;
62
59
  text-decoration: none;
63
60
 
64
61
  @include govuk-media-query($until: tablet) {
65
- border-bottom: 4px solid transparent;
66
62
  padding: govuk-spacing(3);
67
63
  padding-bottom: govuk-spacing(3) - 4px; // Compensate for 4px border
64
+ border-bottom: 4px solid transparent;
68
65
  }
69
66
 
70
67
  @include govuk-media-query($from: tablet) {
71
- background-color: inherit;
72
- border-left: 4px solid transparent;
73
68
  padding: govuk-spacing(2);
69
+ border-left: 4px solid transparent;
70
+ background-color: inherit;
74
71
  }
75
-
76
-
77
72
  }
78
73
 
79
74
  a:hover {
@@ -81,16 +76,14 @@
81
76
  }
82
77
 
83
78
  a:focus {
79
+ position: relative;
80
+ border-color: $govuk-focus-text-colour;
84
81
  color: $govuk-focus-text-colour;
85
82
  background-color: $govuk-focus-colour;
86
- border-color: $govuk-focus-text-colour;
87
- position: relative;
88
83
  }
89
-
90
84
  }
91
85
 
92
86
  .moj-side-navigation__item--active {
93
-
94
87
  a:link,
95
88
  a:visited {
96
89
  border-color: $govuk-link-colour;
@@ -99,14 +92,14 @@
99
92
  }
100
93
 
101
94
  a:hover {
102
- color: $govuk-link-hover-colour;
103
95
  border-color: $govuk-link-hover-colour;
96
+ color: $govuk-link-hover-colour;
104
97
  }
105
98
 
106
99
  a:focus {
100
+ border-color: $govuk-focus-text-colour;
107
101
  color: $govuk-focus-text-colour;
108
102
  background-color: $govuk-focus-colour;
109
- border-color: $govuk-focus-text-colour;
110
103
  }
111
104
 
112
105
  @include govuk-media-query($from: tablet) {
@@ -120,6 +113,4 @@
120
113
  background-color: $govuk-focus-colour;
121
114
  }
122
115
  }
123
-
124
-
125
116
  }
@@ -1,66 +1,68 @@
1
1
  [aria-sort] button,
2
2
  [aria-sort] button:hover {
3
- background-color: transparent;
3
+ position: relative;
4
+ margin: 0;
5
+ padding: 0 10px 0 0;
4
6
  border-width: 0;
7
+ color: #005ea5;
8
+ background-color: transparent;
5
9
  -webkit-box-shadow: 0 0 0 0;
6
10
  -moz-box-shadow: 0 0 0 0;
7
11
  box-shadow: 0 0 0 0;
8
- color: #005ea5;
9
- cursor: pointer;
10
12
  font-family: inherit;
11
13
  font-size: inherit;
14
+ font-size: 1em;
12
15
  font-weight: inherit;
13
- padding: 0 10px 0 0;
14
- position: relative;
15
16
  text-align: inherit;
16
- font-size: 1em;
17
- margin: 0;
17
+ cursor: pointer;
18
18
  }
19
19
 
20
20
  [aria-sort] button:focus {
21
- background-color: $govuk-focus-colour;
22
- color: $govuk-focus-text-colour;
23
- box-shadow: 0 -2px $govuk-focus-colour, 0 4px $govuk-focus-text-colour;
24
21
  outline: none;
22
+ color: $govuk-focus-text-colour;
23
+ background-color: $govuk-focus-colour;
24
+ box-shadow:
25
+ 0 -2px $govuk-focus-colour,
26
+ 0 4px $govuk-focus-text-colour;
25
27
  }
26
28
 
27
29
  [aria-sort]:first-child button {
28
30
  right: auto;
29
31
  }
30
32
 
31
- [aria-sort] button:before {
33
+ [aria-sort] button::before {
32
34
  content: " \25bc";
33
35
  position: absolute;
34
- right: -1px;
35
36
  top: 9px;
37
+ right: -1px;
36
38
  font-size: 0.5em;
37
39
  }
38
40
 
39
- [aria-sort] button:after {
41
+ [aria-sort] button::after {
40
42
  content: " \25b2";
41
43
  position: absolute;
42
- right: -1px;
43
44
  top: 1px;
45
+ right: -1px;
44
46
  font-size: 0.5em;
45
47
  }
46
48
 
47
- [aria-sort="ascending"] button:before,
48
- [aria-sort="descending"] button:before {
49
+ [aria-sort="ascending"] button::before,
50
+ [aria-sort="descending"] button::before {
49
51
  content: none;
50
52
  }
51
53
 
52
- [aria-sort="ascending"] button:after {
54
+ [aria-sort="ascending"] button::after {
53
55
  content: " \25b2";
54
- font-size: .8em;
55
56
  position: absolute;
56
- right: -5px;
57
57
  top: 2px;
58
+ right: -5px;
59
+ font-size: 0.8em;
58
60
  }
59
61
 
60
- [aria-sort="descending"] button:after {
62
+ [aria-sort="descending"] button::after {
61
63
  content: " \25bc";
62
- font-size: .8em;
63
64
  position: absolute;
64
- right: -5px;
65
65
  top: 2px;
66
- }
66
+ right: -5px;
67
+ font-size: 0.8em;
68
+ }
@@ -1,124 +1,146 @@
1
- MOJFrontend.SortableTable = function(params) {
2
- this.table = $(params.table);
3
-
4
- if (this.table.data('moj-search-toggle-initialised')) {
5
- return
6
- }
7
-
8
- this.table.data('moj-search-toggle-initialised', true);
9
-
10
- this.setupOptions(params);
11
- this.body = this.table.find('tbody');
12
- this.createHeadingButtons();
13
- this.createStatusBox();
14
- this.initialiseSortedColumn();
15
- this.table.on('click', 'th button', $.proxy(this, 'onSortButtonClick'));
16
- };
17
-
18
- MOJFrontend.SortableTable.prototype.setupOptions = function(params) {
19
- params = params || {};
20
- this.statusMessage = params.statusMessage || 'Sort by %heading% (%direction%)';
21
- this.ascendingText = params.ascendingText || 'ascending';
22
- this.descendingText = params.descendingText || 'descending';
23
- };
24
-
25
- MOJFrontend.SortableTable.prototype.createHeadingButtons = function() {
26
- var headings = this.table.find('thead th');
27
- var heading;
28
- for(var i = 0; i < headings.length; i++) {
29
- heading = $(headings[i]);
30
- if(heading.attr('aria-sort')) {
31
- this.createHeadingButton(heading, i);
32
- }
33
- }
34
- };
35
-
36
- MOJFrontend.SortableTable.prototype.createHeadingButton = function(heading, i) {
37
- var text = heading.text();
38
- var button = $('<button type="button" data-index="'+i+'">'+text+'</button>');
39
- heading.text('');
40
- heading.append(button);
41
- };
42
-
43
- MOJFrontend.SortableTable.prototype.createStatusBox = function() {
44
- this.status = $('<div aria-live="polite" role="status" aria-atomic="true" class="govuk-visually-hidden" />');
45
- this.table.parent().append(this.status);
46
- };
1
+ MOJFrontend.SortableTable = function (params) {
2
+ this.table = $(params.table)
3
+
4
+ if (this.table.data('moj-search-toggle-initialised')) {
5
+ return
6
+ }
7
+
8
+ this.table.data('moj-search-toggle-initialised', true)
9
+
10
+ this.setupOptions(params)
11
+ this.body = this.table.find('tbody')
12
+ this.createHeadingButtons()
13
+ this.createStatusBox()
14
+ this.initialiseSortedColumn()
15
+ this.table.on('click', 'th button', $.proxy(this, 'onSortButtonClick'))
16
+ }
17
+
18
+ MOJFrontend.SortableTable.prototype.setupOptions = function (params) {
19
+ params = params || {}
20
+ this.statusMessage = params.statusMessage || 'Sort by %heading% (%direction%)'
21
+ this.ascendingText = params.ascendingText || 'ascending'
22
+ this.descendingText = params.descendingText || 'descending'
23
+ }
24
+
25
+ MOJFrontend.SortableTable.prototype.createHeadingButtons = function () {
26
+ const headings = this.table.find('thead th')
27
+ let heading
28
+ for (let i = 0; i < headings.length; i++) {
29
+ heading = $(headings[i])
30
+ if (heading.attr('aria-sort')) {
31
+ this.createHeadingButton(heading, i)
32
+ }
33
+ }
34
+ }
35
+
36
+ MOJFrontend.SortableTable.prototype.createHeadingButton = function (
37
+ heading,
38
+ i
39
+ ) {
40
+ const text = heading.text()
41
+ const button = $(`<button type="button" data-index="${i}">${text}</button>`)
42
+ heading.text('')
43
+ heading.append(button)
44
+ }
45
+
46
+ MOJFrontend.SortableTable.prototype.createStatusBox = function () {
47
+ this.status = $(
48
+ '<div aria-live="polite" role="status" aria-atomic="true" class="govuk-visually-hidden" />'
49
+ )
50
+ this.table.parent().append(this.status)
51
+ }
47
52
 
48
53
  MOJFrontend.SortableTable.prototype.initialiseSortedColumn = function () {
49
- var rows = this.getTableRowsArray();
54
+ const rows = this.getTableRowsArray()
50
55
 
51
- this.table.find("th")
56
+ this.table
57
+ .find('th')
52
58
  .filter('[aria-sort="ascending"], [aria-sort="descending"]')
53
59
  .first()
54
60
  .each((index, el) => {
55
- var sortDirection = $(el).attr('aria-sort');
56
- var columnNumber = $(el).find('button').attr('data-index');
57
- var sortedRows = this.sort(rows, columnNumber, sortDirection);
58
- this.addRows(sortedRows);
61
+ const sortDirection = $(el).attr('aria-sort')
62
+ const columnNumber = $(el).find('button').attr('data-index')
63
+ const sortedRows = this.sort(rows, columnNumber, sortDirection)
64
+ this.addRows(sortedRows)
59
65
  })
60
- };
61
-
62
- MOJFrontend.SortableTable.prototype.onSortButtonClick = function(e) {
63
- var columnNumber = e.currentTarget.getAttribute('data-index');
64
- var sortDirection = $(e.currentTarget).parent().attr('aria-sort');
65
- var newSortDirection;
66
- if(sortDirection === 'none' || sortDirection === 'descending') {
67
- newSortDirection = 'ascending';
68
- } else {
69
- newSortDirection = 'descending';
70
- }
71
- var rows = this.getTableRowsArray();
72
- var sortedRows = this.sort(rows, columnNumber, newSortDirection);
73
- this.addRows(sortedRows);
74
- this.removeButtonStates();
75
- this.updateButtonState($(e.currentTarget), newSortDirection);
76
- };
77
-
78
- MOJFrontend.SortableTable.prototype.updateButtonState = function(button, direction) {
79
- button.parent().attr('aria-sort', direction);
80
- var message = this.statusMessage;
81
- message = message.replace(/%heading%/, button.text());
82
- message = message.replace(/%direction%/, this[direction+'Text']);
83
- this.status.text(message);
84
- };
85
-
86
- MOJFrontend.SortableTable.prototype.removeButtonStates = function() {
87
- this.table.find('thead th').attr('aria-sort', 'none');
88
- };
89
-
90
- MOJFrontend.SortableTable.prototype.addRows = function(rows) {
91
- for(var i = 0; i < rows.length; i++) {
92
- this.body.append(rows[i]);
93
- }
94
- };
95
-
96
- MOJFrontend.SortableTable.prototype.getTableRowsArray = function() {
97
- var rows = [];
98
- var trs = this.body.find('tr');
99
- for (var i = 0; i < trs.length; i++) {
100
- rows.push(trs[i]);
101
- }
102
- return rows;
103
- };
104
-
105
- MOJFrontend.SortableTable.prototype.sort = function(rows, columnNumber, sortDirection) {
106
- var newRows = rows.sort((function(rowA, rowB) {
107
- var tdA = $(rowA).find('td,th').eq(columnNumber);
108
- var tdB = $(rowB).find('td,th').eq(columnNumber);
109
-
110
- var valueA = sortDirection === 'ascending' ? this.getCellValue(tdA) : this.getCellValue(tdB);
111
- var valueB = sortDirection === 'ascending' ? this.getCellValue(tdB) : this.getCellValue(tdA);
112
-
113
- if (typeof valueA === 'string' || typeof valueB === 'string') return valueA.toString().localeCompare(valueB.toString());
114
- return valueA-valueB;
115
- }.bind(this)));
116
- return newRows;
117
- };
118
-
119
- MOJFrontend.SortableTable.prototype.getCellValue = function(cell) {
120
- var val = cell.attr('data-sort-value') || cell.html();
121
-
122
- var floatVal = parseFloat(val)
123
- return isNaN(floatVal) ? val : floatVal
124
- };
66
+ }
67
+
68
+ MOJFrontend.SortableTable.prototype.onSortButtonClick = function (e) {
69
+ const columnNumber = e.currentTarget.getAttribute('data-index')
70
+ const sortDirection = $(e.currentTarget).parent().attr('aria-sort')
71
+ let newSortDirection
72
+ if (sortDirection === 'none' || sortDirection === 'descending') {
73
+ newSortDirection = 'ascending'
74
+ } else {
75
+ newSortDirection = 'descending'
76
+ }
77
+ const rows = this.getTableRowsArray()
78
+ const sortedRows = this.sort(rows, columnNumber, newSortDirection)
79
+ this.addRows(sortedRows)
80
+ this.removeButtonStates()
81
+ this.updateButtonState($(e.currentTarget), newSortDirection)
82
+ }
83
+
84
+ MOJFrontend.SortableTable.prototype.updateButtonState = function (
85
+ button,
86
+ direction
87
+ ) {
88
+ button.parent().attr('aria-sort', direction)
89
+ let message = this.statusMessage
90
+ message = message.replace(/%heading%/, button.text())
91
+ message = message.replace(/%direction%/, this[`${direction}Text`])
92
+ this.status.text(message)
93
+ }
94
+
95
+ MOJFrontend.SortableTable.prototype.removeButtonStates = function () {
96
+ this.table.find('thead th').attr('aria-sort', 'none')
97
+ }
98
+
99
+ MOJFrontend.SortableTable.prototype.addRows = function (rows) {
100
+ for (let i = 0; i < rows.length; i++) {
101
+ this.body.append(rows[i])
102
+ }
103
+ }
104
+
105
+ MOJFrontend.SortableTable.prototype.getTableRowsArray = function () {
106
+ const rows = []
107
+ const trs = this.body.find('tr')
108
+ for (let i = 0; i < trs.length; i++) {
109
+ rows.push(trs[i])
110
+ }
111
+ return rows
112
+ }
113
+
114
+ MOJFrontend.SortableTable.prototype.sort = function (
115
+ rows,
116
+ columnNumber,
117
+ sortDirection
118
+ ) {
119
+ const newRows = rows.sort(
120
+ function (rowA, rowB) {
121
+ const tdA = $(rowA).find('td,th').eq(columnNumber)
122
+ const tdB = $(rowB).find('td,th').eq(columnNumber)
123
+
124
+ const valueA =
125
+ sortDirection === 'ascending'
126
+ ? this.getCellValue(tdA)
127
+ : this.getCellValue(tdB)
128
+ const valueB =
129
+ sortDirection === 'ascending'
130
+ ? this.getCellValue(tdB)
131
+ : this.getCellValue(tdA)
132
+
133
+ if (typeof valueA === 'string' || typeof valueB === 'string')
134
+ return valueA.toString().localeCompare(valueB.toString())
135
+ return valueA - valueB
136
+ }.bind(this)
137
+ )
138
+ return newRows
139
+ }
140
+
141
+ MOJFrontend.SortableTable.prototype.getCellValue = function (cell) {
142
+ const val = cell.attr('data-sort-value') || cell.html()
143
+
144
+ const valAsNumber = Number(val)
145
+ return isNaN(valAsNumber) ? val : valAsNumber
146
+ }