PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 4.0.0
WP 2FA – Two-factor authentication for WordPress v4.0.0
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 1 week ago micromodal.js 1 week ago select2.min.js 1 week ago wp-2fa.js 1 week ago
micromodal.js
485 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]):not(.modal__close)', '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 if (document.activeElement.tagName.toLowerCase() === 'button' || (" "+document.activeElement.className+" ").indexOf(" button ") > -1) {
246 document.activeElement.click();
247 } else {
248 if ( modal.find('.button:visible:first').length > 0 ) {
249 modal.find('.button:visible:first').click();
250 }
251 }
252 }
253 }
254 }, {
255 key: "getFocusableNodes",
256 value: function getFocusableNodes() {
257 var nodes = this.modal.querySelectorAll(FOCUSABLE_ELEMENTS);
258 var visibleElements = new Array();
259
260 for (var i = 0; i < nodes.length; i++) {
261 var currentElement = nodes[i];
262 var $style = window.getComputedStyle(currentElement, null);
263
264 if (!currentElement) {
265 return false;
266
267 } else if (!$style) {
268 return false;
269 } else if ($style.display === 'none') {
270 return false;
271 } else {
272 if (currentElement.offsetParent !== null)
273 visibleElements.push(currentElement);
274 }
275 }
276 nodes = visibleElements;
277
278 return Array.apply(void 0, _toConsumableArray(nodes));
279 }
280 /**
281 * Tries to set focus on a node which is not a close trigger
282 * if no other nodes exist then focuses on first close trigger
283 */
284
285 }, {
286 key: "setFocusToFirstNode",
287 value: function setFocusToFirstNode() {
288 var _this3 = this;
289
290 if (this.config.disableFocus) return;
291 var focusableNodes = this.getFocusableNodes(); // no focusable nodes
292
293
294 if (focusableNodes.length === 0) return; // remove nodes on whose click, the modal closes
295 // could not think of a better name :(
296
297 var nodesWhichAreNotCloseTargets = focusableNodes.filter(function (node) {
298 return !node.hasAttribute(_this3.config.closeTrigger);
299 });
300 //this.activeElement.blur();
301 focusableNodes[0].focus();
302 //jQuery('#basic').focus();
303 // if (nodesWhichAreNotCloseTargets.length > 0) nodesWhichAreNotCloseTargets[0].focus();
304 // if (nodesWhichAreNotCloseTargets.length === 0) focusableNodes[0].focus();
305 }
306 }, {
307 key: "retainFocus",
308 value: function retainFocus(event) {
309 var focusableNodes = this.getFocusableNodes(); // no focusable nodes
310
311 if (focusableNodes.length === 0) return;
312 /**
313 * Filters nodes which are hidden to prevent
314 * focus leak outside modal
315 */
316
317 focusableNodes = focusableNodes.filter(function (node) {
318 return node.offsetParent !== null;
319 }); // if disableFocus is true
320
321 if (!this.modal.contains(document.activeElement)) {
322 focusableNodes[0].focus();
323 } else {
324 var focusedItemIndex = focusableNodes.indexOf(document.activeElement);
325
326 if (event.shiftKey && focusedItemIndex === 0) {
327 focusableNodes[focusableNodes.length - 1].focus();
328 event.preventDefault();
329 }
330
331 if (!event.shiftKey && focusableNodes.length > 0 && focusedItemIndex === focusableNodes.length - 1) {
332 focusableNodes[0].focus();
333 event.preventDefault();
334 }
335 }
336 }
337 }]);
338
339 return Modal;
340 }();
341 /**
342 * Modal prototype ends.
343 * Here on code is responsible for detecting and
344 * auto binding event handlers on modal triggers
345 */
346 // Keep a reference to the opened modal
347
348
349 var activeModal = null;
350 /**
351 * Generates an associative array of modals and it's
352 * respective triggers
353 * @param {array} triggers An array of all triggers
354 * @param {string} triggerAttr The data-attribute which triggers the module
355 * @return {array}
356 */
357
358 var generateTriggerMap = function generateTriggerMap(triggers, triggerAttr) {
359 var triggerMap = [];
360 triggers.forEach(function (trigger) {
361 var targetModal = trigger.attributes[triggerAttr].value;
362 if (triggerMap[targetModal] === undefined) triggerMap[targetModal] = [];
363 triggerMap[targetModal].push(trigger);
364 });
365 return triggerMap;
366 };
367 /**
368 * Validates whether a modal of the given id exists
369 * in the DOM
370 * @param {number} id The id of the modal
371 * @return {boolean}
372 */
373
374
375 var validateModalPresence = function validateModalPresence(id) {
376 if (!document.getElementById(id)) {
377 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.');
378 console.warn("%cExample:", 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', "<div class=\"modal\" id=\"".concat(id, "\"></div>"));
379 return false;
380 }
381 };
382 /**
383 * Validates if there are modal triggers present
384 * in the DOM
385 * @param {array} triggers An array of data-triggers
386 * @return {boolean}
387 */
388
389
390 var validateTriggerPresence = function validateTriggerPresence(triggers) {
391 if (triggers.length <= 0) {
392 console.warn("MicroModal: \u2757Please specify at least one %c'micromodal-trigger'", 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'data attribute.');
393 console.warn("%cExample:", 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', "<a href=\"#\" data-micromodal-trigger=\"my-modal\"></a>");
394 return false;
395 }
396 };
397 /**
398 * Checks if triggers and their corresponding modals
399 * are present in the DOM
400 * @param {array} triggers Array of DOM nodes which have data-triggers
401 * @param {array} triggerMap Associative array of modals and their triggers
402 * @return {boolean}
403 */
404
405
406 var validateArgs = function validateArgs(triggers, triggerMap) {
407 validateTriggerPresence(triggers);
408 if (!triggerMap) return true;
409
410 for (var id in triggerMap) {
411 validateModalPresence(id);
412 }
413
414 return true;
415 };
416 /**
417 * Binds click handlers to all modal triggers
418 * @param {object} config [description]
419 * @return void
420 */
421
422
423 var init = function init(config) {
424 // Create an config object with default openTrigger
425 var options = Object.assign({}, {
426 openTrigger: 'data-micromodal-trigger'
427 }, config); // Collects all the nodes with the trigger
428
429 var triggers = _toConsumableArray(document.querySelectorAll("[".concat(options.openTrigger, "]"))); // Makes a mappings of modals with their trigger nodes
430
431
432 var triggerMap = generateTriggerMap(triggers, options.openTrigger); // Checks if modals and triggers exist in dom
433
434 if (options.debugMode === true && validateArgs(triggers, triggerMap) === false) return; // For every target modal creates a new instance
435
436 for (var key in triggerMap) {
437 var value = triggerMap[key];
438 options.targetModal = key;
439 options.triggers = _toConsumableArray(value);
440 activeModal = new Modal(options); // eslint-disable-line no-new
441 }
442 };
443 /**
444 * Shows a particular modal
445 * @param {string} targetModal [The id of the modal to display]
446 * @param {object} config [The configuration object to pass]
447 * @return {void}
448 */
449
450
451 var show = function show(targetModal, config) {
452 var options = config || {};
453 options.targetModal = targetModal; // Checks if modals and triggers exist in dom
454
455 if (options.debugMode === true && validateModalPresence(targetModal) === false) return; // clear events in case previous modal wasn't close
456
457 if (activeModal) activeModal.removeEventListeners(); // stores reference to active modal
458
459 activeModal = new Modal(options); // eslint-disable-line no-new
460
461 activeModal.showModal();
462 };
463 /**
464 * Closes the active modal
465 * @param {string} targetModal [The id of the modal to close]
466 * @return {void}
467 */
468
469
470 var close = function close(targetModal) {
471 targetModal ? activeModal.closeModalById(targetModal) : activeModal.closeModal();
472 };
473
474 return {
475 init: init,
476 show: show,
477 close: close
478 };
479 }();
480 window.MicroModal = MicroModal;
481
482 return MicroModal;
483
484 })));
485