@internetstiftelsen/styleguide 4.0.10-beta.0.1 → 4.0.11
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/dist/assets/js/charCounter.js +139 -0
- package/dist/assets/js/htmlTextLength.js +13 -0
- package/dist/assets/js/textToggle.js +5 -3
- package/dist/assets/js/utmGenerator.js +40 -0
- package/dist/assets/js/youtube.js +3 -0
- package/dist/atoms/textarea/rich-text.js +8 -0
- package/dist/components.js +9 -1
- package/dist/molecules/multi-select/multi-select.js +132 -0
- package/package.json +1 -1
- package/src/app.scss +1 -0
- package/src/assets/js/charCounter.js +111 -0
- package/src/assets/js/htmlTextLength.js +7 -0
- package/src/assets/js/textToggle.js +5 -3
- package/src/assets/js/utmGenerator.js +38 -0
- package/src/assets/js/youtube.js +3 -0
- package/src/atoms/textarea/rich-text.js +8 -0
- package/src/atoms/textarea/textarea.config.js +38 -0
- package/src/components.js +4 -0
- package/src/molecules/multi-select/_multi-select.scss +116 -0
- package/src/molecules/multi-select/multi-select.js +159 -0
- package/src/molecules/multi-select/readme.md +2 -0
- package/src/utilities/_hide.scss +4 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
4
|
+
|
|
5
|
+
var _className = require('./className');
|
|
6
|
+
|
|
7
|
+
var _className2 = _interopRequireDefault(_className);
|
|
8
|
+
|
|
9
|
+
var _htmlTextLength = require('./htmlTextLength');
|
|
10
|
+
|
|
11
|
+
var _htmlTextLength2 = _interopRequireDefault(_htmlTextLength);
|
|
12
|
+
|
|
13
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
|
+
|
|
15
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
16
|
+
|
|
17
|
+
var CharCounter = function () {
|
|
18
|
+
function CharCounter(el) {
|
|
19
|
+
_classCallCheck(this, CharCounter);
|
|
20
|
+
|
|
21
|
+
this.el = el;
|
|
22
|
+
this.counterEl = null;
|
|
23
|
+
this.isRichText = this.el.dataset.richText !== undefined;
|
|
24
|
+
this.min = parseInt(this.el.getAttribute('data-min') || 0, 10);
|
|
25
|
+
this.max = parseInt(this.el.getAttribute('data-max') || 0, 10);
|
|
26
|
+
|
|
27
|
+
if (!this.min && !this.max) {
|
|
28
|
+
console.warn('Either min or max must be set and greater than 0.');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (this.isRichText) {
|
|
33
|
+
this.waitForEditor();
|
|
34
|
+
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.build();
|
|
39
|
+
this.attach();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
_createClass(CharCounter, [{
|
|
43
|
+
key: 'waitForEditor',
|
|
44
|
+
value: function waitForEditor() {
|
|
45
|
+
var _this = this;
|
|
46
|
+
|
|
47
|
+
if (this.el.editor) {
|
|
48
|
+
this.build();
|
|
49
|
+
this.attach();
|
|
50
|
+
} else {
|
|
51
|
+
this.el.addEventListener('editor-ready', function () {
|
|
52
|
+
_this.build();
|
|
53
|
+
_this.attach();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, {
|
|
58
|
+
key: 'count',
|
|
59
|
+
value: function count() {
|
|
60
|
+
if (this.isRichText) {
|
|
61
|
+
return (0, _htmlTextLength2.default)(this.el.editor.getHTML());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return this.el.value.length;
|
|
65
|
+
}
|
|
66
|
+
}, {
|
|
67
|
+
key: 'setCountText',
|
|
68
|
+
value: function setCountText() {
|
|
69
|
+
var count = this.count();
|
|
70
|
+
|
|
71
|
+
if (this.min && count < this.min) {
|
|
72
|
+
this.counterEl.textContent = count + '/' + this.min;
|
|
73
|
+
this.counterEl.className = 'color-ruby ' + (0, _className2.default)('a-meta');
|
|
74
|
+
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (this.max && count > this.max) {
|
|
79
|
+
this.counterEl.textContent = count + '/' + this.max;
|
|
80
|
+
this.counterEl.classList.remove('color-granit');
|
|
81
|
+
this.counterEl.className = 'color-ruby ' + (0, _className2.default)('a-meta');
|
|
82
|
+
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.counterEl.textContent = count + '/' + (this.max || this.min);
|
|
87
|
+
this.counterEl.className = 'color-jade ' + (0, _className2.default)('a-meta');
|
|
88
|
+
}
|
|
89
|
+
}, {
|
|
90
|
+
key: 'build',
|
|
91
|
+
value: function build() {
|
|
92
|
+
var counter = document.createElement('small');
|
|
93
|
+
var wrapper = void 0;
|
|
94
|
+
|
|
95
|
+
if (this.isRichText) {
|
|
96
|
+
wrapper = this.el.editor.options.element;
|
|
97
|
+
wrapper.style.paddingRight = '3.8333333333rem';
|
|
98
|
+
} else {
|
|
99
|
+
wrapper = document.createElement('div');
|
|
100
|
+
|
|
101
|
+
wrapper.className = 'u-position-relative';
|
|
102
|
+
this.el.parentNode.insertBefore(wrapper, this.el);
|
|
103
|
+
wrapper.appendChild(this.el);
|
|
104
|
+
|
|
105
|
+
this.el.style.paddingRight = '3.8333333333rem';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
counter.className = 'color-granit ' + (0, _className2.default)('a-meta');
|
|
109
|
+
counter.style.cssText = 'position: absolute; top: 5px; right: 10px; z-index: 501;';
|
|
110
|
+
|
|
111
|
+
wrapper.appendChild(counter);
|
|
112
|
+
|
|
113
|
+
this.counterEl = counter;
|
|
114
|
+
this.setCountText();
|
|
115
|
+
}
|
|
116
|
+
}, {
|
|
117
|
+
key: 'attach',
|
|
118
|
+
value: function attach() {
|
|
119
|
+
var _this2 = this;
|
|
120
|
+
|
|
121
|
+
if (this.isRichText) {
|
|
122
|
+
this.el.editor.on('update', function () {
|
|
123
|
+
_this2.setCountText();
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
this.el.addEventListener('input', function () {
|
|
127
|
+
_this2.setCountText();
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}]);
|
|
132
|
+
|
|
133
|
+
return CharCounter;
|
|
134
|
+
}();
|
|
135
|
+
|
|
136
|
+
var elements = document.querySelectorAll('[data-min], [data-max]');
|
|
137
|
+
elements.forEach(function (el) {
|
|
138
|
+
el.charCounter = new CharCounter(el);
|
|
139
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = htmlTextLength;
|
|
7
|
+
function htmlTextLength(html) {
|
|
8
|
+
var div = document.createElement('div');
|
|
9
|
+
|
|
10
|
+
div.innerHTML = html;
|
|
11
|
+
|
|
12
|
+
return div.textContent.length;
|
|
13
|
+
}
|
|
@@ -14,8 +14,10 @@ function toggleTextOnClick(e) {
|
|
|
14
14
|
target.innerText = options[nextIteration];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
var
|
|
17
|
+
var toggleTextButtons = document.querySelectorAll('[data-toggle-text]');
|
|
18
18
|
|
|
19
|
-
if (
|
|
20
|
-
|
|
19
|
+
if (toggleTextButtons) {
|
|
20
|
+
[].forEach.call(toggleTextButtons, function (toggleTextButton) {
|
|
21
|
+
toggleTextButton.addEventListener('click', toggleTextOnClick);
|
|
22
|
+
});
|
|
21
23
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Show/hide target container when Radiobutton is selected
|
|
4
|
+
var radioButtons = document.querySelectorAll('[data-toggle="radio"]');
|
|
5
|
+
|
|
6
|
+
// Hide all target containers on page load
|
|
7
|
+
radioButtons.forEach(function (radio) {
|
|
8
|
+
var targetId = radio.getAttribute('data-target');
|
|
9
|
+
var targetContainer = document.getElementById(targetId);
|
|
10
|
+
if (targetContainer) {
|
|
11
|
+
targetContainer.setAttribute('aria-hidden', 'true');
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Function to toggle visibility
|
|
16
|
+
function toggleVisibility(event) {
|
|
17
|
+
// Hide all target containers
|
|
18
|
+
radioButtons.forEach(function (radio) {
|
|
19
|
+
var targetId = radio.getAttribute('data-target');
|
|
20
|
+
var targetContainer = document.getElementById(targetId);
|
|
21
|
+
if (targetContainer) {
|
|
22
|
+
targetContainer.setAttribute('aria-hidden', 'true');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Update aria-expanded for all radio buttons
|
|
26
|
+
radio.setAttribute('aria-expanded', radio.checked ? 'true' : 'false');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Show the selected target container
|
|
30
|
+
var selectedTargetId = event.target.getAttribute('data-target');
|
|
31
|
+
var selectedTargetContainer = document.getElementById(selectedTargetId);
|
|
32
|
+
if (selectedTargetContainer) {
|
|
33
|
+
selectedTargetContainer.setAttribute('aria-hidden', 'false');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Add event listener to radio buttons
|
|
38
|
+
radioButtons.forEach(function (radio) {
|
|
39
|
+
radio.addEventListener('change', toggleVisibility);
|
|
40
|
+
});
|
|
@@ -203,6 +203,14 @@ function setupTextArea(el) {
|
|
|
203
203
|
el.parentNode.insertBefore(editorEl, el);
|
|
204
204
|
|
|
205
205
|
createToolbar(editorEl, editor);
|
|
206
|
+
|
|
207
|
+
var event = new CustomEvent('editor-ready', {
|
|
208
|
+
detail: {
|
|
209
|
+
editor: editor
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
el.dispatchEvent(event);
|
|
206
214
|
}
|
|
207
215
|
|
|
208
216
|
function init() {
|
package/dist/components.js
CHANGED
|
@@ -64,4 +64,12 @@ require('./organisms/schedule/schedule-filter');
|
|
|
64
64
|
|
|
65
65
|
require('./assets/js/ot');
|
|
66
66
|
|
|
67
|
-
require('./
|
|
67
|
+
require('./assets/js/charCounter');
|
|
68
|
+
|
|
69
|
+
require('./atoms/range/range');
|
|
70
|
+
|
|
71
|
+
require('./assets/js/utmGenerator');
|
|
72
|
+
|
|
73
|
+
require('./assets/js/textToggle');
|
|
74
|
+
|
|
75
|
+
require('./molecules/multi-select/multi-select');
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
// Get references to the search input and suggestions box elements
|
|
5
|
+
var className = 'm-multi-select';
|
|
6
|
+
var multiSelectElement = document.querySelector('.js-' + className);
|
|
7
|
+
var multiSelectInput = document.querySelector('.js-' + className + '__input');
|
|
8
|
+
var suggestionsBox = document.querySelector('.js-' + className + '-suggestions-box');
|
|
9
|
+
|
|
10
|
+
if (multiSelectInput && suggestionsBox) {
|
|
11
|
+
|
|
12
|
+
// Function to highlight the active (focused) suggestion
|
|
13
|
+
var setActive = function setActive(items) {
|
|
14
|
+
if (!items.length) return false;
|
|
15
|
+
removeActive(items);
|
|
16
|
+
if (currentFocus >= items.length) currentFocus = 0;
|
|
17
|
+
if (currentFocus < 0) currentFocus = items.length - 1;
|
|
18
|
+
items[currentFocus].classList.add('autocomplete-active');
|
|
19
|
+
|
|
20
|
+
return items;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Function to remove highlighting from all suggestions
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
var removeActive = function removeActive(items) {
|
|
27
|
+
for (var i = 0; i < items.length; i++) {
|
|
28
|
+
items[i].classList.remove('autocomplete-active');
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Function to add a selected item to the list of selected items
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
var addSelectedItem = function addSelectedItem(item) {
|
|
36
|
+
var container = document.getElementById('selectedItemsContainer');
|
|
37
|
+
var newItem = document.createElement('li');
|
|
38
|
+
newItem.textContent = item + ' ';
|
|
39
|
+
var removeBtn = document.createElement('button');
|
|
40
|
+
var buttonTextContainer = document.createElement('span');
|
|
41
|
+
//removeBtn.textContent = 'x';
|
|
42
|
+
buttonTextContainer.classList.add('visually-hidden');
|
|
43
|
+
removeBtn.appendChild(buttonTextContainer);
|
|
44
|
+
buttonTextContainer.textContent = 'Remove ' + item; // Accessibility label for screen readers
|
|
45
|
+
// Event listener for removing the selected item
|
|
46
|
+
removeBtn.addEventListener('click', function () {
|
|
47
|
+
removeItem(newItem, Array.from(container.children).indexOf(newItem));
|
|
48
|
+
});
|
|
49
|
+
newItem.appendChild(removeBtn);
|
|
50
|
+
container.appendChild(newItem);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Function to remove an item and manage focus appropriately
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
var removeItem = function removeItem(item, index) {
|
|
57
|
+
var container = document.getElementById('selectedItemsContainer');
|
|
58
|
+
container.removeChild(item);
|
|
59
|
+
|
|
60
|
+
var remainingItems = container.getElementsByTagName('div');
|
|
61
|
+
// Focus management: set focus to the next item, or the search input if no items left
|
|
62
|
+
if (remainingItems.length > 0) {
|
|
63
|
+
if (index < remainingItems.length) {
|
|
64
|
+
remainingItems[index].getElementsByTagName('button')[0].focus();
|
|
65
|
+
} else {
|
|
66
|
+
remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
multiSelectInput.focus();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Event listener for input changes in the search field
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
var currentFocus = -1; // Tracks the currently focused item in the suggestions
|
|
77
|
+
var namespace = getComputedStyle(multiSelectElement, ':before').content.replace(/["']/g, '');multiSelectInput.addEventListener('input', function () {
|
|
78
|
+
var value = this.value;
|
|
79
|
+
// Clear suggestions if less than 2 characters are typed
|
|
80
|
+
if (value.length < 2) {
|
|
81
|
+
suggestionsBox.innerHTML = '';
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Define a JSON array of 100 real cities
|
|
86
|
+
var suggestions = [{ name: 'New York' }, { name: 'Los Angeles' }, { name: 'Chicago' }, { name: 'Houston' }, { name: 'Phoenix' }, { name: 'Philadelphia' }, { name: 'San Antonio' }, { name: 'San Diego' }, { name: 'Dallas' }, { name: 'San Jose' }, { name: 'Austin' }, { name: 'Jacksonville' }, { name: 'Fort Worth' }, { name: 'Columbus' }, { name: 'San Francisco' }, { name: 'Tokyo' }, { name: 'Delhi' }, { name: 'Shanghai' }, { name: 'Sao Paulo' }, { name: 'Mumbai' }, { name: 'Beijing' }, { name: 'Cairo' }, { name: 'Dhaka' }, { name: 'Mexico City' }, { name: 'Osaka' }, { name: 'Karachi' }, { name: 'Chongqing' }, { name: 'Istanbul' }, { name: 'Buenos Aires' }, { name: 'Kolkata' }, { name: 'Kinshasa' }, { name: 'Lagos' }, { name: 'Manila' }, { name: 'Tianjin' }, { name: 'Rio de Janeiro' }, { name: 'Guangzhou' }, { name: 'Lahore' }, { name: 'Moscow' }, { name: 'Shenzhen' }, { name: 'Bangalore' }, { name: 'Paris' }, { name: 'Bogota' }, { name: 'Jakarta' }, { name: 'Chennai' }, { name: 'Lima' }, { name: 'Bangkok' }, { name: 'Seoul' }, { name: 'Nagoya' }, { name: 'Hyderabad' }, { name: 'London' }, { name: 'Tehran' }, { name: 'Chengdu' }, { name: 'Nanjing' }, { name: 'Wuhan' }, { name: 'Ho Chi Minh City' }, { name: 'Luanda' }, { name: 'Ahmedabad' }, { name: 'Kuala Lumpur' }, { name: 'Xi’an' }, { name: 'Hong Kong' }, { name: 'Dongguan' }, { name: 'Hangzhou' }, { name: 'Foshan' }, { name: 'Shenyang' }, { name: 'Riyadh' }, { name: 'Baghdad' }, { name: 'Santiago' }, { name: 'Surat' }, { name: 'Madrid' }, { name: 'Suzhou' }, { name: 'Pune' }, { name: 'Harbin' }, { name: 'Houston' }, { name: 'Toronto' }, { name: 'Dar es Salaam' }, { name: 'Miami' }, { name: 'Belo Horizonte' }, { name: 'Singapore' }, { name: 'Atlanta' }, { name: 'Fukuoka' }, { name: 'Khartoum' }, { name: 'Barcelona' }, { name: 'Johannesburg' }, { name: 'Saint Petersburg' }, { name: 'Qingdao' }, { name: 'Dalian' }, { name: 'Washington, D.C.' }, { name: 'Yangon' }, { name: 'Alexandria' }, { name: 'Jinan' }, { name: 'Guadalajara' }, { name: 'Sydney' }, { name: 'Melbourne' }, { name: 'Montreal' }, { name: 'Ankara' }, { name: 'Recife' }, { name: 'Durban' }, { name: 'Porto Alegre' }, { name: 'Dusseldorf' }, { name: 'Hamburg' }, { name: 'Cape Town' }];
|
|
87
|
+
|
|
88
|
+
// Filter suggestions based on the input value
|
|
89
|
+
var filtered = suggestions.filter(function (item) {
|
|
90
|
+
return item.name.toLowerCase().startsWith(value.toLowerCase());
|
|
91
|
+
});
|
|
92
|
+
// Populate the suggestions box with the filtered results
|
|
93
|
+
suggestionsBox.innerHTML = filtered.map(function (item) {
|
|
94
|
+
return '<button class=\'' + namespace + 'm-multi-select__suggestion-btn\' tabindex=\'0\'>' + item.name + '</button>';
|
|
95
|
+
}).join('');
|
|
96
|
+
// Reset the current focus
|
|
97
|
+
currentFocus = -1;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Event listener for keydown events for navigation and selection in the suggestions box
|
|
101
|
+
multiSelectInput.addEventListener('keydown', function (e) {
|
|
102
|
+
var items = suggestionsBox.getElementsByClassName(namespace + 'm-multi-select__suggestion-btn');
|
|
103
|
+
// Navigate down in the suggestions list
|
|
104
|
+
if (e.keyCode == 40) {
|
|
105
|
+
currentFocus = (currentFocus + 1) % items.length;
|
|
106
|
+
setActive(items);
|
|
107
|
+
// Navigate up in the suggestions list
|
|
108
|
+
} else if (e.keyCode == 38) {
|
|
109
|
+
currentFocus = (currentFocus - 1 + items.length) % items.length;
|
|
110
|
+
setActive(items);
|
|
111
|
+
// Handle Enter key to select a focused item
|
|
112
|
+
} else if (e.keyCode == 13) {
|
|
113
|
+
e.preventDefault();
|
|
114
|
+
if (currentFocus > -1 && items[currentFocus]) {
|
|
115
|
+
addSelectedItem(items[currentFocus].textContent);
|
|
116
|
+
suggestionsBox.innerHTML = '';
|
|
117
|
+
multiSelectInput.value = '';
|
|
118
|
+
currentFocus = -1;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Click event listener for the suggestions box
|
|
124
|
+
suggestionsBox.addEventListener('click', function (e) {
|
|
125
|
+
// Add the clicked suggestion to the selected items list
|
|
126
|
+
if (e.target && e.target.classList.contains('suggestion-btn')) {
|
|
127
|
+
addSelectedItem(e.target.textContent);
|
|
128
|
+
suggestionsBox.innerHTML = '';
|
|
129
|
+
multiSelectInput.value = '';
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
package/package.json
CHANGED
package/src/app.scss
CHANGED
|
@@ -68,6 +68,7 @@ $namespace: '';
|
|
|
68
68
|
@import 'molecules/glider/glider-hero';
|
|
69
69
|
@import 'molecules/continue-video-guide/continue-video-guide';
|
|
70
70
|
@import 'molecules/overview-navigation/overview-navigation';
|
|
71
|
+
@import 'molecules/multi-select/multi-select';
|
|
71
72
|
|
|
72
73
|
// Organisms
|
|
73
74
|
@import 'organisms/header/header';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import className from './className';
|
|
2
|
+
import htmlTextLength from './htmlTextLength';
|
|
3
|
+
|
|
4
|
+
class CharCounter {
|
|
5
|
+
constructor(el) {
|
|
6
|
+
this.el = el;
|
|
7
|
+
this.counterEl = null;
|
|
8
|
+
this.isRichText = this.el.dataset.richText !== undefined;
|
|
9
|
+
this.min = parseInt(this.el.getAttribute('data-min') || 0, 10);
|
|
10
|
+
this.max = parseInt(this.el.getAttribute('data-max') || 0, 10);
|
|
11
|
+
|
|
12
|
+
if (!this.min && !this.max) {
|
|
13
|
+
console.warn('Either min or max must be set and greater than 0.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (this.isRichText) {
|
|
18
|
+
this.waitForEditor();
|
|
19
|
+
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.build();
|
|
24
|
+
this.attach();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
waitForEditor() {
|
|
28
|
+
if (this.el.editor) {
|
|
29
|
+
this.build();
|
|
30
|
+
this.attach();
|
|
31
|
+
} else {
|
|
32
|
+
this.el.addEventListener('editor-ready', () => {
|
|
33
|
+
this.build();
|
|
34
|
+
this.attach();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
count() {
|
|
40
|
+
if (this.isRichText) {
|
|
41
|
+
return htmlTextLength(this.el.editor.getHTML());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return this.el.value.length;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setCountText() {
|
|
48
|
+
const count = this.count();
|
|
49
|
+
|
|
50
|
+
if (this.min && count < this.min) {
|
|
51
|
+
this.counterEl.textContent = `${count}/${this.min}`;
|
|
52
|
+
this.counterEl.className = `color-ruby ${className('a-meta')}`;
|
|
53
|
+
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (this.max && count > this.max) {
|
|
58
|
+
this.counterEl.textContent = `${count}/${this.max}`;
|
|
59
|
+
this.counterEl.classList.remove('color-granit');
|
|
60
|
+
this.counterEl.className = `color-ruby ${className('a-meta')}`;
|
|
61
|
+
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.counterEl.textContent = `${count}/${this.max || this.min}`;
|
|
66
|
+
this.counterEl.className = `color-jade ${className('a-meta')}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
build() {
|
|
70
|
+
const counter = document.createElement('small');
|
|
71
|
+
let wrapper;
|
|
72
|
+
|
|
73
|
+
if (this.isRichText) {
|
|
74
|
+
wrapper = this.el.editor.options.element;
|
|
75
|
+
wrapper.style.paddingRight = '3.8333333333rem';
|
|
76
|
+
} else {
|
|
77
|
+
wrapper = document.createElement('div');
|
|
78
|
+
|
|
79
|
+
wrapper.className = 'u-position-relative';
|
|
80
|
+
this.el.parentNode.insertBefore(wrapper, this.el);
|
|
81
|
+
wrapper.appendChild(this.el);
|
|
82
|
+
|
|
83
|
+
this.el.style.paddingRight = '3.8333333333rem';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
counter.className = `color-granit ${className('a-meta')}`;
|
|
87
|
+
counter.style.cssText = 'position: absolute; top: 5px; right: 10px; z-index: 501;';
|
|
88
|
+
|
|
89
|
+
wrapper.appendChild(counter);
|
|
90
|
+
|
|
91
|
+
this.counterEl = counter;
|
|
92
|
+
this.setCountText();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
attach() {
|
|
96
|
+
if (this.isRichText) {
|
|
97
|
+
this.el.editor.on('update', () => {
|
|
98
|
+
this.setCountText();
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
this.el.addEventListener('input', () => {
|
|
102
|
+
this.setCountText();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const elements = document.querySelectorAll('[data-min], [data-max]');
|
|
109
|
+
elements.forEach((el) => {
|
|
110
|
+
el.charCounter = new CharCounter(el);
|
|
111
|
+
});
|
|
@@ -12,8 +12,10 @@ function toggleTextOnClick(e) {
|
|
|
12
12
|
target.innerText = options[nextIteration];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const toggleTextButtons = document.querySelectorAll('[data-toggle-text]');
|
|
16
16
|
|
|
17
|
-
if (
|
|
18
|
-
|
|
17
|
+
if (toggleTextButtons) {
|
|
18
|
+
[].forEach.call(toggleTextButtons, (toggleTextButton) => {
|
|
19
|
+
toggleTextButton.addEventListener('click', toggleTextOnClick);
|
|
20
|
+
});
|
|
19
21
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Show/hide target container when Radiobutton is selected
|
|
2
|
+
const radioButtons = document.querySelectorAll('[data-toggle="radio"]');
|
|
3
|
+
|
|
4
|
+
// Hide all target containers on page load
|
|
5
|
+
radioButtons.forEach((radio) => {
|
|
6
|
+
const targetId = radio.getAttribute('data-target');
|
|
7
|
+
const targetContainer = document.getElementById(targetId);
|
|
8
|
+
if (targetContainer) {
|
|
9
|
+
targetContainer.setAttribute('aria-hidden', 'true');
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// Function to toggle visibility
|
|
14
|
+
function toggleVisibility(event) {
|
|
15
|
+
// Hide all target containers
|
|
16
|
+
radioButtons.forEach((radio) => {
|
|
17
|
+
const targetId = radio.getAttribute('data-target');
|
|
18
|
+
const targetContainer = document.getElementById(targetId);
|
|
19
|
+
if (targetContainer) {
|
|
20
|
+
targetContainer.setAttribute('aria-hidden', 'true');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Update aria-expanded for all radio buttons
|
|
24
|
+
radio.setAttribute('aria-expanded', radio.checked ? 'true' : 'false');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Show the selected target container
|
|
28
|
+
const selectedTargetId = event.target.getAttribute('data-target');
|
|
29
|
+
const selectedTargetContainer = document.getElementById(selectedTargetId);
|
|
30
|
+
if (selectedTargetContainer) {
|
|
31
|
+
selectedTargetContainer.setAttribute('aria-hidden', 'false');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Add event listener to radio buttons
|
|
36
|
+
radioButtons.forEach((radio) => {
|
|
37
|
+
radio.addEventListener('change', toggleVisibility);
|
|
38
|
+
});
|
package/src/assets/js/youtube.js
CHANGED
|
@@ -186,6 +186,14 @@ export function setupTextArea(el, onChange = () => {}) {
|
|
|
186
186
|
el.parentNode.insertBefore(editorEl, el);
|
|
187
187
|
|
|
188
188
|
createToolbar(editorEl, editor);
|
|
189
|
+
|
|
190
|
+
const event = new CustomEvent('editor-ready', {
|
|
191
|
+
detail: {
|
|
192
|
+
editor,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
el.dispatchEvent(event);
|
|
189
197
|
}
|
|
190
198
|
|
|
191
199
|
export function init() {
|
|
@@ -51,6 +51,44 @@ module.exports = {
|
|
|
51
51
|
is_richtext: true,
|
|
52
52
|
has_help: false
|
|
53
53
|
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'Counter (max)',
|
|
57
|
+
status: 'wip',
|
|
58
|
+
context: {
|
|
59
|
+
is_richtext: false,
|
|
60
|
+
has_help: false,
|
|
61
|
+
max: 300,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Counter (min)',
|
|
66
|
+
status: 'wip',
|
|
67
|
+
context: {
|
|
68
|
+
is_richtext: false,
|
|
69
|
+
has_help: false,
|
|
70
|
+
min: 30,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'Counter (min and max)',
|
|
75
|
+
status: 'wip',
|
|
76
|
+
context: {
|
|
77
|
+
is_richtext: false,
|
|
78
|
+
has_help: false,
|
|
79
|
+
min: 30,
|
|
80
|
+
max: 300,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'Rich text with counter',
|
|
85
|
+
status: 'wip',
|
|
86
|
+
context: {
|
|
87
|
+
is_richtext: true,
|
|
88
|
+
has_help: true,
|
|
89
|
+
min: 30,
|
|
90
|
+
max: 300,
|
|
91
|
+
},
|
|
54
92
|
}
|
|
55
93
|
]
|
|
56
94
|
}
|
package/src/components.js
CHANGED
|
@@ -30,4 +30,8 @@ import './organisms/timeline/timeline';
|
|
|
30
30
|
import './molecules/overview-navigation/overview-navigation';
|
|
31
31
|
import './organisms/schedule/schedule-filter';
|
|
32
32
|
import './assets/js/ot';
|
|
33
|
+
import './assets/js/charCounter';
|
|
33
34
|
import './atoms/range/range';
|
|
35
|
+
import './assets/js/utmGenerator';
|
|
36
|
+
import './assets/js/textToggle';
|
|
37
|
+
import './molecules/multi-select/multi-select';
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
|
|
3
|
+
@include molecule(multi-select) {
|
|
4
|
+
position: relative;
|
|
5
|
+
|
|
6
|
+
&::before {
|
|
7
|
+
@extend %u-visuallyhidden;
|
|
8
|
+
|
|
9
|
+
content: $namespace;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@include e(suggestions-box) {
|
|
13
|
+
position: absolute;
|
|
14
|
+
border-top: none;
|
|
15
|
+
z-index: z_index(foreground);
|
|
16
|
+
top: 100%;
|
|
17
|
+
left: 0;
|
|
18
|
+
right: 0;
|
|
19
|
+
background-color: $color-snow;
|
|
20
|
+
overflow-y: auto;
|
|
21
|
+
max-height: rhythm(15);
|
|
22
|
+
border-bottom-left-radius: $border-radius;
|
|
23
|
+
border-bottom-right-radius: $border-radius;
|
|
24
|
+
|
|
25
|
+
@extend %box-shadow;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@include e(suggestion-btn) {
|
|
29
|
+
padding: 10px;
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
background-color: #fff;
|
|
32
|
+
border: none;
|
|
33
|
+
border-bottom: 1px solid #d4d4d4;
|
|
34
|
+
width: 100%;
|
|
35
|
+
text-align: left;
|
|
36
|
+
|
|
37
|
+
&:hover,
|
|
38
|
+
&.autocomplete-active {
|
|
39
|
+
background-color: $color-ocean;
|
|
40
|
+
color: $color-snow;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Selected items container */
|
|
46
|
+
.selected-items-container {
|
|
47
|
+
margin-top: -#{rhythm(1)};
|
|
48
|
+
padding: rhythm(2) rhythm(1) rhythm(1) rhythm(1);
|
|
49
|
+
border: 1px solid #d4d4d4;
|
|
50
|
+
background-color: $color-concrete;
|
|
51
|
+
border-bottom-left: $border-radius;
|
|
52
|
+
border-bottom-right-radius: $border-radius;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.selected-items-container:empty {
|
|
56
|
+
display: none;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Style for selected items */
|
|
60
|
+
.selected-items-container li {
|
|
61
|
+
margin-right: 5px;
|
|
62
|
+
padding: 5px;
|
|
63
|
+
border: 1px solid #ccc;
|
|
64
|
+
background-color: #e4e4e4;
|
|
65
|
+
border-radius: 4px;
|
|
66
|
+
display: inline-flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
margin-bottom: 0;
|
|
69
|
+
font-size: 90%;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Remove button for selected items */
|
|
73
|
+
.selected-items-container button {
|
|
74
|
+
margin-left: 5px;
|
|
75
|
+
border: none;
|
|
76
|
+
background-color: #d80000;
|
|
77
|
+
color: white;
|
|
78
|
+
border-radius: 50%;
|
|
79
|
+
cursor: pointer;
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
line-height: 1;
|
|
84
|
+
width: 16px;
|
|
85
|
+
height: 16px;
|
|
86
|
+
position: relative;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.selected-items-container button::after {
|
|
90
|
+
content: '';
|
|
91
|
+
display: block;
|
|
92
|
+
width: 16px;
|
|
93
|
+
height: 16px;
|
|
94
|
+
position: absolute;
|
|
95
|
+
top: 0;
|
|
96
|
+
left: 0;
|
|
97
|
+
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI4LjIuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAxNiAxNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMTYgMTY7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojRkZGRkZGO30KPC9zdHlsZT4KPHBvbHlnb24gY2xhc3M9InN0MCIgcG9pbnRzPSI4LDEwIDIsMTYgMCwxNCA2LDggMCwyIDIsMCA4LDYgMTQsMCAxNiwyIDEwLDggMTYsMTQgMTQsMTYgIi8+Cjwvc3ZnPgo=);
|
|
98
|
+
background-repeat: no-repeat;
|
|
99
|
+
background-position: center center;
|
|
100
|
+
background-size: 8px 8px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.selected-items-container button:hover {
|
|
104
|
+
background-color: darkred;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.visually-hidden {
|
|
108
|
+
position: absolute;
|
|
109
|
+
width: 1px;
|
|
110
|
+
height: 1px;
|
|
111
|
+
margin: -1px;
|
|
112
|
+
padding: 0;
|
|
113
|
+
overflow: hidden;
|
|
114
|
+
clip: rect(0 0 0 0);
|
|
115
|
+
clip: rect(0, 0, 0, 0);
|
|
116
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// Get references to the search input and suggestions box elements
|
|
3
|
+
const className = 'm-multi-select';
|
|
4
|
+
const multiSelectElement = document.querySelector(`.js-${className}`);
|
|
5
|
+
const multiSelectInput = document.querySelector(`.js-${className}__input`);
|
|
6
|
+
const suggestionsBox = document.querySelector(`.js-${className}-suggestions-box`);
|
|
7
|
+
|
|
8
|
+
if (multiSelectInput && suggestionsBox) {
|
|
9
|
+
let currentFocus = -1; // Tracks the currently focused item in the suggestions
|
|
10
|
+
const namespace = getComputedStyle(multiSelectElement, ':before').content.replace(/["']/g, '');
|
|
11
|
+
|
|
12
|
+
// Function to highlight the active (focused) suggestion
|
|
13
|
+
function setActive(items) {
|
|
14
|
+
if (!items.length) return false;
|
|
15
|
+
removeActive(items);
|
|
16
|
+
if (currentFocus >= items.length) currentFocus = 0;
|
|
17
|
+
if (currentFocus < 0) currentFocus = items.length - 1;
|
|
18
|
+
items[currentFocus].classList.add('autocomplete-active');
|
|
19
|
+
|
|
20
|
+
return items;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Function to remove highlighting from all suggestions
|
|
24
|
+
function removeActive(items) {
|
|
25
|
+
for (let i = 0; i < items.length; i++) {
|
|
26
|
+
items[i].classList.remove('autocomplete-active');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Function to add a selected item to the list of selected items
|
|
31
|
+
function addSelectedItem(item) {
|
|
32
|
+
const container = document.getElementById('selectedItemsContainer');
|
|
33
|
+
const newItem = document.createElement('li');
|
|
34
|
+
newItem.textContent = item + ' ';
|
|
35
|
+
const removeBtn = document.createElement('button');
|
|
36
|
+
const buttonTextContainer = document.createElement('span');
|
|
37
|
+
//removeBtn.textContent = 'x';
|
|
38
|
+
buttonTextContainer.classList.add('visually-hidden');
|
|
39
|
+
removeBtn.appendChild(buttonTextContainer);
|
|
40
|
+
buttonTextContainer.textContent ='Remove ' + item; // Accessibility label for screen readers
|
|
41
|
+
// Event listener for removing the selected item
|
|
42
|
+
removeBtn.addEventListener('click', function () {
|
|
43
|
+
removeItem(newItem, Array.from(container.children).indexOf(newItem));
|
|
44
|
+
});
|
|
45
|
+
newItem.appendChild(removeBtn);
|
|
46
|
+
container.appendChild(newItem);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Function to remove an item and manage focus appropriately
|
|
50
|
+
function removeItem(item, index) {
|
|
51
|
+
const container = document.getElementById('selectedItemsContainer');
|
|
52
|
+
container.removeChild(item);
|
|
53
|
+
|
|
54
|
+
let remainingItems = container.getElementsByTagName('div');
|
|
55
|
+
// Focus management: set focus to the next item, or the search input if no items left
|
|
56
|
+
if (remainingItems.length > 0) {
|
|
57
|
+
if (index < remainingItems.length) {
|
|
58
|
+
remainingItems[index].getElementsByTagName('button')[0].focus();
|
|
59
|
+
} else {
|
|
60
|
+
remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
multiSelectInput.focus();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Event listener for input changes in the search field
|
|
68
|
+
multiSelectInput.addEventListener('input', function () {
|
|
69
|
+
const value = this.value;
|
|
70
|
+
// Clear suggestions if less than 2 characters are typed
|
|
71
|
+
if (value.length < 2) {
|
|
72
|
+
suggestionsBox.innerHTML = '';
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Define a JSON array of 100 real cities
|
|
77
|
+
let suggestions = [
|
|
78
|
+
{ name: 'New York' }, { name: 'Los Angeles' }, { name: 'Chicago' },
|
|
79
|
+
{ name: 'Houston' }, { name: 'Phoenix' }, { name: 'Philadelphia' },
|
|
80
|
+
{ name: 'San Antonio' }, { name: 'San Diego' }, { name: 'Dallas' },
|
|
81
|
+
{ name: 'San Jose' }, { name: 'Austin' }, { name: 'Jacksonville' },
|
|
82
|
+
{ name: 'Fort Worth' }, { name: 'Columbus' }, { name: 'San Francisco' },
|
|
83
|
+
{ name: 'Tokyo' }, { name: 'Delhi' }, { name: 'Shanghai' },
|
|
84
|
+
{ name: 'Sao Paulo' }, { name: 'Mumbai' }, { name: 'Beijing' },
|
|
85
|
+
{ name: 'Cairo' }, { name: 'Dhaka' }, { name: 'Mexico City' },
|
|
86
|
+
{ name: 'Osaka' }, { name: 'Karachi' }, { name: 'Chongqing' },
|
|
87
|
+
{ name: 'Istanbul' }, { name: 'Buenos Aires' }, { name: 'Kolkata' },
|
|
88
|
+
{ name: 'Kinshasa' }, { name: 'Lagos' }, { name: 'Manila' },
|
|
89
|
+
{ name: 'Tianjin' }, { name: 'Rio de Janeiro' }, { name: 'Guangzhou' },
|
|
90
|
+
{ name: 'Lahore' }, { name: 'Moscow' }, { name: 'Shenzhen' },
|
|
91
|
+
{ name: 'Bangalore' }, { name: 'Paris' }, { name: 'Bogota' },
|
|
92
|
+
{ name: 'Jakarta' }, { name: 'Chennai' }, { name: 'Lima' },
|
|
93
|
+
{ name: 'Bangkok' }, { name: 'Seoul' }, { name: 'Nagoya' },
|
|
94
|
+
{ name: 'Hyderabad' }, { name: 'London' }, { name: 'Tehran' },
|
|
95
|
+
{ name: 'Chengdu' }, { name: 'Nanjing' },
|
|
96
|
+
{ name: 'Wuhan' }, { name: 'Ho Chi Minh City' }, { name: 'Luanda' },
|
|
97
|
+
{ name: 'Ahmedabad' }, { name: 'Kuala Lumpur' }, { name: 'Xi’an' },
|
|
98
|
+
{ name: 'Hong Kong' }, { name: 'Dongguan' }, { name: 'Hangzhou' },
|
|
99
|
+
{ name: 'Foshan' }, { name: 'Shenyang' }, { name: 'Riyadh' },
|
|
100
|
+
{ name: 'Baghdad' }, { name: 'Santiago' }, { name: 'Surat' },
|
|
101
|
+
{ name: 'Madrid' }, { name: 'Suzhou' }, { name: 'Pune' },
|
|
102
|
+
{ name: 'Harbin' }, { name: 'Houston' },
|
|
103
|
+
{ name: 'Toronto' }, { name: 'Dar es Salaam' }, { name: 'Miami' },
|
|
104
|
+
{ name: 'Belo Horizonte' }, { name: 'Singapore' },
|
|
105
|
+
{ name: 'Atlanta' }, { name: 'Fukuoka' }, { name: 'Khartoum' },
|
|
106
|
+
{ name: 'Barcelona' }, { name: 'Johannesburg' }, { name: 'Saint Petersburg' },
|
|
107
|
+
{ name: 'Qingdao' }, { name: 'Dalian' }, { name: 'Washington, D.C.' },
|
|
108
|
+
{ name: 'Yangon' }, { name: 'Alexandria' }, { name: 'Jinan' },
|
|
109
|
+
{ name: 'Guadalajara' }, { name: 'Sydney' }, { name: 'Melbourne' },
|
|
110
|
+
{ name: 'Montreal' }, { name: 'Ankara' }, { name: 'Recife' },
|
|
111
|
+
{ name: 'Durban' }, { name: 'Porto Alegre' },
|
|
112
|
+
{ name: 'Dusseldorf' }, { name: 'Hamburg' }, { name: 'Cape Town' },
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
// Filter suggestions based on the input value
|
|
116
|
+
const filtered = suggestions.filter(item => item.name.toLowerCase().startsWith(value.toLowerCase()));
|
|
117
|
+
// Populate the suggestions box with the filtered results
|
|
118
|
+
suggestionsBox.innerHTML = filtered.map(item => `<button class='${namespace}m-multi-select__suggestion-btn' tabindex='0'>${item.name}</button>`).join('');
|
|
119
|
+
// Reset the current focus
|
|
120
|
+
currentFocus = -1;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Event listener for keydown events for navigation and selection in the suggestions box
|
|
124
|
+
multiSelectInput.addEventListener('keydown', function (e) {
|
|
125
|
+
let items = suggestionsBox.getElementsByClassName(`${namespace}m-multi-select__suggestion-btn`);
|
|
126
|
+
// Navigate down in the suggestions list
|
|
127
|
+
if (e.keyCode == 40) {
|
|
128
|
+
currentFocus = (currentFocus + 1) % items.length;
|
|
129
|
+
setActive(items);
|
|
130
|
+
// Navigate up in the suggestions list
|
|
131
|
+
} else if (e.keyCode == 38) {
|
|
132
|
+
currentFocus = (currentFocus - 1 + items.length) % items.length;
|
|
133
|
+
setActive(items);
|
|
134
|
+
// Handle Enter key to select a focused item
|
|
135
|
+
} else if (e.keyCode == 13) {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
if (currentFocus > -1 && items[currentFocus]) {
|
|
138
|
+
addSelectedItem(items[currentFocus].textContent);
|
|
139
|
+
suggestionsBox.innerHTML = '';
|
|
140
|
+
multiSelectInput.value = '';
|
|
141
|
+
currentFocus = -1;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Click event listener for the suggestions box
|
|
147
|
+
suggestionsBox.addEventListener('click', function (e) {
|
|
148
|
+
// Add the clicked suggestion to the selected items list
|
|
149
|
+
if (e.target && e.target.classList.contains('suggestion-btn')) {
|
|
150
|
+
addSelectedItem(e.target.textContent);
|
|
151
|
+
suggestionsBox.innerHTML = '';
|
|
152
|
+
multiSelectInput.value = '';
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
}
|