PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.9.1
WP 2FA – Two-factor authentication for WordPress v2.9.1
4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / dist / js / micromodal.js
wp-2fa / dist / js Last commit date
admin.js 11 months ago micromodal.js 11 months ago select2.min.js 11 months ago wp-2fa.js 11 months ago
micromodal.js
455 lines
1 (function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 typeof define === 'function' && define.amd ? define(factory) :
4 (global = global || self, global.MicroModal = factory());
5 }(this, (function () { 'use strict';
6
7 function _classCallCheck(instance, Constructor) {
8 if (!(instance instanceof Constructor)) {
9 throw new TypeError("Cannot call a class as a function");
10 }
11 }
12
13 function _defineProperties(target, props) {
14 for (var i = 0; i < props.length; i++) {
15 var descriptor = props[i];
16 descriptor.enumerable = descriptor.enumerable || false;
17 descriptor.configurable = true;
18 if ("value" in descriptor) descriptor.writable = true;
19 Object.defineProperty(target, descriptor.key, descriptor);
20 }
21 }
22
23 function _createClass(Constructor, protoProps, staticProps) {
24 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
25 if (staticProps) _defineProperties(Constructor, staticProps);
26 return Constructor;
27 }
28
29 function _toConsumableArray(arr) {
30 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
31 }
32
33 function _arrayWithoutHoles(arr) {
34 if (Array.isArray(arr)) return _arrayLikeToArray(arr);
35 }
36
37 function _iterableToArray(iter) {
38 if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
39 }
40
41 function _unsupportedIterableToArray(o, minLen) {
42 if (!o) return;
43 if (typeof o === "string") return _arrayLikeToArray(o, minLen);
44 var n = Object.prototype.toString.call(o).slice(8, -1);
45 if (n === "Object" && o.constructor) n = o.constructor.name;
46 if (n === "Map" || n === "Set") return Array.from(n);
47 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
48 }
49
50 function _arrayLikeToArray(arr, len) {
51 if (len == null || len > arr.length) len = arr.length;
52
53 for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
54
55 return arr2;
56 }
57
58 function _nonIterableSpread() {
59 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
60 }
61
62 var MicroModal = function () {
63
64 var FOCUSABLE_ELEMENTS = ['a[href]', 'area[href]', 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', 'select:not([disabled]):not([aria-hidden])', 'textarea:not([disabled]):not([aria-hidden])', 'button:not([disabled]):not([aria-hidden])', 'iframe', 'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex^="-"])'];
65
66 var Modal = /*#__PURE__*/function () {
67 function Modal(_ref) {
68 var targetModal = _ref.targetModal,
69 _ref$triggers = _ref.triggers,
70 triggers = _ref$triggers === void 0 ? [] : _ref$triggers,
71 _ref$onShow = _ref.onShow,
72 onShow = _ref$onShow === void 0 ? function () {} : _ref$onShow,
73 _ref$onClose = _ref.onClose,
74 onClose = _ref$onClose === void 0 ? function () {} : _ref$onClose,
75 _ref$openTrigger = _ref.openTrigger,
76 openTrigger = _ref$openTrigger === void 0 ? 'data-micromodal-trigger' : _ref$openTrigger,
77 _ref$closeTrigger = _ref.closeTrigger,
78 closeTrigger = _ref$closeTrigger === void 0 ? 'data-micromodal-close' : _ref$closeTrigger,
79 _ref$openClass = _ref.openClass,
80 openClass = _ref$openClass === void 0 ? 'is-open' : _ref$openClass,
81 _ref$disableScroll = _ref.disableScroll,
82 disableScroll = _ref$disableScroll === void 0 ? false : _ref$disableScroll,
83 _ref$disableFocus = _ref.disableFocus,
84 disableFocus = _ref$disableFocus === void 0 ? false : _ref$disableFocus,
85 _ref$awaitCloseAnimat = _ref.awaitCloseAnimation,
86 awaitCloseAnimation = _ref$awaitCloseAnimat === void 0 ? false : _ref$awaitCloseAnimat,
87 _ref$awaitOpenAnimati = _ref.awaitOpenAnimation,
88 awaitOpenAnimation = _ref$awaitOpenAnimati === void 0 ? false : _ref$awaitOpenAnimati,
89 _ref$debugMode = _ref.debugMode,
90 debugMode = _ref$debugMode === void 0 ? false : _ref$debugMode;
91
92 _classCallCheck(this, Modal);
93
94 // Save a reference of the modal
95 this.modal = document.getElementById(targetModal); // Save a reference to the passed config
96
97 this.config = {
98 debugMode: debugMode,
99 disableScroll: disableScroll,
100 openTrigger: openTrigger,
101 closeTrigger: closeTrigger,
102 openClass: openClass,
103 onShow: onShow,
104 onClose: onClose,
105 awaitCloseAnimation: awaitCloseAnimation,
106 awaitOpenAnimation: awaitOpenAnimation,
107 disableFocus: disableFocus
108 }; // Register click events only if pre binding eventListeners
109
110 if (triggers.length > 0) this.registerTriggers.apply(this, _toConsumableArray(triggers)); // pre bind functions for event listeners
111
112 this.onClick = this.onClick.bind(this);
113 this.onKeydown = this.onKeydown.bind(this);
114 }
115 /**
116 * Loops through all openTriggers and binds click event
117 * @param {array} triggers [Array of node elements]
118 * @return {void}
119 */
120
121
122 _createClass(Modal, [{
123 key: "registerTriggers",
124 value: function registerTriggers() {
125 var _this = this;
126
127 for (var _len = arguments.length, triggers = new Array(_len), _key = 0; _key < _len; _key++) {
128 triggers[_key] = arguments[_key];
129 }
130
131 triggers.filter(Boolean).forEach(function (trigger) {
132 trigger.addEventListener('click', function (event) {
133 return _this.showModal(event);
134 });
135 });
136 }
137 }, {
138 key: "showModal",
139 value: function showModal() {
140 var _this2 = this;
141
142 var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
143 this.activeElement = document.activeElement;
144 this.modal.setAttribute('aria-hidden', 'false');
145 this.modal.classList.add(this.config.openClass);
146 this.scrollBehaviour('disable');
147 this.addEventListeners();
148
149 if (this.config.awaitOpenAnimation) {
150 var handler = function handler() {
151 _this2.modal.removeEventListener('animationend', handler, false);
152
153 _this2.setFocusToFirstNode();
154 };
155
156 this.modal.addEventListener('animationend', handler, false);
157 } else {
158 this.setFocusToFirstNode();
159 }
160
161 this.config.onShow(this.modal, this.activeElement, event);
162 }
163 }, {
164 key: "closeModal",
165 value: function closeModal() {
166 var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
167 var modal = this.modal;
168 this.modal.setAttribute('aria-hidden', 'true');
169 this.removeEventListeners();
170 this.scrollBehaviour('enable');
171
172 if (this.activeElement && this.activeElement.focus) {
173 this.activeElement.focus();
174 }
175
176 this.config.onClose(this.modal, this.activeElement, event);
177
178 if (this.config.awaitCloseAnimation) {
179 var openClass = this.config.openClass; // <- old school ftw
180
181 this.modal.addEventListener('animationend', function handler() {
182 modal.classList.remove(openClass);
183 modal.removeEventListener('animationend', handler, false);
184 }, false);
185 } else {
186 modal.classList.remove(this.config.openClass);
187 }
188 }
189 }, {
190 key: "closeModalById",
191 value: function closeModalById(targetModal) {
192 this.modal = document.getElementById(targetModal);
193 if (this.modal) this.closeModal();
194 }
195 }, {
196 key: "scrollBehaviour",
197 value: function scrollBehaviour(toggle) {
198 if (!this.config.disableScroll) return;
199 var body = document.querySelector('body');
200
201 switch (toggle) {
202 case 'enable':
203 Object.assign(body.style, {
204 overflow: ''
205 });
206 break;
207
208 case 'disable':
209 Object.assign(body.style, {
210 overflow: 'hidden'
211 });
212 break;
213 }
214 }
215 }, {
216 key: "addEventListeners",
217 value: function addEventListeners() {
218 this.modal.addEventListener('touchstart', this.onClick);
219 this.modal.addEventListener('click', this.onClick);
220 document.addEventListener('keydown', this.onKeydown);
221 }
222 }, {
223 key: "removeEventListeners",
224 value: function removeEventListeners() {
225 this.modal.removeEventListener('touchstart', this.onClick);
226 this.modal.removeEventListener('click', this.onClick);
227 document.removeEventListener('keydown', this.onKeydown);
228 }
229 }, {
230 key: "onClick",
231 value: function onClick(event) {
232 if (event.target.hasAttribute(this.config.closeTrigger)) {
233 this.closeModal(event);
234 }
235 }
236 }, {
237 key: "onKeydown",
238 value: function onKeydown(event) {
239 if (event.keyCode === 27) this.closeModal(event); // esc
240
241 if (event.keyCode === 9) this.retainFocus(event); // tab
242
243 if (event.keyCode === 13) { // enter
244 var modal = jQuery('#' + this.modal.id);
245 modal.find('.button:visible:first').click();
246 }
247 }
248 }, {
249 key: "getFocusableNodes",
250 value: function getFocusableNodes() {
251 var nodes = this.modal.querySelectorAll(FOCUSABLE_ELEMENTS);
252 return Array.apply(void 0, _toConsumableArray(nodes));
253 }
254 /**
255 * Tries to set focus on a node which is not a close trigger
256 * if no other nodes exist then focuses on first close trigger
257 */
258
259 }, {
260 key: "setFocusToFirstNode",
261 value: function setFocusToFirstNode() {
262 var _this3 = this;
263
264 if (this.config.disableFocus) return;
265 var focusableNodes = this.getFocusableNodes(); // no focusable nodes
266
267 if (focusableNodes.length === 0) return; // remove nodes on whose click, the modal closes
268 // could not think of a better name :(
269
270 var nodesWhichAreNotCloseTargets = focusableNodes.filter(function (node) {
271 return !node.hasAttribute(_this3.config.closeTrigger);
272 });
273 if (nodesWhichAreNotCloseTargets.length > 0) nodesWhichAreNotCloseTargets[0].focus();
274 if (nodesWhichAreNotCloseTargets.length === 0) focusableNodes[0].focus();
275 }
276 }, {
277 key: "retainFocus",
278 value: function retainFocus(event) {
279 var focusableNodes = this.getFocusableNodes(); // no focusable nodes
280
281 if (focusableNodes.length === 0) return;
282 /**
283 * Filters nodes which are hidden to prevent
284 * focus leak outside modal
285 */
286
287 focusableNodes = focusableNodes.filter(function (node) {
288 return node.offsetParent !== null;
289 }); // if disableFocus is true
290
291 if (!this.modal.contains(document.activeElement)) {
292 focusableNodes[0].focus();
293 } else {
294 var focusedItemIndex = focusableNodes.indexOf(document.activeElement);
295
296 if (event.shiftKey && focusedItemIndex === 0) {
297 focusableNodes[focusableNodes.length - 1].focus();
298 event.preventDefault();
299 }
300
301 if (!event.shiftKey && focusableNodes.length > 0 && focusedItemIndex === focusableNodes.length - 1) {
302 focusableNodes[0].focus();
303 event.preventDefault();
304 }
305 }
306 }
307 }]);
308
309 return Modal;
310 }();
311 /**
312 * Modal prototype ends.
313 * Here on code is responsible for detecting and
314 * auto binding event handlers on modal triggers
315 */
316 // Keep a reference to the opened modal
317
318
319 var activeModal = null;
320 /**
321 * Generates an associative array of modals and it's
322 * respective triggers
323 * @param {array} triggers An array of all triggers
324 * @param {string} triggerAttr The data-attribute which triggers the module
325 * @return {array}
326 */
327
328 var generateTriggerMap = function generateTriggerMap(triggers, triggerAttr) {
329 var triggerMap = [];
330 triggers.forEach(function (trigger) {
331 var targetModal = trigger.attributes[triggerAttr].value;
332 if (triggerMap[targetModal] === undefined) triggerMap[targetModal] = [];
333 triggerMap[targetModal].push(trigger);
334 });
335 return triggerMap;
336 };
337 /**
338 * Validates whether a modal of the given id exists
339 * in the DOM
340 * @param {number} id The id of the modal
341 * @return {boolean}
342 */
343
344
345 var validateModalPresence = function validateModalPresence(id) {
346 if (!document.getElementById(id)) {
347 console.warn("MicroModal: \u2757Seems like you have missed %c'".concat(id, "'"), 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'ID somewhere in your code. Refer example below to resolve it.');
348 console.warn("%cExample:", 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', "<div class=\"modal\" id=\"".concat(id, "\"></div>"));
349 return false;
350 }
351 };
352 /**
353 * Validates if there are modal triggers present
354 * in the DOM
355 * @param {array} triggers An array of data-triggers
356 * @return {boolean}
357 */
358
359
360 var validateTriggerPresence = function validateTriggerPresence(triggers) {
361 if (triggers.length <= 0) {
362 console.warn("MicroModal: \u2757Please specify at least one %c'micromodal-trigger'", 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'data attribute.');
363 console.warn("%cExample:", 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', "<a href=\"#\" data-micromodal-trigger=\"my-modal\"></a>");
364 return false;
365 }
366 };
367 /**
368 * Checks if triggers and their corresponding modals
369 * are present in the DOM
370 * @param {array} triggers Array of DOM nodes which have data-triggers
371 * @param {array} triggerMap Associative array of modals and their triggers
372 * @return {boolean}
373 */
374
375
376 var validateArgs = function validateArgs(triggers, triggerMap) {
377 validateTriggerPresence(triggers);
378 if (!triggerMap) return true;
379
380 for (var id in triggerMap) {
381 validateModalPresence(id);
382 }
383
384 return true;
385 };
386 /**
387 * Binds click handlers to all modal triggers
388 * @param {object} config [description]
389 * @return void
390 */
391
392
393 var init = function init(config) {
394 // Create an config object with default openTrigger
395 var options = Object.assign({}, {
396 openTrigger: 'data-micromodal-trigger'
397 }, config); // Collects all the nodes with the trigger
398
399 var triggers = _toConsumableArray(document.querySelectorAll("[".concat(options.openTrigger, "]"))); // Makes a mappings of modals with their trigger nodes
400
401
402 var triggerMap = generateTriggerMap(triggers, options.openTrigger); // Checks if modals and triggers exist in dom
403
404 if (options.debugMode === true && validateArgs(triggers, triggerMap) === false) return; // For every target modal creates a new instance
405
406 for (var key in triggerMap) {
407 var value = triggerMap[key];
408 options.targetModal = key;
409 options.triggers = _toConsumableArray(value);
410 activeModal = new Modal(options); // eslint-disable-line no-new
411 }
412 };
413 /**
414 * Shows a particular modal
415 * @param {string} targetModal [The id of the modal to display]
416 * @param {object} config [The configuration object to pass]
417 * @return {void}
418 */
419
420
421 var show = function show(targetModal, config) {
422 var options = config || {};
423 options.targetModal = targetModal; // Checks if modals and triggers exist in dom
424
425 if (options.debugMode === true && validateModalPresence(targetModal) === false) return; // clear events in case previous modal wasn't close
426
427 if (activeModal) activeModal.removeEventListeners(); // stores reference to active modal
428
429 activeModal = new Modal(options); // eslint-disable-line no-new
430
431 activeModal.showModal();
432 };
433 /**
434 * Closes the active modal
435 * @param {string} targetModal [The id of the modal to close]
436 * @return {void}
437 */
438
439
440 var close = function close(targetModal) {
441 targetModal ? activeModal.closeModalById(targetModal) : activeModal.closeModal();
442 };
443
444 return {
445 init: init,
446 show: show,
447 close: close
448 };
449 }();
450 window.MicroModal = MicroModal;
451
452 return MicroModal;
453
454 })));
455