PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.2
Secure Custom Fields v6.4.2
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 / src / js / _acf.js
secure-custom-fields / assets / src / js Last commit date
pro 1 year ago _acf-compatibility.js 1 year ago _acf-condition-types.js 1 year ago _acf-condition.js 1 year ago _acf-conditions.js 1 year ago _acf-field-accordion.js 1 year ago _acf-field-button-group.js 1 year ago _acf-field-checkbox.js 1 year ago _acf-field-color-picker.js 1 year ago _acf-field-date-picker.js 1 year ago _acf-field-date-time-picker.js 1 year ago _acf-field-file.js 1 year ago _acf-field-google-map.js 1 year ago _acf-field-icon-picker.js 1 year ago _acf-field-image.js 1 year ago _acf-field-link.js 1 year ago _acf-field-oembed.js 1 year ago _acf-field-page-link.js 1 year ago _acf-field-post-object.js 1 year ago _acf-field-radio.js 1 year ago _acf-field-range.js 1 year ago _acf-field-relationship.js 1 year ago _acf-field-select.js 1 year ago _acf-field-tab.js 1 year ago _acf-field-taxonomy.js 1 year ago _acf-field-time-picker.js 1 year ago _acf-field-true-false.js 1 year ago _acf-field-url.js 1 year ago _acf-field-user.js 1 year ago _acf-field-wysiwyg.js 1 year ago _acf-field.js 1 year ago _acf-fields.js 1 year ago _acf-helpers.js 1 year ago _acf-hooks.js 1 year ago _acf-internal-post-type.js 1 year ago _acf-media.js 1 year ago _acf-modal.js 1 year ago _acf-model.js 1 year ago _acf-notice.js 1 year ago _acf-panel.js 1 year ago _acf-popup.js 1 year ago _acf-postbox.js 1 year ago _acf-screen.js 1 year ago _acf-select2.js 1 year ago _acf-tinymce.js 1 year ago _acf-tooltip.js 1 year ago _acf-unload.js 1 year ago _acf-validation.js 1 year ago _acf.js 1 year ago _browse-fields-modal.js 1 year ago _field-group-compatibility.js 1 year ago _field-group-conditions.js 1 year ago _field-group-field.js 1 year ago _field-group-fields.js 1 year ago _field-group-locations.js 1 year ago _field-group-settings.js 1 year ago _field-group.js 1 year ago acf-escaped-html-notice.js 1 year ago acf-field-group.js 1 year ago acf-input.js 1 year ago acf-internal-post-type.js 1 year ago acf.js 1 year ago
_acf.js
2587 lines
1 ( function ( $, undefined ) {
2 /**
3 * acf
4 *
5 * description
6 *
7 * @date 14/12/17
8 * @since ACF 5.6.5
9 *
10 * @param type $var Description. Default.
11 * @return type Description.
12 */
13
14 // The global acf object
15 var acf = {};
16
17 // Set as a browser global
18 window.acf = acf;
19
20 /** @var object Data sent from PHP */
21 acf.data = {};
22
23 /**
24 * get
25 *
26 * Gets a specific data value
27 *
28 * @date 14/12/17
29 * @since ACF 5.6.5
30 *
31 * @param string name
32 * @return mixed
33 */
34
35 acf.get = function ( name ) {
36 return this.data[ name ] || null;
37 };
38
39 /**
40 * has
41 *
42 * Returns `true` if the data exists and is not null
43 *
44 * @date 14/12/17
45 * @since ACF 5.6.5
46 *
47 * @param string name
48 * @return boolean
49 */
50
51 acf.has = function ( name ) {
52 return this.get( name ) !== null;
53 };
54
55 /**
56 * set
57 *
58 * Sets a specific data value
59 *
60 * @date 14/12/17
61 * @since ACF 5.6.5
62 *
63 * @param string name
64 * @param mixed value
65 * @return this
66 */
67
68 acf.set = function ( name, value ) {
69 this.data[ name ] = value;
70 return this;
71 };
72
73 /**
74 * uniqueId
75 *
76 * Returns a unique ID
77 *
78 * @date 9/11/17
79 * @since ACF 5.6.3
80 *
81 * @param string prefix Optional prefix.
82 * @return string
83 */
84
85 var idCounter = 0;
86 acf.uniqueId = function ( prefix ) {
87 var id = ++idCounter + '';
88 return prefix ? prefix + id : id;
89 };
90
91 /**
92 * acf.uniqueArray
93 *
94 * Returns a new array with only unique values
95 * Credit: https://stackoverflow.com/questions/1960473/get-all-unique-values-in-an-array-remove-duplicates
96 *
97 * @date 23/3/18
98 * @since ACF 5.6.9
99 *
100 * @param type $var Description. Default.
101 * @return type Description.
102 */
103
104 acf.uniqueArray = function ( array ) {
105 function onlyUnique( value, index, self ) {
106 return self.indexOf( value ) === index;
107 }
108 return array.filter( onlyUnique );
109 };
110
111 /**
112 * uniqid
113 *
114 * Returns a unique ID (PHP version)
115 *
116 * @date 9/11/17
117 * @since ACF 5.6.3
118 * @source http://locutus.io/php/misc/uniqid/
119 *
120 * @param string prefix Optional prefix.
121 * @return string
122 */
123
124 var uniqidSeed = '';
125 acf.uniqid = function ( prefix, moreEntropy ) {
126 // discuss at: http://locutus.io/php/uniqid/
127 // original by: Kevin van Zonneveld (http://kvz.io)
128 // revised by: Kankrelune (http://www.webfaktory.info/)
129 // note 1: Uses an internal counter (in locutus global) to avoid collision
130 // example 1: var $id = uniqid()
131 // example 1: var $result = $id.length === 13
132 // returns 1: true
133 // example 2: var $id = uniqid('foo')
134 // example 2: var $result = $id.length === (13 + 'foo'.length)
135 // returns 2: true
136 // example 3: var $id = uniqid('bar', true)
137 // example 3: var $result = $id.length === (23 + 'bar'.length)
138 // returns 3: true
139 if ( typeof prefix === 'undefined' ) {
140 prefix = '';
141 }
142
143 var retId;
144 var formatSeed = function ( seed, reqWidth ) {
145 seed = parseInt( seed, 10 ).toString( 16 ); // to hex str
146 if ( reqWidth < seed.length ) {
147 // so long we split
148 return seed.slice( seed.length - reqWidth );
149 }
150 if ( reqWidth > seed.length ) {
151 // so short we pad
152 return Array( 1 + ( reqWidth - seed.length ) ).join( '0' ) + seed;
153 }
154 return seed;
155 };
156
157 if ( ! uniqidSeed ) {
158 // init seed with big random int
159 uniqidSeed = Math.floor( Math.random() * 0x75bcd15 );
160 }
161 uniqidSeed++;
162
163 retId = prefix; // start with prefix, add current milliseconds hex string
164 retId += formatSeed( parseInt( new Date().getTime() / 1000, 10 ), 8 );
165 retId += formatSeed( uniqidSeed, 5 ); // add seed hex string
166 if ( moreEntropy ) {
167 // for more entropy we add a float lower to 10
168 retId += ( Math.random() * 10 ).toFixed( 8 ).toString();
169 }
170
171 return retId;
172 };
173
174 /**
175 * strReplace
176 *
177 * Performs a string replace
178 *
179 * @date 14/12/17
180 * @since ACF 5.6.5
181 *
182 * @param string search
183 * @param string replace
184 * @param string subject
185 * @return string
186 */
187
188 acf.strReplace = function ( search, replace, subject ) {
189 return subject.split( search ).join( replace );
190 };
191
192 /**
193 * strCamelCase
194 *
195 * Converts a string into camelCase
196 * Thanks to https://stackoverflow.com/questions/2970525/converting-any-string-into-camel-case
197 *
198 * @date 14/12/17
199 * @since ACF 5.6.5
200 *
201 * @param string str
202 * @return string
203 */
204
205 acf.strCamelCase = function ( str ) {
206 var matches = str.match( /([a-zA-Z0-9]+)/g );
207 return matches
208 ? matches
209 .map( function ( s, i ) {
210 var c = s.charAt( 0 );
211 return ( i === 0 ? c.toLowerCase() : c.toUpperCase() ) + s.slice( 1 );
212 } )
213 .join( '' )
214 : '';
215 };
216
217 /**
218 * strPascalCase
219 *
220 * Converts a string into PascalCase
221 * Thanks to https://stackoverflow.com/questions/1026069/how-do-i-make-the-first-letter-of-a-string-uppercase-in-javascript
222 *
223 * @date 14/12/17
224 * @since ACF 5.6.5
225 *
226 * @param string str
227 * @return string
228 */
229
230 acf.strPascalCase = function ( str ) {
231 var camel = acf.strCamelCase( str );
232 return camel.charAt( 0 ).toUpperCase() + camel.slice( 1 );
233 };
234
235 /**
236 * acf.strSlugify
237 *
238 * Converts a string into a HTML class friendly slug
239 *
240 * @date 21/3/18
241 * @since ACF 5.6.9
242 *
243 * @param string str
244 * @return string
245 */
246
247 acf.strSlugify = function ( str ) {
248 return acf.strReplace( '_', '-', str.toLowerCase() );
249 };
250
251 acf.strSanitize = function ( str, toLowerCase = true ) {
252 // chars (https://jsperf.com/replace-foreign-characters)
253 var map = {
254 À: 'A',
255 Á: 'A',
256 Â: 'A',
257 Ã: 'A',
258 Ä: 'A',
259
260 : 'A',
261 Æ: 'AE',
262 Ç: 'C',
263 È: 'E',
264 É: 'E',
265 Ê: 'E',
266 Ë: 'E',
267 Ì: 'I',
268 Í: 'I',
269 Î: 'I',
270 Ï: 'I',
271 Ð: 'D',
272 Ñ: 'N',
273 Ò: 'O',
274 Ó: 'O',
275 Ô: 'O',
276 Õ: 'O',
277 Ö: 'O',
278 Ø: 'O',
279 Ù: 'U',
280 Ú: 'U',
281 Û: 'U',
282 Ü: 'U',
283 Ý: 'Y',
284 ß: 's',
285 à: 'a',
286 á: 'a',
287 â: 'a',
288 ã: 'a',
289 ä: 'a',
290 å: 'a',
291 æ: 'ae',
292 ç: 'c',
293 è: 'e',
294 é: 'e',
295 ê: 'e',
296 ë: 'e',
297 ì: 'i',
298 í: 'i',
299 î: 'i',
300 ï: 'i',
301 ñ: 'n',
302 ò: 'o',
303 ó: 'o',
304 ô: 'o',
305 õ: 'o',
306 ö: 'o',
307 ø: 'o',
308 ù: 'u',
309 ú: 'u',
310 û: 'u',
311 ü: 'u',
312 ý: 'y',
313 ÿ: 'y',
314 Ā: 'A',
315 ā: 'a',
316 Ă: 'A',
317 ă: 'a',
318 Ą: 'A',
319
320 : 'a',
321 Ć: 'C',
322 ć: 'c',
323 Ĉ: 'C',
324 ĉ: 'c',
325 Ċ: 'C',
326 ċ: 'c',
327 Č: 'C',
328 č: 'c',
329 Ď: 'D',
330 ď: 'd',
331 Đ: 'D',
332 đ: 'd',
333 Ē: 'E',
334 ē: 'e',
335 Ĕ: 'E',
336 ĕ: 'e',
337 Ė: 'E',
338 ė: 'e',
339 Ę: 'E',
340 ę: 'e',
341 Ě: 'E',
342 ě: 'e',
343 Ĝ: 'G',
344 ĝ: 'g',
345 Ğ: 'G',
346 ğ: 'g',
347 Ġ: 'G',
348 ġ: 'g',
349 Ģ: 'G',
350 ģ: 'g',
351 Ĥ: 'H',
352 ĥ: 'h',
353 Ħ: 'H',
354 ħ: 'h',
355 Ĩ: 'I',
356 ĩ: 'i',
357 Ī: 'I',
358 ī: 'i',
359 Ĭ: 'I',
360 ĭ: 'i',
361 Į: 'I',
362 į: 'i',
363 İ: 'I',
364 ı: 'i',
365 IJ: 'IJ',
366 ij: 'ij',
367 Ĵ: 'J',
368 ĵ: 'j',
369 Ķ: 'K',
370 ķ: 'k',
371 Ĺ: 'L',
372 ĺ: 'l',
373 Ļ: 'L',
374 ļ: 'l',
375 Ľ: 'L',
376 ľ: 'l',
377 Ŀ: 'L',
378 ŀ: 'l',
379 Ł: 'l',
380 ł: 'l',
381 Ń: 'N',
382 ń: 'n',
383
384 : 'N',
385 ņ: 'n',
386 Ň: 'N',
387 ň: 'n',
388 ʼn: 'n',
389 Ō: 'O',
390 ō: 'o',
391 Ŏ: 'O',
392 ŏ: 'o',
393 Ő: 'O',
394 ő: 'o',
395 Œ: 'OE',
396 œ: 'oe',
397 Ŕ: 'R',
398 ŕ: 'r',
399 Ŗ: 'R',
400 ŗ: 'r',
401 Ř: 'R',
402 ř: 'r',
403 Ś: 'S',
404 ś: 's',
405 Ŝ: 'S',
406 ŝ: 's',
407 Ş: 'S',
408 ş: 's',
409 Š: 'S',
410 š: 's',
411 Ţ: 'T',
412 ţ: 't',
413 Ť: 'T',
414 ť: 't',
415 Ŧ: 'T',
416 ŧ: 't',
417 Ũ: 'U',
418 ũ: 'u',
419 Ū: 'U',
420 ū: 'u',
421 Ŭ: 'U',
422 ŭ: 'u',
423 Ů: 'U',
424 ů: 'u',
425 Ű: 'U',
426 ű: 'u',
427 Ų: 'U',
428 ų: 'u',
429 Ŵ: 'W',
430 ŵ: 'w',
431 Ŷ: 'Y',
432 ŷ: 'y',
433 Ÿ: 'Y',
434 Ź: 'Z',
435 ź: 'z',
436 Ż: 'Z',
437 ż: 'z',
438 Ž: 'Z',
439 ž: 'z',
440 ſ: 's',
441 ƒ: 'f',
442 Ơ: 'O',
443 ơ: 'o',
444 Ư: 'U',
445 ư: 'u',
446 Ǎ: 'A',
447 ǎ: 'a',
448 Ǐ: 'I',
449 ǐ: 'i',
450 Ǒ: 'O',
451 ǒ: 'o',
452 Ǔ: 'U',
453 ǔ: 'u',
454 Ǖ: 'U',
455 ǖ: 'u',
456 Ǘ: 'U',
457 ǘ: 'u',
458 Ǚ: 'U',
459 ǚ: 'u',
460 Ǜ: 'U',
461 ǜ: 'u',
462 Ǻ: 'A',
463 ǻ: 'a',
464 Ǽ: 'AE',
465 ǽ: 'ae',
466 Ǿ: 'O',
467 ǿ: 'o',
468
469 // extra
470 ' ': '_',
471 "'": '',
472 '?': '',
473 '/': '',
474 '\\': '',
475 '.': '',
476 ',': '',
477 '`': '',
478 '>': '',
479 '<': '',
480 '"': '',
481 '[': '',
482 ']': '',
483 '|': '',
484 '{': '',
485 '}': '',
486 '(': '',
487 ')': '',
488 };
489
490 // vars
491 var nonWord = /\W/g;
492 var mapping = function ( c ) {
493 return map[ c ] !== undefined ? map[ c ] : c;
494 };
495
496 // replace
497 str = str.replace( nonWord, mapping );
498
499 // lowercase
500 if ( toLowerCase ) {
501 str = str.toLowerCase();
502 }
503
504 // return
505 return str;
506 };
507
508 /**
509 * acf.strMatch
510 *
511 * Returns the number of characters that match between two strings
512 *
513 * @date 1/2/18
514 * @since ACF 5.6.5
515 *
516 * @param type $var Description. Default.
517 * @return type Description.
518 */
519
520 acf.strMatch = function ( s1, s2 ) {
521 // vars
522 var val = 0;
523 var min = Math.min( s1.length, s2.length );
524
525 // loop
526 for ( var i = 0; i < min; i++ ) {
527 if ( s1[ i ] !== s2[ i ] ) {
528 break;
529 }
530 val++;
531 }
532
533 // return
534 return val;
535 };
536
537 /**
538 * Escapes HTML entities from a string.
539 *
540 * @date 08/06/2020
541 * @since ACF 5.9.0
542 *
543 * @param string string The input string.
544 * @return string
545 */
546 acf.strEscape = function ( string ) {
547 var htmlEscapes = {
548 '&': '&amp;',
549 '<': '&lt;',
550 '>': '&gt;',
551 '"': '&quot;',
552 "'": '&#39;',
553 };
554 return ( '' + string ).replace( /[&<>"']/g, function ( chr ) {
555 return htmlEscapes[ chr ];
556 } );
557 };
558
559 // Tests.
560 //console.log( acf.strEscape('Test 1') );
561 //console.log( acf.strEscape('Test & 1') );
562 //console.log( acf.strEscape('Test\'s &amp; 1') );
563 //console.log( acf.strEscape('<script>js</script>') );
564
565 /**
566 * Unescapes HTML entities from a string.
567 *
568 * @date 08/06/2020
569 * @since ACF 5.9.0
570 *
571 * @param string string The input string.
572 * @return string
573 */
574 acf.strUnescape = function ( string ) {
575 var htmlUnescapes = {
576 '&amp;': '&',
577 '&lt;': '<',
578 '&gt;': '>',
579 '&quot;': '"',
580 '&#39;': "'",
581 };
582 return ( '' + string ).replace( /&amp;|&lt;|&gt;|&quot;|&#39;/g, function ( entity ) {
583 return htmlUnescapes[ entity ];
584 } );
585 };
586
587 // Tests.
588 //console.log( acf.strUnescape( acf.strEscape('Test 1') ) );
589 //console.log( acf.strUnescape( acf.strEscape('Test & 1') ) );
590 //console.log( acf.strUnescape( acf.strEscape('Test\'s &amp; 1') ) );
591 //console.log( acf.strUnescape( acf.strEscape('<script>js</script>') ) );
592
593 /**
594 * Escapes HTML entities from a string.
595 *
596 * @date 08/06/2020
597 * @since ACF 5.9.0
598 *
599 * @param string string The input string.
600 * @return string
601 */
602 acf.escAttr = acf.strEscape;
603
604 /**
605 * Encodes <script> tags for safe HTML output.
606 *
607 * @date 08/06/2020
608 * @since ACF 5.9.0
609 *
610 * @param string string The input string.
611 * @return string
612 */
613 acf.escHtml = function ( string ) {
614 return ( '' + string ).replace( /<script|<\/script/g, function ( html ) {
615 return acf.strEscape( html );
616 } );
617 };
618
619 // Tests.
620 //console.log( acf.escHtml('<script>js</script>') );
621 //console.log( acf.escHtml( acf.strEscape('<script>js</script>') ) );
622 //console.log( acf.escHtml( '<script>js1</script><script>js2</script>' ) );
623
624 /**
625 * Encode a string potentially containing HTML into it's HTML entities equivalent.
626 *
627 * @since ACF 6.3.6
628 *
629 * @param {string} string String to encode.
630 * @return {string} The encoded string
631 */
632 acf.encode = function ( string ) {
633 return $( '<textarea/>' ).text( string ).html();
634 };
635
636 /**
637 * Decode a HTML encoded string into it's original form.
638 *
639 * @since ACF 5.6.5
640 *
641 * @param {string} string String to encode.
642 * @return {string} The encoded string
643 */
644 acf.decode = function ( string ) {
645 return $( '<textarea/>' ).html( string ).text();
646 };
647
648 /**
649 * parseArgs
650 *
651 * Merges together defaults and args much like the WP wp_parse_args function
652 *
653 * @date 14/12/17
654 * @since ACF 5.6.5
655 *
656 * @param object args
657 * @param object defaults
658 * @return object
659 */
660
661 acf.parseArgs = function ( args, defaults ) {
662 if ( typeof args !== 'object' ) args = {};
663 if ( typeof defaults !== 'object' ) defaults = {};
664 return $.extend( {}, defaults, args );
665 };
666
667 /**
668 * __
669 *
670 * Retrieve the translation of $text.
671 *
672 * @date 16/4/18
673 * @since ACF 5.6.9
674 *
675 * @param string text Text to translate.
676 * @return string Translated text.
677 */
678
679 if ( window.acfL10n == undefined ) {
680 acfL10n = {};
681 }
682
683 acf.__ = function ( text ) {
684 return acfL10n[ text ] || text;
685 };
686
687 /**
688 * _x
689 *
690 * Retrieve translated string with gettext context.
691 *
692 * @date 16/4/18
693 * @since ACF 5.6.9
694 *
695 * @param string text Text to translate.
696 * @param string context Context information for the translators.
697 * @return string Translated text.
698 */
699
700 acf._x = function ( text, context ) {
701 return acfL10n[ text + '.' + context ] || acfL10n[ text ] || text;
702 };
703
704 /**
705 * _n
706 *
707 * Retrieve the plural or single form based on the amount.
708 *
709 * @date 16/4/18
710 * @since ACF 5.6.9
711 *
712 * @param string single Single text to translate.
713 * @param string plural Plural text to translate.
714 * @param int number The number to compare against.
715 * @return string Translated text.
716 */
717
718 acf._n = function ( single, plural, number ) {
719 if ( number == 1 ) {
720 return acf.__( single );
721 } else {
722 return acf.__( plural );
723 }
724 };
725
726 acf.isArray = function ( a ) {
727 return Array.isArray( a );
728 };
729
730 acf.isObject = function ( a ) {
731 return typeof a === 'object';
732 };
733
734 /**
735 * serialize
736 *
737 * description
738 *
739 * @date 24/12/17
740 * @since ACF 5.6.5
741 *
742 * @param type $var Description. Default.
743 * @return type Description.
744 */
745
746 var buildObject = function ( obj, name, value ) {
747 // replace [] with placeholder
748 name = name.replace( '[]', '[%%index%%]' );
749
750 // vars
751 var keys = name.match( /([^\[\]])+/g );
752 if ( ! keys ) return;
753 var length = keys.length;
754 var ref = obj;
755
756 // loop
757 for ( var i = 0; i < length; i++ ) {
758 // vars
759 var key = String( keys[ i ] );
760
761 // value
762 if ( i == length - 1 ) {
763 // %%index%%
764 if ( key === '%%index%%' ) {
765 ref.push( value );
766
767 // default
768 } else {
769 ref[ key ] = value;
770 }
771
772 // path
773 } else {
774 // array
775 if ( keys[ i + 1 ] === '%%index%%' ) {
776 if ( ! acf.isArray( ref[ key ] ) ) {
777 ref[ key ] = [];
778 }
779
780 // object
781 } else {
782 if ( ! acf.isObject( ref[ key ] ) ) {
783 ref[ key ] = {};
784 }
785 }
786
787 // crawl
788 ref = ref[ key ];
789 }
790 }
791 };
792
793 acf.serialize = function ( $el, prefix ) {
794 // vars
795 var obj = {};
796 var inputs = acf.serializeArray( $el );
797
798 // prefix
799 if ( prefix !== undefined ) {
800 // filter and modify
801 inputs = inputs
802 .filter( function ( item ) {
803 return item.name.indexOf( prefix ) === 0;
804 } )
805 .map( function ( item ) {
806 item.name = item.name.slice( prefix.length );
807 return item;
808 } );
809 }
810
811 // loop
812 for ( var i = 0; i < inputs.length; i++ ) {
813 buildObject( obj, inputs[ i ].name, inputs[ i ].value );
814 }
815
816 // return
817 return obj;
818 };
819
820 /**
821 * acf.serializeArray
822 *
823 * Similar to $.serializeArray() but works with a parent wrapping element.
824 *
825 * @date 19/8/18
826 * @since ACF 5.7.3
827 *
828 * @param jQuery $el The element or form to serialize.
829 * @return array
830 */
831
832 acf.serializeArray = function ( $el ) {
833 return $el.find( 'select, textarea, input' ).serializeArray();
834 };
835
836 /**
837 * acf.serializeForAjax
838 *
839 * Returns an object containing name => value data ready to be encoded for Ajax.
840 *
841 * @date 17/12/18
842 * @since ACF 5.8.0
843 *
844 * @param jQUery $el The element or form to serialize.
845 * @return object
846 */
847 acf.serializeForAjax = function ( $el ) {
848 // vars
849 var data = {};
850 var index = {};
851
852 // Serialize inputs.
853 var inputs = acf.serializeArray( $el );
854
855 // Loop over inputs and build data.
856 inputs.map( function ( item ) {
857 // Append to array.
858 if ( item.name.slice( -2 ) === '[]' ) {
859 data[ item.name ] = data[ item.name ] || [];
860 data[ item.name ].push( item.value );
861 // Append
862 } else {
863 data[ item.name ] = item.value;
864 }
865 } );
866
867 // return
868 return data;
869 };
870
871 /**
872 * addAction
873 *
874 * Wrapper for acf.hooks.addAction
875 *
876 * @date 14/12/17
877 * @since ACF 5.6.5
878 *
879 * @param n/a
880 * @return this
881 */
882
883 /*
884 var prefixAction = function( action ){
885 return 'acf_' + action;
886 }
887 */
888
889 acf.addAction = function ( action, callback, priority, context ) {
890 //action = prefixAction(action);
891 acf.hooks.addAction.apply( this, arguments );
892 return this;
893 };
894
895 /**
896 * removeAction
897 *
898 * Wrapper for acf.hooks.removeAction
899 *
900 * @date 14/12/17
901 * @since ACF 5.6.5
902 *
903 * @param n/a
904 * @return this
905 */
906
907 acf.removeAction = function ( action, callback ) {
908 //action = prefixAction(action);
909 acf.hooks.removeAction.apply( this, arguments );
910 return this;
911 };
912
913 /**
914 * doAction
915 *
916 * Wrapper for acf.hooks.doAction
917 *
918 * @date 14/12/17
919 * @since ACF 5.6.5
920 *
921 * @param n/a
922 * @return this
923 */
924
925 var actionHistory = {};
926 //var currentAction = false;
927 acf.doAction = function ( action ) {
928 //action = prefixAction(action);
929 //currentAction = action;
930 actionHistory[ action ] = 1;
931 acf.hooks.doAction.apply( this, arguments );
932 actionHistory[ action ] = 0;
933 return this;
934 };
935
936 /**
937 * doingAction
938 *
939 * Return true if doing action
940 *
941 * @date 14/12/17
942 * @since ACF 5.6.5
943 *
944 * @param n/a
945 * @return this
946 */
947
948 acf.doingAction = function ( action ) {
949 //action = prefixAction(action);
950 return actionHistory[ action ] === 1;
951 };
952
953 /**
954 * didAction
955 *
956 * Wrapper for acf.hooks.doAction
957 *
958 * @date 14/12/17
959 * @since ACF 5.6.5
960 *
961 * @param n/a
962 * @return this
963 */
964
965 acf.didAction = function ( action ) {
966 //action = prefixAction(action);
967 return actionHistory[ action ] !== undefined;
968 };
969
970 /**
971 * currentAction
972 *
973 * Wrapper for acf.hooks.doAction
974 *
975 * @date 14/12/17
976 * @since ACF 5.6.5
977 *
978 * @param n/a
979 * @return this
980 */
981
982 acf.currentAction = function () {
983 for ( var k in actionHistory ) {
984 if ( actionHistory[ k ] ) {
985 return k;
986 }
987 }
988 return false;
989 };
990
991 /**
992 * addFilter
993 *
994 * Wrapper for acf.hooks.addFilter
995 *
996 * @date 14/12/17
997 * @since ACF 5.6.5
998 *
999 * @param n/a
1000 * @return this
1001 */
1002
1003 acf.addFilter = function ( action ) {
1004 //action = prefixAction(action);
1005 acf.hooks.addFilter.apply( this, arguments );
1006 return this;
1007 };
1008
1009 /**
1010 * removeFilter
1011 *
1012 * Wrapper for acf.hooks.removeFilter
1013 *
1014 * @date 14/12/17
1015 * @since ACF 5.6.5
1016 *
1017 * @param n/a
1018 * @return this
1019 */
1020
1021 acf.removeFilter = function ( action ) {
1022 //action = prefixAction(action);
1023 acf.hooks.removeFilter.apply( this, arguments );
1024 return this;
1025 };
1026
1027 /**
1028 * applyFilters
1029 *
1030 * Wrapper for acf.hooks.applyFilters
1031 *
1032 * @date 14/12/17
1033 * @since ACF 5.6.5
1034 *
1035 * @param n/a
1036 * @return this
1037 */
1038
1039 acf.applyFilters = function ( action ) {
1040 //action = prefixAction(action);
1041 return acf.hooks.applyFilters.apply( this, arguments );
1042 };
1043
1044 /**
1045 * getArgs
1046 *
1047 * description
1048 *
1049 * @date 15/12/17
1050 * @since ACF 5.6.5
1051 *
1052 * @param type $var Description. Default.
1053 * @return type Description.
1054 */
1055
1056 acf.arrayArgs = function ( args ) {
1057 return Array.prototype.slice.call( args );
1058 };
1059
1060 /**
1061 * extendArgs
1062 *
1063 * description
1064 *
1065 * @date 15/12/17
1066 * @since ACF 5.6.5
1067 *
1068 * @param type $var Description. Default.
1069 * @return type Description.
1070 */
1071
1072 /*
1073 acf.extendArgs = function( ){
1074 var args = Array.prototype.slice.call( arguments );
1075 var realArgs = args.shift();
1076
1077 Array.prototype.push.call(arguments, 'bar')
1078 return Array.prototype.push.apply( args, arguments );
1079 };
1080 */
1081
1082 // Preferences
1083 // - use try/catch to avoid JS error if cookies are disabled on front-end form
1084 try {
1085 var preferences = JSON.parse( localStorage.getItem( 'acf' ) ) || {};
1086 } catch ( e ) {
1087 var preferences = {};
1088 }
1089
1090 /**
1091 * getPreferenceName
1092 *
1093 * Gets the true preference name.
1094 * Converts "this.thing" to "thing-123" if editing post 123.
1095 *
1096 * @date 11/11/17
1097 * @since ACF 5.6.5
1098 *
1099 * @param string name
1100 * @return string
1101 */
1102
1103 var getPreferenceName = function ( name ) {
1104 if ( name.substr( 0, 5 ) === 'this.' ) {
1105 name = name.substr( 5 ) + '-' + acf.get( 'post_id' );
1106 }
1107 return name;
1108 };
1109
1110 /**
1111 * acf.getPreference
1112 *
1113 * Gets a preference setting or null if not set.
1114 *
1115 * @date 11/11/17
1116 * @since ACF 5.6.5
1117 *
1118 * @param string name
1119 * @return mixed
1120 */
1121
1122 acf.getPreference = function ( name ) {
1123 name = getPreferenceName( name );
1124 return preferences[ name ] || null;
1125 };
1126
1127 /**
1128 * acf.setPreference
1129 *
1130 * Sets a preference setting.
1131 *
1132 * @date 11/11/17
1133 * @since ACF 5.6.5
1134 *
1135 * @param string name
1136 * @param mixed value
1137 * @return n/a
1138 */
1139
1140 acf.setPreference = function ( name, value ) {
1141 name = getPreferenceName( name );
1142 if ( value === null ) {
1143 delete preferences[ name ];
1144 } else {
1145 preferences[ name ] = value;
1146 }
1147 localStorage.setItem( 'acf', JSON.stringify( preferences ) );
1148 };
1149
1150 /**
1151 * acf.removePreference
1152 *
1153 * Removes a preference setting.
1154 *
1155 * @date 11/11/17
1156 * @since ACF 5.6.5
1157 *
1158 * @param string name
1159 * @return n/a
1160 */
1161
1162 acf.removePreference = function ( name ) {
1163 acf.setPreference( name, null );
1164 };
1165
1166 /**
1167 * remove
1168 *
1169 * Removes an element with fade effect
1170 *
1171 * @date 1/1/18
1172 * @since ACF 5.6.5
1173 *
1174 * @param type $var Description. Default.
1175 * @return type Description.
1176 */
1177
1178 acf.remove = function ( props ) {
1179 // allow jQuery
1180 if ( props instanceof jQuery ) {
1181 props = {
1182 target: props,
1183 };
1184 }
1185
1186 // defaults
1187 props = acf.parseArgs( props, {
1188 target: false,
1189 endHeight: 0,
1190 complete: function () {},
1191 } );
1192
1193 // action
1194 acf.doAction( 'remove', props.target );
1195
1196 // tr
1197 if ( props.target.is( 'tr' ) ) {
1198 removeTr( props );
1199
1200 // div
1201 } else {
1202 removeDiv( props );
1203 }
1204 };
1205
1206 /**
1207 * removeDiv
1208 *
1209 * description
1210 *
1211 * @date 16/2/18
1212 * @since ACF 5.6.9
1213 *
1214 * @param type $var Description. Default.
1215 * @return type Description.
1216 */
1217
1218 var removeDiv = function ( props ) {
1219 // vars
1220 var $el = props.target;
1221 var height = $el.height();
1222 var width = $el.width();
1223 var margin = $el.css( 'margin' );
1224 var outerHeight = $el.outerHeight( true );
1225 var style = $el.attr( 'style' ) + ''; // needed to copy
1226
1227 // wrap
1228 $el.wrap( '<div class="acf-temp-remove" style="height:' + outerHeight + 'px"></div>' );
1229 var $wrap = $el.parent();
1230
1231 // set pos
1232 $el.css( {
1233 height: height,
1234 width: width,
1235 margin: margin,
1236 position: 'absolute',
1237 } );
1238
1239 // fade wrap
1240 setTimeout( function () {
1241 $wrap.css( {
1242 opacity: 0,
1243 height: props.endHeight,
1244 } );
1245 }, 50 );
1246
1247 // remove
1248 setTimeout( function () {
1249 $el.attr( 'style', style );
1250 $wrap.remove();
1251 props.complete();
1252 }, 301 );
1253 };
1254
1255 /**
1256 * removeTr
1257 *
1258 * description
1259 *
1260 * @date 16/2/18
1261 * @since ACF 5.6.9
1262 *
1263 * @param type $var Description. Default.
1264 * @return type Description.
1265 */
1266
1267 var removeTr = function ( props ) {
1268 // vars
1269 var $tr = props.target;
1270 var height = $tr.height();
1271 var children = $tr.children().length;
1272
1273 // create dummy td
1274 var $td = $(
1275 '<td class="acf-temp-remove" style="padding:0; height:' + height + 'px" colspan="' + children + '"></td>'
1276 );
1277
1278 // fade away tr
1279 $tr.addClass( 'acf-remove-element' );
1280
1281 // update HTML after fade animation
1282 setTimeout( function () {
1283 $tr.html( $td );
1284 }, 251 );
1285
1286 // allow .acf-temp-remove to exist before changing CSS
1287 setTimeout( function () {
1288 // remove class
1289 $tr.removeClass( 'acf-remove-element' );
1290
1291 // collapse
1292 $td.css( {
1293 height: props.endHeight,
1294 } );
1295 }, 300 );
1296
1297 // remove
1298 setTimeout( function () {
1299 $tr.remove();
1300 props.complete();
1301 }, 451 );
1302 };
1303
1304 /**
1305 * duplicate
1306 *
1307 * description
1308 *
1309 * @date 3/1/18
1310 * @since ACF 5.6.5
1311 *
1312 * @param type $var Description. Default.
1313 * @return type Description.
1314 */
1315
1316 acf.duplicate = function ( args ) {
1317 // allow jQuery
1318 if ( args instanceof jQuery ) {
1319 args = {
1320 target: args,
1321 };
1322 }
1323
1324 // defaults
1325 args = acf.parseArgs( args, {
1326 target: false,
1327 search: '',
1328 replace: '',
1329 rename: true,
1330 before: function ( $el ) {},
1331 after: function ( $el, $el2 ) {},
1332 append: function ( $el, $el2 ) {
1333 $el.after( $el2 );
1334 },
1335 } );
1336
1337 // compatibility
1338 args.target = args.target || args.$el;
1339
1340 // vars
1341 var $el = args.target;
1342
1343 // search
1344 args.search = args.search || $el.attr( 'data-id' );
1345 args.replace = args.replace || acf.uniqid();
1346
1347 // before
1348 // - allow acf to modify DOM
1349 // - fixes bug where select field option is not selected
1350 args.before( $el );
1351 acf.doAction( 'before_duplicate', $el );
1352
1353 // clone
1354 var $el2 = $el.clone();
1355
1356 // rename
1357 if ( args.rename ) {
1358 acf.rename( {
1359 target: $el2,
1360 search: args.search,
1361 replace: args.replace,
1362 replacer: typeof args.rename === 'function' ? args.rename : null,
1363 } );
1364 }
1365
1366 // remove classes
1367 $el2.removeClass( 'acf-clone' );
1368 $el2.find( '.ui-sortable' ).removeClass( 'ui-sortable' );
1369
1370 // remove any initialised select2s prevent the duplicated object stealing the previous select2.
1371 $el2.find( '[data-select2-id]' ).removeAttr( 'data-select2-id' );
1372 $el2.find( '.select2' ).remove();
1373
1374 // subfield select2 renames happen after init and contain a duplicated ID. force change those IDs to prevent this.
1375 $el2.find( '.acf-is-subfields select[data-ui="1"]' ).each( function () {
1376 $( this ).prop(
1377 'id',
1378 $( this )
1379 .prop( 'id' )
1380 .replace( 'acf_fields', acf.uniqid( 'duplicated_' ) + '_acf_fields' )
1381 );
1382 } );
1383
1384 // remove tab wrapper to ensure proper init
1385 $el2.find( '.acf-field-settings > .acf-tab-wrap' ).remove();
1386
1387 // after
1388 // - allow acf to modify DOM
1389 args.after( $el, $el2 );
1390 acf.doAction( 'after_duplicate', $el, $el2 );
1391
1392 // append
1393 args.append( $el, $el2 );
1394
1395 /**
1396 * Fires after an element has been duplicated and appended to the DOM.
1397 *
1398 * @date 30/10/19
1399 * @since ACF 5.8.7
1400 *
1401 * @param jQuery $el The original element.
1402 * @param jQuery $el2 The duplicated element.
1403 */
1404 acf.doAction( 'duplicate', $el, $el2 );
1405
1406 // append
1407 acf.doAction( 'append', $el2 );
1408
1409 // return
1410 return $el2;
1411 };
1412
1413 /**
1414 * rename
1415 *
1416 * description
1417 *
1418 * @date 7/1/18
1419 * @since ACF 5.6.5
1420 *
1421 * @param type $var Description. Default.
1422 * @return type Description.
1423 */
1424
1425 acf.rename = function ( args ) {
1426 // Allow jQuery param.
1427 if ( args instanceof jQuery ) {
1428 args = {
1429 target: args,
1430 };
1431 }
1432
1433 // Apply default args.
1434 args = acf.parseArgs( args, {
1435 target: false,
1436 destructive: false,
1437 search: '',
1438 replace: '',
1439 replacer: null,
1440 } );
1441
1442 // Extract args.
1443 var $el = args.target;
1444
1445 // Provide backup for empty args.
1446 if ( ! args.search ) {
1447 args.search = $el.attr( 'data-id' );
1448 }
1449 if ( ! args.replace ) {
1450 args.replace = acf.uniqid( 'acf' );
1451 }
1452 if ( ! args.replacer ) {
1453 args.replacer = function ( name, value, search, replace ) {
1454 return value.replace( search, replace );
1455 };
1456 }
1457
1458 // Callback function for jQuery replacing.
1459 var withReplacer = function ( name ) {
1460 return function ( i, value ) {
1461 return args.replacer( name, value, args.search, args.replace );
1462 };
1463 };
1464
1465 // Destructive Replace.
1466 if ( args.destructive ) {
1467 var html = acf.strReplace( args.search, args.replace, $el.outerHTML() );
1468 $el.replaceWith( html );
1469
1470 // Standard Replace.
1471 } else {
1472 $el.attr( 'data-id', args.replace );
1473 $el.find( '[id*="' + args.search + '"]' ).attr( 'id', withReplacer( 'id' ) );
1474 $el.find( '[for*="' + args.search + '"]' ).attr( 'for', withReplacer( 'for' ) );
1475 $el.find( '[name*="' + args.search + '"]' ).attr( 'name', withReplacer( 'name' ) );
1476 }
1477
1478 // return
1479 return $el;
1480 };
1481
1482 /**
1483 * Prepares AJAX data prior to being sent.
1484 *
1485 * @since ACF 5.6.5
1486 *
1487 * @param Object data The data to prepare
1488 * @param boolean use_global_nonce Should we ignore any nonce provided in the data object and force ACF's global nonce for this request
1489 * @return Object The prepared data.
1490 */
1491 acf.prepareForAjax = function ( data, use_global_nonce = false ) {
1492 // Set a default nonce if we don't have one already.
1493 if ( use_global_nonce || 'undefined' === typeof data.nonce ) {
1494 data.nonce = acf.get( 'nonce' );
1495 }
1496
1497 data.post_id = acf.get( 'post_id' );
1498
1499 if ( acf.has( 'language' ) ) {
1500 data.lang = acf.get( 'language' );
1501 }
1502
1503 // Filter for 3rd party customization.
1504 data = acf.applyFilters( 'prepare_for_ajax', data );
1505
1506 return data;
1507 };
1508
1509 /**
1510 * acf.startButtonLoading
1511 *
1512 * description
1513 *
1514 * @date 5/1/18
1515 * @since ACF 5.6.5
1516 *
1517 * @param type $var Description. Default.
1518 * @return type Description.
1519 */
1520
1521 acf.startButtonLoading = function ( $el ) {
1522 $el.prop( 'disabled', true );
1523 $el.after( ' <i class="acf-loading"></i>' );
1524 };
1525
1526 acf.stopButtonLoading = function ( $el ) {
1527 $el.prop( 'disabled', false );
1528 $el.next( '.acf-loading' ).remove();
1529 };
1530
1531 /**
1532 * acf.showLoading
1533 *
1534 * description
1535 *
1536 * @date 12/1/18
1537 * @since ACF 5.6.5
1538 *
1539 * @param type $var Description. Default.
1540 * @return type Description.
1541 */
1542
1543 acf.showLoading = function ( $el ) {
1544 $el.append( '<div class="acf-loading-overlay"><i class="acf-loading"></i></div>' );
1545 };
1546
1547 acf.hideLoading = function ( $el ) {
1548 $el.children( '.acf-loading-overlay' ).remove();
1549 };
1550
1551 /**
1552 * acf.updateUserSetting
1553 *
1554 * description
1555 *
1556 * @date 5/1/18
1557 * @since ACF 5.6.5
1558 *
1559 * @param type $var Description. Default.
1560 * @return type Description.
1561 */
1562
1563 acf.updateUserSetting = function ( name, value ) {
1564 var ajaxData = {
1565 action: 'acf/ajax/user_setting',
1566 name: name,
1567 value: value,
1568 };
1569
1570 $.ajax( {
1571 url: acf.get( 'ajaxurl' ),
1572 data: acf.prepareForAjax( ajaxData ),
1573 type: 'post',
1574 dataType: 'html',
1575 } );
1576 };
1577
1578 /**
1579 * acf.val
1580 *
1581 * description
1582 *
1583 * @date 8/1/18
1584 * @since ACF 5.6.5
1585 *
1586 * @param type $var Description. Default.
1587 * @return type Description.
1588 */
1589
1590 acf.val = function ( $input, value, silent ) {
1591 // vars
1592 var prevValue = $input.val();
1593
1594 // bail if no change
1595 if ( value === prevValue ) {
1596 return false;
1597 }
1598
1599 // update value
1600 $input.val( value );
1601
1602 // prevent select elements displaying blank value if option doesn't exist
1603 if ( $input.is( 'select' ) && $input.val() === null ) {
1604 $input.val( prevValue );
1605 return false;
1606 }
1607
1608 // update with trigger
1609 if ( silent !== true ) {
1610 $input.trigger( 'change' );
1611 }
1612
1613 // return
1614 return true;
1615 };
1616
1617 /**
1618 * acf.show
1619 *
1620 * description
1621 *
1622 * @date 9/2/18
1623 * @since ACF 5.6.5
1624 *
1625 * @param type $var Description. Default.
1626 * @return type Description.
1627 */
1628
1629 acf.show = function ( $el, lockKey ) {
1630 // unlock
1631 if ( lockKey ) {
1632 acf.unlock( $el, 'hidden', lockKey );
1633 }
1634
1635 // bail early if $el is still locked
1636 if ( acf.isLocked( $el, 'hidden' ) ) {
1637 //console.log( 'still locked', getLocks( $el, 'hidden' ));
1638 return false;
1639 }
1640
1641 // $el is hidden, remove class and return true due to change in visibility
1642 if ( $el.hasClass( 'acf-hidden' ) ) {
1643 $el.removeClass( 'acf-hidden' );
1644 return true;
1645
1646 // $el is visible, return false due to no change in visibility
1647 } else {
1648 return false;
1649 }
1650 };
1651
1652 /**
1653 * acf.hide
1654 *
1655 * description
1656 *
1657 * @date 9/2/18
1658 * @since ACF 5.6.5
1659 *
1660 * @param type $var Description. Default.
1661 * @return type Description.
1662 */
1663
1664 acf.hide = function ( $el, lockKey ) {
1665 // lock
1666 if ( lockKey ) {
1667 acf.lock( $el, 'hidden', lockKey );
1668 }
1669
1670 // $el is hidden, return false due to no change in visibility
1671 if ( $el.hasClass( 'acf-hidden' ) ) {
1672 return false;
1673
1674 // $el is visible, add class and return true due to change in visibility
1675 } else {
1676 $el.addClass( 'acf-hidden' );
1677 return true;
1678 }
1679 };
1680
1681 /**
1682 * acf.isHidden
1683 *
1684 * description
1685 *
1686 * @date 9/2/18
1687 * @since ACF 5.6.5
1688 *
1689 * @param type $var Description. Default.
1690 * @return type Description.
1691 */
1692
1693 acf.isHidden = function ( $el ) {
1694 return $el.hasClass( 'acf-hidden' );
1695 };
1696
1697 /**
1698 * acf.isVisible
1699 *
1700 * description
1701 *
1702 * @date 9/2/18
1703 * @since ACF 5.6.5
1704 *
1705 * @param type $var Description. Default.
1706 * @return type Description.
1707 */
1708
1709 acf.isVisible = function ( $el ) {
1710 return ! acf.isHidden( $el );
1711 };
1712
1713 /**
1714 * enable
1715 *
1716 * description
1717 *
1718 * @date 12/3/18
1719 * @since ACF 5.6.9
1720 *
1721 * @param type $var Description. Default.
1722 * @return type Description.
1723 */
1724
1725 var enable = function ( $el, lockKey ) {
1726 // check class. Allow .acf-disabled to overrule all JS
1727 if ( $el.hasClass( 'acf-disabled' ) ) {
1728 return false;
1729 }
1730
1731 // unlock
1732 if ( lockKey ) {
1733 acf.unlock( $el, 'disabled', lockKey );
1734 }
1735
1736 // bail early if $el is still locked
1737 if ( acf.isLocked( $el, 'disabled' ) ) {
1738 return false;
1739 }
1740
1741 // $el is disabled, remove prop and return true due to change
1742 if ( $el.prop( 'disabled' ) ) {
1743 $el.prop( 'disabled', false );
1744 return true;
1745
1746 // $el is enabled, return false due to no change
1747 } else {
1748 return false;
1749 }
1750 };
1751
1752 /**
1753 * acf.enable
1754 *
1755 * description
1756 *
1757 * @date 9/2/18
1758 * @since ACF 5.6.5
1759 *
1760 * @param type $var Description. Default.
1761 * @return type Description.
1762 */
1763
1764 acf.enable = function ( $el, lockKey ) {
1765 // enable single input
1766 if ( $el.attr( 'name' ) ) {
1767 return enable( $el, lockKey );
1768 }
1769
1770 // find and enable child inputs
1771 // return true if any inputs have changed
1772 var results = false;
1773 $el.find( '[name]' ).each( function () {
1774 var result = enable( $( this ), lockKey );
1775 if ( result ) {
1776 results = true;
1777 }
1778 } );
1779 return results;
1780 };
1781
1782 /**
1783 * disable
1784 *
1785 * description
1786 *
1787 * @date 12/3/18
1788 * @since ACF 5.6.9
1789 *
1790 * @param type $var Description. Default.
1791 * @return type Description.
1792 */
1793
1794 var disable = function ( $el, lockKey ) {
1795 // lock
1796 if ( lockKey ) {
1797 acf.lock( $el, 'disabled', lockKey );
1798 }
1799
1800 // $el is disabled, return false due to no change
1801 if ( $el.prop( 'disabled' ) ) {
1802 return false;
1803
1804 // $el is enabled, add prop and return true due to change
1805 } else {
1806 $el.prop( 'disabled', true );
1807 return true;
1808 }
1809 };
1810
1811 /**
1812 * acf.disable
1813 *
1814 * description
1815 *
1816 * @date 9/2/18
1817 * @since ACF 5.6.5
1818 *
1819 * @param type $var Description. Default.
1820 * @return type Description.
1821 */
1822
1823 acf.disable = function ( $el, lockKey ) {
1824 // disable single input
1825 if ( $el.attr( 'name' ) ) {
1826 return disable( $el, lockKey );
1827 }
1828
1829 // find and enable child inputs
1830 // return true if any inputs have changed
1831 var results = false;
1832 $el.find( '[name]' ).each( function () {
1833 var result = disable( $( this ), lockKey );
1834 if ( result ) {
1835 results = true;
1836 }
1837 } );
1838 return results;
1839 };
1840
1841 /**
1842 * acf.isset
1843 *
1844 * description
1845 *
1846 * @date 10/1/18
1847 * @since ACF 5.6.5
1848 *
1849 * @param type $var Description. Default.
1850 * @return type Description.
1851 */
1852
1853 acf.isset = function ( obj /*, level1, level2, ... */ ) {
1854 for ( var i = 1; i < arguments.length; i++ ) {
1855 if ( ! obj || ! obj.hasOwnProperty( arguments[ i ] ) ) {
1856 return false;
1857 }
1858 obj = obj[ arguments[ i ] ];
1859 }
1860 return true;
1861 };
1862
1863 /**
1864 * acf.isget
1865 *
1866 * description
1867 *
1868 * @date 10/1/18
1869 * @since ACF 5.6.5
1870 *
1871 * @param type $var Description. Default.
1872 * @return type Description.
1873 */
1874
1875 acf.isget = function ( obj /*, level1, level2, ... */ ) {
1876 for ( var i = 1; i < arguments.length; i++ ) {
1877 if ( ! obj || ! obj.hasOwnProperty( arguments[ i ] ) ) {
1878 return null;
1879 }
1880 obj = obj[ arguments[ i ] ];
1881 }
1882 return obj;
1883 };
1884
1885 /**
1886 * acf.getFileInputData
1887 *
1888 * description
1889 *
1890 * @date 10/1/18
1891 * @since ACF 5.6.5
1892 *
1893 * @param type $var Description. Default.
1894 * @return type Description.
1895 */
1896
1897 acf.getFileInputData = function ( $input, callback ) {
1898 // vars
1899 var value = $input.val();
1900
1901 // bail early if no value
1902 if ( ! value ) {
1903 return false;
1904 }
1905
1906 // data
1907 var data = {
1908 url: value,
1909 };
1910
1911 // modern browsers
1912 var file = $input[ 0 ].files.length ? acf.isget( $input[ 0 ].files, 0 ) : false;
1913 if ( file ) {
1914 // update data
1915 data.size = file.size;
1916 data.type = file.type;
1917
1918 // image
1919 if ( file.type.indexOf( 'image' ) > -1 ) {
1920 // vars
1921 var windowURL = window.URL || window.webkitURL;
1922 var img = new Image();
1923
1924 img.onload = function () {
1925 // update
1926 data.width = this.width;
1927 data.height = this.height;
1928
1929 callback( data );
1930 };
1931 img.src = windowURL.createObjectURL( file );
1932 } else {
1933 callback( data );
1934 }
1935 } else {
1936 callback( data );
1937 }
1938 };
1939
1940 /**
1941 * acf.isAjaxSuccess
1942 *
1943 * description
1944 *
1945 * @date 18/1/18
1946 * @since ACF 5.6.5
1947 *
1948 * @param type $var Description. Default.
1949 * @return type Description.
1950 */
1951
1952 acf.isAjaxSuccess = function ( json ) {
1953 return json && json.success;
1954 };
1955
1956 /**
1957 * acf.getAjaxMessage
1958 *
1959 * description
1960 *
1961 * @date 18/1/18
1962 * @since ACF 5.6.5
1963 *
1964 * @param type $var Description. Default.
1965 * @return type Description.
1966 */
1967
1968 acf.getAjaxMessage = function ( json ) {
1969 return acf.isget( json, 'data', 'message' );
1970 };
1971
1972 /**
1973 * acf.getAjaxError
1974 *
1975 * description
1976 *
1977 * @date 18/1/18
1978 * @since ACF 5.6.5
1979 *
1980 * @param type $var Description. Default.
1981 * @return type Description.
1982 */
1983
1984 acf.getAjaxError = function ( json ) {
1985 return acf.isget( json, 'data', 'error' );
1986 };
1987
1988 /**
1989 * Returns the error message from an XHR object.
1990 *
1991 * @date 17/3/20
1992 * @since ACF 5.8.9
1993 *
1994 * @param object xhr The XHR object.
1995 * @return (string)
1996 */
1997 acf.getXhrError = function ( xhr ) {
1998 if ( xhr.responseJSON ) {
1999 // Responses via `return new WP_Error();`
2000 if ( xhr.responseJSON.message ) {
2001 return xhr.responseJSON.message;
2002 }
2003
2004 // Responses via `wp_send_json_error();`.
2005 if ( xhr.responseJSON.data && xhr.responseJSON.data.error ) {
2006 return xhr.responseJSON.data.error;
2007 }
2008 } else if ( xhr.statusText ) {
2009 return xhr.statusText;
2010 }
2011
2012 return '';
2013 };
2014
2015 /**
2016 * acf.renderSelect
2017 *
2018 * Renders the innter html for a select field.
2019 *
2020 * @date 19/2/18
2021 * @since ACF 5.6.9
2022 *
2023 * @param jQuery $select The select element.
2024 * @param array choices An array of choices.
2025 * @return void
2026 */
2027
2028 acf.renderSelect = function ( $select, choices ) {
2029 // vars
2030 var value = $select.val();
2031 var values = [];
2032
2033 // callback
2034 var crawl = function ( items ) {
2035 // vars
2036 var itemsHtml = '';
2037
2038 // loop
2039 items.map( function ( item ) {
2040 // vars
2041 var text = item.text || item.label || '';
2042 var id = item.id || item.value || '';
2043
2044 // append
2045 values.push( id );
2046
2047 // optgroup
2048 if ( item.children ) {
2049 itemsHtml +=
2050 '<optgroup label="' + acf.escAttr( text ) + '">' + crawl( item.children ) + '</optgroup>';
2051
2052 // option
2053 } else {
2054 itemsHtml +=
2055 '<option value="' +
2056 acf.escAttr( id ) +
2057 '"' +
2058 ( item.disabled ? ' disabled="disabled"' : '' ) +
2059 '>' +
2060 acf.strEscape( text ) +
2061 '</option>';
2062 }
2063 } );
2064 // return
2065 return itemsHtml;
2066 };
2067
2068 // update HTML
2069 $select.html( crawl( choices ) );
2070
2071 // update value
2072 if ( values.indexOf( value ) > -1 ) {
2073 $select.val( value );
2074 }
2075
2076 // return selected value
2077 return $select.val();
2078 };
2079
2080 /**
2081 * acf.lock
2082 *
2083 * Creates a "lock" on an element for a given type and key
2084 *
2085 * @date 22/2/18
2086 * @since ACF 5.6.9
2087 *
2088 * @param jQuery $el The element to lock.
2089 * @param string type The type of lock such as "condition" or "visibility".
2090 * @param string key The key that will be used to unlock.
2091 * @return void
2092 */
2093
2094 var getLocks = function ( $el, type ) {
2095 return $el.data( 'acf-lock-' + type ) || [];
2096 };
2097
2098 var setLocks = function ( $el, type, locks ) {
2099 $el.data( 'acf-lock-' + type, locks );
2100 };
2101
2102 acf.lock = function ( $el, type, key ) {
2103 var locks = getLocks( $el, type );
2104 var i = locks.indexOf( key );
2105 if ( i < 0 ) {
2106 locks.push( key );
2107 setLocks( $el, type, locks );
2108 }
2109 };
2110
2111 /**
2112 * acf.unlock
2113 *
2114 * Unlocks a "lock" on an element for a given type and key
2115 *
2116 * @date 22/2/18
2117 * @since ACF 5.6.9
2118 *
2119 * @param jQuery $el The element to lock.
2120 * @param string type The type of lock such as "condition" or "visibility".
2121 * @param string key The key that will be used to unlock.
2122 * @return void
2123 */
2124
2125 acf.unlock = function ( $el, type, key ) {
2126 var locks = getLocks( $el, type );
2127 var i = locks.indexOf( key );
2128 if ( i > -1 ) {
2129 locks.splice( i, 1 );
2130 setLocks( $el, type, locks );
2131 }
2132
2133 // return true if is unlocked (no locks)
2134 return locks.length === 0;
2135 };
2136
2137 /**
2138 * acf.isLocked
2139 *
2140 * Returns true if a lock exists for a given type
2141 *
2142 * @date 22/2/18
2143 * @since ACF 5.6.9
2144 *
2145 * @param jQuery $el The element to lock.
2146 * @param string type The type of lock such as "condition" or "visibility".
2147 * @return void
2148 */
2149
2150 acf.isLocked = function ( $el, type ) {
2151 return getLocks( $el, type ).length > 0;
2152 };
2153
2154 /**
2155 * acf.isGutenberg
2156 *
2157 * Returns true if the Gutenberg editor is being used.
2158 *
2159 * @since ACF 5.8.0
2160 *
2161 * @return bool
2162 */
2163 acf.isGutenberg = function () {
2164 return !! ( window.wp && wp.data && wp.data.select && wp.data.select( 'core/editor' ) );
2165 };
2166
2167 /**
2168 * acf.isGutenbergPostEditor
2169 *
2170 * Returns true if the Gutenberg post editor is being used.
2171 *
2172 * @since ACF 6.2.2
2173 *
2174 * @return bool
2175 */
2176 acf.isGutenbergPostEditor = function () {
2177 return !! ( window.wp && wp.data && wp.data.select && wp.data.select( 'core/edit-post' ) );
2178 };
2179
2180 /**
2181 * acf.objectToArray
2182 *
2183 * Returns an array of items from the given object.
2184 *
2185 * @date 20/11/18
2186 * @since ACF 5.8.0
2187 *
2188 * @param object obj The object of items.
2189 * @return array
2190 */
2191 acf.objectToArray = function ( obj ) {
2192 return Object.keys( obj ).map( function ( key ) {
2193 return obj[ key ];
2194 } );
2195 };
2196
2197 /**
2198 * acf.debounce
2199 *
2200 * 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.
2201 *
2202 * @date 28/8/19
2203 * @since ACF 5.8.1
2204 *
2205 * @param function callback The callback function.
2206 * @return int wait The number of milliseconds to wait.
2207 */
2208 acf.debounce = function ( callback, wait ) {
2209 var timeout;
2210 return function () {
2211 var context = this;
2212 var args = arguments;
2213 var later = function () {
2214 callback.apply( context, args );
2215 };
2216 clearTimeout( timeout );
2217 timeout = setTimeout( later, wait );
2218 };
2219 };
2220
2221 /**
2222 * acf.throttle
2223 *
2224 * Returns a throttled version of the passed function which will allow only one execution per `limit` time period.
2225 *
2226 * @date 28/8/19
2227 * @since ACF 5.8.1
2228 *
2229 * @param function callback The callback function.
2230 * @return int wait The number of milliseconds to wait.
2231 */
2232 acf.throttle = function ( callback, limit ) {
2233 var busy = false;
2234 return function () {
2235 if ( busy ) return;
2236 busy = true;
2237 setTimeout( function () {
2238 busy = false;
2239 }, limit );
2240 callback.apply( this, arguments );
2241 };
2242 };
2243
2244 /**
2245 * acf.isInView
2246 *
2247 * Returns true if the given element is in view.
2248 *
2249 * @date 29/8/19
2250 * @since ACF 5.8.1
2251 *
2252 * @param elem el The dom element to inspect.
2253 * @return bool
2254 */
2255 acf.isInView = function ( el ) {
2256 if ( el instanceof jQuery ) {
2257 el = el[ 0 ];
2258 }
2259 var rect = el.getBoundingClientRect();
2260 return (
2261 rect.top !== rect.bottom &&
2262 rect.top >= 0 &&
2263 rect.left >= 0 &&
2264 rect.bottom <= ( window.innerHeight || document.documentElement.clientHeight ) &&
2265 rect.right <= ( window.innerWidth || document.documentElement.clientWidth )
2266 );
2267 };
2268
2269 /**
2270 * acf.onceInView
2271 *
2272 * Watches for a dom element to become visible in the browser and then excecutes the passed callback.
2273 *
2274 * @date 28/8/19
2275 * @since ACF 5.8.1
2276 *
2277 * @param dom el The dom element to inspect.
2278 * @param function callback The callback function.
2279 */
2280 acf.onceInView = ( function () {
2281 // Define list.
2282 var items = [];
2283 var id = 0;
2284
2285 // Define check function.
2286 var check = function () {
2287 items.forEach( function ( item ) {
2288 if ( acf.isInView( item.el ) ) {
2289 item.callback.apply( this );
2290 pop( item.id );
2291 }
2292 } );
2293 };
2294
2295 // And create a debounced version.
2296 var debounced = acf.debounce( check, 300 );
2297
2298 // Define add function.
2299 var push = function ( el, callback ) {
2300 // Add event listener.
2301 if ( ! items.length ) {
2302 $( window ).on( 'scroll resize', debounced ).on( 'acfrefresh orientationchange', check );
2303 }
2304
2305 // Append to list.
2306 items.push( { id: id++, el: el, callback: callback } );
2307 };
2308
2309 // Define remove function.
2310 var pop = function ( id ) {
2311 // Remove from list.
2312 items = items.filter( function ( item ) {
2313 return item.id !== id;
2314 } );
2315
2316 // Clean up listener.
2317 if ( ! items.length ) {
2318 $( window ).off( 'scroll resize', debounced ).off( 'acfrefresh orientationchange', check );
2319 }
2320 };
2321
2322 // Define returned function.
2323 return function ( el, callback ) {
2324 // Allow jQuery object.
2325 if ( el instanceof jQuery ) el = el[ 0 ];
2326
2327 // Execute callback if already in view or add to watch list.
2328 if ( acf.isInView( el ) ) {
2329 callback.apply( this );
2330 } else {
2331 push( el, callback );
2332 }
2333 };
2334 } )();
2335
2336 /**
2337 * acf.once
2338 *
2339 * Creates a function that is restricted to invoking `func` once.
2340 *
2341 * @date 2/9/19
2342 * @since ACF 5.8.1
2343 *
2344 * @param function func The function to restrict.
2345 * @return function
2346 */
2347 acf.once = function ( func ) {
2348 var i = 0;
2349 return function () {
2350 if ( i++ > 0 ) {
2351 return ( func = undefined );
2352 }
2353 return func.apply( this, arguments );
2354 };
2355 };
2356
2357 /**
2358 * Focuses attention to a specific element.
2359 *
2360 * @date 05/05/2020
2361 * @since ACF 5.9.0
2362 *
2363 * @param jQuery $el The jQuery element to focus.
2364 * @return void
2365 */
2366 acf.focusAttention = function ( $el ) {
2367 var wait = 1000;
2368
2369 // Apply class to focus attention.
2370 $el.addClass( 'acf-attention -focused' );
2371
2372 // Scroll to element if needed.
2373 var scrollTime = 500;
2374 if ( ! acf.isInView( $el ) ) {
2375 $( 'body, html' ).animate(
2376 {
2377 scrollTop: $el.offset().top - $( window ).height() / 2,
2378 },
2379 scrollTime
2380 );
2381 wait += scrollTime;
2382 }
2383
2384 // Remove class after $wait amount of time.
2385 var fadeTime = 250;
2386 setTimeout( function () {
2387 $el.removeClass( '-focused' );
2388 setTimeout( function () {
2389 $el.removeClass( 'acf-attention' );
2390 }, fadeTime );
2391 }, wait );
2392 };
2393
2394 /**
2395 * Description
2396 *
2397 * @date 05/05/2020
2398 * @since ACF 5.9.0
2399 *
2400 * @param type Var Description.
2401 * @return type Description.
2402 */
2403 acf.onFocus = function ( $el, callback ) {
2404 // Only run once per element.
2405 // if( $el.data('acf.onFocus') ) {
2406 // return false;
2407 // }
2408
2409 // Vars.
2410 var ignoreBlur = false;
2411 var focus = false;
2412
2413 // Functions.
2414 var onFocus = function () {
2415 ignoreBlur = true;
2416 setTimeout( function () {
2417 ignoreBlur = false;
2418 }, 1 );
2419 setFocus( true );
2420 };
2421 var onBlur = function () {
2422 if ( ! ignoreBlur ) {
2423 setFocus( false );
2424 }
2425 };
2426 var addEvents = function () {
2427 $( document ).on( 'click', onBlur );
2428 //$el.on('acfBlur', onBlur);
2429 $el.on( 'blur', 'input, select, textarea', onBlur );
2430 };
2431 var removeEvents = function () {
2432 $( document ).off( 'click', onBlur );
2433 //$el.off('acfBlur', onBlur);
2434 $el.off( 'blur', 'input, select, textarea', onBlur );
2435 };
2436 var setFocus = function ( value ) {
2437 if ( focus === value ) {
2438 return;
2439 }
2440 if ( value ) {
2441 addEvents();
2442 } else {
2443 removeEvents();
2444 }
2445 focus = value;
2446 callback( value );
2447 };
2448
2449 // Add events and set data.
2450 $el.on( 'click', onFocus );
2451 //$el.on('acfFocus', onFocus);
2452 $el.on( 'focus', 'input, select, textarea', onFocus );
2453 //$el.data('acf.onFocus', true);
2454 };
2455
2456 /**
2457 * Disable form submit buttons
2458 *
2459 * @since ACF 6.2.3
2460 *
2461 * @param event e
2462 * @returns void
2463 */
2464 acf.disableForm = function ( e ) {
2465 // Disable submit button.
2466 if ( e.submitter ) e.submitter.classList.add( 'disabled' );
2467 };
2468
2469 /*
2470 * exists
2471 *
2472 * This function will return true if a jQuery selection exists
2473 *
2474 * @type function
2475 * @date 8/09/2014
2476 * @since ACF 5.0.0
2477 *
2478 * @param n/a
2479 * @return (boolean)
2480 */
2481
2482 $.fn.exists = function () {
2483 return $( this ).length > 0;
2484 };
2485
2486 /*
2487 * outerHTML
2488 *
2489 * This function will return a string containing the HTML of the selected element
2490 *
2491 * @type function
2492 * @date 19/11/2013
2493 * @since ACF 5.0.0
2494 *
2495 * @param $.fn
2496 * @return (string)
2497 */
2498
2499 $.fn.outerHTML = function () {
2500 return $( this ).get( 0 ).outerHTML;
2501 };
2502
2503 /*
2504 * indexOf
2505 *
2506 * This function will provide compatibility for ie8
2507 *
2508 * @type function
2509 * @date 5/3/17
2510 * @since ACF 5.5.10
2511 *
2512 * @param n/a
2513 * @return n/a
2514 */
2515
2516 if ( ! Array.prototype.indexOf ) {
2517 Array.prototype.indexOf = function ( val ) {
2518 return $.inArray( val, this );
2519 };
2520 }
2521
2522 /**
2523 * Returns true if value is a number or a numeric string.
2524 *
2525 * @date 30/11/20
2526 * @since ACF 5.9.4
2527 * @link https://stackoverflow.com/questions/9716468/pure-javascript-a-function-like-jquerys-isnumeric/9716488#9716488
2528 *
2529 * @param mixed n The variable being evaluated.
2530 * @return bool.
2531 */
2532 acf.isNumeric = function ( n ) {
2533 return ! isNaN( parseFloat( n ) ) && isFinite( n );
2534 };
2535
2536 /**
2537 * Triggers a "refresh" action used by various Components to redraw the DOM.
2538 *
2539 * @date 26/05/2020
2540 * @since ACF 5.9.0
2541 *
2542 * @param void
2543 * @return void
2544 */
2545 acf.refresh = acf.debounce( function () {
2546 $( window ).trigger( 'acfrefresh' );
2547 acf.doAction( 'refresh' );
2548 }, 0 );
2549
2550 /**
2551 * Log something to console if we're in debug mode.
2552 *
2553 * @since ACF 6.3
2554 */
2555 acf.debug = function () {
2556 if ( acf.get( 'debug' ) ) console.log.apply( null, arguments );
2557 };
2558
2559 // Set up actions from events
2560 $( document ).ready( function () {
2561 acf.doAction( 'ready' );
2562 } );
2563
2564 $( window ).on( 'load', function () {
2565 // Use timeout to ensure action runs after Gutenberg has modified DOM elements during "DOMContentLoaded".
2566 setTimeout( function () {
2567 acf.doAction( 'load' );
2568 } );
2569 } );
2570
2571 $( window ).on( 'beforeunload', function () {
2572 acf.doAction( 'unload' );
2573 } );
2574
2575 $( window ).on( 'resize', function () {
2576 acf.doAction( 'resize' );
2577 } );
2578
2579 $( document ).on( 'sortstart', function ( event, ui ) {
2580 acf.doAction( 'sortstart', ui.item, ui.placeholder );
2581 } );
2582
2583 $( document ).on( 'sortstop', function ( event, ui ) {
2584 acf.doAction( 'sortstop', ui.item, ui.placeholder );
2585 } );
2586 } )( jQuery );
2587