PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.5.2
Secure Custom Fields v6.5.2
6.9.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
bindings 11 months ago commands 1 year ago 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
2586 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 // Make sure a global acfL10n object exists to prevent errors in other scopes
680 window.acfL10n = window.acfL10n || {};
681
682 acf.__ = function ( text ) {
683 return acfL10n[ text ] || text;
684 };
685
686 /**
687 * _x
688 *
689 * Retrieve translated string with gettext context.
690 *
691 * @date 16/4/18
692 * @since ACF 5.6.9
693 *
694 * @param string text Text to translate.
695 * @param string context Context information for the translators.
696 * @return string Translated text.
697 */
698
699 acf._x = function ( text, context ) {
700 return acfL10n[ text + '.' + context ] || acfL10n[ text ] || text;
701 };
702
703 /**
704 * _n
705 *
706 * Retrieve the plural or single form based on the amount.
707 *
708 * @date 16/4/18
709 * @since ACF 5.6.9
710 *
711 * @param string single Single text to translate.
712 * @param string plural Plural text to translate.
713 * @param int number The number to compare against.
714 * @return string Translated text.
715 */
716
717 acf._n = function ( single, plural, number ) {
718 if ( number == 1 ) {
719 return acf.__( single );
720 } else {
721 return acf.__( plural );
722 }
723 };
724
725 acf.isArray = function ( a ) {
726 return Array.isArray( a );
727 };
728
729 acf.isObject = function ( a ) {
730 return typeof a === 'object';
731 };
732
733 /**
734 * serialize
735 *
736 * description
737 *
738 * @date 24/12/17
739 * @since ACF 5.6.5
740 *
741 * @param type $var Description. Default.
742 * @return type Description.
743 */
744
745 var buildObject = function ( obj, name, value ) {
746 // replace [] with placeholder
747 name = name.replace( '[]', '[%%index%%]' );
748
749 // vars
750 var keys = name.match( /([^\[\]])+/g );
751 if ( ! keys ) return;
752 var length = keys.length;
753 var ref = obj;
754
755 // loop
756 for ( var i = 0; i < length; i++ ) {
757 // vars
758 var key = String( keys[ i ] );
759
760 // value
761 if ( i == length - 1 ) {
762 // %%index%%
763 if ( key === '%%index%%' ) {
764 ref.push( value );
765
766 // default
767 } else {
768 ref[ key ] = value;
769 }
770
771 // path
772 } else {
773 // array
774 if ( keys[ i + 1 ] === '%%index%%' ) {
775 if ( ! acf.isArray( ref[ key ] ) ) {
776 ref[ key ] = [];
777 }
778
779 // object
780 } else {
781 if ( ! acf.isObject( ref[ key ] ) ) {
782 ref[ key ] = {};
783 }
784 }
785
786 // crawl
787 ref = ref[ key ];
788 }
789 }
790 };
791
792 acf.serialize = function ( $el, prefix ) {
793 // vars
794 var obj = {};
795 var inputs = acf.serializeArray( $el );
796
797 // prefix
798 if ( prefix !== undefined ) {
799 // filter and modify
800 inputs = inputs
801 .filter( function ( item ) {
802 return item.name.indexOf( prefix ) === 0;
803 } )
804 .map( function ( item ) {
805 item.name = item.name.slice( prefix.length );
806 return item;
807 } );
808 }
809
810 // loop
811 for ( var i = 0; i < inputs.length; i++ ) {
812 buildObject( obj, inputs[ i ].name, inputs[ i ].value );
813 }
814
815 // return
816 return obj;
817 };
818
819 /**
820 * acf.serializeArray
821 *
822 * Similar to $.serializeArray() but works with a parent wrapping element.
823 *
824 * @date 19/8/18
825 * @since ACF 5.7.3
826 *
827 * @param jQuery $el The element or form to serialize.
828 * @return array
829 */
830
831 acf.serializeArray = function ( $el ) {
832 return $el.find( 'select, textarea, input' ).serializeArray();
833 };
834
835 /**
836 * acf.serializeForAjax
837 *
838 * Returns an object containing name => value data ready to be encoded for Ajax.
839 *
840 * @date 17/12/18
841 * @since ACF 5.8.0
842 *
843 * @param jQuery $el The element or form to serialize.
844 * @return object
845 */
846 acf.serializeForAjax = function ( $el ) {
847 // vars
848 var data = {};
849 var index = {};
850
851 // Serialize inputs.
852 var inputs = acf.serializeArray( $el );
853
854 // Loop over inputs and build data.
855 inputs.map( function ( item ) {
856 // Append to array.
857 if ( item.name.slice( -2 ) === '[]' ) {
858 data[ item.name ] = data[ item.name ] || [];
859 data[ item.name ].push( item.value );
860 // Append
861 } else {
862 data[ item.name ] = item.value;
863 }
864 } );
865
866 // return
867 return data;
868 };
869
870 /**
871 * addAction
872 *
873 * Wrapper for acf.hooks.addAction
874 *
875 * @date 14/12/17
876 * @since ACF 5.6.5
877 *
878 * @param n/a
879 * @return this
880 */
881
882 /*
883 var prefixAction = function( action ){
884 return 'acf_' + action;
885 }
886 */
887
888 acf.addAction = function ( action, callback, priority, context ) {
889 //action = prefixAction(action);
890 acf.hooks.addAction.apply( this, arguments );
891 return this;
892 };
893
894 /**
895 * removeAction
896 *
897 * Wrapper for acf.hooks.removeAction
898 *
899 * @date 14/12/17
900 * @since ACF 5.6.5
901 *
902 * @param n/a
903 * @return this
904 */
905
906 acf.removeAction = function ( action, callback ) {
907 //action = prefixAction(action);
908 acf.hooks.removeAction.apply( this, arguments );
909 return this;
910 };
911
912 /**
913 * doAction
914 *
915 * Wrapper for acf.hooks.doAction
916 *
917 * @date 14/12/17
918 * @since ACF 5.6.5
919 *
920 * @param n/a
921 * @return this
922 */
923
924 var actionHistory = {};
925 //var currentAction = false;
926 acf.doAction = function ( action ) {
927 //action = prefixAction(action);
928 //currentAction = action;
929 actionHistory[ action ] = 1;
930 acf.hooks.doAction.apply( this, arguments );
931 actionHistory[ action ] = 0;
932 return this;
933 };
934
935 /**
936 * doingAction
937 *
938 * Return true if doing action
939 *
940 * @date 14/12/17
941 * @since ACF 5.6.5
942 *
943 * @param n/a
944 * @return this
945 */
946
947 acf.doingAction = function ( action ) {
948 //action = prefixAction(action);
949 return actionHistory[ action ] === 1;
950 };
951
952 /**
953 * didAction
954 *
955 * Wrapper for acf.hooks.doAction
956 *
957 * @date 14/12/17
958 * @since ACF 5.6.5
959 *
960 * @param n/a
961 * @return this
962 */
963
964 acf.didAction = function ( action ) {
965 //action = prefixAction(action);
966 return actionHistory[ action ] !== undefined;
967 };
968
969 /**
970 * currentAction
971 *
972 * Wrapper for acf.hooks.doAction
973 *
974 * @date 14/12/17
975 * @since ACF 5.6.5
976 *
977 * @param n/a
978 * @return this
979 */
980
981 acf.currentAction = function () {
982 for ( var k in actionHistory ) {
983 if ( actionHistory[ k ] ) {
984 return k;
985 }
986 }
987 return false;
988 };
989
990 /**
991 * addFilter
992 *
993 * Wrapper for acf.hooks.addFilter
994 *
995 * @date 14/12/17
996 * @since ACF 5.6.5
997 *
998 * @param n/a
999 * @return this
1000 */
1001
1002 acf.addFilter = function ( action ) {
1003 //action = prefixAction(action);
1004 acf.hooks.addFilter.apply( this, arguments );
1005 return this;
1006 };
1007
1008 /**
1009 * removeFilter
1010 *
1011 * Wrapper for acf.hooks.removeFilter
1012 *
1013 * @date 14/12/17
1014 * @since ACF 5.6.5
1015 *
1016 * @param n/a
1017 * @return this
1018 */
1019
1020 acf.removeFilter = function ( action ) {
1021 //action = prefixAction(action);
1022 acf.hooks.removeFilter.apply( this, arguments );
1023 return this;
1024 };
1025
1026 /**
1027 * applyFilters
1028 *
1029 * Wrapper for acf.hooks.applyFilters
1030 *
1031 * @date 14/12/17
1032 * @since ACF 5.6.5
1033 *
1034 * @param n/a
1035 * @return this
1036 */
1037
1038 acf.applyFilters = function ( action ) {
1039 //action = prefixAction(action);
1040 return acf.hooks.applyFilters.apply( this, arguments );
1041 };
1042
1043 /**
1044 * getArgs
1045 *
1046 * description
1047 *
1048 * @date 15/12/17
1049 * @since ACF 5.6.5
1050 *
1051 * @param type $var Description. Default.
1052 * @return type Description.
1053 */
1054
1055 acf.arrayArgs = function ( args ) {
1056 return Array.prototype.slice.call( args );
1057 };
1058
1059 /**
1060 * extendArgs
1061 *
1062 * description
1063 *
1064 * @date 15/12/17
1065 * @since ACF 5.6.5
1066 *
1067 * @param type $var Description. Default.
1068 * @return type Description.
1069 */
1070
1071 /*
1072 acf.extendArgs = function( ){
1073 var args = Array.prototype.slice.call( arguments );
1074 var realArgs = args.shift();
1075
1076 Array.prototype.push.call(arguments, 'bar')
1077 return Array.prototype.push.apply( args, arguments );
1078 };
1079 */
1080
1081 // Preferences
1082 // - use try/catch to avoid JS error if cookies are disabled on front-end form
1083 try {
1084 var preferences = JSON.parse( localStorage.getItem( 'acf' ) ) || {};
1085 } catch ( e ) {
1086 var preferences = {};
1087 }
1088
1089 /**
1090 * getPreferenceName
1091 *
1092 * Gets the true preference name.
1093 * Converts "this.thing" to "thing-123" if editing post 123.
1094 *
1095 * @date 11/11/17
1096 * @since ACF 5.6.5
1097 *
1098 * @param string name
1099 * @return string
1100 */
1101
1102 var getPreferenceName = function ( name ) {
1103 if ( name.substr( 0, 5 ) === 'this.' ) {
1104 name = name.substr( 5 ) + '-' + acf.get( 'post_id' );
1105 }
1106 return name;
1107 };
1108
1109 /**
1110 * acf.getPreference
1111 *
1112 * Gets a preference setting or null if not set.
1113 *
1114 * @date 11/11/17
1115 * @since ACF 5.6.5
1116 *
1117 * @param string name
1118 * @return mixed
1119 */
1120
1121 acf.getPreference = function ( name ) {
1122 name = getPreferenceName( name );
1123 return preferences[ name ] || null;
1124 };
1125
1126 /**
1127 * acf.setPreference
1128 *
1129 * Sets a preference setting.
1130 *
1131 * @date 11/11/17
1132 * @since ACF 5.6.5
1133 *
1134 * @param string name
1135 * @param mixed value
1136 * @return n/a
1137 */
1138
1139 acf.setPreference = function ( name, value ) {
1140 name = getPreferenceName( name );
1141 if ( value === null ) {
1142 delete preferences[ name ];
1143 } else {
1144 preferences[ name ] = value;
1145 }
1146 localStorage.setItem( 'acf', JSON.stringify( preferences ) );
1147 };
1148
1149 /**
1150 * acf.removePreference
1151 *
1152 * Removes a preference setting.
1153 *
1154 * @date 11/11/17
1155 * @since ACF 5.6.5
1156 *
1157 * @param string name
1158 * @return n/a
1159 */
1160
1161 acf.removePreference = function ( name ) {
1162 acf.setPreference( name, null );
1163 };
1164
1165 /**
1166 * remove
1167 *
1168 * Removes an element with fade effect
1169 *
1170 * @date 1/1/18
1171 * @since ACF 5.6.5
1172 *
1173 * @param type $var Description. Default.
1174 * @return type Description.
1175 */
1176
1177 acf.remove = function ( props ) {
1178 // allow jQuery
1179 if ( props instanceof jQuery ) {
1180 props = {
1181 target: props,
1182 };
1183 }
1184
1185 // defaults
1186 props = acf.parseArgs( props, {
1187 target: false,
1188 endHeight: 0,
1189 complete: function () {},
1190 } );
1191
1192 // action
1193 acf.doAction( 'remove', props.target );
1194
1195 // tr
1196 if ( props.target.is( 'tr' ) ) {
1197 removeTr( props );
1198
1199 // div
1200 } else {
1201 removeDiv( props );
1202 }
1203 };
1204
1205 /**
1206 * removeDiv
1207 *
1208 * description
1209 *
1210 * @date 16/2/18
1211 * @since ACF 5.6.9
1212 *
1213 * @param type $var Description. Default.
1214 * @return type Description.
1215 */
1216
1217 var removeDiv = function ( props ) {
1218 // vars
1219 var $el = props.target;
1220 var height = $el.height();
1221 var width = $el.width();
1222 var margin = $el.css( 'margin' );
1223 var outerHeight = $el.outerHeight( true );
1224 var style = $el.attr( 'style' ) + ''; // needed to copy
1225
1226 // wrap
1227 $el.wrap( '<div class="acf-temp-remove" style="height:' + outerHeight + 'px"></div>' );
1228 var $wrap = $el.parent();
1229
1230 // set pos
1231 $el.css( {
1232 height: height,
1233 width: width,
1234 margin: margin,
1235 position: 'absolute',
1236 } );
1237
1238 // fade wrap
1239 setTimeout( function () {
1240 $wrap.css( {
1241 opacity: 0,
1242 height: props.endHeight,
1243 } );
1244 }, 50 );
1245
1246 // remove
1247 setTimeout( function () {
1248 $el.attr( 'style', style );
1249 $wrap.remove();
1250 props.complete();
1251 }, 301 );
1252 };
1253
1254 /**
1255 * removeTr
1256 *
1257 * description
1258 *
1259 * @date 16/2/18
1260 * @since ACF 5.6.9
1261 *
1262 * @param type $var Description. Default.
1263 * @return type Description.
1264 */
1265
1266 var removeTr = function ( props ) {
1267 // vars
1268 var $tr = props.target;
1269 var height = $tr.height();
1270 var children = $tr.children().length;
1271
1272 // create dummy td
1273 var $td = $(
1274 '<td class="acf-temp-remove" style="padding:0; height:' + height + 'px" colspan="' + children + '"></td>'
1275 );
1276
1277 // fade away tr
1278 $tr.addClass( 'acf-remove-element' );
1279
1280 // update HTML after fade animation
1281 setTimeout( function () {
1282 $tr.html( $td );
1283 }, 251 );
1284
1285 // allow .acf-temp-remove to exist before changing CSS
1286 setTimeout( function () {
1287 // remove class
1288 $tr.removeClass( 'acf-remove-element' );
1289
1290 // collapse
1291 $td.css( {
1292 height: props.endHeight,
1293 } );
1294 }, 300 );
1295
1296 // remove
1297 setTimeout( function () {
1298 $tr.remove();
1299 props.complete();
1300 }, 451 );
1301 };
1302
1303 /**
1304 * duplicate
1305 *
1306 * description
1307 *
1308 * @date 3/1/18
1309 * @since ACF 5.6.5
1310 *
1311 * @param type $var Description. Default.
1312 * @return type Description.
1313 */
1314
1315 acf.duplicate = function ( args ) {
1316 // allow jQuery
1317 if ( args instanceof jQuery ) {
1318 args = {
1319 target: args,
1320 };
1321 }
1322
1323 // defaults
1324 args = acf.parseArgs( args, {
1325 target: false,
1326 search: '',
1327 replace: '',
1328 rename: true,
1329 before: function ( $el ) {},
1330 after: function ( $el, $el2 ) {},
1331 append: function ( $el, $el2 ) {
1332 $el.after( $el2 );
1333 },
1334 } );
1335
1336 // compatibility
1337 args.target = args.target || args.$el;
1338
1339 // vars
1340 var $el = args.target;
1341
1342 // search
1343 args.search = args.search || $el.attr( 'data-id' );
1344 args.replace = args.replace || acf.uniqid();
1345
1346 // before
1347 // - allow acf to modify DOM
1348 // - fixes bug where select field option is not selected
1349 args.before( $el );
1350 acf.doAction( 'before_duplicate', $el );
1351
1352 // clone
1353 var $el2 = $el.clone();
1354
1355 // rename
1356 if ( args.rename ) {
1357 acf.rename( {
1358 target: $el2,
1359 search: args.search,
1360 replace: args.replace,
1361 replacer: typeof args.rename === 'function' ? args.rename : null,
1362 } );
1363 }
1364
1365 // remove classes
1366 $el2.removeClass( 'acf-clone' );
1367 $el2.find( '.ui-sortable' ).removeClass( 'ui-sortable' );
1368
1369 // remove any initialised select2s prevent the duplicated object stealing the previous select2.
1370 $el2.find( '[data-select2-id]' ).removeAttr( 'data-select2-id' );
1371 $el2.find( '.select2' ).remove();
1372
1373 // subfield select2 renames happen after init and contain a duplicated ID. force change those IDs to prevent this.
1374 $el2.find( '.acf-is-subfields select[data-ui="1"]' ).each( function () {
1375 $( this ).prop(
1376 'id',
1377 $( this )
1378 .prop( 'id' )
1379 .replace( 'acf_fields', acf.uniqid( 'duplicated_' ) + '_acf_fields' )
1380 );
1381 } );
1382
1383 // remove tab wrapper to ensure proper init
1384 $el2.find( '.acf-field-settings > .acf-tab-wrap' ).remove();
1385
1386 // after
1387 // - allow acf to modify DOM
1388 args.after( $el, $el2 );
1389 acf.doAction( 'after_duplicate', $el, $el2 );
1390
1391 // append
1392 args.append( $el, $el2 );
1393
1394 /**
1395 * Fires after an element has been duplicated and appended to the DOM.
1396 *
1397 * @date 30/10/19
1398 * @since ACF 5.8.7
1399 *
1400 * @param jQuery $el The original element.
1401 * @param jQuery $el2 The duplicated element.
1402 */
1403 acf.doAction( 'duplicate', $el, $el2 );
1404
1405 // append
1406 acf.doAction( 'append', $el2 );
1407
1408 // return
1409 return $el2;
1410 };
1411
1412 /**
1413 * rename
1414 *
1415 * description
1416 *
1417 * @date 7/1/18
1418 * @since ACF 5.6.5
1419 *
1420 * @param type $var Description. Default.
1421 * @return type Description.
1422 */
1423
1424 acf.rename = function ( args ) {
1425 // Allow jQuery param.
1426 if ( args instanceof jQuery ) {
1427 args = {
1428 target: args,
1429 };
1430 }
1431
1432 // Apply default args.
1433 args = acf.parseArgs( args, {
1434 target: false,
1435 destructive: false,
1436 search: '',
1437 replace: '',
1438 replacer: null,
1439 } );
1440
1441 // Extract args.
1442 var $el = args.target;
1443
1444 // Provide backup for empty args.
1445 if ( ! args.search ) {
1446 args.search = $el.attr( 'data-id' );
1447 }
1448 if ( ! args.replace ) {
1449 args.replace = acf.uniqid( 'acf' );
1450 }
1451 if ( ! args.replacer ) {
1452 args.replacer = function ( name, value, search, replace ) {
1453 return value.replace( search, replace );
1454 };
1455 }
1456
1457 // Callback function for jQuery replacing.
1458 var withReplacer = function ( name ) {
1459 return function ( i, value ) {
1460 return args.replacer( name, value, args.search, args.replace );
1461 };
1462 };
1463
1464 // Destructive Replace.
1465 if ( args.destructive ) {
1466 var html = acf.strReplace( args.search, args.replace, $el.outerHTML() );
1467 $el.replaceWith( html );
1468
1469 // Standard Replace.
1470 } else {
1471 $el.attr( 'data-id', args.replace );
1472 $el.find( '[id*="' + args.search + '"]' ).attr( 'id', withReplacer( 'id' ) );
1473 $el.find( '[for*="' + args.search + '"]' ).attr( 'for', withReplacer( 'for' ) );
1474 $el.find( '[name*="' + args.search + '"]' ).attr( 'name', withReplacer( 'name' ) );
1475 }
1476
1477 // return
1478 return $el;
1479 };
1480
1481 /**
1482 * Prepares AJAX data prior to being sent.
1483 *
1484 * @since ACF 5.6.5
1485 *
1486 * @param Object data The data to prepare
1487 * @param boolean use_global_nonce Should we ignore any nonce provided in the data object and force ACF's global nonce for this request
1488 * @return Object The prepared data.
1489 */
1490 acf.prepareForAjax = function ( data, use_global_nonce = false ) {
1491 // Set a default nonce if we don't have one already.
1492 if ( use_global_nonce || 'undefined' === typeof data.nonce ) {
1493 data.nonce = acf.get( 'nonce' );
1494 }
1495
1496 data.post_id = acf.get( 'post_id' );
1497
1498 if ( acf.has( 'language' ) ) {
1499 data.lang = acf.get( 'language' );
1500 }
1501
1502 // Filter for 3rd party customization.
1503 data = acf.applyFilters( 'prepare_for_ajax', data );
1504
1505 return data;
1506 };
1507
1508 /**
1509 * acf.startButtonLoading
1510 *
1511 * description
1512 *
1513 * @date 5/1/18
1514 * @since ACF 5.6.5
1515 *
1516 * @param type $var Description. Default.
1517 * @return type Description.
1518 */
1519
1520 acf.startButtonLoading = function ( $el ) {
1521 $el.prop( 'disabled', true );
1522 $el.after( ' <i class="acf-loading"></i>' );
1523 };
1524
1525 acf.stopButtonLoading = function ( $el ) {
1526 $el.prop( 'disabled', false );
1527 $el.next( '.acf-loading' ).remove();
1528 };
1529
1530 /**
1531 * acf.showLoading
1532 *
1533 * description
1534 *
1535 * @date 12/1/18
1536 * @since ACF 5.6.5
1537 *
1538 * @param type $var Description. Default.
1539 * @return type Description.
1540 */
1541
1542 acf.showLoading = function ( $el ) {
1543 $el.append( '<div class="acf-loading-overlay"><i class="acf-loading"></i></div>' );
1544 };
1545
1546 acf.hideLoading = function ( $el ) {
1547 $el.children( '.acf-loading-overlay' ).remove();
1548 };
1549
1550 /**
1551 * acf.updateUserSetting
1552 *
1553 * description
1554 *
1555 * @date 5/1/18
1556 * @since ACF 5.6.5
1557 *
1558 * @param type $var Description. Default.
1559 * @return type Description.
1560 */
1561
1562 acf.updateUserSetting = function ( name, value ) {
1563 var ajaxData = {
1564 action: 'acf/ajax/user_setting',
1565 name: name,
1566 value: value,
1567 };
1568
1569 $.ajax( {
1570 url: acf.get( 'ajaxurl' ),
1571 data: acf.prepareForAjax( ajaxData ),
1572 type: 'post',
1573 dataType: 'html',
1574 } );
1575 };
1576
1577 /**
1578 * acf.val
1579 *
1580 * description
1581 *
1582 * @date 8/1/18
1583 * @since ACF 5.6.5
1584 *
1585 * @param type $var Description. Default.
1586 * @return type Description.
1587 */
1588
1589 acf.val = function ( $input, value, silent ) {
1590 // vars
1591 var prevValue = $input.val();
1592
1593 // bail if no change
1594 if ( value === prevValue ) {
1595 return false;
1596 }
1597
1598 // update value
1599 $input.val( value );
1600
1601 // prevent select elements displaying blank value if option doesn't exist
1602 if ( $input.is( 'select' ) && $input.val() === null ) {
1603 $input.val( prevValue );
1604 return false;
1605 }
1606
1607 // update with trigger
1608 if ( silent !== true ) {
1609 $input.trigger( 'change' );
1610 }
1611
1612 // return
1613 return true;
1614 };
1615
1616 /**
1617 * acf.show
1618 *
1619 * description
1620 *
1621 * @date 9/2/18
1622 * @since ACF 5.6.5
1623 *
1624 * @param type $var Description. Default.
1625 * @return type Description.
1626 */
1627
1628 acf.show = function ( $el, lockKey ) {
1629 // unlock
1630 if ( lockKey ) {
1631 acf.unlock( $el, 'hidden', lockKey );
1632 }
1633
1634 // bail early if $el is still locked
1635 if ( acf.isLocked( $el, 'hidden' ) ) {
1636 //console.log( 'still locked', getLocks( $el, 'hidden' ));
1637 return false;
1638 }
1639
1640 // $el is hidden, remove class and return true due to change in visibility
1641 if ( $el.hasClass( 'acf-hidden' ) ) {
1642 $el.removeClass( 'acf-hidden' );
1643 return true;
1644
1645 // $el is visible, return false due to no change in visibility
1646 } else {
1647 return false;
1648 }
1649 };
1650
1651 /**
1652 * acf.hide
1653 *
1654 * description
1655 *
1656 * @date 9/2/18
1657 * @since ACF 5.6.5
1658 *
1659 * @param type $var Description. Default.
1660 * @return type Description.
1661 */
1662
1663 acf.hide = function ( $el, lockKey ) {
1664 // lock
1665 if ( lockKey ) {
1666 acf.lock( $el, 'hidden', lockKey );
1667 }
1668
1669 // $el is hidden, return false due to no change in visibility
1670 if ( $el.hasClass( 'acf-hidden' ) ) {
1671 return false;
1672
1673 // $el is visible, add class and return true due to change in visibility
1674 } else {
1675 $el.addClass( 'acf-hidden' );
1676 return true;
1677 }
1678 };
1679
1680 /**
1681 * acf.isHidden
1682 *
1683 * description
1684 *
1685 * @date 9/2/18
1686 * @since ACF 5.6.5
1687 *
1688 * @param type $var Description. Default.
1689 * @return type Description.
1690 */
1691
1692 acf.isHidden = function ( $el ) {
1693 return $el.hasClass( 'acf-hidden' );
1694 };
1695
1696 /**
1697 * acf.isVisible
1698 *
1699 * description
1700 *
1701 * @date 9/2/18
1702 * @since ACF 5.6.5
1703 *
1704 * @param type $var Description. Default.
1705 * @return type Description.
1706 */
1707
1708 acf.isVisible = function ( $el ) {
1709 return ! acf.isHidden( $el );
1710 };
1711
1712 /**
1713 * enable
1714 *
1715 * description
1716 *
1717 * @date 12/3/18
1718 * @since ACF 5.6.9
1719 *
1720 * @param type $var Description. Default.
1721 * @return type Description.
1722 */
1723
1724 var enable = function ( $el, lockKey ) {
1725 // check class. Allow .acf-disabled to overrule all JS
1726 if ( $el.hasClass( 'acf-disabled' ) ) {
1727 return false;
1728 }
1729
1730 // unlock
1731 if ( lockKey ) {
1732 acf.unlock( $el, 'disabled', lockKey );
1733 }
1734
1735 // bail early if $el is still locked
1736 if ( acf.isLocked( $el, 'disabled' ) ) {
1737 return false;
1738 }
1739
1740 // $el is disabled, remove prop and return true due to change
1741 if ( $el.prop( 'disabled' ) ) {
1742 $el.prop( 'disabled', false );
1743 return true;
1744
1745 // $el is enabled, return false due to no change
1746 } else {
1747 return false;
1748 }
1749 };
1750
1751 /**
1752 * acf.enable
1753 *
1754 * description
1755 *
1756 * @date 9/2/18
1757 * @since ACF 5.6.5
1758 *
1759 * @param type $var Description. Default.
1760 * @return type Description.
1761 */
1762
1763 acf.enable = function ( $el, lockKey ) {
1764 // enable single input
1765 if ( $el.attr( 'name' ) ) {
1766 return enable( $el, lockKey );
1767 }
1768
1769 // find and enable child inputs
1770 // return true if any inputs have changed
1771 var results = false;
1772 $el.find( '[name]' ).each( function () {
1773 var result = enable( $( this ), lockKey );
1774 if ( result ) {
1775 results = true;
1776 }
1777 } );
1778 return results;
1779 };
1780
1781 /**
1782 * disable
1783 *
1784 * description
1785 *
1786 * @date 12/3/18
1787 * @since ACF 5.6.9
1788 *
1789 * @param type $var Description. Default.
1790 * @return type Description.
1791 */
1792
1793 var disable = function ( $el, lockKey ) {
1794 // lock
1795 if ( lockKey ) {
1796 acf.lock( $el, 'disabled', lockKey );
1797 }
1798
1799 // $el is disabled, return false due to no change
1800 if ( $el.prop( 'disabled' ) ) {
1801 return false;
1802
1803 // $el is enabled, add prop and return true due to change
1804 } else {
1805 $el.prop( 'disabled', true );
1806 return true;
1807 }
1808 };
1809
1810 /**
1811 * acf.disable
1812 *
1813 * description
1814 *
1815 * @date 9/2/18
1816 * @since ACF 5.6.5
1817 *
1818 * @param type $var Description. Default.
1819 * @return type Description.
1820 */
1821
1822 acf.disable = function ( $el, lockKey ) {
1823 // disable single input
1824 if ( $el.attr( 'name' ) ) {
1825 return disable( $el, lockKey );
1826 }
1827
1828 // find and enable child inputs
1829 // return true if any inputs have changed
1830 var results = false;
1831 $el.find( '[name]' ).each( function () {
1832 var result = disable( $( this ), lockKey );
1833 if ( result ) {
1834 results = true;
1835 }
1836 } );
1837 return results;
1838 };
1839
1840 /**
1841 * acf.isset
1842 *
1843 * description
1844 *
1845 * @date 10/1/18
1846 * @since ACF 5.6.5
1847 *
1848 * @param type $var Description. Default.
1849 * @return type Description.
1850 */
1851
1852 acf.isset = function ( obj /*, level1, level2, ... */ ) {
1853 for ( var i = 1; i < arguments.length; i++ ) {
1854 if ( ! obj || ! obj.hasOwnProperty( arguments[ i ] ) ) {
1855 return false;
1856 }
1857 obj = obj[ arguments[ i ] ];
1858 }
1859 return true;
1860 };
1861
1862 /**
1863 * acf.isget
1864 *
1865 * description
1866 *
1867 * @date 10/1/18
1868 * @since ACF 5.6.5
1869 *
1870 * @param type $var Description. Default.
1871 * @return type Description.
1872 */
1873
1874 acf.isget = function ( obj /*, level1, level2, ... */ ) {
1875 for ( var i = 1; i < arguments.length; i++ ) {
1876 if ( ! obj || ! obj.hasOwnProperty( arguments[ i ] ) ) {
1877 return null;
1878 }
1879 obj = obj[ arguments[ i ] ];
1880 }
1881 return obj;
1882 };
1883
1884 /**
1885 * acf.getFileInputData
1886 *
1887 * description
1888 *
1889 * @date 10/1/18
1890 * @since ACF 5.6.5
1891 *
1892 * @param type $var Description. Default.
1893 * @return type Description.
1894 */
1895
1896 acf.getFileInputData = function ( $input, callback ) {
1897 // vars
1898 var value = $input.val();
1899
1900 // bail early if no value
1901 if ( ! value ) {
1902 return false;
1903 }
1904
1905 // data
1906 var data = {
1907 url: value,
1908 };
1909
1910 // modern browsers
1911 var file = $input[ 0 ].files.length ? acf.isget( $input[ 0 ].files, 0 ) : false;
1912 if ( file ) {
1913 // update data
1914 data.size = file.size;
1915 data.type = file.type;
1916
1917 // image
1918 if ( file.type.indexOf( 'image' ) > -1 ) {
1919 // vars
1920 var windowURL = window.URL || window.webkitURL;
1921 var img = new Image();
1922
1923 img.onload = function () {
1924 // update
1925 data.width = this.width;
1926 data.height = this.height;
1927
1928 callback( data );
1929 };
1930 img.src = windowURL.createObjectURL( file );
1931 } else {
1932 callback( data );
1933 }
1934 } else {
1935 callback( data );
1936 }
1937 };
1938
1939 /**
1940 * acf.isAjaxSuccess
1941 *
1942 * description
1943 *
1944 * @date 18/1/18
1945 * @since ACF 5.6.5
1946 *
1947 * @param type $var Description. Default.
1948 * @return type Description.
1949 */
1950
1951 acf.isAjaxSuccess = function ( json ) {
1952 return json && json.success;
1953 };
1954
1955 /**
1956 * acf.getAjaxMessage
1957 *
1958 * description
1959 *
1960 * @date 18/1/18
1961 * @since ACF 5.6.5
1962 *
1963 * @param type $var Description. Default.
1964 * @return type Description.
1965 */
1966
1967 acf.getAjaxMessage = function ( json ) {
1968 return acf.isget( json, 'data', 'message' );
1969 };
1970
1971 /**
1972 * acf.getAjaxError
1973 *
1974 * description
1975 *
1976 * @date 18/1/18
1977 * @since ACF 5.6.5
1978 *
1979 * @param type $var Description. Default.
1980 * @return type Description.
1981 */
1982
1983 acf.getAjaxError = function ( json ) {
1984 return acf.isget( json, 'data', 'error' );
1985 };
1986
1987 /**
1988 * Returns the error message from an XHR object.
1989 *
1990 * @date 17/3/20
1991 * @since ACF 5.8.9
1992 *
1993 * @param object xhr The XHR object.
1994 * @return (string)
1995 */
1996 acf.getXhrError = function ( xhr ) {
1997 if ( xhr.responseJSON ) {
1998 // Responses via `return new WP_Error();`
1999 if ( xhr.responseJSON.message ) {
2000 return xhr.responseJSON.message;
2001 }
2002
2003 // Responses via `wp_send_json_error();`.
2004 if ( xhr.responseJSON.data && xhr.responseJSON.data.error ) {
2005 return xhr.responseJSON.data.error;
2006 }
2007 } else if ( xhr.statusText ) {
2008 return xhr.statusText;
2009 }
2010
2011 return '';
2012 };
2013
2014 /**
2015 * acf.renderSelect
2016 *
2017 * Renders the inner html for a select field.
2018 *
2019 * @date 19/2/18
2020 * @since ACF 5.6.9
2021 *
2022 * @param jQuery $select The select element.
2023 * @param array choices An array of choices.
2024 * @return void
2025 */
2026
2027 acf.renderSelect = function ( $select, choices ) {
2028 // vars
2029 var value = $select.val();
2030 var values = [];
2031
2032 // callback
2033 var crawl = function ( items ) {
2034 // vars
2035 var itemsHtml = '';
2036
2037 // loop
2038 items.map( function ( item ) {
2039 // vars
2040 var text = item.text || item.label || '';
2041 var id = item.id || item.value || '';
2042
2043 // append
2044 values.push( id );
2045
2046 // optgroup
2047 if ( item.children ) {
2048 itemsHtml +=
2049 '<optgroup label="' + acf.escAttr( text ) + '">' + crawl( item.children ) + '</optgroup>';
2050
2051 // option
2052 } else {
2053 itemsHtml +=
2054 '<option value="' +
2055 acf.escAttr( id ) +
2056 '"' +
2057 ( item.disabled ? ' disabled="disabled"' : '' ) +
2058 '>' +
2059 acf.strEscape( text ) +
2060 '</option>';
2061 }
2062 } );
2063 // return
2064 return itemsHtml;
2065 };
2066
2067 // update HTML
2068 $select.html( crawl( choices ) );
2069
2070 // update value
2071 if ( values.indexOf( value ) > -1 ) {
2072 $select.val( value );
2073 }
2074
2075 // return selected value
2076 return $select.val();
2077 };
2078
2079 /**
2080 * acf.lock
2081 *
2082 * Creates a "lock" on an element for a given type and key
2083 *
2084 * @date 22/2/18
2085 * @since ACF 5.6.9
2086 *
2087 * @param jQuery $el The element to lock.
2088 * @param string type The type of lock such as "condition" or "visibility".
2089 * @param string key The key that will be used to unlock.
2090 * @return void
2091 */
2092
2093 var getLocks = function ( $el, type ) {
2094 return $el.data( 'acf-lock-' + type ) || [];
2095 };
2096
2097 var setLocks = function ( $el, type, locks ) {
2098 $el.data( 'acf-lock-' + type, locks );
2099 };
2100
2101 acf.lock = function ( $el, type, key ) {
2102 var locks = getLocks( $el, type );
2103 var i = locks.indexOf( key );
2104 if ( i < 0 ) {
2105 locks.push( key );
2106 setLocks( $el, type, locks );
2107 }
2108 };
2109
2110 /**
2111 * acf.unlock
2112 *
2113 * Unlocks a "lock" on an element for a given type and key
2114 *
2115 * @date 22/2/18
2116 * @since ACF 5.6.9
2117 *
2118 * @param jQuery $el The element to lock.
2119 * @param string type The type of lock such as "condition" or "visibility".
2120 * @param string key The key that will be used to unlock.
2121 * @return void
2122 */
2123
2124 acf.unlock = function ( $el, type, key ) {
2125 var locks = getLocks( $el, type );
2126 var i = locks.indexOf( key );
2127 if ( i > -1 ) {
2128 locks.splice( i, 1 );
2129 setLocks( $el, type, locks );
2130 }
2131
2132 // return true if is unlocked (no locks)
2133 return locks.length === 0;
2134 };
2135
2136 /**
2137 * acf.isLocked
2138 *
2139 * Returns true if a lock exists for a given type
2140 *
2141 * @date 22/2/18
2142 * @since ACF 5.6.9
2143 *
2144 * @param jQuery $el The element to lock.
2145 * @param string type The type of lock such as "condition" or "visibility".
2146 * @return void
2147 */
2148
2149 acf.isLocked = function ( $el, type ) {
2150 return getLocks( $el, type ).length > 0;
2151 };
2152
2153 /**
2154 * acf.isGutenberg
2155 *
2156 * Returns true if the Gutenberg editor is being used.
2157 *
2158 * @since ACF 5.8.0
2159 *
2160 * @return bool
2161 */
2162 acf.isGutenberg = function () {
2163 return !! ( window.wp && wp.data && wp.data.select && wp.data.select( 'core/editor' ) );
2164 };
2165
2166 /**
2167 * acf.isGutenbergPostEditor
2168 *
2169 * Returns true if the Gutenberg post editor is being used.
2170 *
2171 * @since ACF 6.2.2
2172 *
2173 * @return bool
2174 */
2175 acf.isGutenbergPostEditor = function () {
2176 return !! ( window.wp && wp.data && wp.data.select && wp.data.select( 'core/edit-post' ) );
2177 };
2178
2179 /**
2180 * acf.objectToArray
2181 *
2182 * Returns an array of items from the given object.
2183 *
2184 * @date 20/11/18
2185 * @since ACF 5.8.0
2186 *
2187 * @param object obj The object of items.
2188 * @return array
2189 */
2190 acf.objectToArray = function ( obj ) {
2191 return Object.keys( obj ).map( function ( key ) {
2192 return obj[ key ];
2193 } );
2194 };
2195
2196 /**
2197 * acf.debounce
2198 *
2199 * 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.
2200 *
2201 * @date 28/8/19
2202 * @since ACF 5.8.1
2203 *
2204 * @param function callback The callback function.
2205 * @return int wait The number of milliseconds to wait.
2206 */
2207 acf.debounce = function ( callback, wait ) {
2208 var timeout;
2209 return function () {
2210 var context = this;
2211 var args = arguments;
2212 var later = function () {
2213 callback.apply( context, args );
2214 };
2215 clearTimeout( timeout );
2216 timeout = setTimeout( later, wait );
2217 };
2218 };
2219
2220 /**
2221 * acf.throttle
2222 *
2223 * Returns a throttled version of the passed function which will allow only one execution per `limit` time period.
2224 *
2225 * @date 28/8/19
2226 * @since ACF 5.8.1
2227 *
2228 * @param function callback The callback function.
2229 * @return int wait The number of milliseconds to wait.
2230 */
2231 acf.throttle = function ( callback, limit ) {
2232 var busy = false;
2233 return function () {
2234 if ( busy ) return;
2235 busy = true;
2236 setTimeout( function () {
2237 busy = false;
2238 }, limit );
2239 callback.apply( this, arguments );
2240 };
2241 };
2242
2243 /**
2244 * acf.isInView
2245 *
2246 * Returns true if the given element is in view.
2247 *
2248 * @date 29/8/19
2249 * @since ACF 5.8.1
2250 *
2251 * @param elem el The dom element to inspect.
2252 * @return bool
2253 */
2254 acf.isInView = function ( el ) {
2255 if ( el instanceof jQuery ) {
2256 el = el[ 0 ];
2257 }
2258 var rect = el.getBoundingClientRect();
2259 return (
2260 rect.top !== rect.bottom &&
2261 rect.top >= 0 &&
2262 rect.left >= 0 &&
2263 rect.bottom <= ( window.innerHeight || document.documentElement.clientHeight ) &&
2264 rect.right <= ( window.innerWidth || document.documentElement.clientWidth )
2265 );
2266 };
2267
2268 /**
2269 * acf.onceInView
2270 *
2271 * Watches for a dom element to become visible in the browser and then executes the passed callback.
2272 *
2273 * @date 28/8/19
2274 * @since ACF 5.8.1
2275 *
2276 * @param dom el The dom element to inspect.
2277 * @param function callback The callback function.
2278 */
2279 acf.onceInView = ( function () {
2280 // Define list.
2281 var items = [];
2282 var id = 0;
2283
2284 // Define check function.
2285 var check = function () {
2286 items.forEach( function ( item ) {
2287 if ( acf.isInView( item.el ) ) {
2288 item.callback.apply( this );
2289 pop( item.id );
2290 }
2291 } );
2292 };
2293
2294 // And create a debounced version.
2295 var debounced = acf.debounce( check, 300 );
2296
2297 // Define add function.
2298 var push = function ( el, callback ) {
2299 // Add event listener.
2300 if ( ! items.length ) {
2301 $( window ).on( 'scroll resize', debounced ).on( 'acfrefresh orientationchange', check );
2302 }
2303
2304 // Append to list.
2305 items.push( { id: id++, el: el, callback: callback } );
2306 };
2307
2308 // Define remove function.
2309 var pop = function ( id ) {
2310 // Remove from list.
2311 items = items.filter( function ( item ) {
2312 return item.id !== id;
2313 } );
2314
2315 // Clean up listener.
2316 if ( ! items.length ) {
2317 $( window ).off( 'scroll resize', debounced ).off( 'acfrefresh orientationchange', check );
2318 }
2319 };
2320
2321 // Define returned function.
2322 return function ( el, callback ) {
2323 // Allow jQuery object.
2324 if ( el instanceof jQuery ) el = el[ 0 ];
2325
2326 // Execute callback if already in view or add to watch list.
2327 if ( acf.isInView( el ) ) {
2328 callback.apply( this );
2329 } else {
2330 push( el, callback );
2331 }
2332 };
2333 } )();
2334
2335 /**
2336 * acf.once
2337 *
2338 * Creates a function that is restricted to invoking `func` once.
2339 *
2340 * @date 2/9/19
2341 * @since ACF 5.8.1
2342 *
2343 * @param function func The function to restrict.
2344 * @return function
2345 */
2346 acf.once = function ( func ) {
2347 var i = 0;
2348 return function () {
2349 if ( i++ > 0 ) {
2350 return ( func = undefined );
2351 }
2352 return func.apply( this, arguments );
2353 };
2354 };
2355
2356 /**
2357 * Focuses attention to a specific element.
2358 *
2359 * @date 05/05/2020
2360 * @since ACF 5.9.0
2361 *
2362 * @param jQuery $el The jQuery element to focus.
2363 * @return void
2364 */
2365 acf.focusAttention = function ( $el ) {
2366 var wait = 1000;
2367
2368 // Apply class to focus attention.
2369 $el.addClass( 'acf-attention -focused' );
2370
2371 // Scroll to element if needed.
2372 var scrollTime = 500;
2373 if ( ! acf.isInView( $el ) ) {
2374 $( 'body, html' ).animate(
2375 {
2376 scrollTop: $el.offset().top - $( window ).height() / 2,
2377 },
2378 scrollTime
2379 );
2380 wait += scrollTime;
2381 }
2382
2383 // Remove class after $wait amount of time.
2384 var fadeTime = 250;
2385 setTimeout( function () {
2386 $el.removeClass( '-focused' );
2387 setTimeout( function () {
2388 $el.removeClass( 'acf-attention' );
2389 }, fadeTime );
2390 }, wait );
2391 };
2392
2393 /**
2394 * Description
2395 *
2396 * @date 05/05/2020
2397 * @since ACF 5.9.0
2398 *
2399 * @param type Var Description.
2400 * @return type Description.
2401 */
2402 acf.onFocus = function ( $el, callback ) {
2403 // Only run once per element.
2404 // if( $el.data('acf.onFocus') ) {
2405 // return false;
2406 // }
2407
2408 // Vars.
2409 var ignoreBlur = false;
2410 var focus = false;
2411
2412 // Functions.
2413 var onFocus = function () {
2414 ignoreBlur = true;
2415 setTimeout( function () {
2416 ignoreBlur = false;
2417 }, 1 );
2418 setFocus( true );
2419 };
2420 var onBlur = function () {
2421 if ( ! ignoreBlur ) {
2422 setFocus( false );
2423 }
2424 };
2425 var addEvents = function () {
2426 $( document ).on( 'click', onBlur );
2427 //$el.on('acfBlur', onBlur);
2428 $el.on( 'blur', 'input, select, textarea', onBlur );
2429 };
2430 var removeEvents = function () {
2431 $( document ).off( 'click', onBlur );
2432 //$el.off('acfBlur', onBlur);
2433 $el.off( 'blur', 'input, select, textarea', onBlur );
2434 };
2435 var setFocus = function ( value ) {
2436 if ( focus === value ) {
2437 return;
2438 }
2439 if ( value ) {
2440 addEvents();
2441 } else {
2442 removeEvents();
2443 }
2444 focus = value;
2445 callback( value );
2446 };
2447
2448 // Add events and set data.
2449 $el.on( 'click', onFocus );
2450 //$el.on('acfFocus', onFocus);
2451 $el.on( 'focus', 'input, select, textarea', onFocus );
2452 //$el.data('acf.onFocus', true);
2453 };
2454
2455 /**
2456 * Disable form submit buttons
2457 *
2458 * @since ACF 6.2.3
2459 *
2460 * @param event e
2461 * @returns void
2462 */
2463 acf.disableForm = function ( e ) {
2464 // Disable submit button.
2465 if ( e.submitter ) e.submitter.classList.add( 'disabled' );
2466 };
2467
2468 /*
2469 * exists
2470 *
2471 * This function will return true if a jQuery selection exists
2472 *
2473 * @type function
2474 * @date 8/09/2014
2475 * @since ACF 5.0.0
2476 *
2477 * @param n/a
2478 * @return (boolean)
2479 */
2480
2481 $.fn.exists = function () {
2482 return $( this ).length > 0;
2483 };
2484
2485 /*
2486 * outerHTML
2487 *
2488 * This function will return a string containing the HTML of the selected element
2489 *
2490 * @type function
2491 * @date 19/11/2013
2492 * @since ACF 5.0.0
2493 *
2494 * @param $.fn
2495 * @return (string)
2496 */
2497
2498 $.fn.outerHTML = function () {
2499 return $( this ).get( 0 ).outerHTML;
2500 };
2501
2502 /*
2503 * indexOf
2504 *
2505 * This function will provide compatibility for ie8
2506 *
2507 * @type function
2508 * @date 5/3/17
2509 * @since ACF 5.5.10
2510 *
2511 * @param n/a
2512 * @return n/a
2513 */
2514
2515 if ( ! Array.prototype.indexOf ) {
2516 Array.prototype.indexOf = function ( val ) {
2517 return $.inArray( val, this );
2518 };
2519 }
2520
2521 /**
2522 * Returns true if value is a number or a numeric string.
2523 *
2524 * @date 30/11/20
2525 * @since ACF 5.9.4
2526 * @link https://stackoverflow.com/questions/9716468/pure-javascript-a-function-like-jquerys-isnumeric/9716488#9716488
2527 *
2528 * @param mixed n The variable being evaluated.
2529 * @return bool.
2530 */
2531 acf.isNumeric = function ( n ) {
2532 return ! isNaN( parseFloat( n ) ) && isFinite( n );
2533 };
2534
2535 /**
2536 * Triggers a "refresh" action used by various Components to redraw the DOM.
2537 *
2538 * @date 26/05/2020
2539 * @since ACF 5.9.0
2540 *
2541 * @param void
2542 * @return void
2543 */
2544 acf.refresh = acf.debounce( function () {
2545 $( window ).trigger( 'acfrefresh' );
2546 acf.doAction( 'refresh' );
2547 }, 0 );
2548
2549 /**
2550 * Log something to console if we're in debug mode.
2551 *
2552 * @since ACF 6.3
2553 */
2554 acf.debug = function () {
2555 if ( acf.get( 'debug' ) ) console.log.apply( null, arguments );
2556 };
2557
2558 // Set up actions from events
2559 $( document ).ready( function () {
2560 acf.doAction( 'ready' );
2561 } );
2562
2563 $( window ).on( 'load', function () {
2564 // Use timeout to ensure action runs after Gutenberg has modified DOM elements during "DOMContentLoaded".
2565 setTimeout( function () {
2566 acf.doAction( 'load' );
2567 } );
2568 } );
2569
2570 $( window ).on( 'beforeunload', function () {
2571 acf.doAction( 'unload' );
2572 } );
2573
2574 $( window ).on( 'resize', function () {
2575 acf.doAction( 'resize' );
2576 } );
2577
2578 $( document ).on( 'sortstart', function ( event, ui ) {
2579 acf.doAction( 'sortstart', ui.item, ui.placeholder );
2580 } );
2581
2582 $( document ).on( 'sortstop', function ( event, ui ) {
2583 acf.doAction( 'sortstop', ui.item, ui.placeholder );
2584 } );
2585 } )( jQuery );
2586