vrembem 1.41.0 → 2.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/dev/scripts.esm.js +1298 -625
- package/dev/scripts.esm.js.map +1 -1
- package/dev/scripts.js +1298 -625
- package/dev/scripts.js.map +1 -1
- package/dev/scripts.modern.js +836 -541
- package/dev/scripts.modern.js.map +1 -1
- package/dev/scripts.umd.js +1298 -625
- package/dev/scripts.umd.js.map +1 -1
- package/dev/styles.css +10 -11
- package/dev/styles.css.map +1 -1
- package/dist/scripts.esm.js +1 -1
- package/dist/scripts.esm.js.map +1 -1
- package/dist/scripts.js +1 -1
- package/dist/scripts.js.map +1 -1
- package/dist/scripts.modern.js +1 -1
- package/dist/scripts.modern.js.map +1 -1
- package/dist/scripts.umd.js +1 -1
- package/dist/scripts.umd.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +26 -26
package/dev/scripts.modern.js
CHANGED
|
@@ -56,10 +56,60 @@ const camelCase = str => {
|
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
class Collection {
|
|
60
|
+
constructor() {
|
|
61
|
+
this.collection = [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async register(item) {
|
|
65
|
+
await this.deregister(item);
|
|
66
|
+
this.collection.push(item);
|
|
67
|
+
return this.collection;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async deregister(ref) {
|
|
71
|
+
const index = this.collection.findIndex(entry => {
|
|
72
|
+
return entry === ref;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (index >= 0) {
|
|
76
|
+
const entry = this.collection[index];
|
|
77
|
+
Object.getOwnPropertyNames(entry).forEach(prop => {
|
|
78
|
+
delete entry[prop];
|
|
79
|
+
});
|
|
80
|
+
this.collection.splice(index, 1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return this.collection;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async registerCollection(items) {
|
|
87
|
+
await Promise.all(Array.from(items, item => {
|
|
88
|
+
this.register(item);
|
|
89
|
+
}));
|
|
90
|
+
return this.collection;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async deregisterCollection() {
|
|
94
|
+
while (this.collection.length > 0) {
|
|
95
|
+
await this.deregister(this.collection[0]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return this.collection;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get(value, key = 'id') {
|
|
102
|
+
return this.collection.find(item => {
|
|
103
|
+
return item[key] === value;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
59
109
|
var focusableSelectors = ['a[href]:not([tabindex^="-"])', 'area[href]:not([tabindex^="-"])', 'input:not([type="hidden"]):not([type="radio"]):not([disabled]):not([tabindex^="-"])', 'input[type="radio"]:not([disabled]):not([tabindex^="-"])', 'select:not([disabled]):not([tabindex^="-"])', 'textarea:not([disabled]):not([tabindex^="-"])', 'button:not([disabled]):not([tabindex^="-"])', 'iframe:not([tabindex^="-"])', 'audio[controls]:not([tabindex^="-"])', 'video[controls]:not([tabindex^="-"])', '[contenteditable]:not([tabindex^="-"])', '[tabindex]:not([tabindex^="-"])'];
|
|
60
110
|
|
|
61
111
|
const focusTarget = (target, settings) => {
|
|
62
|
-
const innerFocus = target.querySelector(
|
|
112
|
+
const innerFocus = target.querySelector(settings.selectorFocus);
|
|
63
113
|
|
|
64
114
|
if (innerFocus) {
|
|
65
115
|
innerFocus.focus();
|
|
@@ -68,7 +118,7 @@ const focusTarget = (target, settings) => {
|
|
|
68
118
|
if (innerElement) innerElement.focus();
|
|
69
119
|
}
|
|
70
120
|
};
|
|
71
|
-
const focusTrigger =
|
|
121
|
+
const focusTrigger = obj => {
|
|
72
122
|
if (!obj || !obj.memory || !obj.memory.trigger) return;
|
|
73
123
|
obj.memory.trigger.focus();
|
|
74
124
|
obj.memory.trigger = null;
|
|
@@ -80,6 +130,7 @@ class FocusTrap {
|
|
|
80
130
|
}
|
|
81
131
|
|
|
82
132
|
init(target) {
|
|
133
|
+
this.destroy();
|
|
83
134
|
this.target = target;
|
|
84
135
|
this.inner = this.target.querySelector('[tabindex="-1"]');
|
|
85
136
|
this.focusable = this.getFocusable();
|
|
@@ -166,16 +217,6 @@ class FocusTrap {
|
|
|
166
217
|
|
|
167
218
|
}
|
|
168
219
|
|
|
169
|
-
/**
|
|
170
|
-
* Get an element(s) from a selector or return value if not a string.
|
|
171
|
-
* @param {String} selector - Selector to query.
|
|
172
|
-
* @param {Boolean} single - Whether to return a single or all matches.
|
|
173
|
-
*/
|
|
174
|
-
const getElement = function getElement(selector, single = 0) {
|
|
175
|
-
if (typeof selector !== 'string') return selector;
|
|
176
|
-
return single ? document.querySelector(selector) : document.querySelectorAll(selector);
|
|
177
|
-
};
|
|
178
|
-
|
|
179
220
|
/**
|
|
180
221
|
* Checks an element or NodeList whether they contain a class or classes.
|
|
181
222
|
* Ref: https://davidwalsh.name/nodelist-array
|
|
@@ -204,60 +245,6 @@ const hyphenCase = str => {
|
|
|
204
245
|
});
|
|
205
246
|
};
|
|
206
247
|
|
|
207
|
-
/**
|
|
208
|
-
* Moves element(s) in the DOM based on a reference and move type.
|
|
209
|
-
* @param {String} target - The element(s) to move.
|
|
210
|
-
* @param {String} type - Move type can be 'after', 'before', 'append' or 'prepend'.
|
|
211
|
-
* @param {String} reference - The reference element the move is relative to.
|
|
212
|
-
*/
|
|
213
|
-
|
|
214
|
-
function moveElement(target, type, reference = false) {
|
|
215
|
-
if (reference) {
|
|
216
|
-
const els = getElement(target);
|
|
217
|
-
if (!els.length) throw new Error(`Move target element "${target}" not found!`);
|
|
218
|
-
const ref = getElement(reference, 1);
|
|
219
|
-
if (!ref) throw new Error(`Move reference element "${reference}" not found!`);
|
|
220
|
-
els.forEach(el => {
|
|
221
|
-
switch (type) {
|
|
222
|
-
case 'after':
|
|
223
|
-
ref.after(el);
|
|
224
|
-
return {
|
|
225
|
-
ref,
|
|
226
|
-
el,
|
|
227
|
-
type
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
case 'before':
|
|
231
|
-
ref.before(el);
|
|
232
|
-
return {
|
|
233
|
-
ref,
|
|
234
|
-
el,
|
|
235
|
-
type
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
case 'append':
|
|
239
|
-
ref.append(el);
|
|
240
|
-
return {
|
|
241
|
-
ref,
|
|
242
|
-
el,
|
|
243
|
-
type
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
case 'prepend':
|
|
247
|
-
ref.prepend(el);
|
|
248
|
-
return {
|
|
249
|
-
ref,
|
|
250
|
-
el,
|
|
251
|
-
type
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
default:
|
|
255
|
-
throw new Error(`Move type "${type}" does not exist!`);
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
248
|
/**
|
|
262
249
|
* Remove a class or classes from an element or NodeList.
|
|
263
250
|
* @param {Node || NodeList} el - Element(s) to remove class(es) from.
|
|
@@ -270,6 +257,48 @@ const removeClass = (el, ...cl) => {
|
|
|
270
257
|
});
|
|
271
258
|
};
|
|
272
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Teleports an element in the DOM based on a reference and teleport method.
|
|
262
|
+
* Provide the comment node as the reference to teleport the element back to its
|
|
263
|
+
* previous location.
|
|
264
|
+
* @param {Node} what - What element to teleport.
|
|
265
|
+
* @param {String || Node} where - Where to teleport the element.
|
|
266
|
+
* @param {String} how - How (method) to teleport the element, e.g: 'after',
|
|
267
|
+
* 'before', 'append' or 'prepend'.
|
|
268
|
+
* @return {Node} Return the return reference if it was teleported else return
|
|
269
|
+
* null if it was returned to a comment reference.
|
|
270
|
+
*/
|
|
271
|
+
function teleport(what, where, how) {
|
|
272
|
+
// Check if ref is either a comment or element node.
|
|
273
|
+
const isComment = where.nodeType === Node.COMMENT_NODE;
|
|
274
|
+
const isElement = where.nodeType === Node.ELEMENT_NODE; // Get the reference element.
|
|
275
|
+
|
|
276
|
+
where = isComment || isElement ? where : document.querySelector(where); // If ref is a comment, set teleport type to 'after'.
|
|
277
|
+
|
|
278
|
+
if (isComment) how = 'after'; // Must be a valid reference element and method.
|
|
279
|
+
|
|
280
|
+
if (!where) throw new Error(`Not a valid teleport reference: '${where}'`);
|
|
281
|
+
if (typeof where[how] != 'function') throw new Error(`Not a valid teleport method: '${how}'`); // Initial return ref is null.
|
|
282
|
+
|
|
283
|
+
let returnRef = null; // If ref is not a comment, set a return reference comment.
|
|
284
|
+
|
|
285
|
+
if (!isComment) {
|
|
286
|
+
returnRef = document.createComment('teleported #' + what.id);
|
|
287
|
+
what.before(returnRef);
|
|
288
|
+
} // Teleport the target node.
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
where[how](what); // Delete the comment node if element was returned to a comment reference.
|
|
292
|
+
|
|
293
|
+
if (isComment) {
|
|
294
|
+
where.remove();
|
|
295
|
+
} // Return the return reference if it was teleported else return null if it was
|
|
296
|
+
// returned to a comment reference.
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
return returnRef;
|
|
300
|
+
}
|
|
301
|
+
|
|
273
302
|
/**
|
|
274
303
|
* Toggle a class or classes on an element or NodeList.
|
|
275
304
|
* @param {Node || NodeList} el - Element(s) to toggle class(es) on.
|
|
@@ -328,14 +357,14 @@ var index = {
|
|
|
328
357
|
setTabindex: setTabindex,
|
|
329
358
|
addClass: addClass,
|
|
330
359
|
camelCase: camelCase,
|
|
360
|
+
Collection: Collection,
|
|
331
361
|
focusTarget: focusTarget,
|
|
332
362
|
focusTrigger: focusTrigger,
|
|
333
363
|
FocusTrap: FocusTrap,
|
|
334
|
-
getElement: getElement,
|
|
335
364
|
hasClass: hasClass,
|
|
336
365
|
hyphenCase: hyphenCase,
|
|
337
|
-
moveElement: moveElement,
|
|
338
366
|
removeClass: removeClass,
|
|
367
|
+
teleport: teleport,
|
|
339
368
|
toggleClass: toggleClass,
|
|
340
369
|
openTransition: openTransition,
|
|
341
370
|
closeTransition: closeTransition
|
|
@@ -429,7 +458,10 @@ var defaults$2 = {
|
|
|
429
458
|
dataOpen: 'drawer-open',
|
|
430
459
|
dataClose: 'drawer-close',
|
|
431
460
|
dataBreakpoint: 'drawer-breakpoint',
|
|
432
|
-
|
|
461
|
+
// Selectors
|
|
462
|
+
selectorFocus: '[data-focus]',
|
|
463
|
+
selectorInert: null,
|
|
464
|
+
selectorOverflow: null,
|
|
433
465
|
// State classes
|
|
434
466
|
stateOpened: 'is-opened',
|
|
435
467
|
stateOpening: 'is-opening',
|
|
@@ -437,9 +469,6 @@ var defaults$2 = {
|
|
|
437
469
|
stateClosed: 'is-closed',
|
|
438
470
|
// Classes
|
|
439
471
|
classModal: 'drawer_modal',
|
|
440
|
-
// Selectors
|
|
441
|
-
selectorInert: null,
|
|
442
|
-
selectorOverflow: null,
|
|
443
472
|
// Feature toggles
|
|
444
473
|
breakpoints: null,
|
|
445
474
|
customEventPrefix: 'drawer:',
|
|
@@ -573,7 +602,7 @@ async function close$2(drawerKey) {
|
|
|
573
602
|
}
|
|
574
603
|
}
|
|
575
604
|
|
|
576
|
-
function handlerClick$
|
|
605
|
+
function handlerClick$1(event) {
|
|
577
606
|
// Working catch
|
|
578
607
|
if (this.working) return; // Toggle data trigger
|
|
579
608
|
|
|
@@ -622,7 +651,7 @@ function handlerClick$2(event) {
|
|
|
622
651
|
return;
|
|
623
652
|
}
|
|
624
653
|
}
|
|
625
|
-
function handlerKeydown$
|
|
654
|
+
function handlerKeydown$1(event) {
|
|
626
655
|
// Working catch
|
|
627
656
|
if (this.working) return;
|
|
628
657
|
|
|
@@ -774,8 +803,8 @@ class Drawer {
|
|
|
774
803
|
this.state = {};
|
|
775
804
|
this.focusTrap = new FocusTrap();
|
|
776
805
|
this.breakpoint = new Breakpoint(this);
|
|
777
|
-
this.__handlerClick = handlerClick$
|
|
778
|
-
this.__handlerKeydown = handlerKeydown$
|
|
806
|
+
this.__handlerClick = handlerClick$1.bind(this);
|
|
807
|
+
this.__handlerKeydown = handlerKeydown$1.bind(this);
|
|
779
808
|
if (this.settings.autoInit) this.init();
|
|
780
809
|
}
|
|
781
810
|
|
|
@@ -885,400 +914,547 @@ class Drawer {
|
|
|
885
914
|
var defaults$1 = {
|
|
886
915
|
autoInit: false,
|
|
887
916
|
// Data attributes
|
|
888
|
-
dataModal: 'modal',
|
|
889
|
-
dataDialog: 'modal-dialog',
|
|
890
917
|
dataOpen: 'modal-open',
|
|
891
918
|
dataClose: 'modal-close',
|
|
892
|
-
|
|
893
|
-
|
|
919
|
+
dataReplace: 'modal-replace',
|
|
920
|
+
dataConfig: 'modal-config',
|
|
921
|
+
// Selectors
|
|
922
|
+
selectorModal: '.modal',
|
|
923
|
+
selectorDialog: '.modal__dialog',
|
|
924
|
+
selectorRequired: '[role="alertdialog"]',
|
|
925
|
+
selectorFocus: '[data-focus]',
|
|
926
|
+
selectorInert: null,
|
|
927
|
+
selectorOverflow: 'body',
|
|
894
928
|
// State classes
|
|
895
929
|
stateOpened: 'is-opened',
|
|
896
930
|
stateOpening: 'is-opening',
|
|
897
931
|
stateClosing: 'is-closing',
|
|
898
932
|
stateClosed: 'is-closed',
|
|
899
|
-
//
|
|
900
|
-
selectorInert: null,
|
|
901
|
-
selectorOverflow: 'body',
|
|
902
|
-
// Feature toggles
|
|
933
|
+
// Feature settings
|
|
903
934
|
customEventPrefix: 'modal:',
|
|
904
935
|
eventListeners: true,
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
type: null
|
|
908
|
-
},
|
|
936
|
+
teleport: null,
|
|
937
|
+
teleportMethod: 'append',
|
|
909
938
|
setTabindex: true,
|
|
910
939
|
transition: true
|
|
911
940
|
};
|
|
912
941
|
|
|
913
|
-
|
|
914
|
-
|
|
942
|
+
function updateGlobalState() {
|
|
943
|
+
// Set inert state based on if a modal is active.
|
|
944
|
+
setInert(!!this.active, this.settings.selectorInert); // Set overflow state based on if a modal is active.
|
|
915
945
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
946
|
+
setOverflowHidden(!!this.active, this.settings.selectorOverflow); // Update the z-index of the stack.
|
|
947
|
+
|
|
948
|
+
updateStackIndex(this.stack);
|
|
949
|
+
}
|
|
950
|
+
function updateFocusState() {
|
|
951
|
+
// Check if there's an active modal
|
|
952
|
+
if (this.active) {
|
|
953
|
+
// Set focus and init focus trap on active modal.
|
|
954
|
+
focusTarget(this.active.target, this.settings);
|
|
955
|
+
this.focusTrap.init(this.active.target);
|
|
956
|
+
} else {
|
|
957
|
+
// Set focus to root trigger and destroy focus trap.
|
|
958
|
+
focusTrigger(this);
|
|
922
959
|
this.focusTrap.destroy();
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
function updateStackIndex(stack) {
|
|
963
|
+
stack.forEach((entry, index) => {
|
|
964
|
+
entry.target.style.zIndex = null;
|
|
965
|
+
const value = getComputedStyle(entry.target)['z-index'];
|
|
966
|
+
entry.target.style.zIndex = parseInt(value) + index + 1;
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
function getConfig$1(el) {
|
|
970
|
+
const string = el.getAttribute(`data-${this.settings.dataConfig}`) || '';
|
|
971
|
+
const json = string.replace(/'/g, '"');
|
|
972
|
+
return json ? JSON.parse(json) : {};
|
|
973
|
+
}
|
|
974
|
+
function getModal(query) {
|
|
975
|
+
// Get the entry from collection.
|
|
976
|
+
const entry = typeof query === 'string' ? this.get(query) : this.get(query.id); // Return entry if it was resolved, otherwise throw error.
|
|
977
|
+
|
|
978
|
+
if (entry) {
|
|
979
|
+
return entry;
|
|
929
980
|
} else {
|
|
930
|
-
|
|
981
|
+
throw new Error(`Modal not found in collection with id of "${query}".`);
|
|
931
982
|
}
|
|
932
983
|
}
|
|
984
|
+
function getModalID(obj) {
|
|
985
|
+
// If it's a string, return the string.
|
|
986
|
+
if (typeof obj === 'string') {
|
|
987
|
+
return obj;
|
|
988
|
+
} // If it's an HTML element.
|
|
989
|
+
else if (typeof obj.hasAttribute === 'function') {
|
|
990
|
+
// If it's a modal open trigger, return data value.
|
|
991
|
+
if (obj.hasAttribute(`data-${this.settings.dataOpen}`)) {
|
|
992
|
+
return obj.getAttribute(`data-${this.settings.dataOpen}`);
|
|
993
|
+
} // If it's a modal close trigger, return data value or false.
|
|
994
|
+
else if (obj.hasAttribute(`data-${this.settings.dataClose}`)) {
|
|
995
|
+
return obj.getAttribute(`data-${this.settings.dataClose}`) || false;
|
|
996
|
+
} // If it's a modal replace trigger, return data value.
|
|
997
|
+
else if (obj.hasAttribute(`data-${this.settings.dataReplace}`)) {
|
|
998
|
+
return obj.getAttribute(`data-${this.settings.dataReplace}`);
|
|
999
|
+
} // If it's a modal target, return the id.
|
|
1000
|
+
else if (obj.closest(this.settings.selectorModal)) {
|
|
1001
|
+
obj = obj.closest(this.settings.selectorModal);
|
|
1002
|
+
return obj.id || false;
|
|
1003
|
+
} // Return false if no id was found.
|
|
1004
|
+
else return false;
|
|
1005
|
+
} // If it has an id property, return its value.
|
|
1006
|
+
else if (obj.id) {
|
|
1007
|
+
return obj.id;
|
|
1008
|
+
} // Return false if no id was found.
|
|
1009
|
+
else return false;
|
|
1010
|
+
}
|
|
1011
|
+
function getModalElements(query) {
|
|
1012
|
+
const id = getModalID.call(this, query);
|
|
933
1013
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1014
|
+
if (id) {
|
|
1015
|
+
const target = document.querySelector(`#${id}`);
|
|
1016
|
+
const dialog = target ? target.querySelector(this.settings.selectorDialog) : null;
|
|
937
1017
|
|
|
938
|
-
|
|
1018
|
+
if (!target && !dialog) {
|
|
1019
|
+
return {
|
|
1020
|
+
error: new Error(`No modal elements found using the ID: "${id}".`)
|
|
1021
|
+
};
|
|
1022
|
+
} else if (!dialog) {
|
|
1023
|
+
return {
|
|
1024
|
+
error: new Error('Modal is missing dialog element.')
|
|
1025
|
+
};
|
|
1026
|
+
} else {
|
|
1027
|
+
return {
|
|
1028
|
+
target,
|
|
1029
|
+
dialog
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
} else {
|
|
1033
|
+
return {
|
|
1034
|
+
error: new Error('Could not resolve the modal ID.')
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
async function handleClick(event) {
|
|
1040
|
+
// If an open or replace button was clicked, open or replace the modal.
|
|
1041
|
+
let trigger = event.target.closest(`[data-${this.settings.dataOpen}], [data-${this.settings.dataReplace}]`);
|
|
939
1042
|
|
|
940
1043
|
if (trigger) {
|
|
941
|
-
event.preventDefault();
|
|
942
|
-
const modalKey = trigger.getAttribute(`data-${this.settings.dataOpen}`);
|
|
943
|
-
const fromModal = event.target.closest(`[data-${this.settings.dataModal}]`);
|
|
944
|
-
if (!fromModal) this.memory.trigger = trigger;
|
|
945
|
-
await this.close(!fromModal);
|
|
946
|
-
this.open(modalKey);
|
|
947
|
-
return;
|
|
948
|
-
} // Close click
|
|
1044
|
+
event.preventDefault(); // Save the trigger if it's not coming from inside a modal.
|
|
949
1045
|
|
|
1046
|
+
const fromModal = event.target.closest(this.settings.selectorModal);
|
|
1047
|
+
if (!fromModal) this.memory.trigger = trigger; // Get the modal.
|
|
950
1048
|
|
|
951
|
-
|
|
952
|
-
event.preventDefault();
|
|
953
|
-
this.close();
|
|
954
|
-
return;
|
|
955
|
-
} // Root click
|
|
1049
|
+
const modal = this.get(getModalID.call(this, trigger)); // Depending on the button type, either open or replace the modal.
|
|
956
1050
|
|
|
1051
|
+
return trigger.matches(`[data-${this.settings.dataOpen}]`) ? modal.open() : modal.replace();
|
|
1052
|
+
} // If a close button was clicked, close the modal.
|
|
957
1053
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1054
|
+
|
|
1055
|
+
trigger = event.target.closest(`[data-${this.settings.dataClose}]`);
|
|
1056
|
+
|
|
1057
|
+
if (trigger) {
|
|
1058
|
+
event.preventDefault(); // Get the value of the data attribute.
|
|
1059
|
+
|
|
1060
|
+
const value = trigger.getAttribute(`data-${this.settings.dataClose}`); // Close all if * wildcard is passed, otherwise close a single modal.
|
|
1061
|
+
|
|
1062
|
+
return value === '*' ? this.closeAll() : this.close(value);
|
|
1063
|
+
} // If the modal screen was clicked, close the modal.
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
if (event.target.matches(this.settings.selectorModal) && !event.target.querySelector(this.settings.selectorRequired)) {
|
|
1067
|
+
return this.close(getModalID.call(this, event.target));
|
|
961
1068
|
}
|
|
962
1069
|
}
|
|
963
|
-
function
|
|
964
|
-
//
|
|
965
|
-
if (this.working) return;
|
|
966
|
-
|
|
1070
|
+
function handleKeydown(event) {
|
|
1071
|
+
// If escape key was pressed.
|
|
967
1072
|
if (event.key === 'Escape') {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
this.close();
|
|
1073
|
+
// If a modal is opened and not required, close the modal.
|
|
1074
|
+
if (this.active && !this.active.dialog.matches(this.settings.selectorRequired)) {
|
|
1075
|
+
return this.close();
|
|
972
1076
|
}
|
|
973
1077
|
}
|
|
974
1078
|
}
|
|
975
1079
|
|
|
976
|
-
function
|
|
977
|
-
|
|
978
|
-
return
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1080
|
+
async function deregister$1(obj, close = true) {
|
|
1081
|
+
// Return collection if nothing was passed.
|
|
1082
|
+
if (!obj) return this.collection; // Check if entry has been registered in the collection.
|
|
1083
|
+
|
|
1084
|
+
const index = this.collection.findIndex(entry => {
|
|
1085
|
+
return entry.id === obj.id;
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
if (index >= 0) {
|
|
1089
|
+
// Get the collection entry.
|
|
1090
|
+
const entry = this.collection[index]; // If entry is in the opened state, close it.
|
|
1091
|
+
|
|
1092
|
+
if (close && entry.state === 'opened') {
|
|
1093
|
+
await entry.close(false);
|
|
1094
|
+
} else {
|
|
1095
|
+
// Get index of modal in stack array.
|
|
1096
|
+
const stackIndex = this.stack.findIndex(item => {
|
|
1097
|
+
return item.id === entry.id;
|
|
1098
|
+
}); // Remove modal from stack array.
|
|
1099
|
+
|
|
1100
|
+
if (stackIndex >= 0) {
|
|
1101
|
+
this.stack.splice(stackIndex, 1);
|
|
1102
|
+
}
|
|
1103
|
+
} // Return teleported modal if a reference has been set.
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
if (entry.getSetting('teleport')) {
|
|
1107
|
+
entry.teleportReturn();
|
|
1108
|
+
} // Delete properties from collection entry.
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
Object.getOwnPropertyNames(entry).forEach(prop => {
|
|
1112
|
+
delete entry[prop];
|
|
1113
|
+
}); // Remove entry from collection.
|
|
1114
|
+
|
|
1115
|
+
this.collection.splice(index, 1);
|
|
1116
|
+
} // Return the modified collection.
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
return this.collection;
|
|
986
1120
|
}
|
|
987
1121
|
|
|
988
|
-
function
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
// Remove opened state setup
|
|
992
|
-
if (el.classList.contains(this.settings.stateOpened)) {
|
|
993
|
-
setInert(false, this.settings.selectorInert);
|
|
994
|
-
setOverflowHidden(false, this.settings.selectorOverflow);
|
|
995
|
-
focusTrigger(this);
|
|
996
|
-
this.focusTrap.destroy();
|
|
997
|
-
} // Remove all state classes and add the default state (closed)
|
|
1122
|
+
async function open$1(query, transition, bulk = false) {
|
|
1123
|
+
// Get the modal from collection.
|
|
1124
|
+
const modal = getModal.call(this, query); // Get the modal configuration.
|
|
998
1125
|
|
|
1126
|
+
const config = _extends({}, this.settings, modal.settings); // Add transition parameter to configuration.
|
|
999
1127
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1128
|
+
|
|
1129
|
+
if (transition !== undefined) config.transition = transition; // Check if modal is already in the stack.
|
|
1130
|
+
|
|
1131
|
+
const index = this.stack.findIndex(entry => {
|
|
1132
|
+
return entry.id === modal.id;
|
|
1133
|
+
}); // If modal is already open.
|
|
1134
|
+
|
|
1135
|
+
if (index >= 0) {
|
|
1136
|
+
// Remove modal from stack array.
|
|
1137
|
+
this.stack.splice(index, 1); // Move back to end of stack.
|
|
1138
|
+
|
|
1139
|
+
this.stack.push(modal);
|
|
1140
|
+
} // If modal is closed.
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
if (modal.state === 'closed') {
|
|
1144
|
+
// Update modal state.
|
|
1145
|
+
modal.state = 'opening'; // Apply z-index styles based on stack length.
|
|
1146
|
+
|
|
1147
|
+
modal.target.style.zIndex = null;
|
|
1148
|
+
const value = getComputedStyle(modal.target)['z-index'];
|
|
1149
|
+
modal.target.style.zIndex = parseInt(value) + this.stack.length + 1; // Store modal in stack array.
|
|
1150
|
+
|
|
1151
|
+
this.stack.push(modal); // Run the open transition.
|
|
1152
|
+
|
|
1153
|
+
await openTransition(modal.target, config); // Update modal state.
|
|
1154
|
+
|
|
1155
|
+
modal.state = 'opened';
|
|
1156
|
+
} // Update the focus state if this is not a bulk action.
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
if (!bulk) {
|
|
1160
|
+
updateFocusState.call(this);
|
|
1161
|
+
} // Dispatch custom opened event.
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
modal.target.dispatchEvent(new CustomEvent(config.customEventPrefix + 'opened', {
|
|
1165
|
+
detail: this,
|
|
1166
|
+
bubbles: true
|
|
1167
|
+
})); // Return the modal.
|
|
1168
|
+
|
|
1169
|
+
return modal;
|
|
1003
1170
|
}
|
|
1004
1171
|
|
|
1005
|
-
async function
|
|
1006
|
-
|
|
1007
|
-
|
|
1172
|
+
async function close$1(query, transition, bulk = false) {
|
|
1173
|
+
// Get the modal from collection, or top modal in stack if no query is provided.
|
|
1174
|
+
const modal = query ? getModal.call(this, query) : this.active; // If a modal exists and its state is opened.
|
|
1008
1175
|
|
|
1009
|
-
if (
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
this.
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1176
|
+
if (modal && modal.state === 'opened') {
|
|
1177
|
+
// Update modal state.
|
|
1178
|
+
modal.state = 'closing'; // Get the modal configuration.
|
|
1179
|
+
|
|
1180
|
+
const config = _extends({}, this.settings, modal.settings); // Add transition parameter to configuration.
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
if (transition !== undefined) config.transition = transition; // Remove focus from active element.
|
|
1184
|
+
|
|
1185
|
+
document.activeElement.blur(); // Run the close transition.
|
|
1186
|
+
|
|
1187
|
+
await closeTransition(modal.target, config); // Remove z-index styles.
|
|
1188
|
+
|
|
1189
|
+
modal.target.style.zIndex = null; // Get index of modal in stack array.
|
|
1190
|
+
|
|
1191
|
+
const index = this.stack.findIndex(entry => {
|
|
1192
|
+
return entry.id === modal.id;
|
|
1193
|
+
}); // Remove modal from stack array.
|
|
1194
|
+
|
|
1195
|
+
this.stack.splice(index, 1); // Update the focus state if this is not a bulk action.
|
|
1196
|
+
|
|
1197
|
+
if (!bulk) {
|
|
1198
|
+
updateFocusState.call(this);
|
|
1199
|
+
} // Update modal state.
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
modal.state = 'closed'; // Dispatch custom closed event.
|
|
1203
|
+
|
|
1204
|
+
modal.target.dispatchEvent(new CustomEvent(config.customEventPrefix + 'closed', {
|
|
1017
1205
|
detail: this,
|
|
1018
1206
|
bubbles: true
|
|
1019
1207
|
}));
|
|
1020
|
-
|
|
1021
|
-
return modal;
|
|
1022
|
-
} else {
|
|
1023
|
-
return modal;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1208
|
+
} // Return the modal.
|
|
1026
1209
|
|
|
1027
|
-
class Modal {
|
|
1028
|
-
constructor(options) {
|
|
1029
|
-
this.defaults = defaults$1;
|
|
1030
|
-
this.settings = _extends({}, this.defaults, options);
|
|
1031
|
-
this.working = false;
|
|
1032
|
-
this.memory = {};
|
|
1033
|
-
this.focusTrap = new FocusTrap();
|
|
1034
|
-
this.__handlerClick = handlerClick$1.bind(this);
|
|
1035
|
-
this.__handlerKeydown = handlerKeydown$1.bind(this);
|
|
1036
|
-
if (this.settings.autoInit) this.init();
|
|
1037
|
-
}
|
|
1038
1210
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
this.moveModals();
|
|
1042
|
-
this.setInitialState();
|
|
1211
|
+
return modal;
|
|
1212
|
+
}
|
|
1043
1213
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1214
|
+
async function closeAll$1(exclude, transition) {
|
|
1215
|
+
const result = [];
|
|
1216
|
+
await Promise.all(this.stack.map(async modal => {
|
|
1217
|
+
if (exclude && exclude === modal.id) {
|
|
1218
|
+
Promise.resolve();
|
|
1219
|
+
} else {
|
|
1220
|
+
result.push(await close$1.call(this, modal, transition, true));
|
|
1046
1221
|
}
|
|
1047
1222
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1223
|
+
modal.trigger = null;
|
|
1224
|
+
}));
|
|
1225
|
+
return result;
|
|
1226
|
+
}
|
|
1052
1227
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1228
|
+
async function replace(query, transition) {
|
|
1229
|
+
// Get the modal from collection.
|
|
1230
|
+
const modal = getModal.call(this, query); // Setup results for return.
|
|
1055
1231
|
|
|
1056
|
-
|
|
1057
|
-
this.destroyEventListeners();
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
/**
|
|
1061
|
-
* Event listeners
|
|
1062
|
-
*/
|
|
1232
|
+
let resultOpened, resultClosed;
|
|
1063
1233
|
|
|
1234
|
+
if (modal.state === 'opened') {
|
|
1235
|
+
// If modal is open, close all modals except for replacement.
|
|
1236
|
+
resultOpened = modal;
|
|
1237
|
+
resultClosed = await closeAll$1.call(this, modal.id, transition);
|
|
1238
|
+
} else {
|
|
1239
|
+
// If modal is closed, close all and open replacement at the same time.
|
|
1240
|
+
resultOpened = open$1.call(this, modal, transition, true);
|
|
1241
|
+
resultClosed = closeAll$1.call(this, false, transition);
|
|
1242
|
+
await Promise.all([resultOpened, resultClosed]);
|
|
1243
|
+
} // Update the focus state.
|
|
1064
1244
|
|
|
1065
|
-
initEventListeners() {
|
|
1066
|
-
document.addEventListener('click', this.__handlerClick, false);
|
|
1067
|
-
document.addEventListener('touchend', this.__handlerClick, false);
|
|
1068
|
-
document.addEventListener('keydown', this.__handlerKeydown, false);
|
|
1069
|
-
}
|
|
1070
1245
|
|
|
1071
|
-
|
|
1072
|
-
document.removeEventListener('click', this.__handlerClick, false);
|
|
1073
|
-
document.removeEventListener('touchend', this.__handlerClick, false);
|
|
1074
|
-
document.removeEventListener('keydown', this.__handlerKeydown, false);
|
|
1075
|
-
}
|
|
1076
|
-
/**
|
|
1077
|
-
* Helpers
|
|
1078
|
-
*/
|
|
1246
|
+
updateFocusState.call(this); // Return the modals there were opened and closed.
|
|
1079
1247
|
|
|
1248
|
+
return {
|
|
1249
|
+
opened: resultOpened,
|
|
1250
|
+
closed: resultClosed
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1080
1253
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1254
|
+
async function register$1(target, dialog) {
|
|
1255
|
+
// Deregister entry incase it has already been registered.
|
|
1256
|
+
await deregister$1.call(this, target, false); // Save root this for use inside methods API.
|
|
1084
1257
|
|
|
1085
|
-
|
|
1086
|
-
return setTabindex(`
|
|
1087
|
-
[data-${this.settings.dataModal}]
|
|
1088
|
-
[data-${this.settings.dataDialog}]
|
|
1089
|
-
`);
|
|
1090
|
-
}
|
|
1258
|
+
const root = this; // Setup methods API.
|
|
1091
1259
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1260
|
+
const methods = {
|
|
1261
|
+
open(transition) {
|
|
1262
|
+
return open$1.call(root, this, transition);
|
|
1263
|
+
},
|
|
1095
1264
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
/**
|
|
1100
|
-
* Change state functionality
|
|
1101
|
-
*/
|
|
1265
|
+
close(transition) {
|
|
1266
|
+
return close$1.call(root, this, transition);
|
|
1267
|
+
},
|
|
1102
1268
|
|
|
1269
|
+
replace(transition) {
|
|
1270
|
+
return replace.call(root, this, transition);
|
|
1271
|
+
},
|
|
1103
1272
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1273
|
+
deregister() {
|
|
1274
|
+
return deregister$1.call(root, this);
|
|
1275
|
+
},
|
|
1107
1276
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1277
|
+
teleport(ref = this.getSetting('teleport'), method = this.getSetting('teleportMethod')) {
|
|
1278
|
+
if (!this.returnRef) {
|
|
1279
|
+
this.returnRef = teleport(this.target, ref, method);
|
|
1280
|
+
return this.target;
|
|
1281
|
+
} else {
|
|
1282
|
+
console.error('Element has already been teleported:', this.target);
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
},
|
|
1111
1286
|
|
|
1112
|
-
|
|
1287
|
+
teleportReturn() {
|
|
1288
|
+
if (this.returnRef) {
|
|
1289
|
+
this.returnRef = teleport(this.target, this.returnRef);
|
|
1290
|
+
return this.target;
|
|
1291
|
+
} else {
|
|
1292
|
+
console.error('No return reference found:', this.target);
|
|
1293
|
+
return false;
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1113
1296
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
}
|
|
1297
|
+
getSetting(key) {
|
|
1298
|
+
return key in this.settings ? this.settings[key] : root.settings[key];
|
|
1299
|
+
}
|
|
1118
1300
|
|
|
1119
|
-
|
|
1120
|
-
this.deregister(item);
|
|
1121
|
-
this.collection.push(item);
|
|
1122
|
-
return this.collection;
|
|
1123
|
-
}
|
|
1301
|
+
}; // Setup the modal object.
|
|
1124
1302
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1303
|
+
const entry = _extends({
|
|
1304
|
+
id: target.id,
|
|
1305
|
+
state: 'closed',
|
|
1306
|
+
settings: getConfig$1.call(this, target),
|
|
1307
|
+
target: target,
|
|
1308
|
+
dialog: dialog,
|
|
1309
|
+
returnRef: null
|
|
1310
|
+
}, methods); // Set aria-modal attribute to true.
|
|
1129
1311
|
|
|
1130
|
-
if (index >= 0) {
|
|
1131
|
-
const entry = this.collection[index];
|
|
1132
|
-
Object.getOwnPropertyNames(entry).forEach(prop => {
|
|
1133
|
-
delete entry[prop];
|
|
1134
|
-
});
|
|
1135
|
-
this.collection.splice(index, 1);
|
|
1136
|
-
}
|
|
1137
1312
|
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1313
|
+
entry.dialog.setAttribute('aria-modal', 'true'); // If a role attribute is not set, set it to "dialog" as the default.
|
|
1140
1314
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
});
|
|
1145
|
-
return this.collection;
|
|
1146
|
-
}
|
|
1315
|
+
if (!entry.dialog.hasAttribute('role')) {
|
|
1316
|
+
entry.dialog.setAttribute('role', 'dialog');
|
|
1317
|
+
} // Set tabindex="-1" so dialog is focusable via JS or click.
|
|
1147
1318
|
|
|
1148
|
-
deregisterCollection() {
|
|
1149
|
-
while (this.collection.length > 0) {
|
|
1150
|
-
this.deregister(this.collection[0]);
|
|
1151
|
-
}
|
|
1152
1319
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1320
|
+
if (entry.getSetting('setTabindex')) {
|
|
1321
|
+
entry.dialog.setAttribute('tabindex', '-1');
|
|
1322
|
+
} // Teleport modal if a reference has been set.
|
|
1323
|
+
|
|
1324
|
+
|
|
1325
|
+
if (entry.getSetting('teleport')) {
|
|
1326
|
+
entry.teleport();
|
|
1327
|
+
} // Add entry to collection.
|
|
1328
|
+
|
|
1329
|
+
|
|
1330
|
+
this.collection.push(entry); // Setup initial state.
|
|
1331
|
+
|
|
1332
|
+
if (entry.target.classList.contains(this.settings.stateOpened)) {
|
|
1333
|
+
// Open modal with transitions disabled.
|
|
1334
|
+
entry.open(false);
|
|
1335
|
+
} else {
|
|
1336
|
+
// Remove transition state classes.
|
|
1337
|
+
entry.target.classList.remove(this.settings.stateOpening);
|
|
1338
|
+
entry.target.classList.remove(this.settings.stateClosing); // Add closed state class.
|
|
1339
|
+
|
|
1340
|
+
entry.target.classList.add(this.settings.stateClosed);
|
|
1341
|
+
} // Return the registered entry.
|
|
1155
1342
|
|
|
1156
|
-
get(query, key = 'id') {
|
|
1157
|
-
const result = this.collection.find(item => {
|
|
1158
|
-
return item[key] === query;
|
|
1159
|
-
});
|
|
1160
|
-
return result || null;
|
|
1161
|
-
}
|
|
1162
1343
|
|
|
1344
|
+
return entry;
|
|
1163
1345
|
}
|
|
1164
1346
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
// Feature toggles
|
|
1173
|
-
eventListeners: true,
|
|
1174
|
-
eventType: 'click',
|
|
1175
|
-
placement: 'bottom'
|
|
1176
|
-
};
|
|
1347
|
+
class Modal extends Collection {
|
|
1348
|
+
constructor(options) {
|
|
1349
|
+
super();
|
|
1350
|
+
this.defaults = defaults$1;
|
|
1351
|
+
this.settings = _extends({}, this.defaults, options);
|
|
1352
|
+
this.memory = {};
|
|
1353
|
+
this.focusTrap = new FocusTrap(); // Setup a proxy for stack array.
|
|
1177
1354
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1355
|
+
this.stack = new Proxy([], {
|
|
1356
|
+
set: (target, property, value) => {
|
|
1357
|
+
target[property] = value; // Update global state whenever the length property of stack changes.
|
|
1181
1358
|
|
|
1182
|
-
|
|
1359
|
+
if (property === 'length') {
|
|
1360
|
+
updateGlobalState.call(this);
|
|
1361
|
+
}
|
|
1183
1362
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1363
|
+
return true;
|
|
1364
|
+
}
|
|
1365
|
+
});
|
|
1366
|
+
this.__handleClick = handleClick.bind(this);
|
|
1367
|
+
this.__handleKeydown = handleKeydown.bind(this);
|
|
1368
|
+
if (this.settings.autoInit) this.init();
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
get active() {
|
|
1372
|
+
return this.stack[this.stack.length - 1];
|
|
1373
|
+
}
|
|
1190
1374
|
|
|
1191
|
-
|
|
1375
|
+
async init(options) {
|
|
1376
|
+
// Update settings with passed options.
|
|
1377
|
+
if (options) this.settings = _extends({}, this.settings, options); // Get all the modals.
|
|
1192
1378
|
|
|
1193
|
-
|
|
1194
|
-
this.memory.trigger = null;
|
|
1195
|
-
} // Return the popover
|
|
1379
|
+
const modals = document.querySelectorAll(this.settings.selectorModal); // Register the collections array with modal instances.
|
|
1196
1380
|
|
|
1381
|
+
await this.registerCollection(modals); // If eventListeners are enabled, init event listeners.
|
|
1197
1382
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
function closeAll() {
|
|
1201
|
-
this.collection.forEach(popover => {
|
|
1202
|
-
if (popover.state === 'opened') {
|
|
1203
|
-
popover.close();
|
|
1383
|
+
if (this.settings.eventListeners) {
|
|
1384
|
+
this.initEventListeners();
|
|
1204
1385
|
}
|
|
1205
|
-
}
|
|
1386
|
+
}
|
|
1206
1387
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
// Only run closeCheck if provided popover is currently open
|
|
1211
|
-
if (popover.state != 'opened') return; // Needed to correctly check which element is currently being focused
|
|
1388
|
+
async destroy() {
|
|
1389
|
+
// Clear any stored memory.
|
|
1390
|
+
this.memory = {}; // Remove all entries from the collection.
|
|
1212
1391
|
|
|
1213
|
-
|
|
1214
|
-
// Check if trigger or target are being hovered
|
|
1215
|
-
const isHovered = popover.target.closest(':hover') === popover.target || popover.trigger.closest(':hover') === popover.trigger; // Check if trigger or target are being focused
|
|
1392
|
+
await this.deregisterCollection(); // If eventListeners are enabled, destroy event listeners.
|
|
1216
1393
|
|
|
1217
|
-
|
|
1394
|
+
if (this.settings.eventListeners) {
|
|
1395
|
+
this.destroyEventListeners();
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1218
1398
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1399
|
+
initEventListeners() {
|
|
1400
|
+
document.addEventListener('click', this.__handleClick, false);
|
|
1401
|
+
document.addEventListener('touchend', this.__handleClick, false);
|
|
1402
|
+
document.addEventListener('keydown', this.__handleKeydown, false);
|
|
1403
|
+
}
|
|
1222
1404
|
|
|
1405
|
+
destroyEventListeners() {
|
|
1406
|
+
document.removeEventListener('click', this.__handleClick, false);
|
|
1407
|
+
document.removeEventListener('touchend', this.__handleClick, false);
|
|
1408
|
+
document.removeEventListener('keydown', this.__handleKeydown, false);
|
|
1409
|
+
}
|
|
1223
1410
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1411
|
+
register(query) {
|
|
1412
|
+
const els = getModalElements.call(this, query);
|
|
1413
|
+
if (els.error) return Promise.reject(els.error);
|
|
1414
|
+
return register$1.call(this, els.target, els.dialog);
|
|
1415
|
+
}
|
|
1227
1416
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
} else {
|
|
1232
|
-
this.memory.trigger = popover.trigger;
|
|
1233
|
-
popover.open();
|
|
1234
|
-
documentClick.call(this, popover);
|
|
1417
|
+
deregister(query) {
|
|
1418
|
+
const modal = this.get(getModalID.call(this, query));
|
|
1419
|
+
return deregister$1.call(this, modal);
|
|
1235
1420
|
}
|
|
1236
|
-
}
|
|
1237
|
-
function handlerKeydown(event) {
|
|
1238
|
-
switch (event.key) {
|
|
1239
|
-
case 'Escape':
|
|
1240
|
-
if (this.memory.trigger) {
|
|
1241
|
-
this.memory.trigger.focus();
|
|
1242
|
-
}
|
|
1243
1421
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1422
|
+
open(id, transition) {
|
|
1423
|
+
return open$1.call(this, id, transition);
|
|
1424
|
+
}
|
|
1246
1425
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
});
|
|
1251
|
-
return;
|
|
1426
|
+
close(id, transition) {
|
|
1427
|
+
return close$1.call(this, id, transition);
|
|
1428
|
+
}
|
|
1252
1429
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1430
|
+
replace(id, transition) {
|
|
1431
|
+
return replace.call(this, id, transition);
|
|
1255
1432
|
}
|
|
1256
|
-
}
|
|
1257
|
-
function documentClick(popover) {
|
|
1258
|
-
const root = this;
|
|
1259
|
-
document.addEventListener('click', function _f(event) {
|
|
1260
|
-
// Check if a popover was clicked
|
|
1261
|
-
const result = event.target.closest(`#${popover.id}, [aria-controls="${popover.id}"]`);
|
|
1262
1433
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1434
|
+
async closeAll(exclude = false, transition) {
|
|
1435
|
+
const result = await closeAll$1.call(this, exclude, transition);
|
|
1436
|
+
updateFocusState.call(this);
|
|
1437
|
+
return result;
|
|
1438
|
+
}
|
|
1268
1439
|
|
|
1269
|
-
this.removeEventListener('click', _f);
|
|
1270
|
-
} else {
|
|
1271
|
-
// If it does match and popover isn't currently active, remove event listener
|
|
1272
|
-
if (popover.target && !popover.target.classList.contains(root.settings.stateActive)) {
|
|
1273
|
-
this.removeEventListener('click', _f);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
});
|
|
1277
1440
|
}
|
|
1278
1441
|
|
|
1442
|
+
var defaults = {
|
|
1443
|
+
autoInit: false,
|
|
1444
|
+
// Selectors
|
|
1445
|
+
selectorPopover: '.popover',
|
|
1446
|
+
selectorArrow: '.popover__arrow',
|
|
1447
|
+
// State classes
|
|
1448
|
+
stateActive: 'is-active',
|
|
1449
|
+
// Feature settings
|
|
1450
|
+
eventListeners: true,
|
|
1451
|
+
eventType: 'click',
|
|
1452
|
+
placement: 'bottom'
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1279
1455
|
function getConfig(el, settings) {
|
|
1280
|
-
// Get the computed styles of the
|
|
1281
|
-
const styles = getComputedStyle(el); // Setup the config obj with default values
|
|
1456
|
+
// Get the computed styles of the element.
|
|
1457
|
+
const styles = getComputedStyle(el); // Setup the config obj with default values.
|
|
1282
1458
|
|
|
1283
1459
|
const config = {
|
|
1284
1460
|
'placement': settings.placement,
|
|
@@ -1288,29 +1464,29 @@ function getConfig(el, settings) {
|
|
|
1288
1464
|
'flip-padding': 0,
|
|
1289
1465
|
'arrow-element': settings.selectorArrow,
|
|
1290
1466
|
'arrow-padding': 0
|
|
1291
|
-
}; // Loop through config obj
|
|
1467
|
+
}; // Loop through config obj.
|
|
1292
1468
|
|
|
1293
1469
|
for (const prop in config) {
|
|
1294
|
-
// Get the CSS variable property values
|
|
1470
|
+
// Get the CSS variable property values.
|
|
1295
1471
|
const prefix = getComputedStyle(document.body).getPropertyValue('--vrembem-variable-prefix');
|
|
1296
|
-
const value = styles.getPropertyValue(`--${prefix}popover-${prop}`).trim(); // If a value was found, replace the default in config obj
|
|
1472
|
+
const value = styles.getPropertyValue(`--${prefix}popover-${prop}`).trim(); // If a value was found, replace the default in config obj.
|
|
1297
1473
|
|
|
1298
1474
|
if (value) {
|
|
1299
1475
|
config[prop] = value;
|
|
1300
1476
|
}
|
|
1301
|
-
} // Return the config obj
|
|
1477
|
+
} // Return the config obj.
|
|
1302
1478
|
|
|
1303
1479
|
|
|
1304
1480
|
return config;
|
|
1305
1481
|
}
|
|
1306
1482
|
function getPadding(value) {
|
|
1307
|
-
let padding; // Split the value by spaces if it's a string
|
|
1483
|
+
let padding; // Split the value by spaces if it's a string.
|
|
1308
1484
|
|
|
1309
|
-
const array = typeof value === 'string' ? value.trim().split(' ') : [value]; // Convert individual values to integers
|
|
1485
|
+
const array = typeof value === 'string' ? value.trim().split(' ') : [value]; // Convert individual values to integers.
|
|
1310
1486
|
|
|
1311
1487
|
array.forEach(function (item, index) {
|
|
1312
1488
|
array[index] = parseInt(item, 10);
|
|
1313
|
-
}); // Build the padding object based on the number of values passed
|
|
1489
|
+
}); // Build the padding object based on the number of values passed.
|
|
1314
1490
|
|
|
1315
1491
|
switch (array.length) {
|
|
1316
1492
|
case 1:
|
|
@@ -1347,7 +1523,7 @@ function getPadding(value) {
|
|
|
1347
1523
|
default:
|
|
1348
1524
|
padding = false;
|
|
1349
1525
|
break;
|
|
1350
|
-
} // Return the padding object
|
|
1526
|
+
} // Return the padding object.
|
|
1351
1527
|
|
|
1352
1528
|
|
|
1353
1529
|
return padding;
|
|
@@ -1376,43 +1552,59 @@ function getModifiers(options) {
|
|
|
1376
1552
|
}
|
|
1377
1553
|
}];
|
|
1378
1554
|
}
|
|
1555
|
+
function getPopover(query) {
|
|
1556
|
+
// Get the entry from collection.
|
|
1557
|
+
const entry = typeof query === 'string' ? this.get(query) : this.get(query.id); // Return entry if it was resolved, otherwise throw error.
|
|
1558
|
+
|
|
1559
|
+
if (entry) {
|
|
1560
|
+
return entry;
|
|
1561
|
+
} else {
|
|
1562
|
+
throw new Error(`Popover not found in collection with id of "${query}".`);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1379
1565
|
function getPopoverID(obj) {
|
|
1380
|
-
// If it's a string
|
|
1566
|
+
// If it's a string, return the string.
|
|
1381
1567
|
if (typeof obj === 'string') {
|
|
1382
1568
|
return obj;
|
|
1383
|
-
} // If it's an HTML element
|
|
1569
|
+
} // If it's an HTML element.
|
|
1384
1570
|
else if (typeof obj.hasAttribute === 'function') {
|
|
1385
|
-
// If it's a popover
|
|
1386
|
-
if (obj.
|
|
1387
|
-
|
|
1388
|
-
} // If it's a popover target
|
|
1389
|
-
else if (obj.closest(this.settings.selectorPopover)) {
|
|
1571
|
+
// If it's a popover target, return the id.
|
|
1572
|
+
if (obj.closest(this.settings.selectorPopover)) {
|
|
1573
|
+
obj = obj.closest(this.settings.selectorPopover);
|
|
1390
1574
|
return obj.id;
|
|
1391
|
-
} //
|
|
1575
|
+
} // If it's a popover trigger, return value of aria-controls.
|
|
1576
|
+
else if (obj.hasAttribute('aria-controls')) {
|
|
1577
|
+
return obj.getAttribute('aria-controls');
|
|
1578
|
+
} // If it's a popover tooltip trigger, return the value of aria-describedby.
|
|
1579
|
+
else if (obj.hasAttribute('aria-describedby')) {
|
|
1580
|
+
return obj.getAttribute('aria-describedby');
|
|
1581
|
+
} // Return false if no id was found.
|
|
1392
1582
|
else return false;
|
|
1393
|
-
} // If it has an
|
|
1583
|
+
} // If it has an id property, return its value.
|
|
1394
1584
|
else if (obj.id) {
|
|
1395
1585
|
return obj.id;
|
|
1396
|
-
} // Return false if no id was found
|
|
1586
|
+
} // Return false if no id was found.
|
|
1397
1587
|
else return false;
|
|
1398
1588
|
}
|
|
1399
1589
|
function getPopoverElements(query) {
|
|
1400
1590
|
const id = getPopoverID.call(this, query);
|
|
1401
1591
|
|
|
1402
1592
|
if (id) {
|
|
1403
|
-
const trigger = document.querySelector(`[aria-controls="${id}"]`);
|
|
1593
|
+
const trigger = document.querySelector(`[aria-controls="${id}"]`) || document.querySelector(`[aria-describedby="${id}"]`);
|
|
1404
1594
|
const target = document.querySelector(`#${id}`);
|
|
1405
1595
|
|
|
1406
1596
|
if (!trigger && !target) {
|
|
1407
|
-
|
|
1597
|
+
return {
|
|
1598
|
+
error: new Error(`No popover elements found using the ID: "${id}".`)
|
|
1599
|
+
};
|
|
1408
1600
|
} else if (!trigger) {
|
|
1409
|
-
|
|
1601
|
+
return {
|
|
1602
|
+
error: new Error('No popover trigger associated with the provided popover.')
|
|
1603
|
+
};
|
|
1410
1604
|
} else if (!target) {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
if (!trigger || !target) {
|
|
1415
|
-
return false;
|
|
1605
|
+
return {
|
|
1606
|
+
error: new Error('No popover associated with the provided popover trigger.')
|
|
1607
|
+
};
|
|
1416
1608
|
} else {
|
|
1417
1609
|
return {
|
|
1418
1610
|
trigger,
|
|
@@ -1420,10 +1612,120 @@ function getPopoverElements(query) {
|
|
|
1420
1612
|
};
|
|
1421
1613
|
}
|
|
1422
1614
|
} else {
|
|
1423
|
-
|
|
1424
|
-
|
|
1615
|
+
return {
|
|
1616
|
+
error: new Error('Could not resolve the popover ID.')
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
async function close(query) {
|
|
1622
|
+
// Get the popover from collection.
|
|
1623
|
+
const popover = query ? getPopover.call(this, query) : await closeAll.call(this); // If a modal exists and its state is opened.
|
|
1624
|
+
|
|
1625
|
+
if (popover && popover.state === 'opened') {
|
|
1626
|
+
// Update state class.
|
|
1627
|
+
popover.target.classList.remove(this.settings.stateActive); // Update accessibility attribute(s).
|
|
1628
|
+
|
|
1629
|
+
if (popover.trigger.hasAttribute('aria-controls')) {
|
|
1630
|
+
popover.trigger.setAttribute('aria-expanded', 'false');
|
|
1631
|
+
} // Disable popper event listeners.
|
|
1632
|
+
|
|
1633
|
+
|
|
1634
|
+
popover.popper.setOptions({
|
|
1635
|
+
modifiers: [{
|
|
1636
|
+
name: 'eventListeners',
|
|
1637
|
+
enabled: false
|
|
1638
|
+
}]
|
|
1639
|
+
}); // Update popover state.
|
|
1640
|
+
|
|
1641
|
+
popover.state = 'closed'; // Clear memory if popover trigger matches the one saved in memory.
|
|
1642
|
+
|
|
1643
|
+
if (popover.trigger === this.memory.trigger) {
|
|
1644
|
+
this.memory.trigger = null;
|
|
1645
|
+
}
|
|
1646
|
+
} // Return the popover.
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
return popover;
|
|
1650
|
+
}
|
|
1651
|
+
async function closeAll() {
|
|
1652
|
+
const result = [];
|
|
1653
|
+
await Promise.all(this.collection.map(async popover => {
|
|
1654
|
+
if (popover.state === 'opened') {
|
|
1655
|
+
result.push(await close.call(this, popover));
|
|
1656
|
+
}
|
|
1657
|
+
}));
|
|
1658
|
+
return result;
|
|
1659
|
+
}
|
|
1660
|
+
function closeCheck(popover) {
|
|
1661
|
+
// Only run closeCheck if provided popover is currently open.
|
|
1662
|
+
if (popover.state != 'opened') return; // Needed to correctly check which element is currently being focused.
|
|
1663
|
+
|
|
1664
|
+
setTimeout(() => {
|
|
1665
|
+
// Check if trigger or target are being hovered.
|
|
1666
|
+
const isHovered = popover.target.closest(':hover') === popover.target || popover.trigger.closest(':hover') === popover.trigger; // Check if trigger or target are being focused.
|
|
1667
|
+
|
|
1668
|
+
const isFocused = document.activeElement.closest(`#${popover.id}, [aria-controls="${popover.id}"]`); // Close if the trigger and target are not currently hovered or focused.
|
|
1669
|
+
|
|
1670
|
+
if (!isHovered && !isFocused) {
|
|
1671
|
+
popover.close();
|
|
1672
|
+
} // Return the popover.
|
|
1673
|
+
|
|
1674
|
+
|
|
1675
|
+
return popover;
|
|
1676
|
+
}, 1);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
function handlerClick(popover) {
|
|
1680
|
+
if (popover.state === 'opened') {
|
|
1681
|
+
popover.close();
|
|
1682
|
+
} else {
|
|
1683
|
+
this.memory.trigger = popover.trigger;
|
|
1684
|
+
popover.open();
|
|
1685
|
+
documentClick.call(this, popover);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
function handlerKeydown(event) {
|
|
1689
|
+
switch (event.key) {
|
|
1690
|
+
case 'Escape':
|
|
1691
|
+
if (this.memory.trigger) {
|
|
1692
|
+
this.memory.trigger.focus();
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
closeAll.call(this);
|
|
1696
|
+
return;
|
|
1697
|
+
|
|
1698
|
+
case 'Tab':
|
|
1699
|
+
this.collection.forEach(popover => {
|
|
1700
|
+
closeCheck.call(this, popover);
|
|
1701
|
+
});
|
|
1702
|
+
return;
|
|
1703
|
+
|
|
1704
|
+
default:
|
|
1705
|
+
return;
|
|
1425
1706
|
}
|
|
1426
1707
|
}
|
|
1708
|
+
function documentClick(popover) {
|
|
1709
|
+
const root = this;
|
|
1710
|
+
document.addEventListener('click', function _f(event) {
|
|
1711
|
+
// Check if a popover was clicked.
|
|
1712
|
+
const result = event.target.closest(`#${popover.id}, [aria-controls="${popover.id}"]`);
|
|
1713
|
+
|
|
1714
|
+
if (!result) {
|
|
1715
|
+
// If it doesn't match and popover is open, close it and remove event listener.
|
|
1716
|
+
if (popover.target && popover.target.classList.contains(root.settings.stateActive)) {
|
|
1717
|
+
popover.close();
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
this.removeEventListener('click', _f);
|
|
1721
|
+
} else {
|
|
1722
|
+
// If it does match and popover isn't currently active, remove event listener.
|
|
1723
|
+
if (popover.target && !popover.target.classList.contains(root.settings.stateActive)) {
|
|
1724
|
+
this.removeEventListener('click', _f);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1427
1729
|
|
|
1428
1730
|
var top = 'top';
|
|
1429
1731
|
var bottom = 'bottom';
|
|
@@ -1725,6 +2027,10 @@ function getContainingBlock(element) {
|
|
|
1725
2027
|
|
|
1726
2028
|
var currentNode = getParentNode(element);
|
|
1727
2029
|
|
|
2030
|
+
if (isShadowRoot(currentNode)) {
|
|
2031
|
+
currentNode = currentNode.host;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
1728
2034
|
while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
|
|
1729
2035
|
var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that
|
|
1730
2036
|
// create a containing block.
|
|
@@ -1948,7 +2254,7 @@ function mapToStyles(_ref2) {
|
|
|
1948
2254
|
|
|
1949
2255
|
if (placement === top || (placement === left || placement === right) && variation === end) {
|
|
1950
2256
|
sideY = bottom;
|
|
1951
|
-
var offsetY = isFixed && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]
|
|
2257
|
+
var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]
|
|
1952
2258
|
offsetParent[heightProp];
|
|
1953
2259
|
y -= offsetY - popperRect.height;
|
|
1954
2260
|
y *= gpuAcceleration ? 1 : -1;
|
|
@@ -1956,7 +2262,7 @@ function mapToStyles(_ref2) {
|
|
|
1956
2262
|
|
|
1957
2263
|
if (placement === left || (placement === top || placement === bottom) && variation === end) {
|
|
1958
2264
|
sideX = right;
|
|
1959
|
-
var offsetX = isFixed && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]
|
|
2265
|
+
var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]
|
|
1960
2266
|
offsetParent[widthProp];
|
|
1961
2267
|
x -= offsetX - popperRect.width;
|
|
1962
2268
|
x *= gpuAcceleration ? 1 : -1;
|
|
@@ -3208,13 +3514,69 @@ var createPopper = /*#__PURE__*/popperGenerator({
|
|
|
3208
3514
|
defaultModifiers: defaultModifiers
|
|
3209
3515
|
}); // eslint-disable-next-line import/no-unused-modules
|
|
3210
3516
|
|
|
3211
|
-
function
|
|
3212
|
-
//
|
|
3213
|
-
|
|
3517
|
+
async function deregister(obj) {
|
|
3518
|
+
// Return collection if nothing was passed.
|
|
3519
|
+
if (!obj) return this.collection; // Check if entry has been registered in the collection.
|
|
3520
|
+
|
|
3521
|
+
const index = this.collection.findIndex(entry => {
|
|
3522
|
+
return entry.id === obj.id;
|
|
3523
|
+
});
|
|
3524
|
+
|
|
3525
|
+
if (index >= 0) {
|
|
3526
|
+
// Get the collection entry.
|
|
3527
|
+
const entry = this.collection[index]; // If entry is in the opened state, close it.
|
|
3528
|
+
|
|
3529
|
+
if (entry.state === 'opened') {
|
|
3530
|
+
entry.close();
|
|
3531
|
+
} // Clean up the popper instance.
|
|
3532
|
+
|
|
3533
|
+
|
|
3534
|
+
entry.popper.destroy(); // Remove event listeners.
|
|
3535
|
+
|
|
3536
|
+
deregisterEventListeners(entry); // Delete properties from collection entry.
|
|
3537
|
+
|
|
3538
|
+
Object.getOwnPropertyNames(entry).forEach(prop => {
|
|
3539
|
+
delete entry[prop];
|
|
3540
|
+
}); // Remove entry from collection.
|
|
3541
|
+
|
|
3542
|
+
this.collection.splice(index, 1);
|
|
3543
|
+
} // Return the modified collection.
|
|
3544
|
+
|
|
3545
|
+
|
|
3546
|
+
return this.collection;
|
|
3547
|
+
}
|
|
3548
|
+
function deregisterEventListeners(entry) {
|
|
3549
|
+
// If event listeners have been setup.
|
|
3550
|
+
if (entry.__eventListeners) {
|
|
3551
|
+
// Loop through listeners and remove from the appropriate elements.
|
|
3552
|
+
entry.__eventListeners.forEach(evObj => {
|
|
3553
|
+
evObj.el.forEach(el => {
|
|
3554
|
+
evObj.type.forEach(type => {
|
|
3555
|
+
entry[el].removeEventListener(type, evObj.listener, false);
|
|
3556
|
+
});
|
|
3557
|
+
});
|
|
3558
|
+
}); // Remove eventListeners object from collection.
|
|
3559
|
+
|
|
3560
|
+
|
|
3561
|
+
delete entry.__eventListeners;
|
|
3562
|
+
} // Return the entry object.
|
|
3563
|
+
|
|
3564
|
+
|
|
3565
|
+
return entry;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
async function open(query) {
|
|
3569
|
+
// Get the popover from collection.
|
|
3570
|
+
const popover = getPopover.call(this, query); // Update state class.
|
|
3214
3571
|
|
|
3215
|
-
popover.
|
|
3572
|
+
popover.target.classList.add(this.settings.stateActive); // Update accessibility attribute(s).
|
|
3216
3573
|
|
|
3217
|
-
|
|
3574
|
+
if (popover.trigger.hasAttribute('aria-controls')) {
|
|
3575
|
+
popover.trigger.setAttribute('aria-expanded', 'true');
|
|
3576
|
+
} // Update popover config.
|
|
3577
|
+
|
|
3578
|
+
|
|
3579
|
+
popover.config = getConfig(popover.target, this.settings); // Enable popper event listeners and set placement/modifiers.
|
|
3218
3580
|
|
|
3219
3581
|
popover.popper.setOptions({
|
|
3220
3582
|
placement: popover.config['placement'],
|
|
@@ -3222,206 +3584,156 @@ function open(popover) {
|
|
|
3222
3584
|
name: 'eventListeners',
|
|
3223
3585
|
enabled: true
|
|
3224
3586
|
}, ...getModifiers(popover.config)]
|
|
3225
|
-
}); // Update popover position
|
|
3587
|
+
}); // Update popover position.
|
|
3226
3588
|
|
|
3227
|
-
popover.popper.update(); // Update popover state
|
|
3589
|
+
popover.popper.update(); // Update popover state.
|
|
3228
3590
|
|
|
3229
|
-
popover.state = 'opened'; // Return the popover
|
|
3591
|
+
popover.state = 'opened'; // Return the popover.
|
|
3230
3592
|
|
|
3231
3593
|
return popover;
|
|
3232
3594
|
}
|
|
3233
3595
|
|
|
3234
|
-
function register(trigger, target) {
|
|
3235
|
-
// Deregister
|
|
3236
|
-
|
|
3596
|
+
async function register(trigger, target) {
|
|
3597
|
+
// Deregister entry incase it has already been registered.
|
|
3598
|
+
deregister.call(this, target); // Save root this for use inside methods API.
|
|
3237
3599
|
|
|
3238
|
-
const
|
|
3600
|
+
const root = this; // Setup methods API.
|
|
3239
3601
|
|
|
3240
|
-
const root = this;
|
|
3241
3602
|
const methods = {
|
|
3242
3603
|
open() {
|
|
3243
|
-
open.call(root, this);
|
|
3604
|
+
return open.call(root, this);
|
|
3244
3605
|
},
|
|
3245
3606
|
|
|
3246
3607
|
close() {
|
|
3247
|
-
close.call(root, this);
|
|
3608
|
+
return close.call(root, this);
|
|
3248
3609
|
},
|
|
3249
3610
|
|
|
3250
3611
|
deregister() {
|
|
3251
|
-
deregister.call(root, this);
|
|
3612
|
+
return deregister.call(root, this);
|
|
3252
3613
|
}
|
|
3253
3614
|
|
|
3254
|
-
}; //
|
|
3615
|
+
}; // Setup the popover object.
|
|
3255
3616
|
|
|
3256
|
-
const
|
|
3617
|
+
const entry = _extends({
|
|
3257
3618
|
id: target.id,
|
|
3258
3619
|
state: 'closed',
|
|
3259
3620
|
trigger: trigger,
|
|
3260
3621
|
target: target,
|
|
3261
|
-
popper:
|
|
3622
|
+
popper: createPopper(trigger, target),
|
|
3262
3623
|
config: getConfig(target, this.settings)
|
|
3263
|
-
}, methods); //
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
registerEventListeners.call(this, popover); // Set initial state of popover
|
|
3267
|
-
|
|
3268
|
-
if (popover.target.classList.contains(this.settings.stateActive)) {
|
|
3269
|
-
popover.open();
|
|
3270
|
-
documentClick.call(this, popover);
|
|
3271
|
-
} else {
|
|
3272
|
-
popover.close();
|
|
3273
|
-
} // Add item to collection
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
this.collection.push(popover); // Return the popover object
|
|
3277
|
-
|
|
3278
|
-
return popover;
|
|
3279
|
-
}
|
|
3280
|
-
function deregister(popover) {
|
|
3281
|
-
// Check if this item has been registered in the collection
|
|
3282
|
-
const index = this.collection.findIndex(entry => {
|
|
3283
|
-
return entry.id === popover.id;
|
|
3284
|
-
}); // If the entry exists in the collection
|
|
3624
|
+
}, methods); // Set aria-expanded to false if trigger has aria-controls attribute.
|
|
3285
3625
|
|
|
3286
|
-
if (index >= 0) {
|
|
3287
|
-
// Get the collection entry
|
|
3288
|
-
const entry = this.collection[index]; // Close the collection entry if it's open
|
|
3289
|
-
|
|
3290
|
-
if (entry.state === 'opened') {
|
|
3291
|
-
entry.close();
|
|
3292
|
-
} // Clean up the popper instance
|
|
3293
3626
|
|
|
3627
|
+
if (entry.trigger.hasAttribute('aria-controls')) {
|
|
3628
|
+
entry.trigger.setAttribute('aria-expanded', 'false');
|
|
3629
|
+
} // Setup event listeners.
|
|
3294
3630
|
|
|
3295
|
-
entry.popper.destroy(); // Remove event listeners
|
|
3296
3631
|
|
|
3297
|
-
|
|
3632
|
+
registerEventListeners.call(this, entry); // Add entry to collection.
|
|
3298
3633
|
|
|
3299
|
-
|
|
3300
|
-
delete entry[prop];
|
|
3301
|
-
}); // Remove entry from collection
|
|
3634
|
+
this.collection.push(entry); // Set initial state.
|
|
3302
3635
|
|
|
3303
|
-
|
|
3304
|
-
|
|
3636
|
+
if (entry.target.classList.contains(this.settings.stateActive)) {
|
|
3637
|
+
await entry.open();
|
|
3638
|
+
documentClick.call(this, entry);
|
|
3639
|
+
} // Return the registered entry.
|
|
3305
3640
|
|
|
3306
3641
|
|
|
3307
|
-
return
|
|
3642
|
+
return entry;
|
|
3308
3643
|
}
|
|
3309
|
-
function registerEventListeners(
|
|
3310
|
-
// If event listeners aren't already setup
|
|
3311
|
-
if (!
|
|
3312
|
-
// Add event listeners based on event type
|
|
3313
|
-
const eventType =
|
|
3644
|
+
function registerEventListeners(entry) {
|
|
3645
|
+
// If event listeners aren't already setup.
|
|
3646
|
+
if (!entry.__eventListeners) {
|
|
3647
|
+
// Add event listeners based on event type.
|
|
3648
|
+
const eventType = entry.config['event']; // If the event type is hover.
|
|
3314
3649
|
|
|
3315
3650
|
if (eventType === 'hover') {
|
|
3316
|
-
// Setup event listeners object for hover
|
|
3317
|
-
|
|
3651
|
+
// Setup event listeners object for hover.
|
|
3652
|
+
entry.__eventListeners = [{
|
|
3318
3653
|
el: ['trigger'],
|
|
3319
3654
|
type: ['mouseenter', 'focus'],
|
|
3320
|
-
listener: open.bind(this,
|
|
3655
|
+
listener: open.bind(this, entry)
|
|
3321
3656
|
}, {
|
|
3322
3657
|
el: ['trigger', 'target'],
|
|
3323
3658
|
type: ['mouseleave', 'focusout'],
|
|
3324
|
-
listener: closeCheck.bind(this,
|
|
3325
|
-
}]; // Loop through listeners and apply to appropriate elements
|
|
3659
|
+
listener: closeCheck.bind(this, entry)
|
|
3660
|
+
}]; // Loop through listeners and apply to the appropriate elements.
|
|
3326
3661
|
|
|
3327
|
-
|
|
3662
|
+
entry.__eventListeners.forEach(evObj => {
|
|
3328
3663
|
evObj.el.forEach(el => {
|
|
3329
3664
|
evObj.type.forEach(type => {
|
|
3330
|
-
|
|
3665
|
+
entry[el].addEventListener(type, evObj.listener, false);
|
|
3331
3666
|
});
|
|
3332
3667
|
});
|
|
3333
3668
|
});
|
|
3334
|
-
}
|
|
3335
|
-
|
|
3336
|
-
|
|
3669
|
+
} // Else the event type is click.
|
|
3670
|
+
else {
|
|
3671
|
+
// Setup event listeners object for click.
|
|
3672
|
+
entry.__eventListeners = [{
|
|
3337
3673
|
el: ['trigger'],
|
|
3338
3674
|
type: ['click'],
|
|
3339
|
-
listener: handlerClick.bind(this,
|
|
3340
|
-
}]; // Loop through listeners and apply to appropriate elements
|
|
3675
|
+
listener: handlerClick.bind(this, entry)
|
|
3676
|
+
}]; // Loop through listeners and apply to the appropriate elements.
|
|
3341
3677
|
|
|
3342
|
-
|
|
3678
|
+
entry.__eventListeners.forEach(evObj => {
|
|
3343
3679
|
evObj.el.forEach(el => {
|
|
3344
3680
|
evObj.type.forEach(type => {
|
|
3345
|
-
|
|
3681
|
+
entry[el].addEventListener(type, evObj.listener, false);
|
|
3346
3682
|
});
|
|
3347
3683
|
});
|
|
3348
3684
|
});
|
|
3349
3685
|
}
|
|
3350
|
-
} // Return the
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
return popover;
|
|
3354
|
-
}
|
|
3355
|
-
function deregisterEventListeners(popover) {
|
|
3356
|
-
// If event listeners have been setup
|
|
3357
|
-
if (popover.__eventListeners) {
|
|
3358
|
-
// Loop through listeners and remove from appropriate elements
|
|
3359
|
-
popover.__eventListeners.forEach(evObj => {
|
|
3360
|
-
evObj.el.forEach(el => {
|
|
3361
|
-
evObj.type.forEach(type => {
|
|
3362
|
-
popover[el].removeEventListener(type, evObj.listener, false);
|
|
3363
|
-
});
|
|
3364
|
-
});
|
|
3365
|
-
}); // Remove eventListeners object from collection
|
|
3366
|
-
|
|
3686
|
+
} // Return the entry object.
|
|
3367
3687
|
|
|
3368
|
-
delete popover.__eventListeners;
|
|
3369
|
-
} // Return the popover object
|
|
3370
3688
|
|
|
3371
|
-
|
|
3372
|
-
return popover;
|
|
3689
|
+
return entry;
|
|
3373
3690
|
}
|
|
3374
3691
|
|
|
3375
3692
|
class Popover extends Collection {
|
|
3376
3693
|
constructor(options) {
|
|
3377
3694
|
super();
|
|
3378
3695
|
this.defaults = defaults;
|
|
3379
|
-
this.settings = _extends({}, this.defaults, options);
|
|
3380
|
-
|
|
3381
|
-
this.memory = {
|
|
3382
|
-
trigger: null
|
|
3383
|
-
};
|
|
3696
|
+
this.settings = _extends({}, this.defaults, options);
|
|
3697
|
+
this.memory = {};
|
|
3384
3698
|
this.__handlerKeydown = handlerKeydown.bind(this);
|
|
3385
3699
|
if (this.settings.autoInit) this.init();
|
|
3386
3700
|
}
|
|
3387
3701
|
|
|
3388
|
-
init(options
|
|
3389
|
-
// Update settings with passed options
|
|
3390
|
-
if (options) this.settings = _extends({}, this.settings, options); // Get all the popovers
|
|
3702
|
+
async init(options) {
|
|
3703
|
+
// Update settings with passed options.
|
|
3704
|
+
if (options) this.settings = _extends({}, this.settings, options); // Get all the popovers.
|
|
3391
3705
|
|
|
3392
|
-
const popovers = document.querySelectorAll(this.settings.selectorPopover); //
|
|
3706
|
+
const popovers = document.querySelectorAll(this.settings.selectorPopover); // Register the collections array with popover instances.
|
|
3393
3707
|
|
|
3394
|
-
this.registerCollection(popovers); // If eventListeners
|
|
3708
|
+
await this.registerCollection(popovers); // If eventListeners are enabled, init event listeners.
|
|
3395
3709
|
|
|
3396
3710
|
if (this.settings.eventListeners) {
|
|
3397
3711
|
// Pass false to initEventListeners() since registerCollection()
|
|
3398
|
-
// already adds event listeners to popovers
|
|
3712
|
+
// already adds event listeners to popovers.
|
|
3399
3713
|
this.initEventListeners(false);
|
|
3400
3714
|
}
|
|
3401
3715
|
}
|
|
3402
3716
|
|
|
3403
|
-
destroy() {
|
|
3404
|
-
//
|
|
3405
|
-
this.
|
|
3717
|
+
async destroy() {
|
|
3718
|
+
// Clear any stored memory.
|
|
3719
|
+
this.memory = {}; // Remove all entries from the collection.
|
|
3720
|
+
|
|
3721
|
+
await this.deregisterCollection(); // If eventListeners are enabled, destroy event listeners.
|
|
3406
3722
|
|
|
3407
3723
|
if (this.settings.eventListeners) {
|
|
3408
3724
|
// Pass false to destroyEventListeners() since deregisterCollection()
|
|
3409
|
-
// already removes event listeners from popovers
|
|
3725
|
+
// already removes event listeners from popovers.
|
|
3410
3726
|
this.destroyEventListeners(false);
|
|
3411
3727
|
}
|
|
3412
3728
|
}
|
|
3413
|
-
/**
|
|
3414
|
-
* Event listeners
|
|
3415
|
-
*/
|
|
3416
|
-
|
|
3417
3729
|
|
|
3418
3730
|
initEventListeners(processCollection = true) {
|
|
3419
3731
|
if (processCollection) {
|
|
3420
|
-
// Loop through collection and setup event listeners
|
|
3732
|
+
// Loop through collection and setup event listeners.
|
|
3421
3733
|
this.collection.forEach(popover => {
|
|
3422
3734
|
registerEventListeners.call(this, popover);
|
|
3423
3735
|
});
|
|
3424
|
-
} // Add keydown global event listener
|
|
3736
|
+
} // Add keydown global event listener.
|
|
3425
3737
|
|
|
3426
3738
|
|
|
3427
3739
|
document.addEventListener('keydown', this.__handlerKeydown, false);
|
|
@@ -3429,50 +3741,33 @@ class Popover extends Collection {
|
|
|
3429
3741
|
|
|
3430
3742
|
destroyEventListeners(processCollection = true) {
|
|
3431
3743
|
if (processCollection) {
|
|
3432
|
-
// Loop through collection and remove event listeners
|
|
3744
|
+
// Loop through collection and remove event listeners.
|
|
3433
3745
|
this.collection.forEach(popover => {
|
|
3434
3746
|
deregisterEventListeners(popover);
|
|
3435
3747
|
});
|
|
3436
|
-
} // Remove keydown global event listener
|
|
3748
|
+
} // Remove keydown global event listener.
|
|
3437
3749
|
|
|
3438
3750
|
|
|
3439
3751
|
document.removeEventListener('keydown', this.__handlerKeydown, false);
|
|
3440
3752
|
}
|
|
3441
|
-
/**
|
|
3442
|
-
* Register popover functionality
|
|
3443
|
-
*/
|
|
3444
|
-
|
|
3445
3753
|
|
|
3446
3754
|
register(query) {
|
|
3447
3755
|
const els = getPopoverElements.call(this, query);
|
|
3448
|
-
if (
|
|
3756
|
+
if (els.error) return Promise.reject(els.error);
|
|
3449
3757
|
return register.call(this, els.trigger, els.target);
|
|
3450
3758
|
}
|
|
3451
3759
|
|
|
3452
3760
|
deregister(query) {
|
|
3453
|
-
const popover = this.get(getPopoverID(query));
|
|
3454
|
-
if (!popover) return false;
|
|
3761
|
+
const popover = this.get(getPopoverID.call(this, query));
|
|
3455
3762
|
return deregister.call(this, popover);
|
|
3456
3763
|
}
|
|
3457
|
-
/**
|
|
3458
|
-
* Change state functionality
|
|
3459
|
-
*/
|
|
3460
|
-
|
|
3461
3764
|
|
|
3462
3765
|
open(id) {
|
|
3463
|
-
|
|
3464
|
-
if (!popover) return false;
|
|
3465
|
-
return popover.open();
|
|
3766
|
+
return open.call(this, id);
|
|
3466
3767
|
}
|
|
3467
3768
|
|
|
3468
3769
|
close(id) {
|
|
3469
|
-
|
|
3470
|
-
const popover = this.get(id);
|
|
3471
|
-
if (!popover) return false;
|
|
3472
|
-
return popover.close();
|
|
3473
|
-
} else {
|
|
3474
|
-
return closeAll.call(this);
|
|
3475
|
-
}
|
|
3770
|
+
return close.call(this, id);
|
|
3476
3771
|
}
|
|
3477
3772
|
|
|
3478
3773
|
}
|