PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.9.1
Secure Custom Fields v6.9.1
6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / assets / build / js / acf.js
secure-custom-fields / assets / build / js Last commit date
commands 1 week ago pro 1 week ago acf-escaped-html-notice.asset.php 1 year ago acf-escaped-html-notice.js 1 year ago acf-escaped-html-notice.js.map 1 year ago acf-escaped-html-notice.min.asset.php 7 months ago acf-escaped-html-notice.min.js 7 months ago acf-field-group.asset.php 3 months ago acf-field-group.js 3 months ago acf-field-group.js.map 3 months ago acf-field-group.min.asset.php 3 months ago acf-field-group.min.js 3 months ago acf-input.asset.php 1 week ago acf-input.js 1 week ago acf-input.js.map 1 week ago acf-input.min.asset.php 1 week ago acf-input.min.js 1 week ago acf-internal-post-type.asset.php 7 months ago acf-internal-post-type.js 7 months ago acf-internal-post-type.js.map 7 months ago acf-internal-post-type.min.asset.php 7 months ago acf-internal-post-type.min.js 7 months ago acf.asset.php 7 months ago acf.js 7 months ago acf.js.map 7 months ago acf.min.asset.php 7 months ago acf.min.js 7 months ago index.php 1 year ago scf-bindings.asset.php 1 week ago scf-bindings.js 1 week ago scf-bindings.js.map 1 week ago scf-bindings.min.asset.php 1 week ago scf-bindings.min.js 1 week ago
acf.js
6154 lines
1 /******/ (() => { // webpackBootstrap
2 /******/ var __webpack_modules__ = ({
3
4 /***/ "./assets/src/js/_acf-hooks.js":
5 /*!*************************************!*\
6 !*** ./assets/src/js/_acf-hooks.js ***!
7 \*************************************/
8 /***/ (() => {
9
10 (function (window, undefined) {
11 'use strict';
12
13 /**
14 * Handles managing all events for whatever you plug it into. Priorities for hooks are based on lowest to highest in
15 * that, lowest priority hooks are fired first.
16 */
17 var EventManager = function () {
18 /**
19 * Maintain a reference to the object scope so our public methods never get confusing.
20 */
21 var MethodsAvailable = {
22 removeFilter: removeFilter,
23 applyFilters: applyFilters,
24 addFilter: addFilter,
25 removeAction: removeAction,
26 doAction: doAction,
27 addAction: addAction,
28 storage: getStorage
29 };
30
31 /**
32 * Contains the hooks that get registered with this EventManager. The array for storage utilizes a "flat"
33 * object literal such that looking up the hook utilizes the native object literal hash.
34 */
35 var STORAGE = {
36 actions: {},
37 filters: {}
38 };
39 function getStorage() {
40 return STORAGE;
41 }
42
43 /**
44 * Adds an action to the event manager.
45 *
46 * @param action Must contain namespace.identifier
47 * @param callback Must be a valid callback function before this action is added
48 * @param [priority=10] Used to control when the function is executed in relation to other callbacks bound to the same hook
49 * @param [context] Supply a value to be used for this
50 */
51 function addAction(action, callback, priority, context) {
52 if (typeof action === 'string' && typeof callback === 'function') {
53 priority = parseInt(priority || 10, 10);
54 _addHook('actions', action, callback, priority, context);
55 }
56 return MethodsAvailable;
57 }
58
59 /**
60 * Performs an action if it exists. You can pass as many arguments as you want to this function; the only rule is
61 * that the first argument must always be the action.
62 */
63 function doAction(/* action, arg1, arg2, ... */
64 ) {
65 var args = Array.prototype.slice.call(arguments);
66 var action = args.shift();
67 if (typeof action === 'string') {
68 _runHook('actions', action, args);
69 }
70 return MethodsAvailable;
71 }
72
73 /**
74 * Removes the specified action if it contains a namespace.identifier & exists.
75 *
76 * @param action The action to remove
77 * @param [callback] Callback function to remove
78 */
79 function removeAction(action, callback) {
80 if (typeof action === 'string') {
81 _removeHook('actions', action, callback);
82 }
83 return MethodsAvailable;
84 }
85
86 /**
87 * Adds a filter to the event manager.
88 *
89 * @param filter Must contain namespace.identifier
90 * @param callback Must be a valid callback function before this action is added
91 * @param [priority=10] Used to control when the function is executed in relation to other callbacks bound to the same hook
92 * @param [context] Supply a value to be used for this
93 */
94 function addFilter(filter, callback, priority, context) {
95 if (typeof filter === 'string' && typeof callback === 'function') {
96 priority = parseInt(priority || 10, 10);
97 _addHook('filters', filter, callback, priority, context);
98 }
99 return MethodsAvailable;
100 }
101
102 /**
103 * Performs a filter if it exists. You should only ever pass 1 argument to be filtered. The only rule is that
104 * the first argument must always be the filter.
105 */
106 function applyFilters(/* filter, filtered arg, arg2, ... */
107 ) {
108 var args = Array.prototype.slice.call(arguments);
109 var filter = args.shift();
110 if (typeof filter === 'string') {
111 return _runHook('filters', filter, args);
112 }
113 return MethodsAvailable;
114 }
115
116 /**
117 * Removes the specified filter if it contains a namespace.identifier & exists.
118 *
119 * @param filter The action to remove
120 * @param [callback] Callback function to remove
121 */
122 function removeFilter(filter, callback) {
123 if (typeof filter === 'string') {
124 _removeHook('filters', filter, callback);
125 }
126 return MethodsAvailable;
127 }
128
129 /**
130 * Removes the specified hook by resetting the value of it.
131 *
132 * @param type Type of hook, either 'actions' or 'filters'
133 * @param hook The hook (namespace.identifier) to remove
134 * @private
135 */
136 function _removeHook(type, hook, callback, context) {
137 if (!STORAGE[type][hook]) {
138 return;
139 }
140 if (!callback) {
141 STORAGE[type][hook] = [];
142 } else {
143 var handlers = STORAGE[type][hook];
144 var i;
145 if (!context) {
146 for (i = handlers.length; i--;) {
147 if (handlers[i].callback === callback) {
148 handlers.splice(i, 1);
149 }
150 }
151 } else {
152 for (i = handlers.length; i--;) {
153 var handler = handlers[i];
154 if (handler.callback === callback && handler.context === context) {
155 handlers.splice(i, 1);
156 }
157 }
158 }
159 }
160 }
161
162 /**
163 * Adds the hook to the appropriate storage container
164 *
165 * @param type 'actions' or 'filters'
166 * @param hook The hook (namespace.identifier) to add to our event manager
167 * @param callback The function that will be called when the hook is executed.
168 * @param priority The priority of this hook. Must be an integer.
169 * @param [context] A value to be used for this
170 * @private
171 */
172 function _addHook(type, hook, callback, priority, context) {
173 var hookObject = {
174 callback: callback,
175 priority: priority,
176 context: context
177 };
178
179 // Utilize 'prop itself' : http://jsperf.com/hasownproperty-vs-in-vs-undefined/19
180 var hooks = STORAGE[type][hook];
181 if (hooks) {
182 hooks.push(hookObject);
183 hooks = _hookInsertSort(hooks);
184 } else {
185 hooks = [hookObject];
186 }
187 STORAGE[type][hook] = hooks;
188 }
189
190 /**
191 * Use an insert sort for keeping our hooks organized based on priority. This function is ridiculously faster
192 * than bubble sort, etc: http://jsperf.com/javascript-sort
193 *
194 * @param hooks The custom array containing all of the appropriate hooks to perform an insert sort on.
195 * @private
196 */
197 function _hookInsertSort(hooks) {
198 var tmpHook, j, prevHook;
199 for (var i = 1, len = hooks.length; i < len; i++) {
200 tmpHook = hooks[i];
201 j = i;
202 while ((prevHook = hooks[j - 1]) && prevHook.priority > tmpHook.priority) {
203 hooks[j] = hooks[j - 1];
204 --j;
205 }
206 hooks[j] = tmpHook;
207 }
208 return hooks;
209 }
210
211 /**
212 * Runs the specified hook. If it is an action, the value is not modified but if it is a filter, it is.
213 *
214 * @param type 'actions' or 'filters'
215 * @param hook The hook ( namespace.identifier ) to be ran.
216 * @param args Arguments to pass to the action/filter. If it's a filter, args is actually a single parameter.
217 * @private
218 */
219 function _runHook(type, hook, args) {
220 var handlers = STORAGE[type][hook];
221 if (!handlers) {
222 return type === 'filters' ? args[0] : false;
223 }
224 var i = 0,
225 len = handlers.length;
226 if (type === 'filters') {
227 for (; i < len; i++) {
228 args[0] = handlers[i].callback.apply(handlers[i].context, args);
229 }
230 } else {
231 for (; i < len; i++) {
232 handlers[i].callback.apply(handlers[i].context, args);
233 }
234 }
235 return type === 'filters' ? args[0] : true;
236 }
237
238 // return all of the publicly available methods
239 return MethodsAvailable;
240 };
241
242 // instantiate
243 acf.hooks = new EventManager();
244 })(window);
245
246 /***/ }),
247
248 /***/ "./assets/src/js/_acf-modal.js":
249 /*!*************************************!*\
250 !*** ./assets/src/js/_acf-modal.js ***!
251 \*************************************/
252 /***/ (() => {
253
254 (function ($, undefined) {
255 acf.models.Modal = acf.Model.extend({
256 data: {
257 title: '',
258 content: '',
259 toolbar: ''
260 },
261 events: {
262 'click .acf-modal-close': 'onClickClose'
263 },
264 setup: function (props) {
265 $.extend(this.data, props);
266 this.$el = $();
267 this.render();
268 },
269 initialize: function () {
270 this.open();
271 },
272 render: function () {
273 // Extract vars.
274 var title = this.get('title');
275 var content = this.get('content');
276 var toolbar = this.get('toolbar');
277
278 // Create element.
279 var $el = $(['<div>', '<div class="acf-modal">', '<div class="acf-modal-title">', '<h2>' + title + '</h2>', '<button class="acf-modal-close" type="button"><span class="dashicons dashicons-no"></span></button>', '</div>', '<div class="acf-modal-content">' + content + '</div>', '<div class="acf-modal-toolbar">' + toolbar + '</div>', '</div>', '<div class="acf-modal-backdrop acf-modal-close"></div>', '</div>'].join(''));
280
281 // Update DOM.
282 if (this.$el) {
283 this.$el.replaceWith($el);
284 }
285 this.$el = $el;
286
287 // Trigger action.
288 acf.doAction('append', $el);
289 },
290 update: function (props) {
291 this.data = acf.parseArgs(props, this.data);
292 this.render();
293 },
294 title: function (title) {
295 this.$('.acf-modal-title h2').html(title);
296 },
297 content: function (content) {
298 this.$('.acf-modal-content').html(content);
299 },
300 toolbar: function (toolbar) {
301 this.$('.acf-modal-toolbar').html(toolbar);
302 },
303 open: function () {
304 $('body').append(this.$el);
305 },
306 close: function () {
307 this.remove();
308 },
309 onClickClose: function (e, $el) {
310 e.preventDefault();
311 this.close();
312 },
313 /**
314 * Places focus within the popup.
315 */
316 focus: function () {
317 this.$el.find('.acf-icon').first().trigger('focus');
318 },
319 /**
320 * Locks focus within the modal.
321 *
322 * @param {boolean} locked True to lock focus, false to unlock.
323 */
324 lockFocusToModal: function (locked) {
325 let inertElement = $('#wpwrap');
326 if (!inertElement.length) {
327 return;
328 }
329 inertElement[0].inert = locked;
330 inertElement.attr('aria-hidden', locked);
331 },
332 /**
333 * Returns focus to the element that opened the popup
334 * if it still exists in the DOM.
335 */
336 returnFocusToOrigin: function () {
337 if (this.data.openedBy instanceof $ && this.data.openedBy.closest('body').length > 0) {
338 this.data.openedBy.trigger('focus');
339 }
340 }
341 });
342
343 /**
344 * Returns a new modal.
345 *
346 * @date 21/4/20
347 * @since ACF 5.9.0
348 *
349 * @param object props The modal props.
350 * @return object
351 */
352 acf.newModal = function (props) {
353 return new acf.models.Modal(props);
354 };
355 })(jQuery);
356
357 /***/ }),
358
359 /***/ "./assets/src/js/_acf-model.js":
360 /*!*************************************!*\
361 !*** ./assets/src/js/_acf-model.js ***!
362 \*************************************/
363 /***/ (() => {
364
365 (function ($, undefined) {
366 // Cached regex to split keys for `addEvent`.
367 var delegateEventSplitter = /^(\S+)\s*(.*)$/;
368
369 /**
370 * extend
371 *
372 * Helper function to correctly set up the prototype chain for subclasses
373 * Heavily inspired by backbone.js
374 *
375 * @date 14/12/17
376 * @since ACF 5.6.5
377 *
378 * @param object protoProps New properties for this object.
379 * @return function.
380 */
381
382 var extend = function (protoProps) {
383 // vars
384 var Parent = this;
385 var Child;
386
387 // The constructor function for the new subclass is either defined by you
388 // (the "constructor" property in your `extend` definition), or defaulted
389 // by us to simply call the parent constructor.
390 if (protoProps && protoProps.hasOwnProperty('constructor')) {
391 Child = protoProps.constructor;
392 } else {
393 Child = function () {
394 return Parent.apply(this, arguments);
395 };
396 }
397
398 // Add static properties to the constructor function, if supplied.
399 $.extend(Child, Parent);
400
401 // Set the prototype chain to inherit from `parent`, without calling
402 // `parent`'s constructor function and add the prototype properties.
403 Child.prototype = Object.create(Parent.prototype);
404 $.extend(Child.prototype, protoProps);
405 Child.prototype.constructor = Child;
406
407 // Set a convenience property in case the parent's prototype is needed later.
408 //Child.prototype.__parent__ = Parent.prototype;
409
410 // return
411 return Child;
412 };
413
414 /**
415 * Model
416 *
417 * Base class for all inheritance
418 *
419 * @date 14/12/17
420 * @since ACF 5.6.5
421 *
422 * @param object props
423 * @return function.
424 */
425
426 var Model = acf.Model = function () {
427 // generate unique client id
428 this.cid = acf.uniqueId('acf');
429
430 // set vars to avoid modifying prototype
431 this.data = $.extend(true, {}, this.data);
432
433 // pass props to setup function
434 this.setup.apply(this, arguments);
435
436 // store on element (allow this.setup to create this.$el)
437 if (this.$el && !this.$el.data('acf')) {
438 this.$el.data('acf', this);
439 }
440
441 // initialize
442 var initialize = function () {
443 this.initialize();
444 this.addEvents();
445 this.addActions();
446 this.addFilters();
447 };
448
449 // initialize on action
450 if (this.wait && !acf.didAction(this.wait)) {
451 this.addAction(this.wait, initialize);
452
453 // initialize now
454 } else {
455 initialize.apply(this);
456 }
457 };
458
459 // Attach all inheritable methods to the Model prototype.
460 $.extend(Model.prototype, {
461 // Unique model id
462 id: '',
463 // Unique client id
464 cid: '',
465 // jQuery element
466 $el: null,
467 // Data specific to this instance
468 data: {},
469 // toggle used when changing data
470 busy: false,
471 changed: false,
472 // Setup events hooks
473 events: {},
474 actions: {},
475 filters: {},
476 // class used to avoid nested event triggers
477 eventScope: '',
478 // action to wait until initialize
479 wait: false,
480 // action priority default
481 priority: 10,
482 /**
483 * get
484 *
485 * Gets a specific data value
486 *
487 * @date 14/12/17
488 * @since ACF 5.6.5
489 *
490 * @param string name
491 * @return mixed
492 */
493
494 get: function (name) {
495 return this.data[name];
496 },
497 /**
498 * has
499 *
500 * Returns `true` if the data exists and is not null
501 *
502 * @date 14/12/17
503 * @since ACF 5.6.5
504 *
505 * @param string name
506 * @return boolean
507 */
508
509 has: function (name) {
510 return this.get(name) != null;
511 },
512 /**
513 * set
514 *
515 * Sets a specific data value
516 *
517 * @date 14/12/17
518 * @since ACF 5.6.5
519 *
520 * @param string name
521 * @param mixed value
522 * @return this
523 */
524
525 set: function (name, value, silent) {
526 // bail if unchanged
527 var prevValue = this.get(name);
528 if (prevValue == value) {
529 return this;
530 }
531
532 // set data
533 this.data[name] = value;
534
535 // trigger events
536 if (!silent) {
537 this.changed = true;
538 this.trigger('changed:' + name, [value, prevValue]);
539 this.trigger('changed', [name, value, prevValue]);
540 }
541
542 // return
543 return this;
544 },
545 /**
546 * inherit
547 *
548 * Inherits the data from a jQuery element
549 *
550 * @date 14/12/17
551 * @since ACF 5.6.5
552 *
553 * @param jQuery $el
554 * @return this
555 */
556
557 inherit: function (data) {
558 // allow jQuery
559 if (data instanceof jQuery) {
560 data = data.data();
561 }
562
563 // extend
564 $.extend(this.data, data);
565
566 // return
567 return this;
568 },
569 /**
570 * prop
571 *
572 * mimics the jQuery prop function
573 *
574 * @date 4/6/18
575 * @since ACF 5.6.9
576 *
577 * @param type $var Description. Default.
578 * @return type Description.
579 */
580
581 prop: function () {
582 return this.$el.prop.apply(this.$el, arguments);
583 },
584 /**
585 * setup
586 *
587 * Run during constructor function
588 *
589 * @date 14/12/17
590 * @since ACF 5.6.5
591 *
592 * @param n/a
593 * @return n/a
594 */
595
596 setup: function (props) {
597 $.extend(this, props);
598 },
599 /**
600 * initialize
601 *
602 * Also run during constructor function
603 *
604 * @date 14/12/17
605 * @since ACF 5.6.5
606 *
607 * @param n/a
608 * @return n/a
609 */
610
611 initialize: function () {},
612 /**
613 * addElements
614 *
615 * Adds multiple jQuery elements to this object
616 *
617 * @date 9/5/18
618 * @since ACF 5.6.9
619 *
620 * @param type $var Description. Default.
621 * @return type Description.
622 */
623
624 addElements: function (elements) {
625 elements = elements || this.elements || null;
626 if (!elements || !Object.keys(elements).length) return false;
627 for (var i in elements) {
628 this.addElement(i, elements[i]);
629 }
630 },
631 /**
632 * addElement
633 *
634 * description
635 *
636 * @date 9/5/18
637 * @since ACF 5.6.9
638 *
639 * @param type $var Description. Default.
640 * @return type Description.
641 */
642
643 addElement: function (name, selector) {
644 this['$' + name] = this.$(selector);
645 },
646 /**
647 * addEvents
648 *
649 * Adds multiple event handlers
650 *
651 * @date 14/12/17
652 * @since ACF 5.6.5
653 *
654 * @param object events {event1 : callback, event2 : callback, etc }
655 * @return n/a
656 */
657
658 addEvents: function (events) {
659 events = events || this.events || null;
660 if (!events) return false;
661 for (var key in events) {
662 var match = key.match(delegateEventSplitter);
663 this.on(match[1], match[2], events[key]);
664 }
665 },
666 /**
667 * removeEvents
668 *
669 * Removes multiple event handlers
670 *
671 * @date 14/12/17
672 * @since ACF 5.6.5
673 *
674 * @param object events {event1 : callback, event2 : callback, etc }
675 * @return n/a
676 */
677
678 removeEvents: function (events) {
679 events = events || this.events || null;
680 if (!events) return false;
681 for (var key in events) {
682 var match = key.match(delegateEventSplitter);
683 this.off(match[1], match[2], events[key]);
684 }
685 },
686 /**
687 * getEventTarget
688 *
689 * Returns a jQuery element to trigger an event on.
690 *
691 * @date 5/6/18
692 * @since ACF 5.6.9
693 *
694 * @param jQuery $el The default jQuery element. Optional.
695 * @param string event The event name. Optional.
696 * @return jQuery
697 */
698
699 getEventTarget: function ($el, event) {
700 return $el || this.$el || $(document);
701 },
702 /**
703 * validateEvent
704 *
705 * Returns true if the event target's closest $el is the same as this.$el
706 * Requires both this.el and this.$el to be defined
707 *
708 * @date 5/6/18
709 * @since ACF 5.6.9
710 *
711 * @param type $var Description. Default.
712 * @return type Description.
713 */
714
715 validateEvent: function (e) {
716 if (this.eventScope) {
717 return $(e.target).closest(this.eventScope).is(this.$el);
718 } else {
719 return true;
720 }
721 },
722 /**
723 * proxyEvent
724 *
725 * Returns a new event callback function scoped to this model
726 *
727 * @date 29/3/18
728 * @since ACF 5.6.9
729 *
730 * @param function callback
731 * @return function
732 */
733
734 proxyEvent: function (callback) {
735 return this.proxy(function (e) {
736 // validate
737 if (!this.validateEvent(e)) {
738 return;
739 }
740
741 // construct args
742 var args = acf.arrayArgs(arguments);
743 var extraArgs = args.slice(1);
744 var eventArgs = [e, $(e.currentTarget)].concat(extraArgs);
745
746 // callback
747 callback.apply(this, eventArgs);
748 });
749 },
750 /**
751 * on
752 *
753 * Adds an event handler similar to jQuery
754 * Uses the instance 'cid' to namespace event
755 *
756 * @date 14/12/17
757 * @since ACF 5.6.5
758 *
759 * @param string name
760 * @param string callback
761 * @return n/a
762 */
763
764 on: function (a1, a2, a3, a4) {
765 // vars
766 var $el, event, selector, callback, args;
767
768 // find args
769 if (a1 instanceof jQuery) {
770 // 1. args( $el, event, selector, callback )
771 if (a4) {
772 $el = a1;
773 event = a2;
774 selector = a3;
775 callback = a4;
776
777 // 2. args( $el, event, callback )
778 } else {
779 $el = a1;
780 event = a2;
781 callback = a3;
782 }
783 } else {
784 // 3. args( event, selector, callback )
785 if (a3) {
786 event = a1;
787 selector = a2;
788 callback = a3;
789
790 // 4. args( event, callback )
791 } else {
792 event = a1;
793 callback = a2;
794 }
795 }
796
797 // element
798 $el = this.getEventTarget($el);
799
800 // modify callback
801 if (typeof callback === 'string') {
802 callback = this.proxyEvent(this[callback]);
803 }
804
805 // modify event
806 event = event + '.' + this.cid;
807
808 // args
809 if (selector) {
810 args = [event, selector, callback];
811 } else {
812 args = [event, callback];
813 }
814
815 // on()
816 $el.on.apply($el, args);
817 },
818 /**
819 * off
820 *
821 * Removes an event handler similar to jQuery
822 *
823 * @date 14/12/17
824 * @since ACF 5.6.5
825 *
826 * @param string name
827 * @param string callback
828 * @return n/a
829 */
830
831 off: function (a1, a2, a3) {
832 // vars
833 var $el, event, selector, args;
834
835 // find args
836 if (a1 instanceof jQuery) {
837 // 1. args( $el, event, selector )
838 if (a3) {
839 $el = a1;
840 event = a2;
841 selector = a3;
842
843 // 2. args( $el, event )
844 } else {
845 $el = a1;
846 event = a2;
847 }
848 } else {
849 // 3. args( event, selector )
850 if (a2) {
851 event = a1;
852 selector = a2;
853
854 // 4. args( event )
855 } else {
856 event = a1;
857 }
858 }
859
860 // element
861 $el = this.getEventTarget($el);
862
863 // modify event
864 event = event + '.' + this.cid;
865
866 // args
867 if (selector) {
868 args = [event, selector];
869 } else {
870 args = [event];
871 }
872
873 // off()
874 $el.off.apply($el, args);
875 },
876 /**
877 * trigger
878 *
879 * Triggers an event similar to jQuery
880 *
881 * @date 14/12/17
882 * @since ACF 5.6.5
883 *
884 * @param string name
885 * @param string callback
886 * @return n/a
887 */
888
889 trigger: function (name, args, bubbles) {
890 var $el = this.getEventTarget();
891 if (bubbles) {
892 $el.trigger.apply($el, arguments);
893 } else {
894 $el.triggerHandler.apply($el, arguments);
895 }
896 return this;
897 },
898 /**
899 * addActions
900 *
901 * Adds multiple action handlers
902 *
903 * @date 14/12/17
904 * @since ACF 5.6.5
905 *
906 * @param object actions {action1 : callback, action2 : callback, etc }
907 * @return n/a
908 */
909
910 addActions: function (actions) {
911 actions = actions || this.actions || null;
912 if (!actions) return false;
913 for (var i in actions) {
914 this.addAction(i, actions[i]);
915 }
916 },
917 /**
918 * removeActions
919 *
920 * Removes multiple action handlers
921 *
922 * @date 14/12/17
923 * @since ACF 5.6.5
924 *
925 * @param object actions {action1 : callback, action2 : callback, etc }
926 * @return n/a
927 */
928
929 removeActions: function (actions) {
930 actions = actions || this.actions || null;
931 if (!actions) return false;
932 for (var i in actions) {
933 this.removeAction(i, actions[i]);
934 }
935 },
936 /**
937 * addAction
938 *
939 * Adds an action using the wp.hooks library
940 *
941 * @date 14/12/17
942 * @since ACF 5.6.5
943 *
944 * @param string name
945 * @param string callback
946 * @return n/a
947 */
948
949 addAction: function (name, callback, priority) {
950 //console.log('addAction', name, priority);
951 // defaults
952 priority = priority || this.priority;
953
954 // modify callback
955 if (typeof callback === 'string') {
956 callback = this[callback];
957 }
958
959 // add
960 acf.addAction(name, callback, priority, this);
961 },
962 /**
963 * removeAction
964 *
965 * Remove an action using the wp.hooks library
966 *
967 * @date 14/12/17
968 * @since ACF 5.6.5
969 *
970 * @param string name
971 * @param string callback
972 * @return n/a
973 */
974
975 removeAction: function (name, callback) {
976 acf.removeAction(name, this[callback]);
977 },
978 /**
979 * addFilters
980 *
981 * Adds multiple filter handlers
982 *
983 * @date 14/12/17
984 * @since ACF 5.6.5
985 *
986 * @param object filters {filter1 : callback, filter2 : callback, etc }
987 * @return n/a
988 */
989
990 addFilters: function (filters) {
991 filters = filters || this.filters || null;
992 if (!filters) return false;
993 for (var i in filters) {
994 this.addFilter(i, filters[i]);
995 }
996 },
997 /**
998 * addFilter
999 *
1000 * Adds a filter using the wp.hooks library
1001 *
1002 * @date 14/12/17
1003 * @since ACF 5.6.5
1004 *
1005 * @param string name
1006 * @param string callback
1007 * @return n/a
1008 */
1009
1010 addFilter: function (name, callback, priority) {
1011 // defaults
1012 priority = priority || this.priority;
1013
1014 // modify callback
1015 if (typeof callback === 'string') {
1016 callback = this[callback];
1017 }
1018
1019 // add
1020 acf.addFilter(name, callback, priority, this);
1021 },
1022 /**
1023 * removeFilters
1024 *
1025 * Removes multiple filter handlers
1026 *
1027 * @date 14/12/17
1028 * @since ACF 5.6.5
1029 *
1030 * @param object filters {filter1 : callback, filter2 : callback, etc }
1031 * @return n/a
1032 */
1033
1034 removeFilters: function (filters) {
1035 filters = filters || this.filters || null;
1036 if (!filters) return false;
1037 for (var i in filters) {
1038 this.removeFilter(i, filters[i]);
1039 }
1040 },
1041 /**
1042 * removeFilter
1043 *
1044 * Remove a filter using the wp.hooks library
1045 *
1046 * @date 14/12/17
1047 * @since ACF 5.6.5
1048 *
1049 * @param string name
1050 * @param string callback
1051 * @return n/a
1052 */
1053
1054 removeFilter: function (name, callback) {
1055 acf.removeFilter(name, this[callback]);
1056 },
1057 /**
1058 * $
1059 *
1060 * description
1061 *
1062 * @date 16/12/17
1063 * @since ACF 5.6.5
1064 *
1065 * @param type $var Description. Default.
1066 * @return type Description.
1067 */
1068
1069 $: function (selector) {
1070 return this.$el.find(selector);
1071 },
1072 /**
1073 * remove
1074 *
1075 * Removes the element and listeners
1076 *
1077 * @date 19/12/17
1078 * @since ACF 5.6.5
1079 *
1080 * @param type $var Description. Default.
1081 * @return type Description.
1082 */
1083
1084 remove: function () {
1085 this.removeEvents();
1086 this.removeActions();
1087 this.removeFilters();
1088 this.$el.remove();
1089 },
1090 /**
1091 * setTimeout
1092 *
1093 * description
1094 *
1095 * @date 16/1/18
1096 * @since ACF 5.6.5
1097 *
1098 * @param type $var Description. Default.
1099 * @return type Description.
1100 */
1101
1102 setTimeout: function (callback, milliseconds) {
1103 return setTimeout(this.proxy(callback), milliseconds);
1104 },
1105 /**
1106 * time
1107 *
1108 * used for debugging
1109 *
1110 * @date 7/3/18
1111 * @since ACF 5.6.9
1112 *
1113 * @param type $var Description. Default.
1114 * @return type Description.
1115 */
1116
1117 time: function () {
1118 console.time(this.id || this.cid);
1119 },
1120 /**
1121 * timeEnd
1122 *
1123 * used for debugging
1124 *
1125 * @date 7/3/18
1126 * @since ACF 5.6.9
1127 *
1128 * @param type $var Description. Default.
1129 * @return type Description.
1130 */
1131
1132 timeEnd: function () {
1133 console.timeEnd(this.id || this.cid);
1134 },
1135 /**
1136 * show
1137 *
1138 * description
1139 *
1140 * @date 15/3/18
1141 * @since ACF 5.6.9
1142 *
1143 * @param type $var Description. Default.
1144 * @return type Description.
1145 */
1146
1147 show: function () {
1148 acf.show(this.$el);
1149 },
1150 /**
1151 * hide
1152 *
1153 * description
1154 *
1155 * @date 15/3/18
1156 * @since ACF 5.6.9
1157 *
1158 * @param type $var Description. Default.
1159 * @return type Description.
1160 */
1161
1162 hide: function () {
1163 acf.hide(this.$el);
1164 },
1165 /**
1166 * proxy
1167 *
1168 * Returns a new function scoped to this model
1169 *
1170 * @date 29/3/18
1171 * @since ACF 5.6.9
1172 *
1173 * @param function callback
1174 * @return function
1175 */
1176
1177 proxy: function (callback) {
1178 return $.proxy(callback, this);
1179 }
1180 });
1181
1182 // Set up inheritance for the model
1183 Model.extend = extend;
1184
1185 // Global model storage
1186 acf.models = {};
1187
1188 /**
1189 * acf.getInstance
1190 *
1191 * This function will get an instance from an element
1192 *
1193 * @date 5/3/18
1194 * @since ACF 5.6.9
1195 *
1196 * @param type $var Description. Default.
1197 * @return type Description.
1198 */
1199
1200 acf.getInstance = function ($el) {
1201 return $el.data('acf');
1202 };
1203
1204 /**
1205 * acf.getInstances
1206 *
1207 * This function will get an array of instances from multiple elements
1208 *
1209 * @date 5/3/18
1210 * @since ACF 5.6.9
1211 *
1212 * @param type $var Description. Default.
1213 * @return type Description.
1214 */
1215
1216 acf.getInstances = function ($el) {
1217 var instances = [];
1218 $el.each(function () {
1219 instances.push(acf.getInstance($(this)));
1220 });
1221 return instances;
1222 };
1223 })(jQuery);
1224
1225 /***/ }),
1226
1227 /***/ "./assets/src/js/_acf-notice.js":
1228 /*!**************************************!*\
1229 !*** ./assets/src/js/_acf-notice.js ***!
1230 \**************************************/
1231 /***/ (() => {
1232
1233 (function ($, undefined) {
1234 var Notice = acf.Model.extend({
1235 data: {
1236 text: '',
1237 type: '',
1238 timeout: 0,
1239 dismiss: true,
1240 target: false,
1241 location: 'before',
1242 close: function () {}
1243 },
1244 events: {
1245 'click .acf-notice-dismiss': 'onClickClose'
1246 },
1247 tmpl: function () {
1248 return '<div class="acf-notice"></div>';
1249 },
1250 setup: function (props) {
1251 $.extend(this.data, props);
1252 this.$el = $(this.tmpl());
1253 },
1254 initialize: function () {
1255 // render
1256 this.render();
1257
1258 // show
1259 this.show();
1260 },
1261 render: function () {
1262 // class
1263 this.type(this.get('type'));
1264
1265 // text
1266 this.html('<p>' + acf.escHtml(this.get('text')) + '</p>');
1267
1268 // close
1269 if (this.get('dismiss')) {
1270 this.$el.append('<a href="#" class="acf-notice-dismiss acf-icon -cancel small"></a>');
1271 this.$el.addClass('-dismiss');
1272 }
1273
1274 // timeout
1275 var timeout = this.get('timeout');
1276 if (timeout) {
1277 this.away(timeout);
1278 }
1279 },
1280 update: function (props) {
1281 // update
1282 $.extend(this.data, props);
1283
1284 // re-initialize
1285 this.initialize();
1286
1287 // refresh events
1288 this.removeEvents();
1289 this.addEvents();
1290 },
1291 show: function () {
1292 var $target = this.get('target');
1293 var location = this.get('location');
1294 if ($target) {
1295 if (location === 'after') {
1296 $target.append(this.$el);
1297 } else {
1298 $target.prepend(this.$el);
1299 }
1300 }
1301 },
1302 hide: function () {
1303 this.$el.remove();
1304 },
1305 away: function (timeout) {
1306 this.setTimeout(function () {
1307 acf.remove(this.$el);
1308 }, timeout);
1309 },
1310 type: function (type) {
1311 // remove prev type
1312 var prevType = this.get('type');
1313 if (prevType) {
1314 this.$el.removeClass('-' + prevType);
1315 }
1316
1317 // add new type
1318 this.$el.addClass('-' + type);
1319
1320 // backwards compatibility
1321 if (type == 'error') {
1322 this.$el.addClass('acf-error-message');
1323 }
1324 },
1325 html: function (html) {
1326 this.$el.html(acf.escHtml(html));
1327 },
1328 text: function (text) {
1329 this.$('p').html(acf.escHtml(text));
1330 },
1331 onClickClose: function (e, $el) {
1332 e.preventDefault();
1333 this.get('close').apply(this, arguments);
1334 this.remove();
1335 }
1336 });
1337 acf.newNotice = function (props) {
1338 // ensure object
1339 if (typeof props !== 'object') {
1340 props = {
1341 text: props
1342 };
1343 }
1344
1345 // instantiate
1346 return new Notice(props);
1347 };
1348 var noticeManager = new acf.Model({
1349 wait: 'prepare',
1350 priority: 1,
1351 initialize: function () {
1352 const $notices = $('.acf-admin-notice');
1353 if (!$notices.length) {
1354 return;
1355 }
1356 $notices.each(function () {
1357 if ($(this).data('persisted')) {
1358 let dismissed = acf.getPreference('dismissed-notices');
1359 if (dismissed && typeof dismissed == 'object' && dismissed.includes($(this).data('persist-id'))) {
1360 $(this).remove();
1361 } else {
1362 $(this).show();
1363 $(this).on('click', '.notice-dismiss', function (e) {
1364 dismissed = acf.getPreference('dismissed-notices');
1365 if (!dismissed || typeof dismissed != 'object') {
1366 dismissed = [];
1367 }
1368 dismissed.push($(this).closest('.acf-admin-notice').data('persist-id'));
1369 acf.setPreference('dismissed-notices', dismissed);
1370 });
1371 }
1372 }
1373 });
1374 }
1375 });
1376 })(jQuery);
1377
1378 /***/ }),
1379
1380 /***/ "./assets/src/js/_acf-panel.js":
1381 /*!*************************************!*\
1382 !*** ./assets/src/js/_acf-panel.js ***!
1383 \*************************************/
1384 /***/ (() => {
1385
1386 (function ($, undefined) {
1387 var panel = new acf.Model({
1388 events: {
1389 'click .acf-panel-title': 'onClick'
1390 },
1391 onClick: function (e, $el) {
1392 e.preventDefault();
1393 this.toggle($el.parent());
1394 },
1395 isOpen: function ($el) {
1396 return $el.hasClass('-open');
1397 },
1398 toggle: function ($el) {
1399 this.isOpen($el) ? this.close($el) : this.open($el);
1400 },
1401 open: function ($el) {
1402 $el.addClass('-open');
1403 $el.find('.acf-panel-title i').attr('class', 'dashicons dashicons-arrow-down');
1404 },
1405 close: function ($el) {
1406 $el.removeClass('-open');
1407 $el.find('.acf-panel-title i').attr('class', 'dashicons dashicons-arrow-right');
1408 }
1409 });
1410 })(jQuery);
1411
1412 /***/ }),
1413
1414 /***/ "./assets/src/js/_acf-popup.js":
1415 /*!*************************************!*\
1416 !*** ./assets/src/js/_acf-popup.js ***!
1417 \*************************************/
1418 /***/ (() => {
1419
1420 (function ($, undefined) {
1421 acf.models.Popup = acf.Model.extend({
1422 data: {
1423 title: '',
1424 content: '',
1425 width: 0,
1426 height: 0,
1427 loading: false,
1428 openedBy: null,
1429 confirmRemove: false
1430 },
1431 events: {
1432 'click [data-event="close"]': 'onClickClose',
1433 'click .acf-close-popup': 'onClickClose',
1434 keydown: 'onPressEscapeClose'
1435 },
1436 setup: function (props) {
1437 $.extend(this.data, props);
1438 this.$el = $(this.tmpl());
1439 },
1440 initialize: function () {
1441 this.render();
1442 this.open();
1443 this.focus();
1444 this.lockFocusToPopup(true);
1445 },
1446 tmpl: function () {
1447 return ['<div id="acf-popup" role="dialog" tabindex="-1">', '<div class="acf-popup-box acf-box">', '<div class="title"><h3></h3><a href="#" class="acf-icon -cancel grey" data-event="close" aria-label="' + acf.__('Close modal') + '"></a></div>', '<div class="inner"></div>', '<div class="loading"><i class="acf-loading"></i></div>', '</div>', '<div class="bg" data-event="close"></div>', '</div>'].join('');
1448 },
1449 render: function () {
1450 // Extract Vars.
1451 var title = this.get('title');
1452 var content = this.get('content');
1453 var loading = this.get('loading');
1454 var width = this.get('width');
1455 var height = this.get('height');
1456
1457 // Update.
1458 this.title(title);
1459 this.content(content);
1460 if (width) {
1461 this.$('.acf-popup-box').css('width', width);
1462 }
1463 if (height) {
1464 this.$('.acf-popup-box').css('min-height', height);
1465 }
1466 this.loading(loading);
1467
1468 // Trigger action.
1469 acf.doAction('append', this.$el);
1470 },
1471 /**
1472 * Places focus within the popup.
1473 */
1474 focus: function () {
1475 this.$el.find('.acf-icon').first().trigger('focus');
1476 },
1477 /**
1478 * Locks focus within the popup.
1479 *
1480 * @param {boolean} locked True to lock focus, false to unlock.
1481 */
1482 lockFocusToPopup: function (locked) {
1483 let inertElement = $('#wpwrap');
1484 if (!inertElement.length) {
1485 return;
1486 }
1487 inertElement[0].inert = locked;
1488 inertElement.attr('aria-hidden', locked);
1489 },
1490 update: function (props) {
1491 this.data = acf.parseArgs(props, this.data);
1492 this.render();
1493 },
1494 title: function (title) {
1495 this.$('.title:first h3').html(title);
1496 },
1497 content: function (content) {
1498 this.$('.inner:first').html(content);
1499 },
1500 loading: function (show) {
1501 var $loading = this.$('.loading:first');
1502 show ? $loading.show() : $loading.hide();
1503 },
1504 open: function () {
1505 $('body').append(this.$el);
1506 },
1507 close: function () {
1508 this.lockFocusToPopup(false);
1509 this.returnFocusToOrigin();
1510 this.remove();
1511 },
1512 onClickClose: function (e, $el) {
1513 e.preventDefault();
1514 this.close();
1515 },
1516 /**
1517 * Closes the popup when the escape key is pressed.
1518 *
1519 * @param {KeyboardEvent} e
1520 */
1521 onPressEscapeClose: function (e) {
1522 if (e.key === 'Escape') {
1523 this.close();
1524 }
1525 },
1526 /**
1527 * Returns focus to the element that opened the popup
1528 * if it still exists in the DOM.
1529 */
1530 returnFocusToOrigin: function () {
1531 if (this.data.openedBy instanceof $ && this.data.openedBy.closest('body').length > 0) {
1532 this.data.openedBy.trigger('focus');
1533 }
1534 }
1535 });
1536
1537 /**
1538 * PopupConfirm
1539 *
1540 * Extends the Popup model to provide confirmation functionality
1541 *
1542 * @date 17/12/17
1543 * @since ACF 5.6.5
1544 */
1545
1546 acf.models.PopupConfirm = acf.models.Popup.extend({
1547 data: {
1548 text: '',
1549 textConfirm: '',
1550 textCancel: '',
1551 context: false,
1552 confirm: function () {},
1553 cancel: function () {}
1554 },
1555 events: {
1556 'click [data-event="close"]': 'onCancel',
1557 'click .acf-close-popup': 'onClickClose',
1558 keydown: 'onPressEscapeClose',
1559 'click [data-event="confirm"]': 'onConfirm'
1560 },
1561 tmpl: function () {
1562 return `
1563 <div id="acf-popup" role="dialog" tabindex="-1">
1564 <div class="acf-popup-box acf-box acf-confirm-popup">
1565 <div class="title">
1566 <h3>${this.get('title')}</h3>
1567 <a href="#" data-event="close" aria-label="${acf.__('Close modal')}">
1568 <i class="acf-icon -close"></i>
1569 </a>
1570 </div>
1571 <div class="inner">
1572 <p>${acf.escHtml(this.get('text'))}</p>
1573 <div class="acf-actions">
1574 <button tabindex="0" type="button" data-event="close" class="acf-btn acf-btn-secondary acf-close-popup">${acf.strEscape(this.get('textCancel'))}</button>
1575 <button tabindex="0" type="submit" data-event="confirm" class="acf-btn acf-btn-primary acf-confirm">${acf.strEscape(this.get('textConfirm'))}</button>
1576 </div>
1577 </div>
1578 </div>
1579 <div class="bg" data-event="close"></div>
1580 </div>`;
1581 },
1582 render: function () {
1583 const loading = this.get('loading');
1584 const width = this.get('width');
1585 const height = this.get('height');
1586 const self = this;
1587 if (width) {
1588 this.$('.acf-popup-box').css('width', width);
1589 }
1590 if (height) {
1591 this.$('.acf-popup-box').css('min-height', height);
1592 }
1593 this.loading(loading);
1594 acf.doAction('append', this.$el);
1595 setTimeout(function () {
1596 self.$el.find('.acf-close-popup').trigger('focus');
1597 }, 1);
1598 },
1599 onConfirm: function (e, $el) {
1600 e.preventDefault();
1601 e.stopPropagation();
1602 this.close();
1603 const confirm = this.get('confirm');
1604 const context = this.get('context') || this;
1605 confirm.apply(context, arguments);
1606 },
1607 onCancel: function (e, $el) {
1608 e.preventDefault();
1609 e.stopPropagation();
1610 this.close();
1611 const cancel = this.get('cancel');
1612 const context = this.get('context') || this;
1613 cancel.apply(context, arguments);
1614 }
1615 });
1616
1617 /**
1618 * newPopup
1619 *
1620 * Creates a new Popup with the supplied props
1621 *
1622 * @date 17/12/17
1623 * @since ACF 5.6.5
1624 *
1625 * @param object props
1626 * @return object
1627 */
1628
1629 acf.newPopup = function (props) {
1630 return props.confirmRemove ? new acf.models.PopupConfirm(props) : new acf.models.Popup(props);
1631 };
1632 })(jQuery);
1633
1634 /***/ }),
1635
1636 /***/ "./assets/src/js/_acf-tooltip.js":
1637 /*!***************************************!*\
1638 !*** ./assets/src/js/_acf-tooltip.js ***!
1639 \***************************************/
1640 /***/ (() => {
1641
1642 (function ($, undefined) {
1643 acf.newTooltip = function (props) {
1644 // ensure object
1645 if (typeof props !== 'object') {
1646 props = {
1647 text: props
1648 };
1649 }
1650
1651 // confirmRemove
1652 if (props.confirmRemove !== undefined) {
1653 props.textConfirm = acf.__('Remove');
1654 props.textCancel = acf.__('Cancel');
1655 return new TooltipConfirm(props);
1656
1657 // confirm
1658 } else if (props.confirm !== undefined) {
1659 return new TooltipConfirm(props);
1660
1661 // default
1662 } else {
1663 return new Tooltip(props);
1664 }
1665 };
1666 var Tooltip = acf.Model.extend({
1667 data: {
1668 text: '',
1669 timeout: 0,
1670 target: null
1671 },
1672 tmpl: function () {
1673 return '<div class="acf-tooltip"></div>';
1674 },
1675 setup: function (props) {
1676 $.extend(this.data, props);
1677 this.$el = $(this.tmpl());
1678 },
1679 initialize: function () {
1680 // render
1681 this.render();
1682
1683 // append
1684 this.show();
1685
1686 // position
1687 this.position();
1688
1689 // timeout
1690 var timeout = this.get('timeout');
1691 if (timeout) {
1692 setTimeout($.proxy(this.fade, this), timeout);
1693 }
1694 },
1695 update: function (props) {
1696 $.extend(this.data, props);
1697 this.initialize();
1698 },
1699 render: function () {
1700 this.$el.text(this.get('text'));
1701 },
1702 show: function () {
1703 $('body').append(this.$el);
1704 },
1705 hide: function () {
1706 this.$el.remove();
1707 },
1708 fade: function () {
1709 // add class
1710 this.$el.addClass('acf-fade-up');
1711
1712 // remove
1713 this.setTimeout(function () {
1714 this.remove();
1715 }, 250);
1716 },
1717 html: function (html) {
1718 this.$el.html(html);
1719 },
1720 position: function () {
1721 // vars
1722 var $tooltip = this.$el;
1723 var $target = this.get('target');
1724 if (!$target) return;
1725
1726 // Reset position.
1727 $tooltip.removeClass('right left bottom top').css({
1728 top: 0,
1729 left: 0
1730 });
1731
1732 // Declare tolerance to edge of screen.
1733 var tolerance = 10;
1734
1735 // Find target position.
1736 var targetWidth = $target.outerWidth();
1737 var targetHeight = $target.outerHeight();
1738 var targetTop = $target.offset().top;
1739 var targetLeft = $target.offset().left;
1740
1741 // Find tooltip position.
1742 var tooltipWidth = $tooltip.outerWidth();
1743 var tooltipHeight = $tooltip.outerHeight();
1744 var tooltipTop = $tooltip.offset().top; // Should be 0, but WP media grid causes this to be 32 (toolbar padding).
1745
1746 // Assume default top alignment.
1747 var top = targetTop - tooltipHeight - tooltipTop;
1748 var left = targetLeft + targetWidth / 2 - tooltipWidth / 2;
1749
1750 // Check if too far left.
1751 if (left < tolerance) {
1752 $tooltip.addClass('right');
1753 left = targetLeft + targetWidth;
1754 top = targetTop + targetHeight / 2 - tooltipHeight / 2 - tooltipTop;
1755
1756 // Check if too far right.
1757 } else if (left + tooltipWidth + tolerance > $(window).width()) {
1758 $tooltip.addClass('left');
1759 left = targetLeft - tooltipWidth;
1760 top = targetTop + targetHeight / 2 - tooltipHeight / 2 - tooltipTop;
1761
1762 // Check if too far up.
1763 } else if (top - $(window).scrollTop() < tolerance) {
1764 $tooltip.addClass('bottom');
1765 top = targetTop + targetHeight - tooltipTop;
1766
1767 // No collision with edges.
1768 } else {
1769 $tooltip.addClass('top');
1770 }
1771
1772 // update css
1773 $tooltip.css({
1774 top: top,
1775 left: left
1776 });
1777 }
1778 });
1779 var TooltipConfirm = Tooltip.extend({
1780 data: {
1781 text: '',
1782 textConfirm: '',
1783 textCancel: '',
1784 target: null,
1785 targetConfirm: true,
1786 confirm: function () {},
1787 cancel: function () {},
1788 context: false
1789 },
1790 events: {
1791 'click [data-event="cancel"]': 'onCancel',
1792 'click [data-event="confirm"]': 'onConfirm'
1793 },
1794 addEvents: function () {
1795 // add events
1796 acf.Model.prototype.addEvents.apply(this);
1797
1798 // vars
1799 var $document = $(document);
1800 var $target = this.get('target');
1801
1802 // add global 'cancel' click event
1803 // - use timeout to avoid the current 'click' event triggering the onCancel function
1804 this.setTimeout(function () {
1805 this.on($document, 'click', 'onCancel');
1806 });
1807
1808 // add target 'confirm' click event
1809 // - allow setting to control this feature
1810 if (this.get('targetConfirm')) {
1811 this.on($target, 'click', 'onConfirm');
1812 }
1813 },
1814 removeEvents: function () {
1815 // remove events
1816 acf.Model.prototype.removeEvents.apply(this);
1817
1818 // vars
1819 var $document = $(document);
1820 var $target = this.get('target');
1821
1822 // remove custom events
1823 this.off($document, 'click');
1824 this.off($target, 'click');
1825 },
1826 render: function () {
1827 // defaults
1828 var text = this.get('text') || acf.__('Are you sure?');
1829 var textConfirm = this.get('textConfirm') || acf.__('Yes');
1830 var textCancel = this.get('textCancel') || acf.__('No');
1831
1832 // html
1833 var html = [text, '<a href="#" data-event="confirm">' + textConfirm + '</a>', '<a href="#" data-event="cancel">' + textCancel + '</a>'].join(' ');
1834
1835 // html
1836 this.html(html);
1837
1838 // class
1839 this.$el.addClass('-confirm');
1840 },
1841 onCancel: function (e, $el) {
1842 // prevent default
1843 e.preventDefault();
1844 e.stopImmediatePropagation();
1845
1846 // callback
1847 var callback = this.get('cancel');
1848 var context = this.get('context') || this;
1849 callback.apply(context, arguments);
1850
1851 //remove
1852 this.remove();
1853 },
1854 onConfirm: function (e, $el) {
1855 // Prevent event from propagating completely to allow "targetConfirm" to be clicked.
1856 e.preventDefault();
1857 e.stopImmediatePropagation();
1858
1859 // callback
1860 var callback = this.get('confirm');
1861 var context = this.get('context') || this;
1862 callback.apply(context, arguments);
1863
1864 //remove
1865 this.remove();
1866 }
1867 });
1868
1869 // storage
1870 acf.models.Tooltip = Tooltip;
1871 acf.models.TooltipConfirm = TooltipConfirm;
1872
1873 /**
1874 * tooltipManager
1875 *
1876 * description
1877 *
1878 * @date 17/4/18
1879 * @since ACF 5.6.9
1880 *
1881 * @param type $var Description. Default.
1882 * @return type Description.
1883 */
1884
1885 var tooltipHoverHelper = new acf.Model({
1886 tooltip: false,
1887 events: {
1888 'mouseenter .acf-js-tooltip': 'showTitle',
1889 'mouseup .acf-js-tooltip': 'hideTitle',
1890 'mouseleave .acf-js-tooltip': 'hideTitle',
1891 'focus .acf-js-tooltip': 'showTitle',
1892 'blur .acf-js-tooltip': 'hideTitle',
1893 'keyup .acf-js-tooltip': 'onKeyUp'
1894 },
1895 showTitle: function (e, $el) {
1896 // vars
1897 let title = $el.attr('title');
1898
1899 // bail early if no title
1900 if (!title) {
1901 return;
1902 }
1903
1904 // clear title to avoid default browser tooltip
1905 $el.attr('title', '');
1906 $el.data('acf-js-tooltip-title', title);
1907 title = acf.strEscape(title);
1908
1909 // create
1910 if (!this.tooltip) {
1911 this.tooltip = acf.newTooltip({
1912 text: title,
1913 target: $el
1914 });
1915
1916 // update
1917 } else {
1918 this.tooltip.update({
1919 text: title,
1920 target: $el
1921 });
1922 }
1923 },
1924 hideTitle: function (e, $el) {
1925 // hide tooltip
1926 this.tooltip.hide();
1927 $el.attr('title', $el.data('acf-js-tooltip-title'));
1928
1929 // restore title
1930 $el.removeData('acf-js-tooltip-title');
1931 },
1932 onKeyUp: function (e, $el) {
1933 if ('Escape' === e.key) {
1934 this.hideTitle(e, $el);
1935 }
1936 }
1937 });
1938 })(jQuery);
1939
1940 /***/ }),
1941
1942 /***/ "./assets/src/js/_acf.js":
1943 /*!*******************************!*\
1944 !*** ./assets/src/js/_acf.js ***!
1945 \*******************************/
1946 /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
1947
1948 (function ($, undefined) {
1949 /**
1950 * acf
1951 *
1952 * description
1953 *
1954 * @date 14/12/17
1955 * @since ACF 5.6.5
1956 *
1957 * @param type $var Description. Default.
1958 * @return type Description.
1959 */
1960
1961 // The global acf object
1962 var acf = {};
1963
1964 // Set as a browser global
1965 window.acf = acf;
1966
1967 /** @var object Data sent from PHP */
1968 acf.data = {};
1969
1970 /**
1971 * get
1972 *
1973 * Gets a specific data value
1974 *
1975 * @date 14/12/17
1976 * @since ACF 5.6.5
1977 *
1978 * @param string name
1979 * @return mixed
1980 */
1981
1982 acf.get = function (name) {
1983 return this.data[name] || null;
1984 };
1985
1986 /**
1987 * has
1988 *
1989 * Returns `true` if the data exists and is not null
1990 *
1991 * @date 14/12/17
1992 * @since ACF 5.6.5
1993 *
1994 * @param string name
1995 * @return boolean
1996 */
1997
1998 acf.has = function (name) {
1999 return this.get(name) !== null;
2000 };
2001
2002 /**
2003 * set
2004 *
2005 * Sets a specific data value
2006 *
2007 * @date 14/12/17
2008 * @since ACF 5.6.5
2009 *
2010 * @param string name
2011 * @param mixed value
2012 * @return this
2013 */
2014
2015 acf.set = function (name, value) {
2016 this.data[name] = value;
2017 return this;
2018 };
2019
2020 /**
2021 * uniqueId
2022 *
2023 * Returns a unique ID
2024 *
2025 * @date 9/11/17
2026 * @since ACF 5.6.3
2027 *
2028 * @param string prefix Optional prefix.
2029 * @return string
2030 */
2031
2032 var idCounter = 0;
2033 acf.uniqueId = function (prefix) {
2034 var id = ++idCounter + '';
2035 return prefix ? prefix + id : id;
2036 };
2037
2038 /**
2039 * acf.uniqueArray
2040 *
2041 * Returns a new array with only unique values
2042 * Credit: https://stackoverflow.com/questions/1960473/get-all-unique-values-in-an-array-remove-duplicates
2043 *
2044 * @date 23/3/18
2045 * @since ACF 5.6.9
2046 *
2047 * @param type $var Description. Default.
2048 * @return type Description.
2049 */
2050
2051 acf.uniqueArray = function (array) {
2052 function onlyUnique(value, index, self) {
2053 return self.indexOf(value) === index;
2054 }
2055 return array.filter(onlyUnique);
2056 };
2057
2058 /**
2059 * uniqid
2060 *
2061 * Returns a unique ID (PHP version)
2062 *
2063 * @date 9/11/17
2064 * @since ACF 5.6.3
2065 * @source http://locutus.io/php/misc/uniqid/
2066 *
2067 * @param string prefix Optional prefix.
2068 * @return string
2069 */
2070
2071 var uniqidSeed = '';
2072 acf.uniqid = function (prefix, moreEntropy) {
2073 // discuss at: http://locutus.io/php/uniqid/
2074 // original by: Kevin van Zonneveld (http://kvz.io)
2075 // revised by: Kankrelune (http://www.webfaktory.info/)
2076 // note 1: Uses an internal counter (in locutus global) to avoid collision
2077 // example 1: var $id = uniqid()
2078 // example 1: var $result = $id.length === 13
2079 // returns 1: true
2080 // example 2: var $id = uniqid('foo')
2081 // example 2: var $result = $id.length === (13 + 'foo'.length)
2082 // returns 2: true
2083 // example 3: var $id = uniqid('bar', true)
2084 // example 3: var $result = $id.length === (23 + 'bar'.length)
2085 // returns 3: true
2086 if (typeof prefix === 'undefined') {
2087 prefix = '';
2088 }
2089 var retId;
2090 var formatSeed = function (seed, reqWidth) {
2091 seed = parseInt(seed, 10).toString(16); // to hex str
2092 if (reqWidth < seed.length) {
2093 // so long we split
2094 return seed.slice(seed.length - reqWidth);
2095 }
2096 if (reqWidth > seed.length) {
2097 // so short we pad
2098 return Array(1 + (reqWidth - seed.length)).join('0') + seed;
2099 }
2100 return seed;
2101 };
2102 if (!uniqidSeed) {
2103 // init seed with big random int
2104 uniqidSeed = Math.floor(Math.random() * 0x75bcd15);
2105 }
2106 uniqidSeed++;
2107 retId = prefix; // start with prefix, add current milliseconds hex string
2108 retId += formatSeed(parseInt(new Date().getTime() / 1000, 10), 8);
2109 retId += formatSeed(uniqidSeed, 5); // add seed hex string
2110 if (moreEntropy) {
2111 // for more entropy we add a float lower to 10
2112 retId += (Math.random() * 10).toFixed(8).toString();
2113 }
2114 return retId;
2115 };
2116
2117 /**
2118 * strReplace
2119 *
2120 * Performs a string replace
2121 *
2122 * @date 14/12/17
2123 * @since ACF 5.6.5
2124 *
2125 * @param string search
2126 * @param string replace
2127 * @param string subject
2128 * @return string
2129 */
2130
2131 acf.strReplace = function (search, replace, subject) {
2132 return subject.split(search).join(replace);
2133 };
2134
2135 /**
2136 * strCamelCase
2137 *
2138 * Converts a string into camelCase
2139 * Thanks to https://stackoverflow.com/questions/2970525/converting-any-string-into-camel-case
2140 *
2141 * @date 14/12/17
2142 * @since ACF 5.6.5
2143 *
2144 * @param string str
2145 * @return string
2146 */
2147
2148 acf.strCamelCase = function (str) {
2149 var matches = str.match(/([a-zA-Z0-9]+)/g);
2150 return matches ? matches.map(function (s, i) {
2151 var c = s.charAt(0);
2152 return (i === 0 ? c.toLowerCase() : c.toUpperCase()) + s.slice(1);
2153 }).join('') : '';
2154 };
2155
2156 /**
2157 * strPascalCase
2158 *
2159 * Converts a string into PascalCase
2160 * Thanks to https://stackoverflow.com/questions/1026069/how-do-i-make-the-first-letter-of-a-string-uppercase-in-javascript
2161 *
2162 * @date 14/12/17
2163 * @since ACF 5.6.5
2164 *
2165 * @param string str
2166 * @return string
2167 */
2168
2169 acf.strPascalCase = function (str) {
2170 var camel = acf.strCamelCase(str);
2171 return camel.charAt(0).toUpperCase() + camel.slice(1);
2172 };
2173
2174 /**
2175 * acf.strSlugify
2176 *
2177 * Converts a string into a HTML class friendly slug
2178 *
2179 * @date 21/3/18
2180 * @since ACF 5.6.9
2181 *
2182 * @param string str
2183 * @return string
2184 */
2185
2186 acf.strSlugify = function (str) {
2187 return acf.strReplace('_', '-', str.toLowerCase());
2188 };
2189 acf.strSanitize = function (str, toLowerCase = true) {
2190 // chars (https://jsperf.com/replace-foreign-characters)
2191 var map = {
2192 À: 'A',
2193 Á: 'A',
2194 Â: 'A',
2195 Ã: 'A',
2196 Ä: 'A',
2197
2198 : 'A',
2199 Æ: 'AE',
2200 Ç: 'C',
2201 È: 'E',
2202 É: 'E',
2203 Ê: 'E',
2204 Ë: 'E',
2205 Ì: 'I',
2206 Í: 'I',
2207 Î: 'I',
2208 Ï: 'I',
2209 Ð: 'D',
2210 Ñ: 'N',
2211 Ò: 'O',
2212 Ó: 'O',
2213 Ô: 'O',
2214 Õ: 'O',
2215 Ö: 'O',
2216 Ø: 'O',
2217 Ù: 'U',
2218 Ú: 'U',
2219 Û: 'U',
2220 Ü: 'U',
2221 Ý: 'Y',
2222 ß: 's',
2223 à: 'a',
2224 á: 'a',
2225 â: 'a',
2226 ã: 'a',
2227 ä: 'a',
2228 å: 'a',
2229 æ: 'ae',
2230 ç: 'c',
2231 è: 'e',
2232 é: 'e',
2233 ê: 'e',
2234 ë: 'e',
2235 ì: 'i',
2236 í: 'i',
2237 î: 'i',
2238 ï: 'i',
2239 ñ: 'n',
2240 ò: 'o',
2241 ó: 'o',
2242 ô: 'o',
2243 õ: 'o',
2244 ö: 'o',
2245 ø: 'o',
2246 ù: 'u',
2247 ú: 'u',
2248 û: 'u',
2249 ü: 'u',
2250 ý: 'y',
2251 ÿ: 'y',
2252 Ā: 'A',
2253 ā: 'a',
2254 Ă: 'A',
2255 ă: 'a',
2256 Ą: 'A',
2257
2258 : 'a',
2259 Ć: 'C',
2260 ć: 'c',
2261 Ĉ: 'C',
2262 ĉ: 'c',
2263 Ċ: 'C',
2264 ċ: 'c',
2265 Č: 'C',
2266 č: 'c',
2267 Ď: 'D',
2268 ď: 'd',
2269 Đ: 'D',
2270 đ: 'd',
2271 Ē: 'E',
2272 ē: 'e',
2273 Ĕ: 'E',
2274 ĕ: 'e',
2275 Ė: 'E',
2276 ė: 'e',
2277 Ę: 'E',
2278 ę: 'e',
2279 Ě: 'E',
2280 ě: 'e',
2281 Ĝ: 'G',
2282 ĝ: 'g',
2283 Ğ: 'G',
2284 ğ: 'g',
2285 Ġ: 'G',
2286 ġ: 'g',
2287 Ģ: 'G',
2288 ģ: 'g',
2289 Ĥ: 'H',
2290 ĥ: 'h',
2291 Ħ: 'H',
2292 ħ: 'h',
2293 Ĩ: 'I',
2294 ĩ: 'i',
2295 Ī: 'I',
2296 ī: 'i',
2297 Ĭ: 'I',
2298 ĭ: 'i',
2299 Į: 'I',
2300 į: 'i',
2301 İ: 'I',
2302 ı: 'i',
2303 IJ: 'IJ',
2304 ij: 'ij',
2305 Ĵ: 'J',
2306 ĵ: 'j',
2307 Ķ: 'K',
2308 ķ: 'k',
2309 Ĺ: 'L',
2310 ĺ: 'l',
2311 Ļ: 'L',
2312 ļ: 'l',
2313 Ľ: 'L',
2314 ľ: 'l',
2315 Ŀ: 'L',
2316 ŀ: 'l',
2317 Ł: 'l',
2318 ł: 'l',
2319 Ń: 'N',
2320 ń: 'n',
2321
2322 : 'N',
2323 ņ: 'n',
2324 Ň: 'N',
2325 ň: 'n',
2326 ʼn: 'n',
2327 Ō: 'O',
2328 ō: 'o',
2329 Ŏ: 'O',
2330 ŏ: 'o',
2331 Ő: 'O',
2332 ő: 'o',
2333 Œ: 'OE',
2334 œ: 'oe',
2335 Ŕ: 'R',
2336 ŕ: 'r',
2337 Ŗ: 'R',
2338 ŗ: 'r',
2339 Ř: 'R',
2340 ř: 'r',
2341 Ś: 'S',
2342 ś: 's',
2343 Ŝ: 'S',
2344 ŝ: 's',
2345 Ş: 'S',
2346 ş: 's',
2347 Š: 'S',
2348 š: 's',
2349 Ţ: 'T',
2350 ţ: 't',
2351 Ť: 'T',
2352 ť: 't',
2353 Ŧ: 'T',
2354 ŧ: 't',
2355 Ũ: 'U',
2356 ũ: 'u',
2357 Ū: 'U',
2358 ū: 'u',
2359 Ŭ: 'U',
2360 ŭ: 'u',
2361 Ů: 'U',
2362 ů: 'u',
2363 Ű: 'U',
2364 ű: 'u',
2365 Ų: 'U',
2366 ų: 'u',
2367 Ŵ: 'W',
2368 ŵ: 'w',
2369 Ŷ: 'Y',
2370 ŷ: 'y',
2371 Ÿ: 'Y',
2372 Ź: 'Z',
2373 ź: 'z',
2374 Ż: 'Z',
2375 ż: 'z',
2376 Ž: 'Z',
2377 ž: 'z',
2378 ſ: 's',
2379 ƒ: 'f',
2380 Ơ: 'O',
2381 ơ: 'o',
2382 Ư: 'U',
2383 ư: 'u',
2384 Ǎ: 'A',
2385 ǎ: 'a',
2386 Ǐ: 'I',
2387 ǐ: 'i',
2388 Ǒ: 'O',
2389 ǒ: 'o',
2390 Ǔ: 'U',
2391 ǔ: 'u',
2392 Ǖ: 'U',
2393 ǖ: 'u',
2394 Ǘ: 'U',
2395 ǘ: 'u',
2396 Ǚ: 'U',
2397 ǚ: 'u',
2398 Ǜ: 'U',
2399 ǜ: 'u',
2400 Ǻ: 'A',
2401 ǻ: 'a',
2402 Ǽ: 'AE',
2403 ǽ: 'ae',
2404 Ǿ: 'O',
2405 ǿ: 'o',
2406 // extra
2407 ' ': '_',
2408 "'": '',
2409 '?': '',
2410 '/': '',
2411 '\\': '',
2412 '.': '',
2413 ',': '',
2414 '`': '',
2415 '>': '',
2416 '<': '',
2417 '"': '',
2418 '[': '',
2419 ']': '',
2420 '|': '',
2421 '{': '',
2422 '}': '',
2423 '(': '',
2424 ')': ''
2425 };
2426
2427 // vars
2428 var nonWord = /\W/g;
2429 var mapping = function (c) {
2430 return map[c] !== undefined ? map[c] : c;
2431 };
2432
2433 // replace
2434 str = str.replace(nonWord, mapping);
2435
2436 // lowercase
2437 if (toLowerCase) {
2438 str = str.toLowerCase();
2439 }
2440
2441 // return
2442 return str;
2443 };
2444
2445 /**
2446 * acf.strMatch
2447 *
2448 * Returns the number of characters that match between two strings
2449 *
2450 * @date 1/2/18
2451 * @since ACF 5.6.5
2452 *
2453 * @param type $var Description. Default.
2454 * @return type Description.
2455 */
2456
2457 acf.strMatch = function (s1, s2) {
2458 // vars
2459 var val = 0;
2460 var min = Math.min(s1.length, s2.length);
2461
2462 // loop
2463 for (var i = 0; i < min; i++) {
2464 if (s1[i] !== s2[i]) {
2465 break;
2466 }
2467 val++;
2468 }
2469
2470 // return
2471 return val;
2472 };
2473
2474 /**
2475 * Escapes HTML entities from a string.
2476 *
2477 * @date 08/06/2020
2478 * @since ACF 5.9.0
2479 *
2480 * @param string string The input string.
2481 * @return string
2482 */
2483 acf.strEscape = function (string) {
2484 var htmlEscapes = {
2485 '&': '&amp;',
2486 '<': '&lt;',
2487 '>': '&gt;',
2488 '"': '&quot;',
2489 "'": '&#39;'
2490 };
2491 return ('' + string).replace(/[&<>"']/g, function (chr) {
2492 return htmlEscapes[chr];
2493 });
2494 };
2495
2496 // Tests.
2497 //console.log( acf.strEscape('Test 1') );
2498 //console.log( acf.strEscape('Test & 1') );
2499 //console.log( acf.strEscape('Test\'s &amp; 1') );
2500 //console.log( acf.strEscape('<script>js</script>') );
2501
2502 /**
2503 * Unescapes HTML entities from a string.
2504 *
2505 * @date 08/06/2020
2506 * @since ACF 5.9.0
2507 *
2508 * @param string string The input string.
2509 * @return string
2510 */
2511 acf.strUnescape = function (string) {
2512 var htmlUnescapes = {
2513 '&amp;': '&',
2514 '&lt;': '<',
2515 '&gt;': '>',
2516 '&quot;': '"',
2517 '&#39;': "'"
2518 };
2519 return ('' + string).replace(/&amp;|&lt;|&gt;|&quot;|&#39;/g, function (entity) {
2520 return htmlUnescapes[entity];
2521 });
2522 };
2523
2524 // Tests.
2525 //console.log( acf.strUnescape( acf.strEscape('Test 1') ) );
2526 //console.log( acf.strUnescape( acf.strEscape('Test & 1') ) );
2527 //console.log( acf.strUnescape( acf.strEscape('Test\'s &amp; 1') ) );
2528 //console.log( acf.strUnescape( acf.strEscape('<script>js</script>') ) );
2529
2530 /**
2531 * Escapes HTML entities from a string.
2532 *
2533 * @date 08/06/2020
2534 * @since ACF 5.9.0
2535 *
2536 * @param string string The input string.
2537 * @return string
2538 */
2539 acf.escAttr = acf.strEscape;
2540
2541 /**
2542 * Encodes <script> tags for safe HTML output.
2543 *
2544 * @date 08/06/2020
2545 * @since ACF 5.9.0
2546 * @since ACF 6.4.3 - Use DOMPurify for better security.
2547 *
2548 * @param string string The input string.
2549 * @return string
2550 */
2551
2552 acf.escHtml = function (string) {
2553 string = '' + string; // Convert to string if not already.
2554 const DOMPurify = __webpack_require__(/*! dompurify */ "./node_modules/dompurify/dist/purify.cjs.js");
2555 if (DOMPurify === undefined || !DOMPurify.isSupported) {
2556 console.warn('ACF: DOMPurify not loaded or not supported. Falling back to basic HTML escaping for security.');
2557 return acf.strEscape(string); // Fallback to basic escaping.
2558 }
2559 const options = acf.applyFilters('esc_html_dompurify_config', {
2560 USE_PROFILES: {
2561 html: true
2562 },
2563 ADD_TAGS: ['audio', 'video'],
2564 ADD_ATTR: ['controls', 'loop', 'muted', 'preload'],
2565 FORBID_TAGS: ['script', 'style', 'iframe', 'object', 'embed', 'base', 'meta', 'form'],
2566 FORBID_ATTR: ['style', 'srcset', 'action', 'background', 'dynsrc', 'lowsrc', 'on*'],
2567 ALLOW_DATA_ATTR: false,
2568 ALLOW_ARIA_ATTR: false
2569 });
2570 return DOMPurify.sanitize(string, options);
2571 };
2572
2573 // Tests.
2574 //console.log( acf.escHtml('<script>js</script>') );
2575 //console.log( acf.escHtml( acf.strEscape('<script>js</script>') ) );
2576 //console.log( acf.escHtml( '<script>js1</script><script>js2</script>' ) );
2577
2578 /**
2579 * Encode a string potentially containing HTML into it's HTML entities equivalent.
2580 *
2581 * @since ACF 6.3.6
2582 *
2583 * @param {string} string String to encode.
2584 * @return {string} The encoded string
2585 */
2586 acf.encode = function (string) {
2587 return $('<textarea/>').text(string).html();
2588 };
2589
2590 /**
2591 * Decode a HTML encoded string into it's original form.
2592 *
2593 * @since ACF 5.6.5
2594 *
2595 * @param {string} string String to encode.
2596 * @return {string} The encoded string
2597 */
2598 acf.decode = function (string) {
2599 return $('<textarea/>').html(string).text();
2600 };
2601
2602 /**
2603 * parseArgs
2604 *
2605 * Merges together defaults and args much like the WP wp_parse_args function
2606 *
2607 * @date 14/12/17
2608 * @since ACF 5.6.5
2609 *
2610 * @param object args
2611 * @param object defaults
2612 * @return object
2613 */
2614
2615 acf.parseArgs = function (args, defaults) {
2616 if (typeof args !== 'object') args = {};
2617 if (typeof defaults !== 'object') defaults = {};
2618 return $.extend({}, defaults, args);
2619 };
2620
2621 /**
2622 * __
2623 *
2624 * Retrieve the translation of $text.
2625 *
2626 * @date 16/4/18
2627 * @since ACF 5.6.9
2628 *
2629 * @param string text Text to translate.
2630 * @return string Translated text.
2631 */
2632
2633 // Make sure a global acfL10n object exists to prevent errors in other scopes
2634 window.acfL10n = window.acfL10n || {};
2635 acf.__ = function (text) {
2636 return acfL10n[text] || text;
2637 };
2638
2639 /**
2640 * _x
2641 *
2642 * Retrieve translated string with gettext context.
2643 *
2644 * @date 16/4/18
2645 * @since ACF 5.6.9
2646 *
2647 * @param string text Text to translate.
2648 * @param string context Context information for the translators.
2649 * @return string Translated text.
2650 */
2651
2652 acf._x = function (text, context) {
2653 return acfL10n[text + '.' + context] || acfL10n[text] || text;
2654 };
2655
2656 /**
2657 * _n
2658 *
2659 * Retrieve the plural or single form based on the amount.
2660 *
2661 * @date 16/4/18
2662 * @since ACF 5.6.9
2663 *
2664 * @param string single Single text to translate.
2665 * @param string plural Plural text to translate.
2666 * @param int number The number to compare against.
2667 * @return string Translated text.
2668 */
2669
2670 acf._n = function (single, plural, number) {
2671 if (number == 1) {
2672 return acf.__(single);
2673 } else {
2674 return acf.__(plural);
2675 }
2676 };
2677 acf.isArray = function (a) {
2678 return Array.isArray(a);
2679 };
2680 acf.isObject = function (a) {
2681 return typeof a === 'object';
2682 };
2683
2684 /**
2685 * serialize
2686 *
2687 * description
2688 *
2689 * @date 24/12/17
2690 * @since ACF 5.6.5
2691 *
2692 * @param type $var Description. Default.
2693 * @return type Description.
2694 */
2695
2696 var buildObject = function (obj, name, value) {
2697 // replace [] with placeholder
2698 name = name.replace('[]', '[%%index%%]');
2699
2700 // vars
2701 var keys = name.match(/([^\[\]])+/g);
2702 if (!keys) return;
2703 var length = keys.length;
2704 var ref = obj;
2705
2706 // loop
2707 for (var i = 0; i < length; i++) {
2708 // vars
2709 var key = String(keys[i]);
2710
2711 // value
2712 if (i == length - 1) {
2713 // %%index%%
2714 if (key === '%%index%%') {
2715 ref.push(value);
2716
2717 // default
2718 } else {
2719 ref[key] = value;
2720 }
2721
2722 // path
2723 } else {
2724 // array
2725 if (keys[i + 1] === '%%index%%') {
2726 if (!acf.isArray(ref[key])) {
2727 ref[key] = [];
2728 }
2729
2730 // object
2731 } else {
2732 if (!acf.isObject(ref[key])) {
2733 ref[key] = {};
2734 }
2735 }
2736
2737 // crawl
2738 ref = ref[key];
2739 }
2740 }
2741 };
2742 acf.serialize = function ($el, prefix) {
2743 // vars
2744 var obj = {};
2745 var inputs = acf.serializeArray($el);
2746
2747 // prefix
2748 if (prefix !== undefined) {
2749 // filter and modify
2750 inputs = inputs.filter(function (item) {
2751 return item.name.indexOf(prefix) === 0;
2752 }).map(function (item) {
2753 item.name = item.name.slice(prefix.length);
2754 return item;
2755 });
2756 }
2757
2758 // loop
2759 for (var i = 0; i < inputs.length; i++) {
2760 buildObject(obj, inputs[i].name, inputs[i].value);
2761 }
2762
2763 // return
2764 return obj;
2765 };
2766
2767 /**
2768 * Check if an object has only numeric string keys.
2769 * Used to detect objects that should be converted to arrays (e.g., checkbox values).
2770 *
2771 * Semantics:
2772 * - Accepts base-10, non-negative integer strings composed of digits only (e.g. "0", "12").
2773 * - Leading zeros are allowed (e.g. "0012") and treated as numeric by downstream logic.
2774 * - Negative ("-1"), decimal ("1.0"), and non-numeric keys are rejected.
2775 *
2776 * @since SCF 6.6.0
2777 * @private
2778 *
2779 * @param object obj The object to check
2780 * @return boolean True if all keys are numeric strings
2781 */
2782 const hasOnlyNumericKeys = function (obj) {
2783 const keys = Object.keys(obj);
2784 if (keys.length === 0) {
2785 return false;
2786 }
2787 for (let i = 0; i < keys.length; i++) {
2788 if (!/^\d+$/.test(keys[i])) {
2789 return false;
2790 }
2791 }
2792 return true;
2793 };
2794
2795 /**
2796 * Convert an object with numeric string keys to a numerically sorted array.
2797 * Example: {"0": "one", "2": "three", "1": "two"} becomes ["one", "two", "three"].
2798 *
2799 * Notes on edge-cases:
2800 * - Leading zeros (e.g. "00123") are supported; order is based on the numeric value
2801 * but the original string key is used to read the value to avoid lookup mismatches.
2802 * - Assumes {@link hasOnlyNumericKeys} has already gated out negatives/decimals.
2803 *
2804 * @since SCF 6.6.0
2805 * @private
2806 *
2807 * @param object obj The object to convert
2808 * @return array The numerically sorted array of values
2809 */
2810 const numericObjectToArray = function (obj) {
2811 const arr = [];
2812 // Pair each original key with its numeric value for stable lookup and sorting.
2813 const entries = Object.keys(obj).map(function (k) {
2814 return {
2815 k: k,
2816 n: parseInt(k, 10)
2817 };
2818 }).sort(function (a, b) {
2819 return a.n - b.n;
2820 });
2821 for (let i = 0; i < entries.length; i++) {
2822 arr.push(obj[entries[i].k]);
2823 }
2824 return arr;
2825 };
2826
2827 /**
2828 * Check if a value looks like flexible content data.
2829 * Flexible content objects contain rows where each row object has an 'acf_fc_layout' property.
2830 * Keys for flexible rows are not guaranteed to be numeric: they are typically unique IDs
2831 * (e.g. '69171156640b5') or strings like 'row-0'. Therefore, flexible content detection does
2832 * not rely on numeric keys and is handled separately from numeric-keyed object normalization.
2833 *
2834 * @since SCF 6.6.0
2835 *
2836 * @param object value The value to check
2837 * @return boolean True if this looks like flexible content data
2838 */
2839 acf.isFlexibleContentData = function (value) {
2840 if (!acf.isObject(value)) {
2841 return false;
2842 }
2843 var keys = Object.keys(value);
2844 for (var i = 0; i < keys.length; i++) {
2845 var key = keys[i];
2846 if (key === 'acfcloneindex') {
2847 continue;
2848 }
2849 var subvalue = value[key];
2850 if (acf.isObject(subvalue) && subvalue.acf_fc_layout) {
2851 return true;
2852 }
2853 }
2854 return false;
2855 };
2856
2857 /**
2858 * Normalizes flexible content data structure by converting objects to arrays.
2859 * Private helper function.
2860 *
2861 * @since 6.6.0
2862 *
2863 * @param {Object} obj The object to normalize.
2864 * @return {Object|Array} The normalized data.
2865 */
2866 const normalizeFlexibleContentData = function (obj) {
2867 if (!acf.isObject(obj)) {
2868 return obj;
2869 }
2870 let result = {};
2871 for (let key in obj) {
2872 if (!obj.hasOwnProperty(key)) {
2873 continue;
2874 }
2875 var value = obj[key];
2876
2877 // Primitives pass through unchanged
2878 if (!acf.isObject(value)) {
2879 result[key] = value;
2880 continue;
2881 }
2882
2883 // Convert numeric-keyed objects to arrays (e.g., checkbox values)
2884 if (hasOnlyNumericKeys(value)) {
2885 result[key] = numericObjectToArray(value);
2886 continue;
2887 } // Convert flexible content to arrays
2888 if (acf.isFlexibleContentData(value)) {
2889 var arr = [];
2890 var keys = Object.keys(value);
2891 for (var i = 0; i < keys.length; i++) {
2892 var subkey = keys[i];
2893 if (subkey === 'acfcloneindex') {
2894 continue;
2895 }
2896 var subvalue = value[subkey];
2897 if (acf.isObject(subvalue) && subvalue.acf_fc_layout) {
2898 arr.push(normalizeFlexibleContentData(subvalue));
2899 }
2900 }
2901 result[key] = arr;
2902 } else {
2903 // Recursively process nested objects
2904 result[key] = normalizeFlexibleContentData(value);
2905 }
2906 }
2907 return result;
2908 };
2909
2910 /**
2911 * Public API wrapper for normalizeFlexibleContentData.
2912 * Normalizes flexible content data structure by converting objects to arrays.
2913 *
2914 * @since 6.6.0
2915 *
2916 * @param {Object} obj The object to normalize.
2917 * @return {Object|Array} The normalized data.
2918 */
2919 acf.normalizeFlexibleContentData = function (obj) {
2920 return normalizeFlexibleContentData(obj);
2921 };
2922
2923 /**
2924 * acf.serializeArray
2925 *
2926 * Similar to $.serializeArray() but works with a parent wrapping element.
2927 *
2928 * @date 19/8/18
2929 * @since ACF 5.7.3
2930 *
2931 * @param jQuery $el The element or form to serialize.
2932 * @return array
2933 */
2934
2935 acf.serializeArray = function ($el) {
2936 return $el.find('select, textarea, input').serializeArray();
2937 };
2938
2939 /**
2940 * acf.serializeForAjax
2941 *
2942 * Returns an object containing name => value data ready to be encoded for Ajax.
2943 *
2944 * @date 17/12/18
2945 * @since ACF 5.8.0
2946 *
2947 * @param jQuery $el The element or form to serialize.
2948 * @return object
2949 */
2950 acf.serializeForAjax = function ($el) {
2951 // vars
2952 var data = {};
2953 var index = {};
2954
2955 // Serialize inputs.
2956 var inputs = acf.serializeArray($el);
2957
2958 // Loop over inputs and build data.
2959 inputs.map(function (item) {
2960 // Append to array.
2961 if (item.name.slice(-2) === '[]') {
2962 data[item.name] = data[item.name] || [];
2963 data[item.name].push(item.value);
2964 // Append
2965 } else {
2966 data[item.name] = item.value;
2967 }
2968 });
2969
2970 // return
2971 return data;
2972 };
2973
2974 /**
2975 * addAction
2976 *
2977 * Wrapper for acf.hooks.addAction
2978 *
2979 * @date 14/12/17
2980 * @since ACF 5.6.5
2981 *
2982 * @param n/a
2983 * @return this
2984 */
2985
2986 /*
2987 var prefixAction = function( action ){
2988 return 'acf_' + action;
2989 }
2990 */
2991
2992 acf.addAction = function () {
2993 //action = prefixAction(action);
2994 acf.hooks.addAction.apply(this, arguments);
2995 return this;
2996 };
2997
2998 /**
2999 * removeAction
3000 *
3001 * Wrapper for acf.hooks.removeAction
3002 *
3003 * @date 14/12/17
3004 * @since ACF 5.6.5
3005 *
3006 * @param n/a
3007 * @return this
3008 */
3009
3010 acf.removeAction = function () {
3011 //action = prefixAction(action);
3012 acf.hooks.removeAction.apply(this, arguments);
3013 return this;
3014 };
3015
3016 /**
3017 * doAction
3018 *
3019 * Wrapper for acf.hooks.doAction
3020 *
3021 * @date 14/12/17
3022 * @since ACF 5.6.5
3023 *
3024 * @param n/a
3025 * @return this
3026 */
3027
3028 var actionHistory = {};
3029 //var currentAction = false;
3030 acf.doAction = function (action) {
3031 //action = prefixAction(action);
3032 //currentAction = action;
3033 actionHistory[action] = 1;
3034 acf.hooks.doAction.apply(this, arguments);
3035 actionHistory[action] = 0;
3036 return this;
3037 };
3038
3039 /**
3040 * doingAction
3041 *
3042 * Return true if doing action
3043 *
3044 * @date 14/12/17
3045 * @since ACF 5.6.5
3046 *
3047 * @param n/a
3048 * @return this
3049 */
3050
3051 acf.doingAction = function (action) {
3052 //action = prefixAction(action);
3053 return actionHistory[action] === 1;
3054 };
3055
3056 /**
3057 * didAction
3058 *
3059 * Wrapper for acf.hooks.doAction
3060 *
3061 * @date 14/12/17
3062 * @since ACF 5.6.5
3063 *
3064 * @param n/a
3065 * @return this
3066 */
3067
3068 acf.didAction = function (action) {
3069 //action = prefixAction(action);
3070 return actionHistory[action] !== undefined;
3071 };
3072
3073 /**
3074 * currentAction
3075 *
3076 * Wrapper for acf.hooks.doAction
3077 *
3078 * @date 14/12/17
3079 * @since ACF 5.6.5
3080 *
3081 * @param n/a
3082 * @return this
3083 */
3084
3085 acf.currentAction = function () {
3086 for (var k in actionHistory) {
3087 if (actionHistory[k]) {
3088 return k;
3089 }
3090 }
3091 return false;
3092 };
3093
3094 /**
3095 * addFilter
3096 *
3097 * Wrapper for acf.hooks.addFilter
3098 *
3099 * @date 14/12/17
3100 * @since ACF 5.6.5
3101 *
3102 * @param n/a
3103 * @return this
3104 */
3105
3106 acf.addFilter = function () {
3107 //action = prefixAction(action);
3108 acf.hooks.addFilter.apply(this, arguments);
3109 return this;
3110 };
3111
3112 /**
3113 * removeFilter
3114 *
3115 * Wrapper for acf.hooks.removeFilter
3116 *
3117 * @date 14/12/17
3118 * @since ACF 5.6.5
3119 *
3120 * @param n/a
3121 * @return this
3122 */
3123
3124 acf.removeFilter = function () {
3125 //action = prefixAction(action);
3126 acf.hooks.removeFilter.apply(this, arguments);
3127 return this;
3128 };
3129
3130 /**
3131 * applyFilters
3132 *
3133 * Wrapper for acf.hooks.applyFilters
3134 *
3135 * @date 14/12/17
3136 * @since ACF 5.6.5
3137 *
3138 * @param n/a
3139 * @return this
3140 */
3141
3142 acf.applyFilters = function () {
3143 //action = prefixAction(action);
3144 return acf.hooks.applyFilters.apply(this, arguments);
3145 };
3146
3147 /**
3148 * getArgs
3149 *
3150 * description
3151 *
3152 * @date 15/12/17
3153 * @since ACF 5.6.5
3154 *
3155 * @param type $var Description. Default.
3156 * @return type Description.
3157 */
3158
3159 acf.arrayArgs = function (args) {
3160 return Array.prototype.slice.call(args);
3161 };
3162
3163 /**
3164 * extendArgs
3165 *
3166 * description
3167 *
3168 * @date 15/12/17
3169 * @since ACF 5.6.5
3170 *
3171 * @param type $var Description. Default.
3172 * @return type Description.
3173 */
3174
3175 /*
3176 acf.extendArgs = function( ){
3177 var args = Array.prototype.slice.call( arguments );
3178 var realArgs = args.shift();
3179
3180 Array.prototype.push.call(arguments, 'bar')
3181 return Array.prototype.push.apply( args, arguments );
3182 };
3183 */
3184
3185 // Preferences
3186 // - use try/catch to avoid JS error if cookies are disabled on front-end form
3187 try {
3188 var preferences = JSON.parse(localStorage.getItem('acf')) || {};
3189 } catch (e) {
3190 var preferences = {};
3191 }
3192
3193 /**
3194 * getPreferenceName
3195 *
3196 * Gets the true preference name.
3197 * Converts "this.thing" to "thing-123" if editing post 123.
3198 *
3199 * @date 11/11/17
3200 * @since ACF 5.6.5
3201 *
3202 * @param string name
3203 * @return string
3204 */
3205
3206 var getPreferenceName = function (name) {
3207 if (name.substr(0, 5) === 'this.') {
3208 name = name.substr(5) + '-' + acf.get('post_id');
3209 }
3210 return name;
3211 };
3212
3213 /**
3214 * acf.getPreference
3215 *
3216 * Gets a preference setting or null if not set.
3217 *
3218 * @date 11/11/17
3219 * @since ACF 5.6.5
3220 *
3221 * @param string name
3222 * @return mixed
3223 */
3224
3225 acf.getPreference = function (name) {
3226 name = getPreferenceName(name);
3227 return preferences[name] || null;
3228 };
3229
3230 /**
3231 * acf.setPreference
3232 *
3233 * Sets a preference setting.
3234 *
3235 * @date 11/11/17
3236 * @since ACF 5.6.5
3237 *
3238 * @param string name
3239 * @param mixed value
3240 * @return n/a
3241 */
3242
3243 acf.setPreference = function (name, value) {
3244 name = getPreferenceName(name);
3245 if (value === null) {
3246 delete preferences[name];
3247 } else {
3248 preferences[name] = value;
3249 }
3250 localStorage.setItem('acf', JSON.stringify(preferences));
3251 };
3252
3253 /**
3254 * acf.removePreference
3255 *
3256 * Removes a preference setting.
3257 *
3258 * @date 11/11/17
3259 * @since ACF 5.6.5
3260 *
3261 * @param string name
3262 * @return n/a
3263 */
3264
3265 acf.removePreference = function (name) {
3266 acf.setPreference(name, null);
3267 };
3268
3269 /**
3270 * remove
3271 *
3272 * Removes an element with fade effect
3273 *
3274 * @date 1/1/18
3275 * @since ACF 5.6.5
3276 *
3277 * @param type $var Description. Default.
3278 * @return type Description.
3279 */
3280
3281 acf.remove = function (props) {
3282 // allow jQuery
3283 if (props instanceof jQuery) {
3284 props = {
3285 target: props
3286 };
3287 }
3288
3289 // defaults
3290 props = acf.parseArgs(props, {
3291 target: false,
3292 endHeight: 0,
3293 complete: function () {}
3294 });
3295
3296 // action
3297 acf.doAction('remove', props.target);
3298
3299 // tr
3300 if (props.target.is('tr')) {
3301 removeTr(props);
3302
3303 // div
3304 } else {
3305 removeDiv(props);
3306 }
3307 };
3308
3309 /**
3310 * removeDiv
3311 *
3312 * description
3313 *
3314 * @date 16/2/18
3315 * @since ACF 5.6.9
3316 *
3317 * @param type $var Description. Default.
3318 * @return type Description.
3319 */
3320
3321 var removeDiv = function (props) {
3322 // vars
3323 var $el = props.target;
3324 var height = $el.height();
3325 var width = $el.width();
3326 var margin = $el.css('margin');
3327 var outerHeight = $el.outerHeight(true);
3328 var style = $el.attr('style') + ''; // needed to copy
3329
3330 // wrap
3331 $el.wrap('<div class="acf-temp-remove" style="height:' + outerHeight + 'px"></div>');
3332 var $wrap = $el.parent();
3333
3334 // set pos
3335 $el.css({
3336 height: height,
3337 width: width,
3338 margin: margin,
3339 position: 'absolute'
3340 });
3341
3342 // fade wrap
3343 setTimeout(function () {
3344 $wrap.css({
3345 opacity: 0,
3346 height: props.endHeight
3347 });
3348 }, 50);
3349
3350 // remove
3351 setTimeout(function () {
3352 $el.attr('style', style);
3353 $wrap.remove();
3354 props.complete();
3355 }, 301);
3356 };
3357
3358 /**
3359 * removeTr
3360 *
3361 * description
3362 *
3363 * @date 16/2/18
3364 * @since ACF 5.6.9
3365 *
3366 * @param type $var Description. Default.
3367 * @return type Description.
3368 */
3369
3370 var removeTr = function (props) {
3371 // vars
3372 var $tr = props.target;
3373 var height = $tr.height();
3374 var children = $tr.children().length;
3375
3376 // create dummy td
3377 var $td = $('<td class="acf-temp-remove" style="padding:0; height:' + height + 'px" colspan="' + children + '"></td>');
3378
3379 // fade away tr
3380 $tr.addClass('acf-remove-element');
3381
3382 // update HTML after fade animation
3383 setTimeout(function () {
3384 $tr.html($td);
3385 }, 251);
3386
3387 // allow .acf-temp-remove to exist before changing CSS
3388 setTimeout(function () {
3389 // remove class
3390 $tr.removeClass('acf-remove-element');
3391
3392 // collapse
3393 $td.css({
3394 height: props.endHeight
3395 });
3396 }, 300);
3397
3398 // remove
3399 setTimeout(function () {
3400 $tr.remove();
3401 props.complete();
3402 }, 451);
3403 };
3404
3405 /**
3406 * duplicate
3407 *
3408 * description
3409 *
3410 * @date 3/1/18
3411 * @since ACF 5.6.5
3412 *
3413 * @param type $var Description. Default.
3414 * @return type Description.
3415 */
3416
3417 acf.duplicate = function (args) {
3418 // allow jQuery
3419 if (args instanceof jQuery) {
3420 args = {
3421 target: args
3422 };
3423 }
3424
3425 // defaults
3426 args = acf.parseArgs(args, {
3427 target: false,
3428 search: '',
3429 replace: '',
3430 rename: true,
3431 before: function ($el) {},
3432 after: function ($el, $el2) {},
3433 append: function ($el, $el2) {
3434 $el.after($el2);
3435 }
3436 });
3437
3438 // compatibility
3439 args.target = args.target || args.$el;
3440
3441 // vars
3442 var $el = args.target;
3443
3444 // search
3445 args.search = args.search || $el.attr('data-id');
3446 args.replace = args.replace || acf.uniqid();
3447
3448 // before
3449 // - allow acf to modify DOM
3450 // - fixes bug where select field option is not selected
3451 args.before($el);
3452 acf.doAction('before_duplicate', $el);
3453
3454 // clone
3455 var $el2 = $el.clone();
3456
3457 // rename
3458 if (args.rename) {
3459 acf.rename({
3460 target: $el2,
3461 search: args.search,
3462 replace: args.replace,
3463 replacer: typeof args.rename === 'function' ? args.rename : null
3464 });
3465 }
3466
3467 // remove classes
3468 $el2.removeClass('acf-clone');
3469 $el2.find('.ui-sortable').removeClass('ui-sortable');
3470
3471 // remove any initialised select2s prevent the duplicated object stealing the previous select2.
3472 $el2.find('[data-select2-id]').removeAttr('data-select2-id');
3473 $el2.find('.select2').remove();
3474
3475 // subfield select2 renames happen after init and contain a duplicated ID. force change those IDs to prevent this.
3476 $el2.find('.acf-is-subfields select[data-ui="1"]').each(function () {
3477 $(this).prop('id', $(this).prop('id').replace('acf_fields', acf.uniqid('duplicated_') + '_acf_fields'));
3478 });
3479
3480 // remove tab wrapper to ensure proper init
3481 $el2.find('.acf-field-settings > .acf-tab-wrap').remove();
3482
3483 // after
3484 // - allow acf to modify DOM
3485 args.after($el, $el2);
3486 acf.doAction('after_duplicate', $el, $el2);
3487
3488 // append
3489 args.append($el, $el2);
3490
3491 /**
3492 * Fires after an element has been duplicated and appended to the DOM.
3493 *
3494 * @date 30/10/19
3495 * @since ACF 5.8.7
3496 *
3497 * @param jQuery $el The original element.
3498 * @param jQuery $el2 The duplicated element.
3499 */
3500 acf.doAction('duplicate', $el, $el2);
3501
3502 // append
3503 acf.doAction('append', $el2);
3504
3505 // return
3506 return $el2;
3507 };
3508
3509 /**
3510 * rename
3511 *
3512 * description
3513 *
3514 * @date 7/1/18
3515 * @since ACF 5.6.5
3516 *
3517 * @param type $var Description. Default.
3518 * @return type Description.
3519 */
3520
3521 acf.rename = function (args) {
3522 // Allow jQuery param.
3523 if (args instanceof jQuery) {
3524 args = {
3525 target: args
3526 };
3527 }
3528
3529 // Apply default args.
3530 args = acf.parseArgs(args, {
3531 target: false,
3532 destructive: false,
3533 search: '',
3534 replace: '',
3535 replacer: null
3536 });
3537
3538 // Extract args.
3539 var $el = args.target;
3540
3541 // Provide backup for empty args.
3542 if (!args.search) {
3543 args.search = $el.attr('data-id');
3544 }
3545 if (!args.replace) {
3546 args.replace = acf.uniqid('acf');
3547 }
3548 if (!args.replacer) {
3549 args.replacer = function (name, value, search, replace) {
3550 return value.replace(search, replace);
3551 };
3552 }
3553
3554 // Callback function for jQuery replacing.
3555 var withReplacer = function (name) {
3556 return function (i, value) {
3557 return args.replacer(name, value, args.search, args.replace);
3558 };
3559 };
3560
3561 // Destructive Replace.
3562 if (args.destructive) {
3563 var html = acf.strReplace(args.search, args.replace, $el.outerHTML());
3564 $el.replaceWith(html);
3565
3566 // Standard Replace.
3567 } else {
3568 $el.attr('data-id', args.replace);
3569 $el.find('[id*="' + args.search + '"]').attr('id', withReplacer('id'));
3570 $el.find('[for*="' + args.search + '"]').attr('for', withReplacer('for'));
3571 $el.find('[name*="' + args.search + '"]').attr('name', withReplacer('name'));
3572 }
3573
3574 // return
3575 return $el;
3576 };
3577
3578 /**
3579 * Prepares AJAX data prior to being sent.
3580 *
3581 * @since ACF 5.6.5
3582 *
3583 * @param Object data The data to prepare
3584 * @param boolean use_global_nonce Should we ignore any nonce provided in the data object and force ACF's global nonce for this request
3585 * @return Object The prepared data.
3586 */
3587 acf.prepareForAjax = function (data, use_global_nonce = false) {
3588 // Set a default nonce if we don't have one already.
3589 if (use_global_nonce || 'undefined' === typeof data.nonce) {
3590 data.nonce = acf.get('nonce');
3591 }
3592 data.post_id = acf.get('post_id');
3593 if (acf.has('language')) {
3594 data.lang = acf.get('language');
3595 }
3596
3597 // Filter for 3rd party customization.
3598 data = acf.applyFilters('prepare_for_ajax', data);
3599 return data;
3600 };
3601
3602 /**
3603 * acf.startButtonLoading
3604 *
3605 * description
3606 *
3607 * @date 5/1/18
3608 * @since ACF 5.6.5
3609 *
3610 * @param type $var Description. Default.
3611 * @return type Description.
3612 */
3613
3614 acf.startButtonLoading = function ($el) {
3615 $el.prop('disabled', true);
3616 $el.after(' <i class="acf-loading"></i>');
3617 };
3618 acf.stopButtonLoading = function ($el) {
3619 $el.prop('disabled', false);
3620 $el.next('.acf-loading').remove();
3621 };
3622
3623 /**
3624 * acf.showLoading
3625 *
3626 * description
3627 *
3628 * @date 12/1/18
3629 * @since ACF 5.6.5
3630 *
3631 * @param type $var Description. Default.
3632 * @return type Description.
3633 */
3634
3635 acf.showLoading = function ($el) {
3636 $el.append('<div class="acf-loading-overlay"><i class="acf-loading"></i></div>');
3637 };
3638 acf.hideLoading = function ($el) {
3639 $el.children('.acf-loading-overlay').remove();
3640 };
3641
3642 /**
3643 * acf.updateUserSetting
3644 *
3645 * description
3646 *
3647 * @date 5/1/18
3648 * @since ACF 5.6.5
3649 *
3650 * @param type $var Description. Default.
3651 * @return type Description.
3652 */
3653
3654 acf.updateUserSetting = function (name, value) {
3655 var ajaxData = {
3656 action: 'acf/ajax/user_setting',
3657 name: name,
3658 value: value
3659 };
3660 $.ajax({
3661 url: acf.get('ajaxurl'),
3662 data: acf.prepareForAjax(ajaxData),
3663 type: 'post',
3664 dataType: 'html'
3665 });
3666 };
3667
3668 /**
3669 * acf.val
3670 *
3671 * description
3672 *
3673 * @date 8/1/18
3674 * @since ACF 5.6.5
3675 *
3676 * @param type $var Description. Default.
3677 * @return type Description.
3678 */
3679
3680 acf.val = function ($input, value, silent) {
3681 // vars
3682 var prevValue = $input.val();
3683
3684 // bail if no change
3685 if (value === prevValue) {
3686 return false;
3687 }
3688
3689 // update value
3690 $input.val(value);
3691
3692 // prevent select elements displaying blank value if option doesn't exist
3693 if ($input.is('select') && $input.val() === null) {
3694 $input.val(prevValue);
3695 return false;
3696 }
3697
3698 // update with trigger
3699 if (silent !== true) {
3700 $input.trigger('change');
3701 }
3702
3703 // return
3704 return true;
3705 };
3706
3707 /**
3708 * acf.show
3709 *
3710 * description
3711 *
3712 * @date 9/2/18
3713 * @since ACF 5.6.5
3714 *
3715 * @param type $var Description. Default.
3716 * @return type Description.
3717 */
3718
3719 acf.show = function ($el, lockKey) {
3720 // unlock
3721 if (lockKey) {
3722 acf.unlock($el, 'hidden', lockKey);
3723 }
3724
3725 // bail early if $el is still locked
3726 if (acf.isLocked($el, 'hidden')) {
3727 //console.log( 'still locked', getLocks( $el, 'hidden' ));
3728 return false;
3729 }
3730
3731 // $el is hidden, remove class and return true due to change in visibility
3732 if ($el.hasClass('acf-hidden')) {
3733 $el.removeClass('acf-hidden');
3734 return true;
3735
3736 // $el is visible, return false due to no change in visibility
3737 } else {
3738 return false;
3739 }
3740 };
3741
3742 /**
3743 * acf.hide
3744 *
3745 * description
3746 *
3747 * @date 9/2/18
3748 * @since ACF 5.6.5
3749 *
3750 * @param type $var Description. Default.
3751 * @return type Description.
3752 */
3753
3754 acf.hide = function ($el, lockKey) {
3755 // lock
3756 if (lockKey) {
3757 acf.lock($el, 'hidden', lockKey);
3758 }
3759
3760 // $el is hidden, return false due to no change in visibility
3761 if ($el.hasClass('acf-hidden')) {
3762 return false;
3763
3764 // $el is visible, add class and return true due to change in visibility
3765 } else {
3766 $el.addClass('acf-hidden');
3767 return true;
3768 }
3769 };
3770
3771 /**
3772 * acf.isHidden
3773 *
3774 * description
3775 *
3776 * @date 9/2/18
3777 * @since ACF 5.6.5
3778 *
3779 * @param type $var Description. Default.
3780 * @return type Description.
3781 */
3782
3783 acf.isHidden = function ($el) {
3784 return $el.hasClass('acf-hidden');
3785 };
3786
3787 /**
3788 * acf.isVisible
3789 *
3790 * description
3791 *
3792 * @date 9/2/18
3793 * @since ACF 5.6.5
3794 *
3795 * @param type $var Description. Default.
3796 * @return type Description.
3797 */
3798
3799 acf.isVisible = function ($el) {
3800 return !acf.isHidden($el);
3801 };
3802
3803 /**
3804 * enable
3805 *
3806 * description
3807 *
3808 * @date 12/3/18
3809 * @since ACF 5.6.9
3810 *
3811 * @param type $var Description. Default.
3812 * @return type Description.
3813 */
3814
3815 var enable = function ($el, lockKey) {
3816 // check class. Allow .acf-disabled to overrule all JS
3817 if ($el.hasClass('acf-disabled')) {
3818 return false;
3819 }
3820
3821 // unlock
3822 if (lockKey) {
3823 acf.unlock($el, 'disabled', lockKey);
3824 }
3825
3826 // bail early if $el is still locked
3827 if (acf.isLocked($el, 'disabled')) {
3828 return false;
3829 }
3830
3831 // $el is disabled, remove prop and return true due to change
3832 if ($el.prop('disabled')) {
3833 $el.prop('disabled', false);
3834 return true;
3835
3836 // $el is enabled, return false due to no change
3837 } else {
3838 return false;
3839 }
3840 };
3841
3842 /**
3843 * acf.enable
3844 *
3845 * description
3846 *
3847 * @date 9/2/18
3848 * @since ACF 5.6.5
3849 *
3850 * @param type $var Description. Default.
3851 * @return type Description.
3852 */
3853
3854 acf.enable = function ($el, lockKey) {
3855 // enable single input
3856 if ($el.attr('name')) {
3857 return enable($el, lockKey);
3858 }
3859
3860 // find and enable child inputs
3861 // return true if any inputs have changed
3862 var results = false;
3863 $el.find('[name]').each(function () {
3864 var result = enable($(this), lockKey);
3865 if (result) {
3866 results = true;
3867 }
3868 });
3869 return results;
3870 };
3871
3872 /**
3873 * disable
3874 *
3875 * description
3876 *
3877 * @date 12/3/18
3878 * @since ACF 5.6.9
3879 *
3880 * @param type $var Description. Default.
3881 * @return type Description.
3882 */
3883
3884 var disable = function ($el, lockKey) {
3885 // lock
3886 if (lockKey) {
3887 acf.lock($el, 'disabled', lockKey);
3888 }
3889
3890 // $el is disabled, return false due to no change
3891 if ($el.prop('disabled')) {
3892 return false;
3893
3894 // $el is enabled, add prop and return true due to change
3895 } else {
3896 $el.prop('disabled', true);
3897 return true;
3898 }
3899 };
3900
3901 /**
3902 * acf.disable
3903 *
3904 * description
3905 *
3906 * @date 9/2/18
3907 * @since ACF 5.6.5
3908 *
3909 * @param type $var Description. Default.
3910 * @return type Description.
3911 */
3912
3913 acf.disable = function ($el, lockKey) {
3914 // disable single input
3915 if ($el.attr('name')) {
3916 return disable($el, lockKey);
3917 }
3918
3919 // find and enable child inputs
3920 // return true if any inputs have changed
3921 var results = false;
3922 $el.find('[name]').each(function () {
3923 var result = disable($(this), lockKey);
3924 if (result) {
3925 results = true;
3926 }
3927 });
3928 return results;
3929 };
3930
3931 /**
3932 * acf.isset
3933 *
3934 * description
3935 *
3936 * @date 10/1/18
3937 * @since ACF 5.6.5
3938 *
3939 * @param type $var Description. Default.
3940 * @return type Description.
3941 */
3942
3943 acf.isset = function (obj /*, level1, level2, ... */) {
3944 for (var i = 1; i < arguments.length; i++) {
3945 if (!obj || !obj.hasOwnProperty(arguments[i])) {
3946 return false;
3947 }
3948 obj = obj[arguments[i]];
3949 }
3950 return true;
3951 };
3952
3953 /**
3954 * acf.isget
3955 *
3956 * description
3957 *
3958 * @date 10/1/18
3959 * @since ACF 5.6.5
3960 *
3961 * @param type $var Description. Default.
3962 * @return type Description.
3963 */
3964
3965 acf.isget = function (obj /*, level1, level2, ... */) {
3966 for (var i = 1; i < arguments.length; i++) {
3967 if (!obj || !obj.hasOwnProperty(arguments[i])) {
3968 return null;
3969 }
3970 obj = obj[arguments[i]];
3971 }
3972 return obj;
3973 };
3974
3975 /**
3976 * acf.getFileInputData
3977 *
3978 * description
3979 *
3980 * @date 10/1/18
3981 * @since ACF 5.6.5
3982 *
3983 * @param type $var Description. Default.
3984 * @return type Description.
3985 */
3986
3987 acf.getFileInputData = function ($input, callback) {
3988 // vars
3989 var value = $input.val();
3990
3991 // bail early if no value
3992 if (!value) {
3993 return false;
3994 }
3995
3996 // data
3997 var data = {
3998 url: value
3999 };
4000
4001 // modern browsers
4002 var file = $input[0].files.length ? acf.isget($input[0].files, 0) : false;
4003 if (file) {
4004 // update data
4005 data.size = file.size;
4006 data.type = file.type;
4007
4008 // image
4009 if (file.type.indexOf('image') > -1) {
4010 // vars
4011 var windowURL = window.URL || window.webkitURL;
4012 var img = new Image();
4013 img.onload = function () {
4014 // update
4015 data.width = this.width;
4016 data.height = this.height;
4017 callback(data);
4018 };
4019 img.src = windowURL.createObjectURL(file);
4020 } else {
4021 callback(data);
4022 }
4023 } else {
4024 callback(data);
4025 }
4026 };
4027
4028 /**
4029 * acf.isAjaxSuccess
4030 *
4031 * description
4032 *
4033 * @date 18/1/18
4034 * @since ACF 5.6.5
4035 *
4036 * @param type $var Description. Default.
4037 * @return type Description.
4038 */
4039
4040 acf.isAjaxSuccess = function (json) {
4041 return json && json.success;
4042 };
4043
4044 /**
4045 * acf.getAjaxMessage
4046 *
4047 * description
4048 *
4049 * @date 18/1/18
4050 * @since ACF 5.6.5
4051 *
4052 * @param type $var Description. Default.
4053 * @return type Description.
4054 */
4055
4056 acf.getAjaxMessage = function (json) {
4057 return acf.isget(json, 'data', 'message');
4058 };
4059
4060 /**
4061 * acf.getAjaxError
4062 *
4063 * description
4064 *
4065 * @date 18/1/18
4066 * @since ACF 5.6.5
4067 *
4068 * @param type $var Description. Default.
4069 * @return type Description.
4070 */
4071
4072 acf.getAjaxError = function (json) {
4073 return acf.isget(json, 'data', 'error');
4074 };
4075
4076 /**
4077 * Returns the error message from an XHR object.
4078 *
4079 * @date 17/3/20
4080 * @since ACF 5.8.9
4081 *
4082 * @param object xhr The XHR object.
4083 * @return (string)
4084 */
4085 acf.getXhrError = function (xhr) {
4086 if (xhr.responseJSON) {
4087 // Responses via `return new WP_Error();`
4088 if (xhr.responseJSON.message) {
4089 return xhr.responseJSON.message;
4090 }
4091
4092 // Responses via `wp_send_json_error();`.
4093 if (xhr.responseJSON.data && xhr.responseJSON.data.error) {
4094 return xhr.responseJSON.data.error;
4095 }
4096 } else if (xhr.statusText) {
4097 return xhr.statusText;
4098 }
4099 return '';
4100 };
4101
4102 /**
4103 * acf.renderSelect
4104 *
4105 * Renders the inner html for a select field.
4106 *
4107 * @date 19/2/18
4108 * @since ACF 5.6.9
4109 *
4110 * @param jQuery $select The select element.
4111 * @param array choices An array of choices.
4112 * @return void
4113 */
4114
4115 acf.renderSelect = function ($select, choices) {
4116 // vars
4117 var value = $select.val();
4118 var values = [];
4119
4120 // callback
4121 var crawl = function (items) {
4122 // vars
4123 var itemsHtml = '';
4124
4125 // loop
4126 items.map(function (item) {
4127 // vars
4128 var text = item.text || item.label || '';
4129 var id = item.id || item.value || '';
4130
4131 // append
4132 values.push(id);
4133
4134 // optgroup
4135 if (item.children) {
4136 itemsHtml += '<optgroup label="' + acf.escAttr(text) + '">' + crawl(item.children) + '</optgroup>';
4137
4138 // option
4139 } else {
4140 itemsHtml += '<option value="' + acf.escAttr(id) + '"' + (item.disabled ? ' disabled="disabled"' : '') + '>' + acf.strEscape(text) + '</option>';
4141 }
4142 });
4143 // return
4144 return itemsHtml;
4145 };
4146
4147 // update HTML
4148 $select.html(crawl(choices));
4149
4150 // update value
4151 if (values.indexOf(value) > -1) {
4152 $select.val(value);
4153 }
4154
4155 // return selected value
4156 return $select.val();
4157 };
4158
4159 /**
4160 * acf.lock
4161 *
4162 * Creates a "lock" on an element for a given type and key
4163 *
4164 * @date 22/2/18
4165 * @since ACF 5.6.9
4166 *
4167 * @param jQuery $el The element to lock.
4168 * @param string type The type of lock such as "condition" or "visibility".
4169 * @param string key The key that will be used to unlock.
4170 * @return void
4171 */
4172
4173 var getLocks = function ($el, type) {
4174 return $el.data('acf-lock-' + type) || [];
4175 };
4176 var setLocks = function ($el, type, locks) {
4177 $el.data('acf-lock-' + type, locks);
4178 };
4179 acf.lock = function ($el, type, key) {
4180 var locks = getLocks($el, type);
4181 var i = locks.indexOf(key);
4182 if (i < 0) {
4183 locks.push(key);
4184 setLocks($el, type, locks);
4185 }
4186 };
4187
4188 /**
4189 * acf.unlock
4190 *
4191 * Unlocks a "lock" on an element for a given type and key
4192 *
4193 * @date 22/2/18
4194 * @since ACF 5.6.9
4195 *
4196 * @param jQuery $el The element to lock.
4197 * @param string type The type of lock such as "condition" or "visibility".
4198 * @param string key The key that will be used to unlock.
4199 * @return void
4200 */
4201
4202 acf.unlock = function ($el, type, key) {
4203 var locks = getLocks($el, type);
4204 var i = locks.indexOf(key);
4205 if (i > -1) {
4206 locks.splice(i, 1);
4207 setLocks($el, type, locks);
4208 }
4209
4210 // return true if is unlocked (no locks)
4211 return locks.length === 0;
4212 };
4213
4214 /**
4215 * acf.isLocked
4216 *
4217 * Returns true if a lock exists for a given type
4218 *
4219 * @date 22/2/18
4220 * @since ACF 5.6.9
4221 *
4222 * @param jQuery $el The element to lock.
4223 * @param string type The type of lock such as "condition" or "visibility".
4224 * @return void
4225 */
4226
4227 acf.isLocked = function ($el, type) {
4228 return getLocks($el, type).length > 0;
4229 };
4230
4231 /**
4232 * acf.isGutenberg
4233 *
4234 * Returns true if the Gutenberg editor is being used.
4235 *
4236 * @since ACF 5.8.0
4237 *
4238 * @return bool
4239 */
4240 acf.isGutenberg = function () {
4241 return !!(window.wp && wp.data && wp.data.select && wp.data.select('core/editor'));
4242 };
4243
4244 /**
4245 * acf.isGutenbergPostEditor
4246 *
4247 * Returns true if the Gutenberg post editor is being used.
4248 *
4249 * @since ACF 6.2.2
4250 *
4251 * @return bool
4252 */
4253 acf.isGutenbergPostEditor = function () {
4254 return !!(window.wp && wp.data && wp.data.select && wp.data.select('core/edit-post'));
4255 };
4256
4257 /**
4258 * acf.objectToArray
4259 *
4260 * Returns an array of items from the given object.
4261 *
4262 * @date 20/11/18
4263 * @since ACF 5.8.0
4264 *
4265 * @param object obj The object of items.
4266 * @return array
4267 */
4268 acf.objectToArray = function (obj) {
4269 return Object.keys(obj).map(function (key) {
4270 return obj[key];
4271 });
4272 };
4273
4274 /**
4275 * acf.debounce
4276 *
4277 * Returns a debounced version of the passed function which will postpone its execution until after `wait` milliseconds have elapsed since the last time it was invoked.
4278 *
4279 * @date 28/8/19
4280 * @since ACF 5.8.1
4281 *
4282 * @param function callback The callback function.
4283 * @return int wait The number of milliseconds to wait.
4284 */
4285 acf.debounce = function (callback, wait) {
4286 var timeout;
4287 return function () {
4288 var context = this;
4289 var args = arguments;
4290 var later = function () {
4291 callback.apply(context, args);
4292 };
4293 clearTimeout(timeout);
4294 timeout = setTimeout(later, wait);
4295 };
4296 };
4297
4298 /**
4299 * acf.throttle
4300 *
4301 * Returns a throttled version of the passed function which will allow only one execution per `limit` time period.
4302 *
4303 * @date 28/8/19
4304 * @since ACF 5.8.1
4305 *
4306 * @param function callback The callback function.
4307 * @return int wait The number of milliseconds to wait.
4308 */
4309 acf.throttle = function (callback, limit) {
4310 var busy = false;
4311 return function () {
4312 if (busy) return;
4313 busy = true;
4314 setTimeout(function () {
4315 busy = false;
4316 }, limit);
4317 callback.apply(this, arguments);
4318 };
4319 };
4320
4321 /**
4322 * acf.isInView
4323 *
4324 * Returns true if the given element is in view.
4325 *
4326 * @date 29/8/19
4327 * @since ACF 5.8.1
4328 *
4329 * @param elem el The dom element to inspect.
4330 * @return bool
4331 */
4332 acf.isInView = function (el) {
4333 if (el instanceof jQuery) {
4334 el = el[0];
4335 }
4336 var rect = el.getBoundingClientRect();
4337 return rect.top !== rect.bottom && rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
4338 };
4339
4340 /**
4341 * acf.onceInView
4342 *
4343 * Watches for a dom element to become visible in the browser and then executes the passed callback.
4344 *
4345 * @date 28/8/19
4346 * @since ACF 5.8.1
4347 *
4348 * @param dom el The dom element to inspect.
4349 * @param function callback The callback function.
4350 */
4351 acf.onceInView = function () {
4352 // Define list.
4353 var items = [];
4354 var id = 0;
4355
4356 // Define check function.
4357 var check = function () {
4358 items.forEach(function (item) {
4359 if (acf.isInView(item.el)) {
4360 item.callback.apply(this);
4361 pop(item.id);
4362 }
4363 });
4364 };
4365
4366 // And create a debounced version.
4367 var debounced = acf.debounce(check, 300);
4368
4369 // Define add function.
4370 var push = function (el, callback) {
4371 // Add event listener.
4372 if (!items.length) {
4373 $(window).on('scroll resize', debounced).on('acfrefresh orientationchange', check);
4374 }
4375
4376 // Append to list.
4377 items.push({
4378 id: id++,
4379 el: el,
4380 callback: callback
4381 });
4382 };
4383
4384 // Define remove function.
4385 var pop = function (id) {
4386 // Remove from list.
4387 items = items.filter(function (item) {
4388 return item.id !== id;
4389 });
4390
4391 // Clean up listener.
4392 if (!items.length) {
4393 $(window).off('scroll resize', debounced).off('acfrefresh orientationchange', check);
4394 }
4395 };
4396
4397 // Define returned function.
4398 return function (el, callback) {
4399 // Allow jQuery object.
4400 if (el instanceof jQuery) el = el[0];
4401
4402 // Execute callback if already in view or add to watch list.
4403 if (acf.isInView(el)) {
4404 callback.apply(this);
4405 } else {
4406 push(el, callback);
4407 }
4408 };
4409 }();
4410
4411 /**
4412 * acf.once
4413 *
4414 * Creates a function that is restricted to invoking `func` once.
4415 *
4416 * @date 2/9/19
4417 * @since ACF 5.8.1
4418 *
4419 * @param function func The function to restrict.
4420 * @return function
4421 */
4422 acf.once = function (func) {
4423 var i = 0;
4424 return function () {
4425 if (i++ > 0) {
4426 return func = undefined;
4427 }
4428 return func.apply(this, arguments);
4429 };
4430 };
4431
4432 /**
4433 * Focuses attention to a specific element.
4434 *
4435 * @date 05/05/2020
4436 * @since ACF 5.9.0
4437 *
4438 * @param jQuery $el The jQuery element to focus.
4439 * @return void
4440 */
4441 acf.focusAttention = function ($el) {
4442 var wait = 1000;
4443
4444 // Apply class to focus attention.
4445 $el.addClass('acf-attention -focused');
4446
4447 // Scroll to element if needed.
4448 var scrollTime = 500;
4449 if (!acf.isInView($el)) {
4450 $('body, html').animate({
4451 scrollTop: $el.offset().top - $(window).height() / 2
4452 }, scrollTime);
4453 wait += scrollTime;
4454 }
4455
4456 // Remove class after $wait amount of time.
4457 var fadeTime = 250;
4458 setTimeout(function () {
4459 $el.removeClass('-focused');
4460 setTimeout(function () {
4461 $el.removeClass('acf-attention');
4462 }, fadeTime);
4463 }, wait);
4464 };
4465
4466 /**
4467 * Description
4468 *
4469 * @date 05/05/2020
4470 * @since ACF 5.9.0
4471 *
4472 * @param type Var Description.
4473 * @return type Description.
4474 */
4475 acf.onFocus = function ($el, callback) {
4476 // Only run once per element.
4477 // if( $el.data('acf.onFocus') ) {
4478 // return false;
4479 // }
4480
4481 // Vars.
4482 var ignoreBlur = false;
4483 var focus = false;
4484
4485 // Functions.
4486 var onFocus = function () {
4487 ignoreBlur = true;
4488 setTimeout(function () {
4489 ignoreBlur = false;
4490 }, 1);
4491 setFocus(true);
4492 };
4493 var onBlur = function () {
4494 if (!ignoreBlur) {
4495 setFocus(false);
4496 }
4497 };
4498 var addEvents = function () {
4499 $(document).on('click', onBlur);
4500 //$el.on('acfBlur', onBlur);
4501 $el.on('blur', 'input, select, textarea', onBlur);
4502 };
4503 var removeEvents = function () {
4504 $(document).off('click', onBlur);
4505 //$el.off('acfBlur', onBlur);
4506 $el.off('blur', 'input, select, textarea', onBlur);
4507 };
4508 var setFocus = function (value) {
4509 if (focus === value) {
4510 return;
4511 }
4512 if (value) {
4513 addEvents();
4514 } else {
4515 removeEvents();
4516 }
4517 focus = value;
4518 callback(value);
4519 };
4520
4521 // Add events and set data.
4522 $el.on('click', onFocus);
4523 //$el.on('acfFocus', onFocus);
4524 $el.on('focus', 'input, select, textarea', onFocus);
4525 //$el.data('acf.onFocus', true);
4526 };
4527
4528 /**
4529 * Disable form submit buttons
4530 *
4531 * @since ACF 6.2.3
4532 *
4533 * @param event e
4534 * @returns void
4535 */
4536 acf.disableForm = function (e) {
4537 // Disable submit button.
4538 if (e.submitter) e.submitter.classList.add('disabled');
4539 };
4540
4541 /*
4542 * exists
4543 *
4544 * This function will return true if a jQuery selection exists
4545 *
4546 * @type function
4547 * @date 8/09/2014
4548 * @since ACF 5.0.0
4549 *
4550 * @param n/a
4551 * @return (boolean)
4552 */
4553
4554 $.fn.exists = function () {
4555 return $(this).length > 0;
4556 };
4557
4558 /*
4559 * outerHTML
4560 *
4561 * This function will return a string containing the HTML of the selected element
4562 *
4563 * @type function
4564 * @date 19/11/2013
4565 * @since ACF 5.0.0
4566 *
4567 * @param $.fn
4568 * @return (string)
4569 */
4570
4571 $.fn.outerHTML = function () {
4572 return $(this).get(0).outerHTML;
4573 };
4574
4575 /*
4576 * indexOf
4577 *
4578 * This function will provide compatibility for ie8
4579 *
4580 * @type function
4581 * @date 5/3/17
4582 * @since ACF 5.5.10
4583 *
4584 * @param n/a
4585 * @return n/a
4586 */
4587
4588 if (!Array.prototype.indexOf) {
4589 Array.prototype.indexOf = function (val) {
4590 return $.inArray(val, this);
4591 };
4592 }
4593
4594 /**
4595 * Returns true if value is a number or a numeric string.
4596 *
4597 * @date 30/11/20
4598 * @since ACF 5.9.4
4599 * @link https://stackoverflow.com/questions/9716468/pure-javascript-a-function-like-jquerys-isnumeric/9716488#9716488
4600 *
4601 * @param mixed n The variable being evaluated.
4602 * @return bool.
4603 */
4604 acf.isNumeric = function (n) {
4605 return !isNaN(parseFloat(n)) && isFinite(n);
4606 };
4607
4608 /**
4609 * Triggers a "refresh" action used by various Components to redraw the DOM.
4610 *
4611 * @date 26/05/2020
4612 * @since ACF 5.9.0
4613 *
4614 * @param void
4615 * @return void
4616 */
4617 acf.refresh = acf.debounce(function () {
4618 $(window).trigger('acfrefresh');
4619 acf.doAction('refresh');
4620 }, 0);
4621
4622 /**
4623 * Log something to console if we're in debug mode.
4624 *
4625 * @since ACF 6.3
4626 */
4627 acf.debug = function () {
4628 if (acf.get('debug')) console.log.apply(null, arguments);
4629 };
4630
4631 // Set up actions from events
4632 $(document).ready(function () {
4633 acf.doAction('ready');
4634 });
4635 $(window).on('load', function () {
4636 // Use timeout to ensure action runs after Gutenberg has modified DOM elements during "DOMContentLoaded".
4637 setTimeout(function () {
4638 acf.doAction('load');
4639 });
4640 });
4641 $(window).on('beforeunload', function () {
4642 acf.doAction('unload');
4643 });
4644 $(window).on('resize', function () {
4645 acf.doAction('resize');
4646 });
4647 $(document).on('sortstart', function (event, ui) {
4648 acf.doAction('sortstart', ui.item, ui.placeholder);
4649 });
4650 $(document).on('sortstop', function (event, ui) {
4651 acf.doAction('sortstop', ui.item, ui.placeholder);
4652 });
4653 })(jQuery);
4654
4655 /***/ }),
4656
4657 /***/ "./node_modules/dompurify/dist/purify.cjs.js":
4658 /*!***************************************************!*\
4659 !*** ./node_modules/dompurify/dist/purify.cjs.js ***!
4660 \***************************************************/
4661 /***/ ((module) => {
4662
4663 "use strict";
4664 /*! @license DOMPurify 3.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.0/LICENSE */
4665
4666
4667
4668 const {
4669 entries,
4670 setPrototypeOf,
4671 isFrozen,
4672 getPrototypeOf,
4673 getOwnPropertyDescriptor
4674 } = Object;
4675 let {
4676 freeze,
4677 seal,
4678 create
4679 } = Object; // eslint-disable-line import/no-mutable-exports
4680 let {
4681 apply,
4682 construct
4683 } = typeof Reflect !== 'undefined' && Reflect;
4684 if (!freeze) {
4685 freeze = function freeze(x) {
4686 return x;
4687 };
4688 }
4689 if (!seal) {
4690 seal = function seal(x) {
4691 return x;
4692 };
4693 }
4694 if (!apply) {
4695 apply = function apply(func, thisArg) {
4696 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
4697 args[_key - 2] = arguments[_key];
4698 }
4699 return func.apply(thisArg, args);
4700 };
4701 }
4702 if (!construct) {
4703 construct = function construct(Func) {
4704 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
4705 args[_key2 - 1] = arguments[_key2];
4706 }
4707 return new Func(...args);
4708 };
4709 }
4710 const arrayForEach = unapply(Array.prototype.forEach);
4711 const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
4712 const arrayPop = unapply(Array.prototype.pop);
4713 const arrayPush = unapply(Array.prototype.push);
4714 const arraySplice = unapply(Array.prototype.splice);
4715 const stringToLowerCase = unapply(String.prototype.toLowerCase);
4716 const stringToString = unapply(String.prototype.toString);
4717 const stringMatch = unapply(String.prototype.match);
4718 const stringReplace = unapply(String.prototype.replace);
4719 const stringIndexOf = unapply(String.prototype.indexOf);
4720 const stringTrim = unapply(String.prototype.trim);
4721 const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
4722 const regExpTest = unapply(RegExp.prototype.test);
4723 const typeErrorCreate = unconstruct(TypeError);
4724 /**
4725 * Creates a new function that calls the given function with a specified thisArg and arguments.
4726 *
4727 * @param func - The function to be wrapped and called.
4728 * @returns A new function that calls the given function with a specified thisArg and arguments.
4729 */
4730 function unapply(func) {
4731 return function (thisArg) {
4732 if (thisArg instanceof RegExp) {
4733 thisArg.lastIndex = 0;
4734 }
4735 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
4736 args[_key3 - 1] = arguments[_key3];
4737 }
4738 return apply(func, thisArg, args);
4739 };
4740 }
4741 /**
4742 * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
4743 *
4744 * @param func - The constructor function to be wrapped and called.
4745 * @returns A new function that constructs an instance of the given constructor function with the provided arguments.
4746 */
4747 function unconstruct(Func) {
4748 return function () {
4749 for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
4750 args[_key4] = arguments[_key4];
4751 }
4752 return construct(Func, args);
4753 };
4754 }
4755 /**
4756 * Add properties to a lookup table
4757 *
4758 * @param set - The set to which elements will be added.
4759 * @param array - The array containing elements to be added to the set.
4760 * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
4761 * @returns The modified set with added elements.
4762 */
4763 function addToSet(set, array) {
4764 let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
4765 if (setPrototypeOf) {
4766 // Make 'in' and truthy checks like Boolean(set.constructor)
4767 // independent of any properties defined on Object.prototype.
4768 // Prevent prototype setters from intercepting set as a this value.
4769 setPrototypeOf(set, null);
4770 }
4771 let l = array.length;
4772 while (l--) {
4773 let element = array[l];
4774 if (typeof element === 'string') {
4775 const lcElement = transformCaseFunc(element);
4776 if (lcElement !== element) {
4777 // Config presets (e.g. tags.js, attrs.js) are immutable.
4778 if (!isFrozen(array)) {
4779 array[l] = lcElement;
4780 }
4781 element = lcElement;
4782 }
4783 }
4784 set[element] = true;
4785 }
4786 return set;
4787 }
4788 /**
4789 * Clean up an array to harden against CSPP
4790 *
4791 * @param array - The array to be cleaned.
4792 * @returns The cleaned version of the array
4793 */
4794 function cleanArray(array) {
4795 for (let index = 0; index < array.length; index++) {
4796 const isPropertyExist = objectHasOwnProperty(array, index);
4797 if (!isPropertyExist) {
4798 array[index] = null;
4799 }
4800 }
4801 return array;
4802 }
4803 /**
4804 * Shallow clone an object
4805 *
4806 * @param object - The object to be cloned.
4807 * @returns A new object that copies the original.
4808 */
4809 function clone(object) {
4810 const newObject = create(null);
4811 for (const [property, value] of entries(object)) {
4812 const isPropertyExist = objectHasOwnProperty(object, property);
4813 if (isPropertyExist) {
4814 if (Array.isArray(value)) {
4815 newObject[property] = cleanArray(value);
4816 } else if (value && typeof value === 'object' && value.constructor === Object) {
4817 newObject[property] = clone(value);
4818 } else {
4819 newObject[property] = value;
4820 }
4821 }
4822 }
4823 return newObject;
4824 }
4825 /**
4826 * This method automatically checks if the prop is function or getter and behaves accordingly.
4827 *
4828 * @param object - The object to look up the getter function in its prototype chain.
4829 * @param prop - The property name for which to find the getter function.
4830 * @returns The getter function found in the prototype chain or a fallback function.
4831 */
4832 function lookupGetter(object, prop) {
4833 while (object !== null) {
4834 const desc = getOwnPropertyDescriptor(object, prop);
4835 if (desc) {
4836 if (desc.get) {
4837 return unapply(desc.get);
4838 }
4839 if (typeof desc.value === 'function') {
4840 return unapply(desc.value);
4841 }
4842 }
4843 object = getPrototypeOf(object);
4844 }
4845 function fallbackValue() {
4846 return null;
4847 }
4848 return fallbackValue;
4849 }
4850
4851 const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
4852 const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
4853 const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
4854 // List of SVG elements that are disallowed by default.
4855 // We still need to know them so that we can do namespace
4856 // checks properly in case one wants to add them to
4857 // allow-list.
4858 const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
4859 const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
4860 // Similarly to SVG, we want to know all MathML elements,
4861 // even those that we disallow by default.
4862 const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
4863 const text = freeze(['#text']);
4864
4865 const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
4866 const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
4867 const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
4868 const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
4869
4870 // eslint-disable-next-line unicorn/better-regex
4871 const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
4872 const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
4873 const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
4874 const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
4875 const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
4876 const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
4877 );
4878 const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
4879 const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
4880 );
4881 const DOCTYPE_NAME = seal(/^html$/i);
4882 const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
4883
4884 var EXPRESSIONS = /*#__PURE__*/Object.freeze({
4885 __proto__: null,
4886 ARIA_ATTR: ARIA_ATTR,
4887 ATTR_WHITESPACE: ATTR_WHITESPACE,
4888 CUSTOM_ELEMENT: CUSTOM_ELEMENT,
4889 DATA_ATTR: DATA_ATTR,
4890 DOCTYPE_NAME: DOCTYPE_NAME,
4891 ERB_EXPR: ERB_EXPR,
4892 IS_ALLOWED_URI: IS_ALLOWED_URI,
4893 IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
4894 MUSTACHE_EXPR: MUSTACHE_EXPR,
4895 TMPLIT_EXPR: TMPLIT_EXPR
4896 });
4897
4898 /* eslint-disable @typescript-eslint/indent */
4899 // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
4900 const NODE_TYPE = {
4901 element: 1,
4902 attribute: 2,
4903 text: 3,
4904 cdataSection: 4,
4905 entityReference: 5,
4906 // Deprecated
4907 entityNode: 6,
4908 // Deprecated
4909 progressingInstruction: 7,
4910 comment: 8,
4911 document: 9,
4912 documentType: 10,
4913 documentFragment: 11,
4914 notation: 12 // Deprecated
4915 };
4916 const getGlobal = function getGlobal() {
4917 return typeof window === 'undefined' ? null : window;
4918 };
4919 /**
4920 * Creates a no-op policy for internal use only.
4921 * Don't export this function outside this module!
4922 * @param trustedTypes The policy factory.
4923 * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
4924 * @return The policy created (or null, if Trusted Types
4925 * are not supported or creating the policy failed).
4926 */
4927 const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
4928 if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
4929 return null;
4930 }
4931 // Allow the callers to control the unique policy name
4932 // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
4933 // Policy creation with duplicate names throws in Trusted Types.
4934 let suffix = null;
4935 const ATTR_NAME = 'data-tt-policy-suffix';
4936 if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
4937 suffix = purifyHostElement.getAttribute(ATTR_NAME);
4938 }
4939 const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
4940 try {
4941 return trustedTypes.createPolicy(policyName, {
4942 createHTML(html) {
4943 return html;
4944 },
4945 createScriptURL(scriptUrl) {
4946 return scriptUrl;
4947 }
4948 });
4949 } catch (_) {
4950 // Policy creation failed (most likely another DOMPurify script has
4951 // already run). Skip creating the policy, as this will only cause errors
4952 // if TT are enforced.
4953 console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
4954 return null;
4955 }
4956 };
4957 const _createHooksMap = function _createHooksMap() {
4958 return {
4959 afterSanitizeAttributes: [],
4960 afterSanitizeElements: [],
4961 afterSanitizeShadowDOM: [],
4962 beforeSanitizeAttributes: [],
4963 beforeSanitizeElements: [],
4964 beforeSanitizeShadowDOM: [],
4965 uponSanitizeAttribute: [],
4966 uponSanitizeElement: [],
4967 uponSanitizeShadowNode: []
4968 };
4969 };
4970 function createDOMPurify() {
4971 let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
4972 const DOMPurify = root => createDOMPurify(root);
4973 DOMPurify.version = '3.3.0';
4974 DOMPurify.removed = [];
4975 if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
4976 // Not running in a browser, provide a factory function
4977 // so that you can pass your own Window
4978 DOMPurify.isSupported = false;
4979 return DOMPurify;
4980 }
4981 let {
4982 document
4983 } = window;
4984 const originalDocument = document;
4985 const currentScript = originalDocument.currentScript;
4986 const {
4987 DocumentFragment,
4988 HTMLTemplateElement,
4989 Node,
4990 Element,
4991 NodeFilter,
4992 NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
4993 HTMLFormElement,
4994 DOMParser,
4995 trustedTypes
4996 } = window;
4997 const ElementPrototype = Element.prototype;
4998 const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
4999 const remove = lookupGetter(ElementPrototype, 'remove');
5000 const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
5001 const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
5002 const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
5003 // As per issue #47, the web-components registry is inherited by a
5004 // new document created via createHTMLDocument. As per the spec
5005 // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
5006 // a new empty registry is used when creating a template contents owner
5007 // document, so we use that as our parent document to ensure nothing
5008 // is inherited.
5009 if (typeof HTMLTemplateElement === 'function') {
5010 const template = document.createElement('template');
5011 if (template.content && template.content.ownerDocument) {
5012 document = template.content.ownerDocument;
5013 }
5014 }
5015 let trustedTypesPolicy;
5016 let emptyHTML = '';
5017 const {
5018 implementation,
5019 createNodeIterator,
5020 createDocumentFragment,
5021 getElementsByTagName
5022 } = document;
5023 const {
5024 importNode
5025 } = originalDocument;
5026 let hooks = _createHooksMap();
5027 /**
5028 * Expose whether this browser supports running the full DOMPurify.
5029 */
5030 DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
5031 const {
5032 MUSTACHE_EXPR,
5033 ERB_EXPR,
5034 TMPLIT_EXPR,
5035 DATA_ATTR,
5036 ARIA_ATTR,
5037 IS_SCRIPT_OR_DATA,
5038 ATTR_WHITESPACE,
5039 CUSTOM_ELEMENT
5040 } = EXPRESSIONS;
5041 let {
5042 IS_ALLOWED_URI: IS_ALLOWED_URI$1
5043 } = EXPRESSIONS;
5044 /**
5045 * We consider the elements and attributes below to be safe. Ideally
5046 * don't add any new ones but feel free to remove unwanted ones.
5047 */
5048 /* allowed element names */
5049 let ALLOWED_TAGS = null;
5050 const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
5051 /* Allowed attribute names */
5052 let ALLOWED_ATTR = null;
5053 const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
5054 /*
5055 * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
5056 * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
5057 * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
5058 * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
5059 */
5060 let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
5061 tagNameCheck: {
5062 writable: true,
5063 configurable: false,
5064 enumerable: true,
5065 value: null
5066 },
5067 attributeNameCheck: {
5068 writable: true,
5069 configurable: false,
5070 enumerable: true,
5071 value: null
5072 },
5073 allowCustomizedBuiltInElements: {
5074 writable: true,
5075 configurable: false,
5076 enumerable: true,
5077 value: false
5078 }
5079 }));
5080 /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
5081 let FORBID_TAGS = null;
5082 /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
5083 let FORBID_ATTR = null;
5084 /* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */
5085 const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
5086 tagCheck: {
5087 writable: true,
5088 configurable: false,
5089 enumerable: true,
5090 value: null
5091 },
5092 attributeCheck: {
5093 writable: true,
5094 configurable: false,
5095 enumerable: true,
5096 value: null
5097 }
5098 }));
5099 /* Decide if ARIA attributes are okay */
5100 let ALLOW_ARIA_ATTR = true;
5101 /* Decide if custom data attributes are okay */
5102 let ALLOW_DATA_ATTR = true;
5103 /* Decide if unknown protocols are okay */
5104 let ALLOW_UNKNOWN_PROTOCOLS = false;
5105 /* Decide if self-closing tags in attributes are allowed.
5106 * Usually removed due to a mXSS issue in jQuery 3.0 */
5107 let ALLOW_SELF_CLOSE_IN_ATTR = true;
5108 /* Output should be safe for common template engines.
5109 * This means, DOMPurify removes data attributes, mustaches and ERB
5110 */
5111 let SAFE_FOR_TEMPLATES = false;
5112 /* Output should be safe even for XML used within HTML and alike.
5113 * This means, DOMPurify removes comments when containing risky content.
5114 */
5115 let SAFE_FOR_XML = true;
5116 /* Decide if document with <html>... should be returned */
5117 let WHOLE_DOCUMENT = false;
5118 /* Track whether config is already set on this instance of DOMPurify. */
5119 let SET_CONFIG = false;
5120 /* Decide if all elements (e.g. style, script) must be children of
5121 * document.body. By default, browsers might move them to document.head */
5122 let FORCE_BODY = false;
5123 /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
5124 * string (or a TrustedHTML object if Trusted Types are supported).
5125 * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
5126 */
5127 let RETURN_DOM = false;
5128 /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
5129 * string (or a TrustedHTML object if Trusted Types are supported) */
5130 let RETURN_DOM_FRAGMENT = false;
5131 /* Try to return a Trusted Type object instead of a string, return a string in
5132 * case Trusted Types are not supported */
5133 let RETURN_TRUSTED_TYPE = false;
5134 /* Output should be free from DOM clobbering attacks?
5135 * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
5136 */
5137 let SANITIZE_DOM = true;
5138 /* Achieve full DOM Clobbering protection by isolating the namespace of named
5139 * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
5140 *
5141 * HTML/DOM spec rules that enable DOM Clobbering:
5142 * - Named Access on Window (§7.3.3)
5143 * - DOM Tree Accessors (§3.1.5)
5144 * - Form Element Parent-Child Relations (§4.10.3)
5145 * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
5146 * - HTMLCollection (§4.2.10.2)
5147 *
5148 * Namespace isolation is implemented by prefixing `id` and `name` attributes
5149 * with a constant string, i.e., `user-content-`
5150 */
5151 let SANITIZE_NAMED_PROPS = false;
5152 const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
5153 /* Keep element content when removing element? */
5154 let KEEP_CONTENT = true;
5155 /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
5156 * of importing it into a new Document and returning a sanitized copy */
5157 let IN_PLACE = false;
5158 /* Allow usage of profiles like html, svg and mathMl */
5159 let USE_PROFILES = {};
5160 /* Tags to ignore content of when KEEP_CONTENT is true */
5161 let FORBID_CONTENTS = null;
5162 const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
5163 /* Tags that are safe for data: URIs */
5164 let DATA_URI_TAGS = null;
5165 const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
5166 /* Attributes safe for values like "javascript:" */
5167 let URI_SAFE_ATTRIBUTES = null;
5168 const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
5169 const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
5170 const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
5171 const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
5172 /* Document namespace */
5173 let NAMESPACE = HTML_NAMESPACE;
5174 let IS_EMPTY_INPUT = false;
5175 /* Allowed XHTML+XML namespaces */
5176 let ALLOWED_NAMESPACES = null;
5177 const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
5178 let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
5179 let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
5180 // Certain elements are allowed in both SVG and HTML
5181 // namespace. We need to specify them explicitly
5182 // so that they don't get erroneously deleted from
5183 // HTML namespace.
5184 const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
5185 /* Parsing of strict XHTML documents */
5186 let PARSER_MEDIA_TYPE = null;
5187 const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
5188 const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
5189 let transformCaseFunc = null;
5190 /* Keep a reference to config to pass to hooks */
5191 let CONFIG = null;
5192 /* Ideally, do not touch anything below this line */
5193 /* ______________________________________________ */
5194 const formElement = document.createElement('form');
5195 const isRegexOrFunction = function isRegexOrFunction(testValue) {
5196 return testValue instanceof RegExp || testValue instanceof Function;
5197 };
5198 /**
5199 * _parseConfig
5200 *
5201 * @param cfg optional config literal
5202 */
5203 // eslint-disable-next-line complexity
5204 const _parseConfig = function _parseConfig() {
5205 let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
5206 if (CONFIG && CONFIG === cfg) {
5207 return;
5208 }
5209 /* Shield configuration object from tampering */
5210 if (!cfg || typeof cfg !== 'object') {
5211 cfg = {};
5212 }
5213 /* Shield configuration object from prototype pollution */
5214 cfg = clone(cfg);
5215 PARSER_MEDIA_TYPE =
5216 // eslint-disable-next-line unicorn/prefer-includes
5217 SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
5218 // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
5219 transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
5220 /* Set configuration parameters */
5221 ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
5222 ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
5223 ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
5224 URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
5225 DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
5226 FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
5227 FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
5228 FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
5229 USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
5230 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
5231 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
5232 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
5233 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
5234 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
5235 SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
5236 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
5237 RETURN_DOM = cfg.RETURN_DOM || false; // Default false
5238 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
5239 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
5240 FORCE_BODY = cfg.FORCE_BODY || false; // Default false
5241 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
5242 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
5243 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
5244 IN_PLACE = cfg.IN_PLACE || false; // Default false
5245 IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
5246 NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
5247 MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
5248 HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
5249 CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
5250 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
5251 CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
5252 }
5253 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
5254 CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
5255 }
5256 if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
5257 CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
5258 }
5259 if (SAFE_FOR_TEMPLATES) {
5260 ALLOW_DATA_ATTR = false;
5261 }
5262 if (RETURN_DOM_FRAGMENT) {
5263 RETURN_DOM = true;
5264 }
5265 /* Parse profile info */
5266 if (USE_PROFILES) {
5267 ALLOWED_TAGS = addToSet({}, text);
5268 ALLOWED_ATTR = [];
5269 if (USE_PROFILES.html === true) {
5270 addToSet(ALLOWED_TAGS, html$1);
5271 addToSet(ALLOWED_ATTR, html);
5272 }
5273 if (USE_PROFILES.svg === true) {
5274 addToSet(ALLOWED_TAGS, svg$1);
5275 addToSet(ALLOWED_ATTR, svg);
5276 addToSet(ALLOWED_ATTR, xml);
5277 }
5278 if (USE_PROFILES.svgFilters === true) {
5279 addToSet(ALLOWED_TAGS, svgFilters);
5280 addToSet(ALLOWED_ATTR, svg);
5281 addToSet(ALLOWED_ATTR, xml);
5282 }
5283 if (USE_PROFILES.mathMl === true) {
5284 addToSet(ALLOWED_TAGS, mathMl$1);
5285 addToSet(ALLOWED_ATTR, mathMl);
5286 addToSet(ALLOWED_ATTR, xml);
5287 }
5288 }
5289 /* Merge configuration parameters */
5290 if (cfg.ADD_TAGS) {
5291 if (typeof cfg.ADD_TAGS === 'function') {
5292 EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
5293 } else {
5294 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
5295 ALLOWED_TAGS = clone(ALLOWED_TAGS);
5296 }
5297 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
5298 }
5299 }
5300 if (cfg.ADD_ATTR) {
5301 if (typeof cfg.ADD_ATTR === 'function') {
5302 EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
5303 } else {
5304 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
5305 ALLOWED_ATTR = clone(ALLOWED_ATTR);
5306 }
5307 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
5308 }
5309 }
5310 if (cfg.ADD_URI_SAFE_ATTR) {
5311 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
5312 }
5313 if (cfg.FORBID_CONTENTS) {
5314 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
5315 FORBID_CONTENTS = clone(FORBID_CONTENTS);
5316 }
5317 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
5318 }
5319 /* Add #text in case KEEP_CONTENT is set to true */
5320 if (KEEP_CONTENT) {
5321 ALLOWED_TAGS['#text'] = true;
5322 }
5323 /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
5324 if (WHOLE_DOCUMENT) {
5325 addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
5326 }
5327 /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
5328 if (ALLOWED_TAGS.table) {
5329 addToSet(ALLOWED_TAGS, ['tbody']);
5330 delete FORBID_TAGS.tbody;
5331 }
5332 if (cfg.TRUSTED_TYPES_POLICY) {
5333 if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
5334 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
5335 }
5336 if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
5337 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
5338 }
5339 // Overwrite existing TrustedTypes policy.
5340 trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
5341 // Sign local variables required by `sanitize`.
5342 emptyHTML = trustedTypesPolicy.createHTML('');
5343 } else {
5344 // Uninitialized policy, attempt to initialize the internal dompurify policy.
5345 if (trustedTypesPolicy === undefined) {
5346 trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
5347 }
5348 // If creating the internal policy succeeded sign internal variables.
5349 if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
5350 emptyHTML = trustedTypesPolicy.createHTML('');
5351 }
5352 }
5353 // Prevent further manipulation of configuration.
5354 // Not available in IE8, Safari 5, etc.
5355 if (freeze) {
5356 freeze(cfg);
5357 }
5358 CONFIG = cfg;
5359 };
5360 /* Keep track of all possible SVG and MathML tags
5361 * so that we can perform the namespace checks
5362 * correctly. */
5363 const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
5364 const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
5365 /**
5366 * @param element a DOM element whose namespace is being checked
5367 * @returns Return false if the element has a
5368 * namespace that a spec-compliant parser would never
5369 * return. Return true otherwise.
5370 */
5371 const _checkValidNamespace = function _checkValidNamespace(element) {
5372 let parent = getParentNode(element);
5373 // In JSDOM, if we're inside shadow DOM, then parentNode
5374 // can be null. We just simulate parent in this case.
5375 if (!parent || !parent.tagName) {
5376 parent = {
5377 namespaceURI: NAMESPACE,
5378 tagName: 'template'
5379 };
5380 }
5381 const tagName = stringToLowerCase(element.tagName);
5382 const parentTagName = stringToLowerCase(parent.tagName);
5383 if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
5384 return false;
5385 }
5386 if (element.namespaceURI === SVG_NAMESPACE) {
5387 // The only way to switch from HTML namespace to SVG
5388 // is via <svg>. If it happens via any other tag, then
5389 // it should be killed.
5390 if (parent.namespaceURI === HTML_NAMESPACE) {
5391 return tagName === 'svg';
5392 }
5393 // The only way to switch from MathML to SVG is via`
5394 // svg if parent is either <annotation-xml> or MathML
5395 // text integration points.
5396 if (parent.namespaceURI === MATHML_NAMESPACE) {
5397 return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
5398 }
5399 // We only allow elements that are defined in SVG
5400 // spec. All others are disallowed in SVG namespace.
5401 return Boolean(ALL_SVG_TAGS[tagName]);
5402 }
5403 if (element.namespaceURI === MATHML_NAMESPACE) {
5404 // The only way to switch from HTML namespace to MathML
5405 // is via <math>. If it happens via any other tag, then
5406 // it should be killed.
5407 if (parent.namespaceURI === HTML_NAMESPACE) {
5408 return tagName === 'math';
5409 }
5410 // The only way to switch from SVG to MathML is via
5411 // <math> and HTML integration points
5412 if (parent.namespaceURI === SVG_NAMESPACE) {
5413 return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
5414 }
5415 // We only allow elements that are defined in MathML
5416 // spec. All others are disallowed in MathML namespace.
5417 return Boolean(ALL_MATHML_TAGS[tagName]);
5418 }
5419 if (element.namespaceURI === HTML_NAMESPACE) {
5420 // The only way to switch from SVG to HTML is via
5421 // HTML integration points, and from MathML to HTML
5422 // is via MathML text integration points
5423 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
5424 return false;
5425 }
5426 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
5427 return false;
5428 }
5429 // We disallow tags that are specific for MathML
5430 // or SVG and should never appear in HTML namespace
5431 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
5432 }
5433 // For XHTML and XML documents that support custom namespaces
5434 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
5435 return true;
5436 }
5437 // The code should never reach this place (this means
5438 // that the element somehow got namespace that is not
5439 // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
5440 // Return false just in case.
5441 return false;
5442 };
5443 /**
5444 * _forceRemove
5445 *
5446 * @param node a DOM node
5447 */
5448 const _forceRemove = function _forceRemove(node) {
5449 arrayPush(DOMPurify.removed, {
5450 element: node
5451 });
5452 try {
5453 // eslint-disable-next-line unicorn/prefer-dom-node-remove
5454 getParentNode(node).removeChild(node);
5455 } catch (_) {
5456 remove(node);
5457 }
5458 };
5459 /**
5460 * _removeAttribute
5461 *
5462 * @param name an Attribute name
5463 * @param element a DOM node
5464 */
5465 const _removeAttribute = function _removeAttribute(name, element) {
5466 try {
5467 arrayPush(DOMPurify.removed, {
5468 attribute: element.getAttributeNode(name),
5469 from: element
5470 });
5471 } catch (_) {
5472 arrayPush(DOMPurify.removed, {
5473 attribute: null,
5474 from: element
5475 });
5476 }
5477 element.removeAttribute(name);
5478 // We void attribute values for unremovable "is" attributes
5479 if (name === 'is') {
5480 if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
5481 try {
5482 _forceRemove(element);
5483 } catch (_) {}
5484 } else {
5485 try {
5486 element.setAttribute(name, '');
5487 } catch (_) {}
5488 }
5489 }
5490 };
5491 /**
5492 * _initDocument
5493 *
5494 * @param dirty - a string of dirty markup
5495 * @return a DOM, filled with the dirty markup
5496 */
5497 const _initDocument = function _initDocument(dirty) {
5498 /* Create a HTML document */
5499 let doc = null;
5500 let leadingWhitespace = null;
5501 if (FORCE_BODY) {
5502 dirty = '<remove></remove>' + dirty;
5503 } else {
5504 /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
5505 const matches = stringMatch(dirty, /^[\r\n\t ]+/);
5506 leadingWhitespace = matches && matches[0];
5507 }
5508 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
5509 // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
5510 dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
5511 }
5512 const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
5513 /*
5514 * Use the DOMParser API by default, fallback later if needs be
5515 * DOMParser not work for svg when has multiple root element.
5516 */
5517 if (NAMESPACE === HTML_NAMESPACE) {
5518 try {
5519 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
5520 } catch (_) {}
5521 }
5522 /* Use createHTMLDocument in case DOMParser is not available */
5523 if (!doc || !doc.documentElement) {
5524 doc = implementation.createDocument(NAMESPACE, 'template', null);
5525 try {
5526 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
5527 } catch (_) {
5528 // Syntax error if dirtyPayload is invalid xml
5529 }
5530 }
5531 const body = doc.body || doc.documentElement;
5532 if (dirty && leadingWhitespace) {
5533 body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
5534 }
5535 /* Work on whole document or just its body */
5536 if (NAMESPACE === HTML_NAMESPACE) {
5537 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
5538 }
5539 return WHOLE_DOCUMENT ? doc.documentElement : body;
5540 };
5541 /**
5542 * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
5543 *
5544 * @param root The root element or node to start traversing on.
5545 * @return The created NodeIterator
5546 */
5547 const _createNodeIterator = function _createNodeIterator(root) {
5548 return createNodeIterator.call(root.ownerDocument || root, root,
5549 // eslint-disable-next-line no-bitwise
5550 NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
5551 };
5552 /**
5553 * _isClobbered
5554 *
5555 * @param element element to check for clobbering attacks
5556 * @return true if clobbered, false if safe
5557 */
5558 const _isClobbered = function _isClobbered(element) {
5559 return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
5560 };
5561 /**
5562 * Checks whether the given object is a DOM node.
5563 *
5564 * @param value object to check whether it's a DOM node
5565 * @return true is object is a DOM node
5566 */
5567 const _isNode = function _isNode(value) {
5568 return typeof Node === 'function' && value instanceof Node;
5569 };
5570 function _executeHooks(hooks, currentNode, data) {
5571 arrayForEach(hooks, hook => {
5572 hook.call(DOMPurify, currentNode, data, CONFIG);
5573 });
5574 }
5575 /**
5576 * _sanitizeElements
5577 *
5578 * @protect nodeName
5579 * @protect textContent
5580 * @protect removeChild
5581 * @param currentNode to check for permission to exist
5582 * @return true if node was killed, false if left alive
5583 */
5584 const _sanitizeElements = function _sanitizeElements(currentNode) {
5585 let content = null;
5586 /* Execute a hook if present */
5587 _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
5588 /* Check if element is clobbered or can clobber */
5589 if (_isClobbered(currentNode)) {
5590 _forceRemove(currentNode);
5591 return true;
5592 }
5593 /* Now let's check the element's type and name */
5594 const tagName = transformCaseFunc(currentNode.nodeName);
5595 /* Execute a hook if present */
5596 _executeHooks(hooks.uponSanitizeElement, currentNode, {
5597 tagName,
5598 allowedTags: ALLOWED_TAGS
5599 });
5600 /* Detect mXSS attempts abusing namespace confusion */
5601 if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
5602 _forceRemove(currentNode);
5603 return true;
5604 }
5605 /* Remove any occurrence of processing instructions */
5606 if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
5607 _forceRemove(currentNode);
5608 return true;
5609 }
5610 /* Remove any kind of possibly harmful comments */
5611 if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
5612 _forceRemove(currentNode);
5613 return true;
5614 }
5615 /* Remove element if anything forbids its presence */
5616 if (!(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName])) {
5617 /* Check if we have a custom element to handle */
5618 if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
5619 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
5620 return false;
5621 }
5622 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
5623 return false;
5624 }
5625 }
5626 /* Keep content except for bad-listed elements */
5627 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
5628 const parentNode = getParentNode(currentNode) || currentNode.parentNode;
5629 const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
5630 if (childNodes && parentNode) {
5631 const childCount = childNodes.length;
5632 for (let i = childCount - 1; i >= 0; --i) {
5633 const childClone = cloneNode(childNodes[i], true);
5634 childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
5635 parentNode.insertBefore(childClone, getNextSibling(currentNode));
5636 }
5637 }
5638 }
5639 _forceRemove(currentNode);
5640 return true;
5641 }
5642 /* Check whether element has a valid namespace */
5643 if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
5644 _forceRemove(currentNode);
5645 return true;
5646 }
5647 /* Make sure that older browsers don't get fallback-tag mXSS */
5648 if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
5649 _forceRemove(currentNode);
5650 return true;
5651 }
5652 /* Sanitize element content to be template-safe */
5653 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
5654 /* Get the element's text content */
5655 content = currentNode.textContent;
5656 arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
5657 content = stringReplace(content, expr, ' ');
5658 });
5659 if (currentNode.textContent !== content) {
5660 arrayPush(DOMPurify.removed, {
5661 element: currentNode.cloneNode()
5662 });
5663 currentNode.textContent = content;
5664 }
5665 }
5666 /* Execute a hook if present */
5667 _executeHooks(hooks.afterSanitizeElements, currentNode, null);
5668 return false;
5669 };
5670 /**
5671 * _isValidAttribute
5672 *
5673 * @param lcTag Lowercase tag name of containing element.
5674 * @param lcName Lowercase attribute name.
5675 * @param value Attribute value.
5676 * @return Returns true if `value` is valid, otherwise false.
5677 */
5678 // eslint-disable-next-line complexity
5679 const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
5680 /* Make sure attribute cannot clobber */
5681 if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
5682 return false;
5683 }
5684 /* Allow valid data-* attributes: At least one character after "-"
5685 (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
5686 XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
5687 We don't need to check the value; it's always URI safe. */
5688 if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
5689 if (
5690 // First condition does a very basic check if a) it's basically a valid custom element tagname AND
5691 // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
5692 // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
5693 _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) ||
5694 // Alternative, second condition checks if it's an `is`-attribute, AND
5695 // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
5696 lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {
5697 return false;
5698 }
5699 /* Check value is safe. First, is attr inert? If so, is safe */
5700 } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
5701 return false;
5702 } else ;
5703 return true;
5704 };
5705 /**
5706 * _isBasicCustomElement
5707 * checks if at least one dash is included in tagName, and it's not the first char
5708 * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
5709 *
5710 * @param tagName name of the tag of the node to sanitize
5711 * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
5712 */
5713 const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
5714 return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
5715 };
5716 /**
5717 * _sanitizeAttributes
5718 *
5719 * @protect attributes
5720 * @protect nodeName
5721 * @protect removeAttribute
5722 * @protect setAttribute
5723 *
5724 * @param currentNode to sanitize
5725 */
5726 const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
5727 /* Execute a hook if present */
5728 _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
5729 const {
5730 attributes
5731 } = currentNode;
5732 /* Check if we have attributes; if not we might have a text node */
5733 if (!attributes || _isClobbered(currentNode)) {
5734 return;
5735 }
5736 const hookEvent = {
5737 attrName: '',
5738 attrValue: '',
5739 keepAttr: true,
5740 allowedAttributes: ALLOWED_ATTR,
5741 forceKeepAttr: undefined
5742 };
5743 let l = attributes.length;
5744 /* Go backwards over all attributes; safely remove bad ones */
5745 while (l--) {
5746 const attr = attributes[l];
5747 const {
5748 name,
5749 namespaceURI,
5750 value: attrValue
5751 } = attr;
5752 const lcName = transformCaseFunc(name);
5753 const initValue = attrValue;
5754 let value = name === 'value' ? initValue : stringTrim(initValue);
5755 /* Execute a hook if present */
5756 hookEvent.attrName = lcName;
5757 hookEvent.attrValue = value;
5758 hookEvent.keepAttr = true;
5759 hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
5760 _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
5761 value = hookEvent.attrValue;
5762 /* Full DOM Clobbering protection via namespace isolation,
5763 * Prefix id and name attributes with `user-content-`
5764 */
5765 if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
5766 // Remove the attribute with this value
5767 _removeAttribute(name, currentNode);
5768 // Prefix the value and later re-create the attribute with the sanitized value
5769 value = SANITIZE_NAMED_PROPS_PREFIX + value;
5770 }
5771 /* Work around a security issue with comments inside attributes */
5772 if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title|textarea)/i, value)) {
5773 _removeAttribute(name, currentNode);
5774 continue;
5775 }
5776 /* Make sure we cannot easily use animated hrefs, even if animations are allowed */
5777 if (lcName === 'attributename' && stringMatch(value, 'href')) {
5778 _removeAttribute(name, currentNode);
5779 continue;
5780 }
5781 /* Did the hooks approve of the attribute? */
5782 if (hookEvent.forceKeepAttr) {
5783 continue;
5784 }
5785 /* Did the hooks approve of the attribute? */
5786 if (!hookEvent.keepAttr) {
5787 _removeAttribute(name, currentNode);
5788 continue;
5789 }
5790 /* Work around a security issue in jQuery 3.0 */
5791 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
5792 _removeAttribute(name, currentNode);
5793 continue;
5794 }
5795 /* Sanitize attribute content to be template-safe */
5796 if (SAFE_FOR_TEMPLATES) {
5797 arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
5798 value = stringReplace(value, expr, ' ');
5799 });
5800 }
5801 /* Is `value` valid for this attribute? */
5802 const lcTag = transformCaseFunc(currentNode.nodeName);
5803 if (!_isValidAttribute(lcTag, lcName, value)) {
5804 _removeAttribute(name, currentNode);
5805 continue;
5806 }
5807 /* Handle attributes that require Trusted Types */
5808 if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
5809 if (namespaceURI) ; else {
5810 switch (trustedTypes.getAttributeType(lcTag, lcName)) {
5811 case 'TrustedHTML':
5812 {
5813 value = trustedTypesPolicy.createHTML(value);
5814 break;
5815 }
5816 case 'TrustedScriptURL':
5817 {
5818 value = trustedTypesPolicy.createScriptURL(value);
5819 break;
5820 }
5821 }
5822 }
5823 }
5824 /* Handle invalid data-* attribute set by try-catching it */
5825 if (value !== initValue) {
5826 try {
5827 if (namespaceURI) {
5828 currentNode.setAttributeNS(namespaceURI, name, value);
5829 } else {
5830 /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
5831 currentNode.setAttribute(name, value);
5832 }
5833 if (_isClobbered(currentNode)) {
5834 _forceRemove(currentNode);
5835 } else {
5836 arrayPop(DOMPurify.removed);
5837 }
5838 } catch (_) {
5839 _removeAttribute(name, currentNode);
5840 }
5841 }
5842 }
5843 /* Execute a hook if present */
5844 _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
5845 };
5846 /**
5847 * _sanitizeShadowDOM
5848 *
5849 * @param fragment to iterate over recursively
5850 */
5851 const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
5852 let shadowNode = null;
5853 const shadowIterator = _createNodeIterator(fragment);
5854 /* Execute a hook if present */
5855 _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
5856 while (shadowNode = shadowIterator.nextNode()) {
5857 /* Execute a hook if present */
5858 _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
5859 /* Sanitize tags and elements */
5860 _sanitizeElements(shadowNode);
5861 /* Check attributes next */
5862 _sanitizeAttributes(shadowNode);
5863 /* Deep shadow DOM detected */
5864 if (shadowNode.content instanceof DocumentFragment) {
5865 _sanitizeShadowDOM(shadowNode.content);
5866 }
5867 }
5868 /* Execute a hook if present */
5869 _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
5870 };
5871 // eslint-disable-next-line complexity
5872 DOMPurify.sanitize = function (dirty) {
5873 let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
5874 let body = null;
5875 let importedNode = null;
5876 let currentNode = null;
5877 let returnNode = null;
5878 /* Make sure we have a string to sanitize.
5879 DO NOT return early, as this will return the wrong type if
5880 the user has requested a DOM object rather than a string */
5881 IS_EMPTY_INPUT = !dirty;
5882 if (IS_EMPTY_INPUT) {
5883 dirty = '<!-->';
5884 }
5885 /* Stringify, in case dirty is an object */
5886 if (typeof dirty !== 'string' && !_isNode(dirty)) {
5887 if (typeof dirty.toString === 'function') {
5888 dirty = dirty.toString();
5889 if (typeof dirty !== 'string') {
5890 throw typeErrorCreate('dirty is not a string, aborting');
5891 }
5892 } else {
5893 throw typeErrorCreate('toString is not a function');
5894 }
5895 }
5896 /* Return dirty HTML if DOMPurify cannot run */
5897 if (!DOMPurify.isSupported) {
5898 return dirty;
5899 }
5900 /* Assign config vars */
5901 if (!SET_CONFIG) {
5902 _parseConfig(cfg);
5903 }
5904 /* Clean up removed elements */
5905 DOMPurify.removed = [];
5906 /* Check if dirty is correctly typed for IN_PLACE */
5907 if (typeof dirty === 'string') {
5908 IN_PLACE = false;
5909 }
5910 if (IN_PLACE) {
5911 /* Do some early pre-sanitization to avoid unsafe root nodes */
5912 if (dirty.nodeName) {
5913 const tagName = transformCaseFunc(dirty.nodeName);
5914 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
5915 throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
5916 }
5917 }
5918 } else if (dirty instanceof Node) {
5919 /* If dirty is a DOM element, append to an empty document to avoid
5920 elements being stripped by the parser */
5921 body = _initDocument('<!---->');
5922 importedNode = body.ownerDocument.importNode(dirty, true);
5923 if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
5924 /* Node is already a body, use as is */
5925 body = importedNode;
5926 } else if (importedNode.nodeName === 'HTML') {
5927 body = importedNode;
5928 } else {
5929 // eslint-disable-next-line unicorn/prefer-dom-node-append
5930 body.appendChild(importedNode);
5931 }
5932 } else {
5933 /* Exit directly if we have nothing to do */
5934 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
5935 // eslint-disable-next-line unicorn/prefer-includes
5936 dirty.indexOf('<') === -1) {
5937 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
5938 }
5939 /* Initialize the document to work on */
5940 body = _initDocument(dirty);
5941 /* Check we have a DOM node from the data */
5942 if (!body) {
5943 return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
5944 }
5945 }
5946 /* Remove first element node (ours) if FORCE_BODY is set */
5947 if (body && FORCE_BODY) {
5948 _forceRemove(body.firstChild);
5949 }
5950 /* Get node iterator */
5951 const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
5952 /* Now start iterating over the created document */
5953 while (currentNode = nodeIterator.nextNode()) {
5954 /* Sanitize tags and elements */
5955 _sanitizeElements(currentNode);
5956 /* Check attributes next */
5957 _sanitizeAttributes(currentNode);
5958 /* Shadow DOM detected, sanitize it */
5959 if (currentNode.content instanceof DocumentFragment) {
5960 _sanitizeShadowDOM(currentNode.content);
5961 }
5962 }
5963 /* If we sanitized `dirty` in-place, return it. */
5964 if (IN_PLACE) {
5965 return dirty;
5966 }
5967 /* Return sanitized string or DOM */
5968 if (RETURN_DOM) {
5969 if (RETURN_DOM_FRAGMENT) {
5970 returnNode = createDocumentFragment.call(body.ownerDocument);
5971 while (body.firstChild) {
5972 // eslint-disable-next-line unicorn/prefer-dom-node-append
5973 returnNode.appendChild(body.firstChild);
5974 }
5975 } else {
5976 returnNode = body;
5977 }
5978 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
5979 /*
5980 AdoptNode() is not used because internal state is not reset
5981 (e.g. the past names map of a HTMLFormElement), this is safe
5982 in theory but we would rather not risk another attack vector.
5983 The state that is cloned by importNode() is explicitly defined
5984 by the specs.
5985 */
5986 returnNode = importNode.call(originalDocument, returnNode, true);
5987 }
5988 return returnNode;
5989 }
5990 let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
5991 /* Serialize doctype if allowed */
5992 if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
5993 serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
5994 }
5995 /* Sanitize final string template-safe */
5996 if (SAFE_FOR_TEMPLATES) {
5997 arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
5998 serializedHTML = stringReplace(serializedHTML, expr, ' ');
5999 });
6000 }
6001 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
6002 };
6003 DOMPurify.setConfig = function () {
6004 let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
6005 _parseConfig(cfg);
6006 SET_CONFIG = true;
6007 };
6008 DOMPurify.clearConfig = function () {
6009 CONFIG = null;
6010 SET_CONFIG = false;
6011 };
6012 DOMPurify.isValidAttribute = function (tag, attr, value) {
6013 /* Initialize shared config vars if necessary. */
6014 if (!CONFIG) {
6015 _parseConfig({});
6016 }
6017 const lcTag = transformCaseFunc(tag);
6018 const lcName = transformCaseFunc(attr);
6019 return _isValidAttribute(lcTag, lcName, value);
6020 };
6021 DOMPurify.addHook = function (entryPoint, hookFunction) {
6022 if (typeof hookFunction !== 'function') {
6023 return;
6024 }
6025 arrayPush(hooks[entryPoint], hookFunction);
6026 };
6027 DOMPurify.removeHook = function (entryPoint, hookFunction) {
6028 if (hookFunction !== undefined) {
6029 const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
6030 return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
6031 }
6032 return arrayPop(hooks[entryPoint]);
6033 };
6034 DOMPurify.removeHooks = function (entryPoint) {
6035 hooks[entryPoint] = [];
6036 };
6037 DOMPurify.removeAllHooks = function () {
6038 hooks = _createHooksMap();
6039 };
6040 return DOMPurify;
6041 }
6042 var purify = createDOMPurify();
6043
6044 module.exports = purify;
6045 //# sourceMappingURL=purify.cjs.js.map
6046
6047
6048 /***/ })
6049
6050 /******/ });
6051 /************************************************************************/
6052 /******/ // The module cache
6053 /******/ var __webpack_module_cache__ = {};
6054 /******/
6055 /******/ // The require function
6056 /******/ function __webpack_require__(moduleId) {
6057 /******/ // Check if module is in cache
6058 /******/ var cachedModule = __webpack_module_cache__[moduleId];
6059 /******/ if (cachedModule !== undefined) {
6060 /******/ return cachedModule.exports;
6061 /******/ }
6062 /******/ // Create a new module (and put it into the cache)
6063 /******/ var module = __webpack_module_cache__[moduleId] = {
6064 /******/ // no module.id needed
6065 /******/ // no module.loaded needed
6066 /******/ exports: {}
6067 /******/ };
6068 /******/
6069 /******/ // Execute the module function
6070 /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
6071 /******/
6072 /******/ // Return the exports of the module
6073 /******/ return module.exports;
6074 /******/ }
6075 /******/
6076 /************************************************************************/
6077 /******/ /* webpack/runtime/compat get default export */
6078 /******/ (() => {
6079 /******/ // getDefaultExport function for compatibility with non-harmony modules
6080 /******/ __webpack_require__.n = (module) => {
6081 /******/ var getter = module && module.__esModule ?
6082 /******/ () => (module['default']) :
6083 /******/ () => (module);
6084 /******/ __webpack_require__.d(getter, { a: getter });
6085 /******/ return getter;
6086 /******/ };
6087 /******/ })();
6088 /******/
6089 /******/ /* webpack/runtime/define property getters */
6090 /******/ (() => {
6091 /******/ // define getter functions for harmony exports
6092 /******/ __webpack_require__.d = (exports, definition) => {
6093 /******/ for(var key in definition) {
6094 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
6095 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
6096 /******/ }
6097 /******/ }
6098 /******/ };
6099 /******/ })();
6100 /******/
6101 /******/ /* webpack/runtime/hasOwnProperty shorthand */
6102 /******/ (() => {
6103 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
6104 /******/ })();
6105 /******/
6106 /******/ /* webpack/runtime/make namespace object */
6107 /******/ (() => {
6108 /******/ // define __esModule on exports
6109 /******/ __webpack_require__.r = (exports) => {
6110 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
6111 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
6112 /******/ }
6113 /******/ Object.defineProperty(exports, '__esModule', { value: true });
6114 /******/ };
6115 /******/ })();
6116 /******/
6117 /************************************************************************/
6118 var __webpack_exports__ = {};
6119 // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
6120 (() => {
6121 "use strict";
6122 /*!******************************!*\
6123 !*** ./assets/src/js/acf.js ***!
6124 \******************************/
6125 __webpack_require__.r(__webpack_exports__);
6126 /* harmony import */ var _acf_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_acf.js */ "./assets/src/js/_acf.js");
6127 /* harmony import */ var _acf_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_acf_js__WEBPACK_IMPORTED_MODULE_0__);
6128 /* harmony import */ var _acf_hooks_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./_acf-hooks.js */ "./assets/src/js/_acf-hooks.js");
6129 /* harmony import */ var _acf_hooks_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_acf_hooks_js__WEBPACK_IMPORTED_MODULE_1__);
6130 /* harmony import */ var _acf_model_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./_acf-model.js */ "./assets/src/js/_acf-model.js");
6131 /* harmony import */ var _acf_model_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_acf_model_js__WEBPACK_IMPORTED_MODULE_2__);
6132 /* harmony import */ var _acf_popup_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./_acf-popup.js */ "./assets/src/js/_acf-popup.js");
6133 /* harmony import */ var _acf_popup_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_acf_popup_js__WEBPACK_IMPORTED_MODULE_3__);
6134 /* harmony import */ var _acf_modal_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./_acf-modal.js */ "./assets/src/js/_acf-modal.js");
6135 /* harmony import */ var _acf_modal_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_acf_modal_js__WEBPACK_IMPORTED_MODULE_4__);
6136 /* harmony import */ var _acf_panel_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./_acf-panel.js */ "./assets/src/js/_acf-panel.js");
6137 /* harmony import */ var _acf_panel_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_acf_panel_js__WEBPACK_IMPORTED_MODULE_5__);
6138 /* harmony import */ var _acf_notice_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./_acf-notice.js */ "./assets/src/js/_acf-notice.js");
6139 /* harmony import */ var _acf_notice_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_acf_notice_js__WEBPACK_IMPORTED_MODULE_6__);
6140 /* harmony import */ var _acf_tooltip_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./_acf-tooltip.js */ "./assets/src/js/_acf-tooltip.js");
6141 /* harmony import */ var _acf_tooltip_js__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_acf_tooltip_js__WEBPACK_IMPORTED_MODULE_7__);
6142
6143
6144
6145
6146
6147
6148
6149
6150 })();
6151
6152 /******/ })()
6153 ;
6154 //# sourceMappingURL=acf.js.map