PluginProbe ʕ •ᴥ•ʔ
Advanced Custom Fields: Extended / 0.9.2.7
Advanced Custom Fields: Extended v0.9.2.7
0.9.2.7 0.9.2.6 0.9.2.5 0.8.6 0.8.6.1 0.8.6.3 0.8.6.5 0.8.6.6 0.8.6.7 0.8.6.8 0.8.6.9 0.8.7 0.8.7.1 0.8.7.2 0.8.7.3 0.8.7.4 0.8.7.5 0.8.7.6 0.8.8 0.8.8.1 0.8.8.10 0.8.8.11 0.8.8.2 0.8.8.3 0.8.8.4 0.8.8.5 0.8.8.6 0.8.8.7 0.8.8.8 0.8.8.9 0.8.9 0.8.9.1 0.8.9.2 0.8.9.3 0.8.9.4 0.8.9.5 0.9 0.9.0.1 0.9.0.2 0.9.0.3 0.9.0.4 0.9.0.5 0.9.0.6 0.9.0.7 0.9.0.8 0.9.0.9 0.9.1 0.9.1.1 0.9.2 0.9.2.1 0.9.2.2 0.9.2.3 0.9.2.4 trunk 0.5 0.5.1 0.5.2 0.5.2.1 0.5.2.3 0.5.5 0.5.5.1 0.5.8 0.5.8.1 0.6 0.6.0.1 0.6.0.2 0.6.1 0.6.3 0.6.5 0.6.7 0.6.7.2 0.7 0.7.0.3 0.7.5 0.7.5.5 0.7.8 0.7.9 0.7.9.3 0.7.9.4 0.7.9.9.8 0.7.9.9.9 0.8 0.8.1 0.8.2 0.8.3 0.8.3.1 0.8.4 0.8.4.1 0.8.4.5 0.8.4.6 0.8.5 0.8.5.5
acf-extended / assets / js / acfe-input.js
acf-extended / assets / js Last commit date
acfe-admin.js 9 months ago acfe-admin.min.js 9 months ago acfe-field-group.js 3 months ago acfe-field-group.min.js 3 months ago acfe-input.js 3 months ago acfe-input.min.js 3 months ago acfe-ui.js 7 months ago acfe-ui.min.js 7 months ago acfe.js 3 months ago acfe.min.js 3 months ago
acfe-input.js
6065 lines
1 (function($) {
2
3 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4 return;
5 }
6
7
8 /**
9 * acf.newCondition
10 *
11 * Allows field conditions to work between two field groups
12 */
13 acf.newCondition = function(rule, conditions) {
14
15 // currently setting up conditions for fieldX, this field is the 'target'
16 var target = conditions.get('field');
17
18 // use the 'target' to find the 'trigger' field.
19 // - this field is used to setup the conditional logic events
20 var field = target.getField(rule.field);
21
22 // acfe: found target, but not the field to check value against
23 if (target && !field) {
24
25 // acfe: find the field in the whole page
26 // we must add this step because acf.getField('do_not_exists') will instantiate an empty field
27 var findField = acf.findField(rule.field);
28
29 // instatiate field once found
30 if (findField.length) {
31 field = acf.getField(rule.field);
32 }
33
34 }
35
36 // bail ealry if no target or no field (possible if field doesn't exist due to HTML error)
37 if (!target || !field) {
38 return false;
39 }
40
41 // vars
42 var args = {
43 rule: rule,
44 target: target,
45 conditions: conditions,
46 field: field
47 };
48
49 // vars
50 var fieldType = field.get('type');
51 var operator = rule.operator;
52
53 // get avaibale conditions
54 var conditionTypes = acf.getConditionTypes({
55 fieldType: fieldType,
56 operator: operator,
57 });
58
59 // instantiate
60 var model = conditionTypes[0] || acf.Condition;
61
62 // instantiate
63 var condition = new model(args);
64
65 // return
66 return condition;
67
68 };
69
70 })(jQuery);
71 (function($) {
72
73 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
74 return;
75 }
76
77 /**
78 * Checkbox & Radio
79 */
80 acf.registerConditionForFieldType('contains', 'checkbox');
81 acf.registerConditionForFieldType('contains', 'radio');
82
83 /**
84 * Code Editor
85 */
86 acf.registerConditionForFieldType('equalTo', 'acfe_code_editor');
87 acf.registerConditionForFieldType('notEqualTo', 'acfe_code_editor');
88 acf.registerConditionForFieldType('patternMatch', 'acfe_code_editor');
89 acf.registerConditionForFieldType('contains', 'acfe_code_editor');
90 acf.registerConditionForFieldType('hasValue', 'acfe_code_editor');
91 acf.registerConditionForFieldType('hasNoValue', 'acfe_code_editor');
92
93 /**
94 * Date Picker
95 */
96 acf.registerConditionForFieldType('equalTo', 'date_picker');
97 acf.registerConditionForFieldType('notEqualTo', 'date_picker');
98 acf.registerConditionForFieldType('patternMatch', 'date_picker');
99 acf.registerConditionForFieldType('contains', 'date_picker');
100 acf.registerConditionForFieldType('greaterThan', 'date_picker');
101 acf.registerConditionForFieldType('lessThan', 'date_picker');
102
103 /**
104 * Date Time Picker
105 */
106 acf.registerConditionForFieldType('equalTo', 'date_time_picker');
107 acf.registerConditionForFieldType('notEqualTo', 'date_time_picker');
108 acf.registerConditionForFieldType('patternMatch', 'date_time_picker');
109 acf.registerConditionForFieldType('contains', 'date_time_picker');
110
111 /**
112 * Forms
113 */
114 acf.registerConditionForFieldType('equalTo', 'acfe_forms');
115 acf.registerConditionForFieldType('notEqualTo', 'acfe_forms');
116 acf.registerConditionForFieldType('patternMatch', 'acfe_forms');
117 acf.registerConditionForFieldType('contains', 'acfe_forms');
118 acf.registerConditionForFieldType('hasValue', 'acfe_forms');
119 acf.registerConditionForFieldType('hasNoValue', 'acfe_forms');
120
121 /**
122 * Hidden
123 */
124 acf.registerConditionForFieldType('equalTo', 'acfe_hidden');
125 acf.registerConditionForFieldType('notEqualTo', 'acfe_hidden');
126 acf.registerConditionForFieldType('patternMatch', 'acfe_hidden');
127 acf.registerConditionForFieldType('contains', 'acfe_hidden');
128 acf.registerConditionForFieldType('hasValue', 'acfe_hidden');
129 acf.registerConditionForFieldType('hasNoValue', 'acfe_hidden');
130
131 /**
132 * Post Status
133 */
134 acf.registerConditionForFieldType('equalTo', 'acfe_post_statuses');
135 acf.registerConditionForFieldType('notEqualTo', 'acfe_post_statuses');
136 acf.registerConditionForFieldType('patternMatch', 'acfe_post_statuses');
137 acf.registerConditionForFieldType('contains', 'acfe_post_statuses');
138 acf.registerConditionForFieldType('hasValue', 'acfe_post_statuses');
139 acf.registerConditionForFieldType('hasNoValue', 'acfe_post_statuses');
140
141 /**
142 * Post Types
143 */
144 acf.registerConditionForFieldType('equalTo', 'acfe_post_types');
145 acf.registerConditionForFieldType('notEqualTo', 'acfe_post_types');
146 acf.registerConditionForFieldType('patternMatch', 'acfe_post_types');
147 acf.registerConditionForFieldType('contains', 'acfe_post_types');
148 acf.registerConditionForFieldType('hasValue', 'acfe_post_types');
149 acf.registerConditionForFieldType('hasNoValue', 'acfe_post_types');
150
151 /**
152 * Slug
153 */
154 acf.registerConditionForFieldType('equalTo', 'acfe_slug');
155 acf.registerConditionForFieldType('notEqualTo', 'acfe_slug');
156 acf.registerConditionForFieldType('patternMatch', 'acfe_slug');
157 acf.registerConditionForFieldType('contains', 'acfe_slug');
158 acf.registerConditionForFieldType('hasValue', 'acfe_slug');
159 acf.registerConditionForFieldType('hasNoValue', 'acfe_slug');
160
161 /**
162 * Taxonomies
163 */
164 acf.registerConditionForFieldType('equalTo', 'acfe_taxonomies');
165 acf.registerConditionForFieldType('notEqualTo', 'acfe_taxonomies');
166 acf.registerConditionForFieldType('patternMatch', 'acfe_taxonomies');
167 acf.registerConditionForFieldType('contains', 'acfe_taxonomies');
168 acf.registerConditionForFieldType('hasValue', 'acfe_taxonomies');
169 acf.registerConditionForFieldType('hasNoValue', 'acfe_taxonomies');
170
171 /**
172 * Taxonomy
173 */
174 acf.registerConditionForFieldType('equalTo', 'taxonomy');
175 acf.registerConditionForFieldType('notEqualTo', 'taxonomy');
176 acf.registerConditionForFieldType('patternMatch', 'taxonomy');
177 acf.registerConditionForFieldType('contains', 'taxonomy');
178 acf.registerConditionForFieldType('hasValue', 'taxonomy');
179 acf.registerConditionForFieldType('hasNoValue', 'taxonomy');
180
181 /**
182 * Taxonomy Terms
183 */
184 acf.registerConditionForFieldType('equalTo', 'acfe_taxonomy_terms');
185 acf.registerConditionForFieldType('notEqualTo', 'acfe_taxonomy_terms');
186 acf.registerConditionForFieldType('patternMatch', 'acfe_taxonomy_terms');
187 acf.registerConditionForFieldType('contains', 'acfe_taxonomy_terms');
188 acf.registerConditionForFieldType('hasValue', 'acfe_taxonomy_terms');
189 acf.registerConditionForFieldType('hasNoValue', 'acfe_taxonomy_terms');
190
191 /**
192 * Time Picker
193 */
194 acf.registerConditionForFieldType('equalTo', 'time_picker');
195 acf.registerConditionForFieldType('notEqualTo', 'time_picker');
196 acf.registerConditionForFieldType('patternMatch', 'time_picker');
197 acf.registerConditionForFieldType('contains', 'time_picker');
198
199 /**
200 * User Roles
201 */
202 acf.registerConditionForFieldType('equalTo', 'acfe_user_roles');
203 acf.registerConditionForFieldType('notEqualTo', 'acfe_user_roles');
204 acf.registerConditionForFieldType('patternMatch', 'acfe_user_roles');
205 acf.registerConditionForFieldType('contains', 'acfe_user_roles');
206 acf.registerConditionForFieldType('hasValue', 'acfe_user_roles');
207 acf.registerConditionForFieldType('hasNoValue', 'acfe_user_roles');
208
209 })(jQuery);
210 (function($) {
211
212 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
213 return;
214 }
215
216 var storage = [];
217
218 acfe.registerEventForFieldType = function(fieldType, events, callback) {
219
220 // force events to array
221 if (typeof events === 'string') {
222 events = [events];
223 }
224
225 // add to storage
226 storage.push({
227 fieldType: fieldType,
228 events: events,
229 callback: callback || false
230 })
231
232 };
233
234 acfe.getEvents = function(args) {
235
236 // defaults
237 args = acf.parseArgs(args, {
238 fieldType: '',
239 });
240
241 var items = [];
242
243 // loop
244 storage.map(function(item) {
245
246 // check args
247 if (args.fieldType && item.fieldType.indexOf(args.fieldType) === -1) {
248 return;
249 }
250
251 // push
252 items.push(item);
253
254 });
255
256 // return
257 return items;
258
259 };
260
261 var FieldEvent = new acf.Model({
262
263 actions: {
264 'new_field': 'newField'
265 },
266
267 priority: 20,
268
269 data: {},
270
271 parseEvent: function(event) {
272 return event.match(/^(\S+)\s*(.*)$/);
273 },
274
275 newField: function(field) {
276
277 // set previous val
278 this.set(field.cid, field.val());
279
280 // get items
281 var items = acfe.getEvents({
282 fieldType: field.get('type')
283 });
284
285 // loop items
286 items.map(function(item) {
287
288 // loop events
289 item.events.map(function(event) {
290
291 // match event "change input"
292 var match = this.parseEvent(event);
293
294 // add event listener
295 field.on(match[1], match[2], this.proxy(function(e) {
296
297 var val = field.val();
298 var prevVal = this.get(field.cid);
299 var $el = $(e.currentTarget);
300
301 var callback = item.callback || this.proxy(function(val, prevVal, field, e, $el) {
302
303 // vars
304 var _val = val;
305 var _prevVal = prevVal;
306
307 // compare object/array values
308 if (typeof _val === 'object') {
309 _val = JSON.stringify(_val);
310 }
311
312 if (typeof _prevVal === 'object') {
313 _prevVal = JSON.stringify(_prevVal);
314 }
315
316 // avoid multiple trigger for the same value
317 if (_prevVal !== _val) {
318
319 this.set(field.cid, val);
320
321 // actions
322 acf.doAction('acfe/change_field', val, prevVal, field, e, $el);
323 acf.doAction('acfe/change_field/type=' + field.get('type'), val, prevVal, field, e, $el);
324 acf.doAction('acfe/change_field/name=' + field.get('name'), val, prevVal, field, e, $el);
325 acf.doAction('acfe/change_field/key=' + field.get('key'), val, prevVal, field, e, $el);
326
327 }
328
329
330 });
331
332 callback(val, prevVal, field, e, $el);
333
334 }));
335
336 }, this);
337
338 }, this);
339
340 }
341
342 });
343
344 // ACF
345 acfe.registerEventForFieldType('button_group', 'change');
346 acfe.registerEventForFieldType('checkbox', 'change');
347 acfe.registerEventForFieldType('color_picker', 'change');
348 acfe.registerEventForFieldType('date_picker', 'change');
349 acfe.registerEventForFieldType('date_time_picker', 'change');
350 acfe.registerEventForFieldType('email', ['input', 'change']);
351 acfe.registerEventForFieldType('file', 'change');
352 acfe.registerEventForFieldType('flexible_content', 'change');
353 acfe.registerEventForFieldType('gallery', 'change');
354 acfe.registerEventForFieldType('google_map', 'change');
355 acfe.registerEventForFieldType('image', 'change');
356 acfe.registerEventForFieldType('link', 'change');
357 acfe.registerEventForFieldType('number', ['input', 'change']);
358 acfe.registerEventForFieldType('oembed', 'change');
359 acfe.registerEventForFieldType('page_link', 'change');
360 acfe.registerEventForFieldType('post_object', 'change');
361 acfe.registerEventForFieldType('relationship', 'change');
362 acfe.registerEventForFieldType('password', ['input', 'change']);
363 acfe.registerEventForFieldType('radio', 'change');
364 acfe.registerEventForFieldType('range', ['input', 'change']);
365 acfe.registerEventForFieldType('repeater', 'change');
366 acfe.registerEventForFieldType('select', 'change');
367 acfe.registerEventForFieldType('taxonomy', 'change');
368 acfe.registerEventForFieldType('text', ['input', 'change']);
369 acfe.registerEventForFieldType('textarea', ['input', 'change']);
370 acfe.registerEventForFieldType('time_picker', 'change');
371 acfe.registerEventForFieldType('true_false', 'change');
372 acfe.registerEventForFieldType('url', ['input', 'change']);
373 acfe.registerEventForFieldType('user', 'change');
374 acfe.registerEventForFieldType('wysiwyg', 'change');
375
376 // ACFE
377 acfe.registerEventForFieldType('acfe_advanced_link', 'change');
378 acfe.registerEventForFieldType('acfe_block_types', 'change');
379 acfe.registerEventForFieldType('acfe_countries', 'change');
380 acfe.registerEventForFieldType('acfe_currencies', 'change');
381 acfe.registerEventForFieldType('acfe_code_editor', 'change');
382 acfe.registerEventForFieldType('acfe_date_range_picker', 'change');
383 acfe.registerEventForFieldType('acfe_field_groups', 'change');
384 acfe.registerEventForFieldType('acfe_field_types', 'change');
385 acfe.registerEventForFieldType('acfe_fields', 'change');
386 acfe.registerEventForFieldType('acfe_forms', 'change');
387 acfe.registerEventForFieldType('acfe_hidden', 'change');
388 acfe.registerEventForFieldType('acfe_image_selector', 'change');
389 acfe.registerEventForFieldType('acfe_image_sizes', 'change');
390 acfe.registerEventForFieldType('acfe_languages', 'change');
391 acfe.registerEventForFieldType('acfe_menu_locations', 'change');
392 acfe.registerEventForFieldType('acfe_options_pages', 'change');
393 acfe.registerEventForFieldType('acfe_payment', 'change');
394 acfe.registerEventForFieldType('acfe_payment_cart', 'change');
395 acfe.registerEventForFieldType('acfe_payment_selector', 'change');
396 acfe.registerEventForFieldType('acfe_phone_number', 'change');
397 acfe.registerEventForFieldType('acfe_post_formats', 'change');
398 acfe.registerEventForFieldType('acfe_post_statuses', 'change');
399 acfe.registerEventForFieldType('acfe_post_types', 'change');
400 acfe.registerEventForFieldType('acfe_recaptcha', 'change');
401 acfe.registerEventForFieldType('acfe_taxonomies', 'change');
402 acfe.registerEventForFieldType('acfe_taxonomy_terms', 'change');
403 acfe.registerEventForFieldType('acfe_templates', 'change');
404 acfe.registerEventForFieldType('acfe_user_roles', 'change');
405 acfe.registerEventForFieldType('acfe_slug', ['input', 'change']);
406
407 })(jQuery);
408 (function($) {
409
410 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
411 return;
412 }
413
414 /**
415 * acfe.FieldExtender
416 *
417 * @param protoProps
418 * @returns {*}
419 * @constructor
420 */
421 var storage = [];
422
423 acfe.FieldExtender = function(protoProps) {
424
425 // vars
426 var id = acfe.extractVar(protoProps, 'id', acf.uniqueId('extender'));
427
428 // validate
429 protoProps.type = acfe.getArray(protoProps.type);
430 protoProps.dependencies = acfe.getArray(protoProps.dependencies);
431 protoProps.extender = id;
432
433 // push to storage
434 storage.push(protoProps);
435
436 // return extender
437 return id;
438
439 }
440
441 /**
442 * acf.Field.setup
443 *
444 * @type {acf.Field.setup}
445 */
446 var setup = acf.Field.prototype.setup;
447
448 acf.Field.prototype.setup = function(props) {
449
450 // parent setup
451 setup.apply(this, arguments);
452
453 var extenders = getFieldExtenders(this);
454
455 if (!extenders.length) {
456 return;
457 }
458
459 // vars
460 var prototype = Object.getPrototypeOf(this);
461 this.extenders = [];
462
463 // loop extenders
464 for (var model of extenders) {
465
466 // append extender
467 this.extenders.push(model.extender);
468
469 // clone model
470 var protoProps = $.extend(true, {}, model);
471 var events = acfe.extractVar(protoProps, 'events');
472
473 // cleanup
474 acfe.extractVars(protoProps, 'type', 'condition', 'dependencies');
475
476 // apply setup method if any
477 if (protoProps.hasOwnProperty('setup')) {
478 protoProps.setup.apply(this, arguments);
479 }
480
481 // generate child
482 var Child = function() {};
483
484 // create proto
485 Child.prototype = Object.create(prototype);
486
487 // extend
488 $.extend(Child.prototype, protoProps);
489
490 // assign events
491 if (events) {
492 Child.prototype.events = $.extend(true, {}, Child.prototype.events, events);
493 }
494
495 // assign parent
496 Child.prototype.__parent__ = prototype;
497
498 // assign prototype for next loop
499 prototype = Child.prototype;
500
501 }
502
503 // getParent function
504 this.getParent = function(extender) {
505
506 var prototype = Object.getPrototypeOf(this);
507 while (prototype) {
508
509 if (prototype.extender === extender) {
510 return prototype.__parent__;
511 }
512
513 if (!prototype.__parent__) {
514 return prototype;
515 }
516
517 prototype = prototype.__parent__;
518
519 }
520
521 return prototype;
522
523 }
524
525 // assign prototype
526 Object.setPrototypeOf(this, prototype);
527
528 }
529
530
531 /**
532 * getFieldExtenders
533 *
534 * @param field
535 * @returns {*[]}
536 */
537 var getFieldExtenders = function(field) {
538
539 var extenders = [];
540
541 for (var extender of getValidExtenders(field)) {
542 extenders.push(getExtender(extender));
543 }
544
545 return extenders;
546
547 };
548
549
550 /**
551 * getExtender
552 *
553 * @param extender
554 * @returns {boolean|*}
555 */
556 var getExtender = function(extender) {
557
558 for (var model of storage) {
559 if (model.extender === extender) {
560 return model;
561 }
562 }
563
564 return false;
565
566 };
567
568
569 /**
570 * getValidExtenders
571 *
572 * @param field
573 * @returns {*|*[]}
574 */
575 var getValidExtenders = function(field) {
576
577 var rules = {};
578
579 for (var model of storage) {
580
581 // validate type
582 if (!acfe.inArray(field.get('type'), model.type)) {
583 continue;
584 }
585
586 // validate condition
587 if (model.hasOwnProperty('condition') && !model.condition.apply(field, arguments)) {
588 continue;
589 }
590
591 // append rule
592 rules[model.extender] = model.dependencies;
593
594 }
595
596 // return array
597 return sortExtenders(rules);
598
599 };
600
601
602 /**
603 * sortExtenders
604 *
605 * https://stackoverflow.com/a/54347328
606 *
607 * @param names
608 * @param obj
609 * @param start
610 * @param depth
611 * @returns {*|*[]}
612 */
613 var sortExtenders = function(names, obj = names, start = [], depth = 0) {
614
615 if (typeof names === 'object' && !Array.isArray(names)) {
616 names = Object.keys(names)
617 }
618
619 const processed = names.reduce(function(a, b, i) {
620
621 if (obj[b].every(Array.prototype.includes, a)) {
622 a.push(b)
623 }
624
625 return a;
626
627 }, start);
628
629 const nextNames = names.filter(function(n) {
630 return !processed.includes(n)
631 });
632
633 const goAgain = nextNames.length && depth <= names.length;
634
635 return goAgain ? sortExtenders(nextNames, obj, processed, depth + 1) : processed;
636
637 };
638
639 })(jQuery);
640 (function($) {
641
642 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
643 return;
644 }
645
646 new acf.Model({
647 actions: {
648 'new_field': 'newField',
649 'duplicate_field': 'duplicateField'
650 },
651 priority: 1,
652 validateField: function(field) {
653
654 // check data correctly set
655 if (!field.has('ftype')) {
656 return false;
657 }
658
659 // check if prototype doesn't already have ftype (acf taxonomy field)
660 return !acf.getFieldType(field.get('type')).prototype.get('ftype');
661
662 },
663 newField: function(field) {
664
665 // validate
666 if (!this.validateField(field)) {
667 return;
668 }
669
670 // real type (checkbox, radio...)
671 field.set('rtype', field.get('type'), true);
672
673 // field type (acfe_post_types, acfe_post_formats...)
674 field.set('type', field.get('ftype'), true);
675
676 // assign attribute
677 field.$el.attr('data-type', field.get('ftype'));
678
679 // cleanup attribute
680 field.$el.removeAttr('data-ftype');
681
682 // cleanup data
683 delete field.data['ftype'];
684
685 },
686 duplicateField: function(field, $fieldDup) {
687 if (field.get('rtype')) {
688 $fieldDup.attr('data-ftype', field.get('type')); // fake type (acfe_post_types, acfe_post_formats...)
689 $fieldDup.attr('data-type', field.get('rtype')); // real type (checkbox, radio...)
690 }
691 },
692 });
693
694 })(jQuery);
695 (function($) {
696
697 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
698 return;
699 }
700
701 /**
702 * Field: Instructions
703 */
704 new acf.Model({
705
706 field: false,
707 placement: false,
708
709 actions: {
710 'new_field': 'newField',
711 },
712
713 newField: function(field) {
714
715 this.field = field;
716
717 if (field.has('instructionTooltip')) {
718 this.setTooltip();
719 }
720
721 if (field.has('instructionAboveField')) {
722 this.setAboveField();
723 }
724
725 if (field.has('instructionPlacement')) {
726 this.overridePlacement(field.get('instructionPlacement'));
727 }
728
729 },
730
731 setTooltip: function() {
732
733 var icon = acfe.isWP('5.5') ? 'dashicons-info-outline' : 'dashicons-info';
734
735 this.field.$labelWrap().prepend('<span class="acfe-field-tooltip acfe-js-tooltip dashicons ' + icon + '" title="' + acf.strEscape(this.field.get('instructionTooltip')) + '"></span>');
736 this.field.$labelWrap().find('.description').remove();
737
738 },
739
740 setAboveField: function() {
741
742 this.field.$inputWrap().prepend('<p class="description">' + this.field.get('instructionAboveField') + '</p>');
743 this.field.$labelWrap().find('.description').remove();
744
745 },
746
747 overridePlacement: function(target) {
748
749 var current = this.getPlacement();
750
751 // No instruction
752 if (!current)
753 return;
754
755 // Placement is correct
756 if (current === target)
757 return;
758
759 this.setPlacement(target);
760
761 },
762
763 getPlacement: function() {
764
765 var placement = false;
766
767 if (this.field.$labelWrap().find('>.description').length)
768 placement = 'label';
769
770 else if (this.field.$inputWrap().find('>.description:first-child').length)
771 placement = 'above_field';
772
773 else if (this.field.$inputWrap().find('>.description:last-child').length)
774 placement = 'field';
775
776 else if (this.field.$labelWrap().find('>.acfe-field-tooltip').length)
777 placement = 'tooltip';
778
779 this.placement = placement;
780
781 return this.placement;
782
783 },
784
785 $getInstruction: function() {
786
787 var placement = this.getPlacement();
788
789 if (placement === 'label') {
790
791 return this.field.$labelWrap().find('>.description');
792
793 } else if (placement === 'above_field') {
794
795 return this.field.$inputWrap().find('>.description:first-child');
796
797 } else if (placement === 'field') {
798
799 return this.field.$inputWrap().find('>.description:last-child');
800
801 } else if (placement === 'tooltip') {
802
803 return this.field.$labelWrap().find('>.acfe-field-tooltip');
804
805 }
806
807 return false;
808
809 },
810
811 setPlacement: function(target) {
812
813 var $instruction = this.$getInstruction();
814
815 if (this.placement === 'tooltip') {
816
817 var text = $instruction.attr('title');
818
819 $instruction.remove();
820 $instruction = $('<p class="description">' + text + '</p>');
821
822 }
823
824 if (target === 'label') {
825
826 this.field.$labelWrap().append($instruction);
827
828 } else if (target === 'above_field') {
829
830 this.field.$inputWrap().prepend($instruction);
831
832 } else if (target === 'field') {
833
834 this.field.$inputWrap().append($instruction);
835
836 } else if (target === 'tooltip') {
837
838 var icon = acfe.isWP('5.5') ? 'dashicons-info-outline' : 'dashicons-info';
839
840 this.field.$labelWrap().prepend($('<span class="acfe-field-tooltip acfe-js-tooltip dashicons ' + icon + '" title="' + acf.strEscape($instruction.html()) + '"></span>'));
841 $instruction.remove();
842
843 }
844
845 }
846
847 });
848
849 })(jQuery);
850 (function($) {
851
852 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
853 return;
854 }
855
856 /**
857 * Field: Labels
858 */
859 new acf.Model({
860
861 actions: {
862 'new_field': 'newField',
863 },
864
865 getFieldType: function(field) {
866 return field.get('rtype', field.get('type'));
867 },
868
869 validateField: function(field) {
870
871 // check setting
872 if (!field.has('acfeLabels')) {
873 return false;
874 }
875
876 // check type & real type
877 return this.getFieldType(field) === 'checkbox' || this.getFieldType(field) === 'radio';
878
879 },
880
881 newField: function(field) {
882
883 // bail early
884 if (!this.validateField(field)) {
885 return;
886 }
887
888 // vars
889 var label, item;
890 var labels = field.get('acfeLabels');
891
892 switch (this.getFieldType(field)) {
893
894 case 'checkbox': {
895
896 // loop
897 for (label in labels) {
898 item = labels[label];
899 field.$control().find('input[type=checkbox][value="' + item + '"]').closest('ul').before('<strong>' + label + '</strong>');
900 }
901
902 break;
903
904 }
905
906 case 'radio': {
907
908 // loop
909 for (label in labels) {
910 item = labels[label];
911 field.$control().find('input[type=radio][value="' + item + '"]').closest('li').addClass('parent').prepend('<strong>' + label + '</strong>');
912 }
913
914 // horizontal rule
915 if (field.$control().hasClass('acf-hl')) {
916
917 field.$control().find('li.parent').each(function() {
918 $(this).nextUntil('li.parent').addBack().wrapAll('<li><ul></ul></li>');
919 });
920
921 }
922
923 break;
924
925 }
926
927 }
928
929 }
930
931 });
932
933 })(jQuery);
934 (function($) {
935
936 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
937 return;
938 }
939
940 acf.Field.prototype.getModal = function(args) {
941
942 var $modal = acfe.findModal('', this.$inputWrap());
943
944 if (!$modal.length) {
945 return false;
946 }
947
948 return acfe.getModal($modal, args);
949
950 };
951
952 })(jQuery);
953 (function($) {
954
955 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
956 return;
957 }
958
959 /**
960 * Field: Select Hooks
961 */
962 new acf.Model({
963
964 actions: {
965 'select2_init': 'init',
966 },
967
968 filters: {
969 'select2_args': 'args',
970 'select2_ajax_data': 'ajaxData',
971 },
972
973 init: function($select, options, data, field, instance) {
974
975 // bail early
976 if (!field) {
977 return;
978 }
979
980 // actions
981 acf.doAction('select2_init/type=' + field.get('type'), $select, options, data, field, instance);
982 acf.doAction('select2_init/name=' + field.get('name'), $select, options, data, field, instance);
983 acf.doAction('select2_init/key=' + field.get('key'), $select, options, data, field, instance);
984
985 },
986
987 args: function(options, $select, data, field, instance) {
988
989 // bail early
990 if (!field) {
991 return options;
992 }
993
994 // filters
995 options = acf.applyFilters('select2_args/type=' + field.get('type'), options, $select, data, field, instance);
996 options = acf.applyFilters('select2_args/name=' + field.get('name'), options, $select, data, field, instance);
997 options = acf.applyFilters('select2_args/key=' + field.get('key'), options, $select, data, field, instance);
998
999 // only on pages without woocommerce
1000 if (!acf.isset(window, 'jQuery', 'fn', 'selectWoo')) {
1001
1002 options.templateSelection = function(selection) {
1003
1004 var text = selection.text;
1005
1006 text = acf.applyFilters('select2_template_selection', text, selection, $select, data, field, instance);
1007 text = acf.applyFilters('select2_template_selection/type=' + field.get('type'), text, selection, $select, data, field, instance);
1008 text = acf.applyFilters('select2_template_selection/name=' + field.get('name'), text, selection, $select, data, field, instance);
1009 text = acf.applyFilters('select2_template_selection/key=' + field.get('key'), text, selection, $select, data, field, instance);
1010
1011 var $selection = $('<span class="acf-selection"></span>');
1012 $selection.html(acf.escHtml(text));
1013 $selection.data('element', selection.element);
1014
1015 return $selection;
1016
1017 };
1018
1019 options.templateResult = function(selection) {
1020
1021 var text = selection.text;
1022
1023 text = acf.applyFilters('select2_template_result', text, selection, $select, data, field, instance);
1024 text = acf.applyFilters('select2_template_result/type=' + field.get('type'), text, selection, $select, data, field, instance);
1025 text = acf.applyFilters('select2_template_result/name=' + field.get('name'), text, selection, $select, data, field, instance);
1026 text = acf.applyFilters('select2_template_result/key=' + field.get('key'), text, selection, $select, data, field, instance);
1027
1028 var $selection = $('<span class="acf-selection"></span>');
1029 $selection.html(acf.escHtml(text));
1030 $selection.data('element', selection.element);
1031
1032 return $selection;
1033
1034 };
1035
1036 // fix old ACF 5.9 version which doesn't escape markup
1037 if (!acfe.isACF('5.10')) {
1038
1039 options.escapeMarkup = function(markup) {
1040 if (typeof markup !== 'string') {
1041 return markup;
1042 }
1043 return acf.escHtml(markup);
1044 }
1045
1046 }
1047
1048 }
1049
1050 return options;
1051
1052 },
1053
1054 ajaxData: function(ajaxData, data, $el, field, instance) {
1055
1056 // bail early
1057 if (!field) {
1058 return ajaxData;
1059 }
1060
1061 // filters
1062 ajaxData = acf.applyFilters('select2_ajax_data/type=' + field.get('type'), ajaxData, data, $el, field, instance);
1063 ajaxData = acf.applyFilters('select2_ajax_data/name=' + field.get('name'), ajaxData, data, $el, field, instance);
1064 ajaxData = acf.applyFilters('select2_ajax_data/key=' + field.get('key'), ajaxData, data, $el, field, instance);
1065
1066 if (ajaxData.action) {
1067 ajaxData = acf.applyFilters('select2_ajax_data/action=' + ajaxData.action, ajaxData, data, $el, field, instance);
1068 }
1069
1070 return ajaxData;
1071
1072 }
1073
1074 });
1075
1076 })(jQuery);
1077 (function($) {
1078
1079 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
1080 return;
1081 }
1082
1083
1084 /**
1085 * acfe.Form model
1086 */
1087 acfe.Form = acf.Model.extend({
1088
1089 notice: false,
1090 validator: false,
1091
1092 events: {
1093 'click .button': 'onClickSubmit',
1094 'click [type="submit"]': 'onClickSubmit',
1095 'invalidField': 'onInvalidField', // inherited from fields
1096 'changed:status': 'onChangeStatus', // inherited from validator
1097 'showErrors': 'onShowErrors', // inherited from validator
1098 },
1099
1100 setup: function($el) {
1101 this.$el = $el;
1102
1103 var cid = $el.data('cid');
1104 $.extend(this.data, acfe.getFormData(cid));
1105
1106 this.$el.data('acfe_form', this);
1107 },
1108
1109 initialize: function() {
1110
1111 // compatibility for acf validator
1112 this.$el.removeData('acf');
1113
1114 // hide unload
1115 if (this.get('hide_unload')) {
1116 acf.unload.disable();
1117 }
1118
1119 },
1120
1121 onClickSubmit: function(e, $el) {
1122 // prevent submit spam
1123 if ($el.hasClass('disabled')) {
1124 e.preventDefault();
1125 }
1126 },
1127
1128 onInvalidField: function(e, $el) {
1129
1130 // get field
1131 var field = acf.getField($(e.target));
1132
1133 // make sure notice is an error
1134 if (!field.notice || field.notice.get('type') !== 'error') {
1135 return;
1136 }
1137
1138 // error class
1139 if (this.get('error_class')) {
1140 field.notice.$el.addClass(this.get('error_class'));
1141 }
1142
1143 // error position
1144 switch (this.get('error_position')) {
1145
1146 case 'hide': {
1147 field.notice.remove();
1148 break;
1149 }
1150
1151 case 'below': {
1152
1153 if (field.$control().length) {
1154 field.notice.$el.insertAfter(field.$control());
1155 } else if (field.$inputWrap().length) {
1156 field.notice.$el.appendTo(field.$inputWrap());
1157 }
1158
1159 field.notice.$el.addClass('-below');
1160 break;
1161 }
1162
1163 case 'group': {
1164
1165 // vars
1166 var label = acfe.getTextNode(field.$labelWrap().find('label')).trim();
1167 var placeholder = field.$('.acf-input-wrap [placeholder!=""]').attr('placeholder');
1168 var message = field.notice.$el.text().trim();
1169
1170 // remove acf notice
1171 field.notice.remove();
1172
1173 // try get label
1174 if (label && label.length && label !== '*') {
1175 message = `${label}: ${message}`;
1176
1177 // otherwise placeholder
1178 } else if (placeholder && placeholder.length && placeholder !== '') {
1179 message = `${placeholder}: ${message}`;
1180
1181 // otherwise field name
1182 } else {
1183 var name = acfe.ucFirst(field.get('name')).replace(/_/g, ' ');
1184 message = `${name}: ${message}`;
1185 }
1186
1187 // append notice error
1188 if (this.notice) {
1189 this.notice.$el.append(acf.escHtml(`<p>${message}</p>`));
1190 }
1191 break;
1192
1193 }
1194
1195 }
1196
1197 },
1198
1199 onChangeStatus: function(e, $el, status, prevStatus) {
1200
1201 switch (status) {
1202
1203 // validating
1204 case 'validating': {
1205
1206 // already has validator
1207 if (this.validator) {
1208 return;
1209 }
1210
1211 // vars
1212 var validator = this.$el.data('acf');
1213 var prototype = Object.getPrototypeOf(validator);
1214
1215 // methods
1216 var showErrors = prototype.showErrors;
1217
1218 // showErrors
1219 validator.showErrors = function() {
1220 showErrors.apply(this, arguments);
1221 validator.trigger('showErrors');
1222 }
1223
1224 this.validator = validator;
1225
1226 break;
1227
1228 }
1229
1230 // invalid
1231 case 'invalid': {
1232
1233 if (this.get('error_position') === 'group') {
1234
1235 // no field errors, probably a global error
1236 // remove grouped notice
1237 if (!this.validator.getFieldErrors().length) {
1238 if (this.notice) {
1239 this.notice.remove();
1240 this.notice = false;
1241 }
1242 break;
1243 }
1244
1245 // notice exists
1246 if (this.notice) {
1247
1248 // reset
1249 this.notice.update({
1250 type: 'error',
1251 html: '',
1252 });
1253
1254 // new notice
1255 } else {
1256
1257 this.notice = acf.newNotice({
1258 type: 'error',
1259 target: this.$el
1260 });
1261
1262 }
1263
1264 // error class
1265 if (this.get('error_class')) {
1266 this.notice.$el.addClass(this.get('error_class'));
1267 }
1268
1269 // remove empty <p></p> added by "html: ''"
1270 this.notice.$el.find('p:empty').remove();
1271
1272 // timeout
1273 this.setTimeout(function() {
1274 acfe.scrollTo(this.notice.$el);
1275 }, 20);
1276
1277 }
1278
1279 break;
1280
1281 }
1282
1283 // valid
1284 case 'valid': {
1285
1286 if (this.get('error_position') === 'group') {
1287 if (this.notice) {
1288 this.notice.remove();
1289 this.notice = false;
1290 }
1291 }
1292
1293 if (this.get('hide_revalidation')) {
1294
1295 if (this.validator.has('notice')) {
1296 this.validator.get('notice').remove();
1297 this.validator.set('notice', null); // remove notice from data
1298 }
1299
1300 }
1301
1302 break;
1303
1304 }
1305
1306 }
1307
1308 },
1309
1310 onShowErrors: function(e, $el) {
1311
1312 if (this.get('hide_error')) {
1313
1314 if (this.validator.has('notice')) {
1315 this.validator.get('notice').remove();
1316 this.validator.set('notice', null); // remove notice from data
1317 }
1318
1319 } else {
1320
1321 if (this.validator.has('notice')) {
1322
1323 var fieldErrors = this.validator.getFieldErrors();
1324 var globalErrors = this.validator.getGlobalErrors();
1325 var errorCount = 0;
1326
1327 // loop
1328 fieldErrors.map(function(error) {
1329
1330 // get input
1331 var $input = this.validator.$('[name="' + error.input + '"]').first();
1332
1333 // if $_POST value was an array, this $input may not exist
1334 if (!$input.length) {
1335 $input = this.validator.$('[name^="' + error.input + '"]').first();
1336 }
1337
1338 if ($input.length) {
1339 errorCount++;
1340 }
1341
1342 }, this);
1343
1344 // errorMessage
1345 var errorMessage = this.get('messages.failure');
1346
1347 // global error
1348 globalErrors.map(function(error) {
1349 errorMessage += errorMessage.length ? '. ' : '';
1350 errorMessage += error.message;
1351 });
1352
1353 // single error
1354 if (errorCount === 1 && this.get('messages.error')) {
1355 errorMessage += errorMessage.length ? '. ' : '';
1356 errorMessage += this.get('messages.error');
1357
1358 // multiple errors
1359 } else if (errorCount > 1 && this.get('messages.errors')) {
1360 errorMessage += errorMessage.length ? '. ' : '';
1361 errorMessage += this.get('messages.errors').replace('%d', errorCount);
1362 }
1363
1364 // update notice text
1365 this.validator.get('notice').update({
1366 text: errorMessage
1367 });
1368
1369 }
1370
1371 }
1372
1373 },
1374
1375 set: function(name, value, silent) {
1376
1377 // bail if unchanged
1378 var prevValue = this.get(name);
1379 if (prevValue === value) {
1380 return this;
1381 }
1382
1383 // nameRoot
1384 // dot notation, ie: 'path.to.key'
1385 var nameArray = name.split('.');
1386 var nameRoot = nameArray.shift();
1387 var prevValueRoot = this.get(nameRoot);
1388
1389 // set data
1390 acfe.arraySet(this.data, name, value);
1391
1392 // update formData
1393 acfe.setFormData(this.get('cid'), name, value);
1394
1395 // valueRoot
1396 var valueRoot = this.get(nameRoot);
1397
1398 // trigger events
1399 if (!silent) {
1400
1401 this.changed = true;
1402
1403 if (nameArray.length > 1) {
1404 this.trigger(`changedData:${nameRoot}`, [valueRoot, prevValueRoot]);
1405 }
1406
1407 this.trigger('changedData:' + name, [value, prevValue]);
1408 this.trigger('changedData', [name, value, prevValue]);
1409
1410 }
1411
1412 // return
1413 return this;
1414
1415 },
1416
1417 });
1418
1419 acf.addAction('acfe/form/validation_success', function($form, validator, form) {
1420
1421 if (validator.has('notice')) {
1422
1423 validator.get('notice').update({
1424 type: 'success',
1425 text: form.get('messages.success'),
1426 timeout: 1000
1427 });
1428
1429 }
1430
1431 });
1432
1433 })(jQuery);
1434 (function($) {
1435
1436 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
1437 return;
1438 }
1439
1440 /**
1441 * spawner
1442 */
1443 new acf.Model({
1444 wait: 'prepare',
1445 priority: 1,
1446 initialize: function() {
1447 if (!acfe.get('is_admin')) {
1448 new formFields();
1449 }
1450 }
1451 });
1452
1453
1454 /**
1455 * formFields
1456 */
1457 var formFields = acf.Model.extend({
1458
1459 actions: {
1460 'new_field/type=date_picker': 'datePicker',
1461 'new_field/type=date_time_picker': 'datePicker',
1462 'new_field/type=time_picker': 'datePicker',
1463 'new_field/type=acfe_date_range_picker': 'datePicker',
1464 'new_field/type=google_map': 'googleMap',
1465 },
1466
1467 datePicker: function(field) {
1468
1469 var form = field.getForm();
1470
1471 if (form && form.get('field_class')) {
1472 field.$inputText().addClass(form.get('field_class'));
1473 }
1474
1475 },
1476
1477 googleMap: function(field) {
1478
1479 var form = field.getForm();
1480
1481 if (form && form.get('field_class')) {
1482 field.$search().addClass(form.get('field_class'));
1483 }
1484
1485 },
1486
1487 });
1488
1489 })(jQuery);
1490 (function($) {
1491
1492 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
1493 return;
1494 }
1495
1496 /**
1497 * acf.Field.prototype.getForm
1498 *
1499 * Allows to retrieve the front-end form instance from a field
1500 *
1501 * @returns {*|jQuery}
1502 */
1503 acf.Field.prototype.getForm = function() {
1504 return acfe.getForm(this.$el.closest('.acfe-form'));
1505 };
1506
1507
1508 /**
1509 * acfe.findForms
1510 *
1511 * @returns {jQuery|HTMLElement|*}
1512 */
1513 acfe.findForms = function(args) {
1514
1515 // string / array
1516 if (!acfe.isObject(args)) {
1517 args = {
1518 name: args,
1519 };
1520 }
1521
1522 // vars
1523 var selector = '.acfe-form';
1524 var $forms = false;
1525
1526 // args
1527 args = acf.parseArgs(args, {
1528 cid: [],
1529 name: [],
1530 parent: false,
1531 limit: false,
1532 });
1533
1534 // force array
1535 args.cid = acfe.getArray(args.cid);
1536 args.name = acfe.getArray(args.name);
1537
1538 // name
1539 if (args.name.length) {
1540
1541 for (var name of args.name) {
1542 acfe.getFormsData({
1543 name: name
1544 }).map(function(form) {
1545 args.cid.push(form.cid);
1546 });
1547 }
1548
1549 // no data found
1550 if (!args.cid.length) {
1551 return $();
1552 }
1553
1554 }
1555
1556 // cid
1557 if (args.cid.length) {
1558
1559 // vars
1560 var array = [];
1561
1562 // loop
1563 for (var cid of args.cid) {
1564 array.push(selector + '[data-cid="' + cid + '"]');
1565 }
1566
1567 selector = array.join(',');
1568 }
1569
1570 // query
1571 if (args.parent) {
1572 $forms = args.parent.find(selector);
1573 } else {
1574 $forms = $(selector);
1575 }
1576
1577 // limit
1578 if (args.limit) {
1579 $forms = $forms.slice(0, args.limit);
1580 }
1581
1582 return $forms;
1583
1584 };
1585
1586
1587 /**
1588 * acfe.getForms
1589 *
1590 * @param $forms
1591 * @returns {*[]}
1592 */
1593 acfe.getForms = function($forms) {
1594
1595 // allow jQuery
1596 if ($forms instanceof jQuery) {
1597
1598 // find forms
1599 } else {
1600 $forms = acfe.findForms($forms);
1601 }
1602
1603 // loop
1604 var forms = [];
1605 $forms.each(function() {
1606 var form = acfe.getForm($(this));
1607 if (form) {
1608 forms.push(form);
1609 }
1610 });
1611
1612 // return
1613 return forms;
1614
1615 };
1616
1617
1618 /**
1619 * acfe.getForm
1620 *
1621 * @param $form
1622 * @returns {*|jQuery}
1623 */
1624 acfe.getForm = function($form) {
1625
1626 // allow jQuery
1627 if ($form instanceof jQuery) {
1628
1629 if (!$form.hasClass('acfe-form')) {
1630 return false;
1631 }
1632
1633 // find form
1634 } else {
1635 $form = acfe.findForm($form);
1636 }
1637
1638 // found form
1639 if ($form.length) {
1640
1641 // instantiate
1642 var form = $form.data('acfe_form');
1643 if (!form) {
1644 form = acfe.newForm($form);
1645 }
1646
1647 // return
1648 return form;
1649
1650 }
1651
1652 return false;
1653
1654 };
1655
1656
1657 /**
1658 * acfe.findForm
1659 *
1660 * @param args
1661 * @returns {*}
1662 */
1663 acfe.findForm = function(args) {
1664
1665 // if string / array
1666 // use form name as default
1667 if (!acfe.isObject(args)) {
1668 args = {
1669 name: args,
1670 };
1671 }
1672
1673 args = acf.parseArgs(args, {
1674 limit: 1,
1675 });
1676
1677 return acfe.findForms(args);
1678 };
1679
1680
1681 /**
1682 * acfe.newForm
1683 *
1684 * @param $form
1685 * @returns {*}
1686 */
1687 acfe.newForm = function($form) {
1688
1689 // instantiate
1690 var form = new acfe.Form($form);
1691
1692 // actions
1693 acf.doAction(`acfe/new_form`, form);
1694 acf.doAction(`acfe/new_form/form=${form.get('name')}`, form);
1695
1696 // return
1697 return form;
1698 };
1699
1700
1701 /**
1702 * acfe.getFormsData
1703 *
1704 * @param args
1705 * @returns {*[]}
1706 */
1707 acfe.getFormsData = function(args) {
1708
1709 // acfe.Form instance
1710 if (args instanceof acfe.Form) {
1711 args = {
1712 form: args,
1713 };
1714
1715 // string
1716 } else if (!acfe.isObject(args)) {
1717 args = {
1718 cid: args,
1719 };
1720 }
1721
1722 // args
1723 args = acf.parseArgs(args, {
1724 form: '',
1725 cid: '',
1726 name: '',
1727 success: '',
1728 });
1729
1730 if (args.form && args.form instanceof acfe.Form) {
1731 args.cid = args.form.get('cid');
1732 }
1733
1734 // get data
1735 var forms = [];
1736 var data = acfe.get('forms', {});
1737
1738 // empty data
1739 if (!Object.keys(data).length) {
1740 return forms;
1741 }
1742
1743 for (var cid in data) {
1744 if (data[cid]) {
1745
1746 var matchCid = true;
1747 var matchName = true;
1748 var matchSuccess = true;
1749
1750 if (args.cid.length) {
1751 matchCid = args.cid === cid;
1752 }
1753 if (args.name.length) {
1754 matchName = args.name === data[cid].name;
1755 }
1756 if (args.success !== '') {
1757 matchSuccess = args.success === data[cid].success;
1758 }
1759
1760 if (matchCid && matchName && matchSuccess) {
1761 forms.push(data[cid]);
1762 }
1763
1764 }
1765 }
1766
1767 return forms;
1768
1769 };
1770
1771
1772 /**
1773 * acfe.getFormData
1774 *
1775 * @param args
1776 * @returns {*|boolean}
1777 */
1778 acfe.getFormData = function(args) {
1779
1780 var forms = acfe.getFormsData(args);
1781
1782 if (forms.length) {
1783 return forms.shift();
1784 }
1785
1786 return false;
1787
1788 };
1789
1790
1791 /**
1792 * acfe.setFormData
1793 *
1794 * @param cid
1795 * @param path
1796 * @param value
1797 */
1798 acfe.setFormData = function(cid, path, value) {
1799 acfe.set(`forms.${cid}.${path}`, value);
1800 };
1801
1802
1803 /**
1804 * acfe.loadForm
1805 *
1806 * @param $parent
1807 */
1808 acfe.renderForm = function($parent) {
1809
1810 // form is passed instead of parent
1811 if ($parent && $parent.length && $parent.hasClass('acfe-form')) {
1812 $parent = $parent.parent();
1813 }
1814
1815 // initialize fields and forms
1816 acf.doAction('append', $parent);
1817
1818 };
1819
1820 })(jQuery);
1821 (function($) {
1822
1823 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
1824 return;
1825 }
1826
1827 new acf.Model({
1828 wait: 'prepare',
1829 priority: 5,
1830 initialize: function() {
1831 if (!acfe.get('is_admin')) {
1832 new renderHooks();
1833 }
1834 }
1835 });
1836
1837
1838 /**
1839 * renderHooks
1840 */
1841 var renderHooks = acf.Model.extend({
1842
1843 actions: {
1844 'validation_begin': 'validationBegin',
1845 'validation_failure': 'validationFailure',
1846 'validation_success': 'validationSuccess',
1847 'submit': 'submit',
1848 },
1849 filters: {
1850 'validation_complete': 'validationComplete',
1851 },
1852
1853 validationBegin: function($el) {
1854
1855 var form = acfe.getForm($el);
1856 if (form) {
1857 var validator = $el.data('acf');
1858 acf.doAction('acfe/form/validation_begin', $el, validator, form);
1859 acf.doAction(`acfe/form/validation_begin/form=${form.get('name')}`, $el, validator, form);
1860 }
1861
1862
1863 },
1864
1865 validationFailure: function($el, validator) {
1866
1867 var form = acfe.getForm($el);
1868 if (form) {
1869 acf.doAction('acfe/form/validation_failure', $el, validator, form);
1870 acf.doAction(`acfe/form/validation_failure/form=${form.get('name')}`, $el, validator, form);
1871 }
1872
1873 },
1874
1875 validationSuccess: function($el, validator) {
1876
1877 var form = acfe.getForm($el);
1878 if (form) {
1879 acf.doAction('acfe/form/validation_success', $el, validator, form);
1880 acf.doAction(`acfe/form/validation_success/form=${form.get('name')}`, $el, validator, form);
1881 }
1882
1883 },
1884
1885 submit: function($el) {
1886
1887 var form = acfe.getForm($el);
1888 if (form) {
1889 var validator = $el.data('acf');
1890 acf.doAction('acfe/form/submit', $el, validator, form);
1891 acf.doAction(`acfe/form/submit/form=${form.get('name')}`, $el, validator, form);
1892 }
1893
1894 },
1895
1896 validationComplete: function(data, $el, validator) {
1897
1898 var form = acfe.getForm($el);
1899 if (form) {
1900 data = acf.applyFilters('acfe/form/validation_complete', data, $el, validator, form);
1901 data = acf.applyFilters(`acfe/form/validation_complete/form=${form.get('name')}`, data, $el, validator, form);
1902 }
1903
1904 return data;
1905 },
1906
1907 });
1908
1909 })(jQuery);
1910 (function($) {
1911
1912 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
1913 return;
1914 }
1915
1916 /**
1917 * form initializer
1918 *
1919 * @type {string[]}
1920 */
1921 var actions = ['prepare', 'ready', 'load', 'append'];
1922
1923 actions.map(function(action) {
1924
1925 acf.addAction(action, function($el) {
1926
1927 // initialize front-end forms
1928 if (!acfe.get('is_admin')) {
1929 acfe.getForms({
1930 parent: $el
1931 });
1932 }
1933
1934 }, 1);
1935
1936 });
1937
1938 })(jQuery);
1939 (function($) {
1940
1941 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
1942 return;
1943 }
1944
1945 /**
1946 * spawner
1947 */
1948 new acf.Model({
1949 wait: 'ready',
1950 priority: 15,
1951 initialize: function() {
1952
1953 if (!acfe.get('is_admin') && acf.isset(window, 'wp', 'media', 'view', 'settings', 'post')) {
1954 new formMedia();
1955 }
1956
1957 }
1958 });
1959
1960
1961 /**
1962 * formMedia
1963 */
1964 var formMedia = acf.Model.extend({
1965
1966 defaultPostId: null,
1967
1968 actions: {
1969 'new_media_popup': 'newMediaPopup',
1970 'acfe/before_editor_media_popup': 'beforeEditorPopup',
1971 'acfe/open_editor_media_popup': 'openEditorPopup',
1972 'acfe/close_editor_media_popup': 'closeEditorPopup',
1973 },
1974
1975 filters: {
1976 'acfe/select_media_popup/args': 'mediaPopupArgs',
1977 'acfe/select_media_popup/frame_options': 'mediaPopupFrameOptions',
1978 },
1979
1980 initialize: function() {
1981 // acf set wp.media.view.settings.post.id on ready:10
1982 this.defaultPostId = wp.media.view.settings.post.id;
1983 },
1984
1985 resetPostId: function() {
1986 // reset upload post id back to default
1987 wp.media.view.settings.post.id = this.defaultPostId;
1988 },
1989
1990 newMediaPopup: function(popup) {
1991
1992 // change the post attached to the uploaded file
1993 if (popup.get('attachTo') !== null) {
1994 wp.media.view.settings.post.id = popup.get('attachTo');
1995 }
1996
1997 // on close: reset post id
1998 popup.frame.on('close', this.proxy(this.resetPostId));
1999
2000 },
2001
2002 beforeEditorPopup: function(field) {
2003
2004 // change the post attached to the uploaded file
2005 var attachTo = this.getFieldAttachTo(field);
2006 if (attachTo !== false) {
2007 wp.media.view.settings.post.id = attachTo;
2008 }
2009
2010 },
2011
2012 openEditorPopup: function(field) {
2013
2014 // fix 'uploaded to' filter
2015 var attachTo = this.getFieldAttachTo(field);
2016 if (attachTo !== false) {
2017 wp.media.view.settings.post.id = attachTo;
2018 }
2019
2020 },
2021
2022 closeEditorPopup: function(field) {
2023
2024 // set timeout to let send.attachment use the correct post id
2025 this.setTimeout(this.resetPostId, 100);
2026
2027 },
2028
2029 mediaPopupArgs: function(args, field) {
2030
2031 var attachTo = this.getFieldAttachTo(field);
2032 if (attachTo !== false) {
2033 args.attachTo = attachTo;
2034 }
2035
2036 // return
2037 return args;
2038
2039 },
2040
2041 mediaPopupFrameOptions: function(options, popup) {
2042
2043 // change the 'uploaded to' filter
2044 // based on 'args.attachTo' set above
2045 if (popup.get('library') === 'uploadedTo' && popup.get('attachTo') !== null) {
2046 options.library.uploadedTo = popup.get('attachTo');
2047 }
2048
2049 // return
2050 return options;
2051
2052 },
2053
2054 getFieldAttachTo: function(field) {
2055
2056 // check if the field is part of an acfe-form
2057 var form = field.getForm();
2058 if (!form) {
2059 return false;
2060 }
2061
2062 // set attachTo 0 by default
2063 // this attach a post to the uploaded media (doesn't attach if 0)
2064 // this set the library 'uploaded to' filter
2065 // it follows the native acf_form logic which doesn't attach when creating a new post (acf.get(post_id) = 0)
2066 var attachTo = 0;
2067
2068 // check if form has 'update_post' action
2069 // check if the field (image/file/gallery) is in 'media' array
2070 if (form.get('media')) {
2071
2072 // loop media rows
2073 form.get('media').some(function(row) {
2074 if (acfe.inArray(field.get('key'), row.fields)) {
2075 attachTo = row.post_id;
2076 return true; // do not process other rows
2077 }
2078 });
2079
2080 }
2081
2082 // return
2083 return attachTo;
2084
2085 }
2086
2087 });
2088
2089 })(jQuery);
2090 (function($) {
2091
2092 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
2093 return;
2094 }
2095
2096
2097 new acf.Model({
2098 wait: 'prepare',
2099 priority: 5,
2100 initialize: function() {
2101 if (!acfe.get('is_admin')) {
2102 new renderSuccess();
2103 }
2104 }
2105 });
2106
2107
2108 /**
2109 * renderSuccess
2110 */
2111 var renderSuccess = acf.Model.extend({
2112
2113 initialize: function() {
2114
2115 // get form success
2116 var object = this.getFormSuccess();
2117
2118 // validate form success
2119 if (!object) {
2120 return;
2121 }
2122
2123 // vars
2124 // form instance might not exist if form is hidden on success
2125 var data = object.data;
2126 var $el = object.form ? object.form.$el : false;
2127 var form = object.form ? object.form : false;
2128 var formData = object.form ? object.form.get('success_data') : object.data.success_data;
2129
2130 // hooks
2131 acf.doAction(`acfe/form/submit_success`, $el, form, formData);
2132 acf.doAction(`acfe/form/submit_success/form=${data.name}`, $el, form, formData);
2133
2134 // deprecated
2135 acfe.doActionDeprecated(`acfe/form/success`, [$el], '0.9.0.3', `acfe/form/submit_success`);
2136 acfe.doActionDeprecated(`acfe/form/success/id=${data.id}`, [$el], '0.9.0.3', `acfe/form/submit_success/form=${data.name}`);
2137 acfe.doActionDeprecated(`acfe/form/success/form=${data.name}`, [$el], '0.9.0.3', `acfe/form/submit_success/form=${data.name}`);
2138 acfe.doActionDeprecated(`acfe/form/success/name=${data.name}`, [$el], '0.9.0.3', `acfe/form/submit_success/form=${data.name}`);
2139
2140 // deprecated
2141 acfe.doActionDeprecated(`acfe/form/submit/success`, [$el], '0.9.0.3', `acfe/form/submit_success`);
2142 acfe.doActionDeprecated(`acfe/form/submit/success/id=${data.id}`, [$el], '0.9.0.3', `acfe/form/submit_success/form=${data.name}`);
2143 acfe.doActionDeprecated(`acfe/form/submit/success/name=${data.name}`, [$el], '0.9.0.3', `acfe/form/submit_success/form=${data.name}`);
2144
2145 // should scroll
2146 if (data.scroll) {
2147
2148 // scroll to message
2149 if (data.selector) {
2150 acfe.scrollTo($(data.selector));
2151
2152 // scroll to previous element
2153 } else if ($el) {
2154 acfe.scrollTo($el.prev());
2155
2156 }
2157
2158 }
2159
2160 },
2161
2162 getFormSuccess: function() {
2163
2164 var formData = acfe.getFormData({
2165 success: true
2166 });
2167 if (formData) {
2168 return {
2169 form: acfe.getForm({
2170 cid: formData.cid
2171 }),
2172 data: formData,
2173 };
2174 }
2175
2176 return false;
2177
2178 },
2179
2180 });
2181
2182 })(jQuery);
2183 (function($) {
2184
2185 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
2186 return;
2187 }
2188
2189 /**
2190 * Image/File
2191 *
2192 * select attachment
2193 */
2194 var selectAttachment = function() {
2195
2196 // vars
2197 var parent = this.parent();
2198 var multiple = parent && parent.get('type') === 'repeater';
2199
2200 // default args
2201 var args = {
2202 mode: 'select',
2203 field: this.get('key'),
2204 multiple: multiple,
2205 library: this.get('library'),
2206 allowedTypes: this.get('mime_types'),
2207 select: $.proxy(function(attachment, i) {
2208 if (i > 0) {
2209 this.append(attachment, parent);
2210 } else {
2211
2212 // fix for ACF 6.8.1
2213 if (acfe.isACF('6.8.1') && this.get('type') === 'image') {
2214 acf.val(this.$input(), String(attachment.id || attachment.attributes?.id || ''));
2215 }
2216
2217 this.render(attachment);
2218
2219 }
2220 }, this)
2221 };
2222
2223 // field type
2224 switch (this.get('type')) {
2225
2226 // image args
2227 case 'image': {
2228 args.type = 'image';
2229 args.title = acf.__('Select Image');
2230 break;
2231 }
2232
2233 // file args
2234 case 'file': {
2235 args.title = acf.__('Select File');
2236 break;
2237 }
2238
2239 }
2240
2241 // filters
2242 args = acf.applyFilters(`acfe/select_media_popup/args`, args, this);
2243 args = acf.applyFilters(`acfe/select_media_popup/args/type=${this.get('type')}`, args, this);
2244 args = acf.applyFilters(`acfe/select_media_popup/args/name=${this.get('name')}`, args, this);
2245 args = acf.applyFilters(`acfe/select_media_popup/args/key=${this.get('key')}`, args, this);
2246
2247 // new frame
2248 var frame = acf.newMediaPopup(args);
2249
2250 };
2251
2252 // assign new function
2253 acf.models.ImageField.prototype.selectAttachment = selectAttachment;
2254 acf.models.FileField.prototype.selectAttachment = selectAttachment;
2255
2256
2257 /**
2258 * Image/File
2259 *
2260 * edit attachment
2261 */
2262 var editAttachment = function() {
2263
2264 // vars
2265 var val = this.val();
2266
2267 // bail early if no val
2268 if (!val) {
2269 return false;
2270 }
2271
2272 // default args
2273 var args = {
2274 mode: 'edit',
2275 attachment: val,
2276 field: this.get('key'),
2277 select: $.proxy(function(attachment, i) {
2278
2279 // fix for ACF 6.8.1
2280 if (acfe.isACF('6.8.1') && this.get('type') === 'image') {
2281 acf.val(this.$input(), String(attachment.id || attachment.attributes?.id || ''));
2282 }
2283
2284 this.render(attachment);
2285
2286 }, this)
2287 };
2288
2289 // field type
2290 switch (this.get('type')) {
2291
2292 // image args
2293 case 'image': {
2294 args.title = acf.__('Edit File');
2295 args.button = acf.__('Update File');
2296 break;
2297 }
2298
2299 // file args
2300 case 'file': {
2301 args.title = acf.__('Edit Image');
2302 args.button = acf.__('Update Image');
2303 break;
2304 }
2305
2306 }
2307
2308 // filters
2309 args = acf.applyFilters(`acfe/edit_media_popup/args`, args, this);
2310 args = acf.applyFilters(`acfe/edit_media_popup/args/type=${this.get('type')}`, args, this);
2311 args = acf.applyFilters(`acfe/edit_media_popup/args/name=${this.get('name')}`, args, this);
2312 args = acf.applyFilters(`acfe/edit_media_popup/args/key=${this.get('key')}`, args, this);
2313
2314 // popup
2315 var frame = acf.newMediaPopup(args);
2316
2317 }
2318
2319 // assign new function
2320 acf.models.ImageField.prototype.editAttachment = editAttachment;
2321 acf.models.FileField.prototype.editAttachment = editAttachment;
2322
2323
2324 /**
2325 * Gallery
2326 *
2327 * select attachment
2328 */
2329 var galleryOnClickAdd = function(e, $el) {
2330
2331 // validate
2332 if (this.isFull()) {
2333 this.showNotice({
2334 text: acf.__('Maximum selection reached'),
2335 type: 'warning'
2336 });
2337 return;
2338 }
2339
2340 // args
2341 var args = {
2342 mode: 'select',
2343 title: acf.__('Add Image to Gallery'),
2344 field: this.get('key'),
2345 multiple: 'add',
2346 library: this.get('library'),
2347 allowedTypes: this.get('mime_types'),
2348 selected: this.val(),
2349 select: $.proxy(function(attachment, i) {
2350 this.appendAttachment(attachment, i);
2351 }, this)
2352 };
2353
2354 // filters
2355 args = acf.applyFilters(`acfe/select_media_popup/args`, args, this);
2356 args = acf.applyFilters(`acfe/select_media_popup/args/type=${this.get('type')}`, args, this);
2357 args = acf.applyFilters(`acfe/select_media_popup/args/name=${this.get('name')}`, args, this);
2358 args = acf.applyFilters(`acfe/select_media_popup/args/key=${this.get('key')}`, args, this);
2359
2360 // new frame
2361 var frame = acf.newMediaPopup(args);
2362
2363 };
2364
2365
2366 /**
2367 * Gallery
2368 *
2369 * edit attachment
2370 */
2371 var galleryEditAttachment = function(id) {
2372
2373 var args = {
2374 mode: 'edit',
2375 title: acf.__('Edit Image'),
2376 button: acf.__('Update Image'),
2377 attachment: id,
2378 field: this.get('key'),
2379 select: $.proxy(function(attachment, i) {
2380 this.renderAttachment(attachment);
2381 }, this)
2382 };
2383
2384 // filters
2385 args = acf.applyFilters(`acfe/edit_media_popup/args`, args, this);
2386 args = acf.applyFilters(`acfe/edit_media_popup/args/type=${this.get('type')}`, args, this);
2387 args = acf.applyFilters(`acfe/edit_media_popup/args/name=${this.get('name')}`, args, this);
2388 args = acf.applyFilters(`acfe/edit_media_popup/args/key=${this.get('key')}`, args, this);
2389
2390 // new frame
2391 var frame = acf.newMediaPopup(args);
2392 }
2393
2394 acf.models.GalleryField.prototype.onClickAdd = galleryOnClickAdd;
2395 acf.models.GalleryField.prototype.editAttachment = galleryEditAttachment;
2396
2397
2398 /**
2399 * MediaPopup
2400 *
2401 * getFrameOptions
2402 *
2403 * @type {function(): *}
2404 */
2405 var selectGetFrameOptions = acf.models.SelectMediaPopup.prototype.getFrameOptions;
2406 acf.models.SelectMediaPopup.prototype.getFrameOptions = function() {
2407
2408 // call original function
2409 var options = selectGetFrameOptions.apply(this, arguments);
2410
2411 // filters
2412 options = acf.applyFilters(`acfe/select_media_popup/frame_options`, options, this);
2413
2414 // return
2415 return options;
2416
2417 }
2418
2419 var editGetFrameOptions = acf.models.EditMediaPopup.prototype.getFrameOptions;
2420 acf.models.EditMediaPopup.prototype.getFrameOptions = function() {
2421
2422 // call original function
2423 var options = editGetFrameOptions.apply(this, arguments);
2424
2425 // filters
2426 options = acf.applyFilters(`acfe/edit_media_popup/frame_options`, options, this);
2427
2428 // return
2429 return options;
2430
2431 }
2432
2433
2434 /**
2435 * ACF WYSIWYG
2436 *
2437 * Media Modal
2438 */
2439 new acf.Model({
2440
2441 wait: 'prepare',
2442 done: [],
2443
2444 initialize: function() {
2445 if (acf.isset(window, 'wp', 'media', 'editor')) {
2446 this.customizeEditor();
2447 }
2448 },
2449
2450 customizeEditor: function() {
2451
2452 // vars
2453 var self = this;
2454 var parent = wp.media.editor.add;
2455
2456 // editor.add
2457 wp.media.editor.add = function(id, options) {
2458
2459 // check id starts with 'acf-editor' & make sure it's not already done
2460 if (typeof id !== 'string' || !id.startsWith('acf-editor') || self.done.includes(id)) {
2461 return parent.apply(this, arguments);
2462 }
2463
2464 // done
2465 self.done.push(id);
2466
2467 // get field
2468 var $field = $('#' + id).closest('.acf-field');
2469 if (!$field.length) {
2470 return parent.apply(this, arguments);
2471 }
2472
2473 // get field instance
2474 var field = acf.getInstance($field);
2475 if (!field) {
2476 return parent.apply(this, arguments);
2477 }
2478
2479 // before popup
2480 acf.doAction('acfe/before_editor_media_popup', field);
2481
2482 // call original function
2483 // this initialize the uploader which use
2484 // wp.media.view.settings.post.id
2485 var frame = parent.apply(this, arguments);
2486
2487 // new popup
2488 acf.doAction('acfe/new_editor_media_popup', field, frame);
2489
2490 // open popup
2491 frame.on('open', function() {
2492 acf.doAction('acfe/open_editor_media_popup', field, frame);
2493 });
2494
2495 // close popup
2496 frame.on('close', function() {
2497 acf.doAction('acfe/close_editor_media_popup', field, frame);
2498 });
2499
2500 // return
2501 return frame;
2502
2503 }
2504
2505 },
2506
2507 });
2508
2509 })(jQuery);
2510 (function($) {
2511
2512 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
2513 return;
2514 }
2515
2516
2517 /**
2518 * acf.validation.onClickSubmit
2519 *
2520 * Fix front-end form triggering validation for all forms is there are multiple forms on the page
2521 * This function is untouched. We just pass the $el to ensureInvalidFieldVisibility($el)
2522 *
2523 * @param e
2524 * @param $el
2525 *
2526 * @since ACF 5.11
2527 */
2528 acf.validation.onClickSubmit = function(e, $el) {
2529
2530 // some browsers (safari) force their browser validation before our AJAX validation,
2531 // so we need to make sure fields are visible earlier than showErrors()
2532 ensureInvalidFieldVisibility($el);
2533
2534 // store the "click event" for later use in this.onSubmit()
2535 this.set('originalEvent', e);
2536
2537 }
2538
2539
2540 /**
2541 * ensureInvalidFieldVisibility
2542 *
2543 * Add current element as argument
2544 *
2545 * @param $el
2546 *
2547 * @since ACF 5.11.4
2548 */
2549 var ensureInvalidFieldVisibility = function($el) {
2550
2551 // load each ACF input field and check it's browser validation state.
2552 var $inputs = $('.acf-field input');
2553
2554 // acfe: retrieve the current element parents form
2555 var $form = $el.closest('form');
2556
2557 // acfe: find fields inside the current form only
2558 if ($form.length) {
2559 $inputs = $form.find('.acf-field input');
2560 }
2561
2562 $inputs.each(function() {
2563 if (!this.checkValidity()) {
2564
2565 // field is invalid, so we need to make sure it's metabox is visible.
2566 ensureFieldPostBoxIsVisible($(this));
2567
2568 }
2569 });
2570
2571 };
2572
2573
2574 /**
2575 * ensureFieldPostBoxIsVisible
2576 *
2577 * @param $el
2578 *
2579 * @since ACF 5.11.4
2580 */
2581 var ensureFieldPostBoxIsVisible = function($el) {
2582
2583 // Find the postbox element containing this field.
2584 var $postbox = $el.parents('.acf-postbox');
2585
2586 if ($postbox.length) {
2587 var acf_postbox = acf.getPostbox($postbox);
2588
2589 // ACFE: use class check instead of isHiddenByScreenOptions() for older ACF versions
2590 if (acf_postbox && (acf_postbox.$el.hasClass('hide-if-js') || acf_postbox.$el.css('display') == 'none')) {
2591 // Rather than using .show() here, we don't want the field to appear next reload.
2592 // So just temporarily show the field group so validation can complete.
2593 acf_postbox.$el.removeClass('hide-if-js');
2594 acf_postbox.$el.css('display', '');
2595 }
2596 }
2597
2598 };
2599
2600 })(jQuery);
2601 (function($) {
2602
2603 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
2604 return;
2605 }
2606
2607 /**
2608 * Field: Advanced Link
2609 */
2610 var ACFE_Advanced_Link = acf.Field.extend({
2611
2612 type: 'acfe_advanced_link',
2613
2614 events: {
2615 'click a[data-name="add"]': 'onClickEdit',
2616 'click a[data-name="edit"]': 'onClickEdit',
2617 'click a[data-name="remove"]': 'onClickRemove',
2618 },
2619
2620 $control: function() {
2621 return this.$('.acf-link');
2622 },
2623
2624 getSubField: function(key) {
2625
2626 return acf.getFields({
2627 key: key,
2628 parent: this.$el
2629 }).shift();
2630
2631 },
2632
2633 getSubFields: function() {
2634
2635 return acf.getFields({
2636 parent: this.$el
2637 });
2638
2639 },
2640
2641 getValue: function() {
2642
2643 // return
2644 var data = {
2645 type: this.getSubField('type').val(),
2646 title: this.getSubField('title').val(),
2647 value: '',
2648 name: '',
2649 target: Boolean(this.getSubField('target').val())
2650 };
2651
2652 // assign value
2653 data.value = this.getSubField(data.type).val();
2654 data.name = data.value;
2655
2656 // post / term value
2657 if (data.type === 'post' || data.type === 'term') {
2658 data.name = this.getSubField(data.type).$input().find(':selected').text();
2659 }
2660
2661 // return
2662 return data;
2663
2664 },
2665
2666 setValue: function(val) {
2667
2668 // clear value
2669 if (!val) {
2670 return this.clearValue();
2671 }
2672
2673 // allow val to be a string
2674 if (acfe.isString(val)) {
2675
2676 val = {
2677 type: 'url',
2678 title: '',
2679 value: val,
2680 target: false
2681 };
2682
2683 }
2684
2685 val = acf.parseArgs(val, {
2686 type: 'url',
2687 value: '',
2688 title: '',
2689 target: false
2690 });
2691
2692 // set sub fields
2693 this.getSubField('type').val(val.type);
2694 this.getSubField(val.type).val(val.value); // post / term value
2695 this.getSubField('title').val(val.title);
2696 this.getSubField('target').val(val.target);
2697
2698 // render value
2699 this.renderValue();
2700
2701 },
2702
2703 clearValue: function() {
2704
2705 // clear subfields values
2706 this.getSubFields().map(function(field) {
2707 field.val('');
2708 });
2709
2710 },
2711
2712 renderValue: function() {
2713
2714 // vars
2715 var val = this.val();
2716 var $control = this.$control();
2717
2718 // remove class
2719 $control.removeClass('-value -external');
2720
2721 // add class
2722 if (val.value || val.title) {
2723 $control.addClass('-value');
2724 }
2725
2726 // target
2727 if (val.target) {
2728 $control.addClass('-external');
2729 }
2730
2731 // update text
2732 var url = val.type === 'url' ? val.value : '#';
2733 this.$('.link-title').html(val.title);
2734 this.$('.link-url').attr('href', url).html(val.name);
2735
2736 },
2737
2738 onClickEdit: function(e, $el) {
2739
2740 // vars
2741 this.getModal({
2742 open: true,
2743 onClose: this.proxy(function() {
2744 this.renderValue();
2745 })
2746 });
2747
2748 },
2749
2750 onClickRemove: function(e, $el) {
2751
2752 this.clearValue();
2753 this.renderValue();
2754
2755 },
2756
2757 });
2758
2759 acf.registerFieldType(ACFE_Advanced_Link);
2760
2761
2762 /**
2763 * Field: Advanced Link Ajax Manager
2764 */
2765 new acf.Model({
2766
2767 filters: {
2768 'select2_ajax_data/action=acfe/fields/advanced_link/post_query': 'ajaxData',
2769 },
2770
2771 ajaxData: function(ajaxData, data, $el, field, select) {
2772
2773 // get advanced link field
2774 var parentField = field.parent();
2775
2776 // assign parent field key
2777 if (parentField) {
2778 ajaxData.field_key = parentField.get('key');
2779 }
2780
2781 return ajaxData;
2782
2783 },
2784
2785 });
2786
2787 })(jQuery);
2788 (function($) {
2789
2790 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
2791 return;
2792 }
2793
2794 /**
2795 * Field: Button
2796 */
2797 var ACFE_Button = acf.Field.extend({
2798
2799 type: 'acfe_button',
2800
2801 events: {
2802 'click input': 'onClick',
2803 'click button': 'onClick',
2804 },
2805
2806 $input: function() {
2807
2808 if (this.$('input').length) {
2809
2810 return this.$('input');
2811
2812 } else if (this.$('button').length) {
2813
2814 return this.$('button');
2815
2816 }
2817
2818 },
2819
2820 initialize: function() {
2821
2822 // vars
2823 var $button = this.$input();
2824
2825 // inherit data
2826 this.inherit($button);
2827
2828 },
2829
2830 onClick: function(e, $el) {
2831
2832 if (!this.get('ajax')) return;
2833
2834 e.preventDefault();
2835
2836 // serialize form data
2837 var data = {
2838 action: 'acfe/fields/button',
2839 field_key: this.get('key'),
2840 acf: acf.serialize(this.$el.closest('form'), 'acf')
2841 };
2842
2843 data = acf.applyFilters('acfe/fields/button/data', data, this.$el);
2844 data = acf.applyFilters('acfe/fields/button/data/name=' + this.get('name'), data, this.$el);
2845 data = acf.applyFilters('acfe/fields/button/data/key=' + this.get('key'), data, this.$el);
2846
2847 // Deprecated
2848 acf.doAction('acfe/fields/button/before_ajax', this.$el, data);
2849
2850 // Actions
2851 acf.doAction('acfe/fields/button/before', this.$el, data);
2852 acf.doAction('acfe/fields/button/before/name=' + this.get('name'), this.$el, data);
2853 acf.doAction('acfe/fields/button/before/key=' + this.get('key'), this.$el, data);
2854
2855 // ajax
2856 $.ajax({
2857 url: acf.get('ajaxurl'),
2858 data: acf.prepareForAjax(data),
2859 type: 'post',
2860 dataType: 'json',
2861 context: this,
2862
2863 // Success
2864 success: function(response) {
2865
2866 // Deprecated
2867 acf.doAction('acfe/fields/button/ajax_success', response, this.$el, data);
2868
2869 // Actions
2870 acf.doAction('acfe/fields/button/success', response, this.$el, data);
2871 acf.doAction('acfe/fields/button/success/name=' + this.get('name'), response, this.$el, data);
2872 acf.doAction('acfe/fields/button/success/key=' + this.get('key'), response, this.$el, data);
2873
2874 },
2875
2876 // Complete
2877 complete: function(xhr) {
2878
2879 var response = xhr.responseText;
2880
2881 // Actions
2882 acf.doAction('acfe/fields/button/complete', response, this.$el, data);
2883 acf.doAction('acfe/fields/button/complete/name=' + this.get('name'), response, this.$el, data);
2884 acf.doAction('acfe/fields/button/complete/key=' + this.get('key'), response, this.$el, data);
2885
2886 }
2887
2888
2889 });
2890
2891 }
2892
2893 });
2894
2895 acf.registerFieldType(ACFE_Button);
2896
2897 })(jQuery);
2898 (function($) {
2899
2900 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
2901 return;
2902 }
2903
2904 /**
2905 * Field: Checkbox
2906 */
2907 var Checkbox = acf.models.CheckboxField;
2908
2909 acf.models.CheckboxField = Checkbox.extend({
2910
2911 // add setValue method
2912 // this allows to use field.val('new_value') to assign a new value to the field
2913 setValue: function(val) {
2914
2915 // clear value
2916 if (!val) {
2917 return this.clearValue();
2918 }
2919
2920 // force value as array
2921 var vals = acfe.getArray(val);
2922
2923 // map values
2924 vals.map(function(val) {
2925
2926 // get option with value
2927 var $option = this.$(':checkbox[value="' + val + '"]');
2928
2929 // option exists and is not already selected
2930 if ($option.length && !$option.is(':checked')) {
2931
2932 // select the option
2933 $option.prop('checked', true).trigger('change');
2934
2935 }
2936
2937 }, this);
2938
2939 },
2940
2941 // add clearValue method
2942 // this allows to set the value to the first radio or if allow_null is enabled, to null
2943 clearValue: function() {
2944
2945 var $inputs = this.$inputs();
2946 var $labels = this.$('label');
2947
2948 // update "checked" state.
2949 $inputs.prop('checked', false);
2950
2951 // remove "selected" class.
2952 $labels.removeClass('selected');
2953
2954 }
2955
2956 });
2957
2958 })(jQuery);
2959 (function($) {
2960
2961 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
2962 return;
2963 }
2964
2965 /**
2966 * Field: Clone
2967 */
2968 var Clone = acf.Field.extend({
2969
2970 wait: false,
2971
2972 type: 'clone',
2973
2974 events: {
2975 'duplicateField': 'onDuplicate'
2976 },
2977
2978 initialize: function() {
2979
2980 if (this.has('acfeCloneModal')) {
2981
2982 this.$el.find('> .acf-input > .acf-fields, > .acf-input > .acf-table').wrapAll('<div class="acfe-modal"><div class="acfe-modal-wrapper"><div class="acfe-modal-content"></div></div></div>');
2983 this.$el.find('> .acf-input').append('<a href="#" class="acf-button button" data-modal>' + this.get('acfeCloneModalButton') + '</a>');
2984
2985 this.initializeModal();
2986
2987 }
2988
2989 },
2990
2991 initializeModal: function() {
2992
2993 // normal title
2994 var title = this.$labelWrap().find('label').text().trim();
2995
2996 // inside table
2997 if (this.$el.is('td')) {
2998
2999 title = this.get('acfeCloneModalButton');
3000 var $th = this.$el.closest('table').find(' > thead th[data-key="' + this.get('key') + '"]');
3001
3002 if ($th.length) {
3003 title = acfe.getTextNode($th);
3004 }
3005
3006 }
3007
3008 // fallback to button text
3009 if (!title.length) {
3010 title = this.get('acfeCloneModalButton');
3011 }
3012
3013 // modal
3014 this.getModal({
3015 title: title,
3016 size: this.has('acfeCloneModalSize') ? this.get('acfeCloneModalSize') : 'large',
3017 footer: this.has('acfeCloneModalClose') ? acf.__('Close') : false,
3018 class: 'acfe-modal-edit-' + this.get('name') + ' acfe-modal-edit-' + this.get('key')
3019 });
3020
3021 },
3022
3023 onDuplicate: function(e, $el, $duplicate) {
3024 $duplicate.find('.acf-input:first > a[data-modal]').remove();
3025 }
3026
3027 });
3028
3029 acf.registerFieldType(Clone);
3030
3031 })(jQuery);
3032 (function($) {
3033
3034 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3035 return;
3036 }
3037
3038 /**
3039 * Field: Code Editor
3040 */
3041 var CodeEditor = acf.Field.extend({
3042
3043 wait: false,
3044
3045 type: 'acfe_code_editor',
3046
3047 editor: {},
3048
3049 events: {
3050 'showField': 'onShow',
3051 'duplicateField': 'onDuplicate'
3052 },
3053
3054 $control: function() {
3055 return this.$('> .acf-input > .acf-input-wrap');
3056 },
3057
3058 $input: function() {
3059 return this.$control().find('> textarea');
3060 },
3061
3062 initialize: function() {
3063
3064 // bail early
3065 if (!acf.isset(wp, 'codeEditor')) {
3066 return;
3067 }
3068
3069 // args
3070 var args = {
3071 lineNumbers: this.get('lines'),
3072 lineWrapping: true,
3073 styleActiveLine: false,
3074 continueComments: true,
3075 indentUnit: this.get('indentUnit'),
3076 tabSize: 1,
3077 indentWithTabs: false,
3078 autoRefresh: true, // needed for gutenberg metabox
3079 mode: this.get('mode'),
3080 extraKeys: {
3081 'Tab': function(cm) {
3082 cm.execCommand('indentMore')
3083 },
3084 'Shift-Tab': function(cm) {
3085 cm.execCommand('indentLess')
3086 },
3087 },
3088 }
3089
3090 // filter args
3091 args = acf.applyFilters('acfe/fields/code_editor/args', args, this);
3092 args = acf.applyFilters('acfe/fields/code_editor/args/name=' + this.get('name'), args, this);
3093 args = acf.applyFilters('acfe/fields/code_editor/args/key=' + this.get('key'), args, this);
3094
3095 // initialize wp editor
3096 this.editor = wp.codeEditor.initialize(this.$input().get(0), {
3097 codemirror: $.extend(wp.codeEditor.defaultSettings.codemirror, args)
3098 });
3099
3100 if (this.get('rows')) {
3101 this.editor.codemirror.getScrollerElement().style.minHeight = this.get('rows') * 18.5 + 'px';
3102 }
3103
3104 if (this.get('maxRows')) {
3105 this.editor.codemirror.getScrollerElement().style.maxHeight = this.get('maxRows') * 18.5 + 'px';
3106 }
3107
3108 this.editor.codemirror.on('change', this.proxy(this.onEditorChange));
3109
3110 acf.doAction('acfe/fields/code_editor/init', this.editor, this);
3111 acf.doAction('acfe/fields/code_editor/init/name=' + this.get('name'), this.editor, this);
3112 acf.doAction('acfe/fields/code_editor/init/key=' + this.get('key'), this.editor, this);
3113
3114 },
3115
3116 onEditorChange: function(e, $el) {
3117
3118 this.editor.codemirror.save();
3119 this.$input().change();
3120
3121 },
3122
3123 setValue: function(val) {
3124 if (this.editor.codemirror) {
3125 this.editor.codemirror.setValue(val);
3126 this.onEditorChange();
3127 }
3128 },
3129
3130 onShow: function() {
3131 if (this.editor.codemirror) {
3132 this.editor.codemirror.refresh();
3133 }
3134 },
3135
3136 onDuplicate: function(e, $el, $duplicate) {
3137 $duplicate.find('.CodeMirror:last').remove();
3138 },
3139
3140 });
3141
3142 acf.registerFieldType(CodeEditor);
3143
3144 })(jQuery);
3145 (function($) {
3146
3147 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3148 return;
3149 }
3150
3151 /**
3152 * Field: Column
3153 */
3154 var Column = acf.Field.extend({
3155
3156 wait: 'new_field',
3157
3158 type: 'acfe_column',
3159
3160 $control: function() {
3161 return this.$('.acf-fields:first');
3162 },
3163
3164 initialize: function() {
3165
3166 if (this.$el.is('td')) {
3167
3168 this.$el.closest('.acf-table').find('th[data-type="acfe_column"]').remove();
3169 this.remove();
3170
3171 }
3172
3173 if (this.get('endpoint')) {
3174
3175 this.$el.find('> .acf-label').remove();
3176 this.$el.find('> .acf-input').remove();
3177
3178 return;
3179
3180 }
3181
3182 var $field = this.$el;
3183 var $label = this.$el.find('> .acf-label');
3184 var $input = this.$inputWrap();
3185 var $wrap = this.$control();
3186
3187 $label.remove();
3188
3189 var $parent = $field.parent();
3190 $parent.addClass('acfe-column-wrapper');
3191 $wrap.addClass($parent.hasClass('-left') ? '-left' : '');
3192 $wrap.addClass($parent.hasClass('-clear') ? '-clear' : '');
3193
3194 $wrap.append($field.nextUntil('.acf-field-acfe-column', '.acf-field'));
3195
3196 }
3197
3198 });
3199
3200 acf.registerFieldType(Column);
3201
3202 })(jQuery);
3203 (function($) {
3204
3205 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3206 return;
3207 }
3208
3209 /**
3210 * Flexible Content: Overwrite
3211 */
3212 var FlexibleContent = acf.models.FlexibleContentField;
3213
3214 acf.models.FlexibleContentField = FlexibleContent.extend({
3215 addSortable: function(self) {
3216
3217 // bail early if max 1 row
3218 if (this.get('max') == 1) {
3219 return;
3220 }
3221
3222 // add sortable
3223 this.$layoutsWrap().sortable({
3224 items: '> .layout',
3225 handle: '> .acf-fc-layout-actions-wrap > .acf-fc-layout-handle',
3226 forceHelperSize: false, // changed to false
3227 forcePlaceholderSize: true,
3228 revert: 50,
3229 tolerance: 'pointer', // changed to pointer
3230 scroll: true,
3231 stop: function(event, ui) {
3232 self.render();
3233 },
3234 update: function(event, ui) {
3235 self.$input().trigger('change');
3236 }
3237 });
3238
3239 },
3240 add: function(args) {
3241
3242 // get element
3243 var $el = FlexibleContent.prototype.add.apply(this, arguments);
3244
3245 if ($el.length) {
3246
3247 // used in append
3248 $el.data('added', true);
3249 }
3250
3251 },
3252 });
3253
3254
3255 /**
3256 * Flexible Content: Validation
3257 */
3258 new acf.Model({
3259 actions: {
3260 'invalid_field': 'onInvalidField',
3261 'valid_field': 'onValidField',
3262 },
3263 onInvalidField: function(field) {
3264 field.$el.parents('.layout').addClass('acfe-flexible-modal-edit-error');
3265 },
3266 onValidField: function(field) {
3267
3268 field.$el.parents('.layout').each(function() {
3269
3270 var $layout = $(this);
3271
3272 if (!$layout.find('.acf-error').length) {
3273 $layout.removeClass('acfe-flexible-modal-edit-error');
3274 }
3275
3276 });
3277
3278 }
3279 });
3280
3281 })(jQuery);
3282 (function($) {
3283
3284 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3285 return;
3286 }
3287
3288 /**
3289 * Flexible Content: Pre-ACF 6.5
3290 *
3291 * Add "-legacy" to select layouts tooltip
3292 */
3293 var TooltipConfirmInitialize = acf.models.TooltipConfirm.prototype.initialize;
3294 acf.models.TooltipConfirm.prototype.initialize = function() {
3295
3296 // run original
3297 TooltipConfirmInitialize.apply(this, arguments);
3298
3299 // only pre-ACF 6.5
3300 if (!acfe.isACF('6.5')) {
3301
3302 if (this.$el.hasClass('acf-fc-popup')) {
3303 this.$el.addClass('-legacy'); // add "-legacy" class
3304 }
3305 }
3306
3307 };
3308
3309
3310 /**
3311 * Flexible Content: More Layouts Actions
3312 *
3313 * Adds hooks to let developers handle custom action buttons in the "more layout actions" popup
3314 */
3315 var TooltipConfirmOnConfirm = acf.models.TooltipConfirm.prototype.onConfirm;
3316 acf.models.TooltipConfirm.prototype.onConfirm = function(e, $el) {
3317
3318 // bail early pre-ACF 6.5
3319 if (!acfe.isACF('6.5')) {
3320 TooltipConfirmOnConfirm.apply(this, arguments); // run original
3321 return;
3322 }
3323
3324 // check we are in "more layout actions" popup
3325 if (!this.$el.hasClass('acf-more-layout-actions')) {
3326 TooltipConfirmOnConfirm.apply(this, arguments); // run original
3327 return;
3328 }
3329
3330 // check the element clicked is data-action="my-copy-layout"
3331 if (!$el.is('[data-action]')) {
3332 TooltipConfirmOnConfirm.apply(this, arguments); // run original
3333 return;
3334 }
3335
3336 // get button (three dots) and the parent .layout
3337 var $dots = this.get('target');
3338 var $layout = $dots.closest('.layout');
3339
3340 // get the parent flexible content
3341 var $field = $layout.closest('.acf-field');
3342
3343 // get flexible content instance
3344 var field = acf.getInstance($field);
3345 if (!field) {
3346 TooltipConfirmOnConfirm.apply(this, arguments); // run original
3347 return;
3348 }
3349
3350 // vars
3351 var key = field.get('key');
3352 var name = field.get('name');
3353 var layout = $layout.data('layout');
3354 var action = $el.data('action');
3355
3356 // should we prevent default?
3357 // this filter allow to prevent default "rename/disable layout" triggers
3358 var prevent = false;
3359 prevent = acf.applyFilters(`acfe/fields/flexible_content/prevent_action_button`, prevent, $el, action, layout, $layout, field);
3360 prevent = acf.applyFilters(`acfe/fields/flexible_content/prevent_action_button/name=${name}`, prevent, $el, action, layout, $layout, field);
3361 prevent = acf.applyFilters(`acfe/fields/flexible_content/prevent_action_button/key=${key}`, prevent, $el, action, layout, $layout, field);
3362 prevent = acf.applyFilters(`acfe/fields/flexible_content/prevent_action_button/layout=${layout}`, prevent, $el, action, layout, $layout, field);
3363 prevent = acf.applyFilters(`acfe/fields/flexible_content/prevent_action_button/action=${action}`, prevent, $el, action, layout, $layout, field);
3364 prevent = acf.applyFilters(`acfe/fields/flexible_content/prevent_action_button/name=${name}&layout=${layout}`, prevent, $el, action, layout, $layout, field);
3365
3366 // not prevented, run original
3367 if (!prevent) {
3368 TooltipConfirmOnConfirm.apply(this, arguments);
3369 }
3370
3371 // actions
3372 acf.doAction(`acfe/fields/flexible_content/click_action_button`, $el, action, layout, $layout, field);
3373 acf.doAction(`acfe/fields/flexible_content/click_action_button/name=${name}`, $el, action, layout, $layout, field);
3374 acf.doAction(`acfe/fields/flexible_content/click_action_button/key=${key}`, $el, action, layout, $layout, field);
3375 acf.doAction(`acfe/fields/flexible_content/click_action_button/layout=${layout}`, $el, action, layout, $layout, field);
3376 acf.doAction(`acfe/fields/flexible_content/click_action_button/action=${action}`, $el, action, layout, $layout, field);
3377 acf.doAction(`acfe/fields/flexible_content/click_action_button/name=${name}&layout=${layout}`, $el, action, layout, $layout, field);
3378 acf.doAction(`acfe/fields/flexible_content/click_action_button/key=${key}&layout=${layout}`, $el, action, layout, $layout, field);
3379
3380 };
3381
3382
3383 /**
3384 * Flexible Content: Pre-ACF 6.5
3385 *
3386 * Unify ajax layout title rendering across all ACF versions
3387 * This override logic for "acf/fields/flexible_content/layout_title"
3388 */
3389 var Field = acfe.FieldExtender({
3390 id: 'fc_pre_acf65',
3391 type: 'flexible_content',
3392 condition: function() {
3393 return !acfe.isACF('6.5');
3394 },
3395 renderLayout: function($layout) {
3396
3397 // do not run if "remove ajax title" setting has been enabled
3398 if (this.has('acfeFlexibleRemoveAjaxTitle')) {
3399 return;
3400 }
3401
3402 var $input = $layout.children('input');
3403 var prefix = $input.attr('name').replace('[acf_fc_layout]', '');
3404
3405 // ajax data
3406 var ajaxData = {
3407 action: 'acf/fields/flexible_content/layout_title',
3408 field_key: this.get('key'),
3409 i: $layout.index(),
3410 layout: $layout.data('layout'),
3411 value: acf.serialize($layout, prefix)
3412 };
3413
3414 // ajax
3415 $.ajax({
3416 url: acf.get('ajaxurl'),
3417 data: acf.prepareForAjax(ajaxData),
3418 dataType: 'html',
3419 type: 'post',
3420 success: function(html) {
3421 if (html) {
3422
3423 // change: only replace .acf-fc-layout-title
3424 // this makes the logic uniform with ACF 6.5+
3425 $layout.find('> .acf-fc-layout-actions-wrap > .acf-fc-layout-handle > .acf-fc-layout-title').html(html);
3426
3427 }
3428 }
3429 });
3430 },
3431 });
3432
3433 })(jQuery);
3434 (function($) {
3435
3436 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3437 return;
3438 }
3439
3440 /**
3441 * Flexible Content: Append
3442 */
3443 var Field = acfe.FieldExtender({
3444
3445 id: 'fc_append',
3446
3447 type: 'flexible_content',
3448
3449 initialize: function() {
3450
3451 // initialize
3452 this.getParent(Field).initialize.apply(this, arguments);
3453
3454 // add events
3455 this.addEvents({
3456 'appendLayout': 'acfeAppendLayout',
3457 });
3458
3459 },
3460
3461 acfeAppendLayout: function(e, $el, $layout) {
3462
3463 // only native acf duplicate
3464 // .acfe-layout-duplicated is old clone & copy/paste
3465 if (!$layout.is('.acfe-layout-duplicated')) {
3466
3467 if (this.has('acfeFlexibleModalEdition')) {
3468 this.acfeModalEdit(null, $layout);
3469 } else {
3470 this.openLayout($layout);
3471 }
3472
3473 }
3474
3475 // check if inside modal
3476 var modal = acfe.getModal($layout.closest('.acfe-modal.-open'));
3477
3478 // already inside another modal
3479 if (modal) {
3480
3481 this.acfeScrollToLayout($layout, modal.$content());
3482
3483 // old clone + copy/paste
3484 } else if ($layout.is('.acfe-layout-duplicated')) {
3485
3486 this.acfeScrollToLayout($layout);
3487
3488 // added or duplicated
3489 } else {
3490
3491 // we must set timeout to let data() being appended
3492 this.setTimeout(function() {
3493 if ($layout.data('added')) {
3494 this.acfeScrollToLayout($layout);
3495 }
3496 }, 10);
3497
3498
3499 }
3500
3501 },
3502
3503 acfeScrollToLayout: function($layout, $parent) {
3504
3505 // vars
3506 var hasParent = $parent || false;
3507 $parent = $parent || $('body, html');
3508
3509 // emulate acf.focusAttention
3510 if (!acf.isInView($layout)) {
3511
3512 var scrollTop = hasParent ? $layout.position().top : $layout.offset().top - $(window).height() / 2;
3513
3514 $parent.animate({
3515 scrollTop: scrollTop
3516 }, 500);
3517
3518 }
3519
3520 },
3521
3522 });
3523
3524 })(jQuery);
3525 (function($) {
3526
3527 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3528 return;
3529 }
3530
3531 /**
3532 * Flexible Content: One Click
3533 */
3534 var Field = acfe.FieldExtender({
3535
3536 id: 'fc_async',
3537
3538 type: 'flexible_content',
3539
3540 condition: function() {
3541 return this.has('acfeFlexibleAjax');
3542 },
3543
3544 add: function(args) {
3545
3546 // defaults
3547 args = acf.parseArgs(args, {
3548 layout: '',
3549 before: false
3550 });
3551
3552 // validate
3553 if (!this.allowAdd()) {
3554 return false;
3555 }
3556
3557 // ajax data
3558 var ajaxData = {
3559 action: 'acfe/flexible/models',
3560 field_key: this.get('key'),
3561 layout: args.layout,
3562 nonce: this.get('nonce')
3563 };
3564
3565 // beforeSend callback
3566 var beforeSend = function() {
3567 $('body').addClass('-loading');
3568 }
3569
3570 // complete callback
3571 var complete = function() {
3572 $('body').removeClass('-loading');
3573 }
3574
3575 // success callback
3576 var success = this.proxy(function(html) {
3577
3578 if (html) {
3579
3580 var $layout = $(html);
3581 var uniqid = acf.uniqid();
3582
3583 var search = 'acf[' + this.get('key') + '][acfcloneindex]';
3584 var replace = this.$control().find('> input[type=hidden]').attr('name') + '[' + uniqid + ']';
3585
3586 // add row
3587 var $el = acf.duplicate({
3588 target: $layout,
3589 search: search,
3590 replace: replace,
3591 append: this.proxy(function($el, $el2) {
3592
3593 // append
3594 if (args.before) {
3595 args.before.before($el2);
3596 } else {
3597 this.$layoutsWrap().append($el2);
3598 }
3599
3600 // enable
3601 acf.enable($el2, this.cid);
3602
3603 // render
3604 this.render();
3605 })
3606 });
3607
3608 // fix data-id
3609 $el.attr('data-id', uniqid);
3610
3611 // trigger change for validation errors
3612 this.$input().trigger('change');
3613
3614 // return
3615 return $el;
3616
3617 }
3618
3619 });
3620
3621 // ajax
3622 $.ajax({
3623 url: acf.get('ajaxurl'),
3624 data: acf.prepareForAjax(ajaxData),
3625 dataType: 'html',
3626 type: 'post',
3627 beforeSend: beforeSend,
3628 success: success,
3629 complete: complete
3630 });
3631
3632 }
3633
3634 });
3635
3636 })(jQuery);
3637 (function($) {
3638
3639 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3640 return;
3641 }
3642
3643 /**
3644 * Flexible Content: Clone Layout (pre ACF 5.9)
3645 */
3646 var Field = acfe.FieldExtender({
3647 id: 'fc_clone_layout',
3648 type: 'flexible_content',
3649 events: {
3650 'click [data-name="acfe-clone-layout"]': 'acfeCloneLayout',
3651 },
3652 acfeCloneLayout: function(e, $el) {
3653
3654 // Vars
3655 var $layout = $el.closest('.layout');
3656 var layout_name = $layout.data('layout');
3657
3658 // Popup min/max
3659 var $popup = $(this.$popup().html());
3660 var $layouts = this.$layouts();
3661
3662 var countLayouts = function(name) {
3663 return $layouts.filter(function() {
3664 return $(this).data('layout') === name;
3665 }).length;
3666 };
3667
3668 // vars
3669 var $a = $popup.find('[data-layout="' + layout_name + '"]');
3670 var min = $a.data('min') || 0;
3671 var max = $a.data('max') || 0;
3672 var count = countLayouts(layout_name);
3673
3674 // max
3675 if (max && count >= max) {
3676 $el.addClass('disabled');
3677 return false;
3678 }
3679
3680 $el.removeClass('disabled');
3681
3682 // Fix inputs
3683 this.acfeFixInputs($layout);
3684
3685 var $_layout = $layout.clone();
3686
3687 // Clean Layout
3688 this.acfeCleanLayouts($_layout);
3689
3690 var parent = $el.closest('.acf-flexible-content').find('> input[type=hidden]').attr('name');
3691
3692 // Clone
3693 var $layout_added = this.acfeDuplicate({
3694 layout: $_layout,
3695 before: $layout,
3696 parent: parent
3697 });
3698
3699 }
3700
3701 });
3702
3703 })(jQuery);
3704 (function($) {
3705
3706 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
3707 return;
3708 }
3709
3710
3711 /**
3712 * Flexible Content: Copy Layout
3713 */
3714 var Field = acfe.FieldExtender({
3715 id: 'fc_copy_layout',
3716 type: 'flexible_content',
3717 events: {
3718 'click [data-name="acfe-copy-layout"]': 'acfeCopyLayout',
3719 },
3720 acfeCopyLayout: function(e, $el) {
3721
3722 // vars
3723 var $layout = $el.closest('.layout');
3724
3725 // mark selected options
3726 $layout.find('option').each(function() {
3727 if (this.selected) {
3728 $(this).attr('selected', 'selected');
3729 } else {
3730 $(this).attr('selected', false);
3731 }
3732 });
3733
3734 // clone layout & input name
3735 var $clone = $layout.clone();
3736 var input = this.$control().find('> input[type=hidden]').attr('name');
3737
3738 // fix inputs
3739 this.acfeFixInputs($clone);
3740
3741 // clean layout
3742 this.acfeCleanLayouts($clone);
3743
3744 // get layout data
3745 var data = JSON.stringify({
3746 source: input,
3747 layouts: $clone[0].outerHTML
3748 });
3749
3750 // copy to clipboard
3751 acfe.copyClipboard(data, {
3752 auto: {
3753 title: acf.__('Layout copied to clipboard'),
3754 text: acf.__('You can now paste it anywhere using the "Paste Layout" secondary action.'),
3755 },
3756 manual: {
3757 title: acf.__('Layout ready to be copied'),
3758 text: acf.__('Please copy the following data to your clipboard.') + "<br /><br />" + acf.__('You can then paste it anywhere using the "Paste Layout" secondary action.'),
3759 },
3760 });
3761
3762 }
3763 });
3764
3765
3766 /**
3767 * Flexible Content: Secondary Actions
3768 */
3769 var Field = acfe.FieldExtender({
3770 id: 'fc_secondary_actions',
3771 type: 'flexible_content',
3772 events: {
3773 'click [data-name="acfe-secondary-actions"]': 'acfeSecondaryActions',
3774 },
3775 acfeSecondaryActions: function(e, $el) {
3776
3777 // Vars
3778 var $dropdown = this.$('.tmpl-acfe-fc-secondary-popup:last').html();
3779
3780 // Init Popup
3781 var Popup = acf.models.TooltipConfirm.extend({
3782 render: function() {
3783 this.html(this.get('text'));
3784 this.$el.addClass('acf-fc-popup acfe-fc-secondary-popup');
3785 }
3786 });
3787
3788 // New Popup
3789 var popup = new Popup({
3790 target: $el,
3791 targetConfirm: false,
3792 text: $dropdown,
3793 context: this,
3794 confirm: function(e, $el) {
3795
3796 if ($el.attr('data-name') === 'acfe-paste-layouts') {
3797 this.acfePasteLayoutsModal();
3798
3799 } else if ($el.attr('data-name') === 'acfe-copy-layouts') {
3800 this.acfeCopyLayouts();
3801 }
3802
3803 }
3804 });
3805
3806 popup.on('click', 'a', 'onConfirm');
3807
3808 },
3809 acfeCopyLayouts: function() {
3810
3811 // vet layouts
3812 var $layouts = this.$layoutsWrap();
3813
3814 // mark selected options
3815 $layouts.find('option').each(function() {
3816 if (this.selected) {
3817 $(this).attr('selected', 'selected');
3818 } else {
3819 $(this).attr('selected', false);
3820 }
3821 });
3822
3823 var $clones = $layouts.clone();
3824 var input = this.$control().find('> input[type=hidden]').attr('name');
3825
3826 // fix inputs
3827 this.acfeFixInputs($clones);
3828
3829 // clean layout
3830 this.acfeCleanLayouts($clones);
3831
3832 // get layouts data
3833 var data = JSON.stringify({
3834 source: input,
3835 layouts: $clones.html()
3836 });
3837
3838 acfe.copyClipboard(data, {
3839 auto: {
3840 title: acf.__('Layouts copied to clipboard'),
3841 text: acf.__('You can now paste them anywhere using the "Paste Layout" secondary action.'),
3842 },
3843 manual: {
3844 title: acf.__('Layouts ready to be copied'),
3845 text: acf.__('Please copy the following data to your clipboard.') + "<br /><br />" + acf.__('You can then paste it anywhere using the "Paste Layout" secondary action.'),
3846 },
3847 });
3848
3849 },
3850
3851
3852 acfePasteLayoutsModal: function() {
3853
3854 // Get Flexible
3855 var self = this;
3856
3857 acfe.newModal({
3858 title: acf.__('Paste layouts data'),
3859 destroy: true,
3860 width: 470,
3861 class: 'acfe-modal-fc-paste-layout',
3862 events: {
3863 'click .apply': 'onClickApply',
3864 },
3865 content: function() {
3866 var html = '';
3867
3868 html += `<div class="acfe-modal-spacer">`;
3869 html += `<div>${acf.__('Paste the layouts data from your clipboard to apply it to this page.')}</div>`;
3870 html += `<textarea></textarea>`;
3871 html += `</div>`;
3872
3873 return html;
3874
3875 },
3876 footer: function() {
3877 return `<a href="#" class="button button-large close cancel">${acf.__('Cancel')}</a> <a href="#" class="button button-large button-primary apply">${acf.__('Apply')}</a>`;
3878 },
3879 onOpen: function() {
3880 this.$('textarea').focus();
3881 },
3882 onClickApply: function(e, $el) {
3883
3884 e.preventDefault();
3885 var value = this.$('textarea').val();
3886 self.acfePasteLayouts(value);
3887 this.close();
3888
3889 }
3890 });
3891
3892 },
3893
3894 acfePasteLayouts: function(paste = null) {
3895
3896 // Get Flexible
3897 var flexible = this;
3898
3899 // No input
3900 if (paste == null || paste === '') {
3901 return;
3902 }
3903
3904 try {
3905
3906 // Paste HTML
3907 var data = JSON.parse(paste);
3908 var source = data.source;
3909 var $html = $(data.layouts);
3910
3911 // Parsed layouts
3912 var $html_layouts = $html.closest('[data-layout]');
3913
3914 if (!$html_layouts.length) {
3915 return alert('No layouts data available');
3916 }
3917
3918 // Popup min/max
3919 var $popup = $(flexible.$popup().html());
3920 var $layouts = flexible.$layouts();
3921
3922 var countLayouts = function(name) {
3923 return $layouts.filter(function() {
3924 return $(this).data('layout') === name;
3925 }).length;
3926 };
3927
3928 // init
3929 var validated_layouts = [];
3930
3931 // Each first level layouts
3932 $html_layouts.each(function() {
3933
3934 var $this = $(this);
3935 var layout_name = $this.data('layout');
3936
3937 // vars
3938 var $a = $popup.find('[data-layout="' + layout_name + '"]');
3939 var min = $a.data('min') || 0;
3940 var max = $a.data('max') || 0;
3941 var count = countLayouts(layout_name);
3942
3943 // max
3944 if (max && count >= max) {
3945 return;
3946 }
3947
3948 // Validate layout against available layouts
3949 var get_clone_layout = flexible.$clone($this.attr('data-layout'));
3950
3951 // Layout is invalid
3952 if (!get_clone_layout.length) {
3953 return;
3954 }
3955
3956 // Add validated layout
3957 validated_layouts.push($this);
3958
3959 });
3960
3961 // Nothing to add
3962 if (!validated_layouts.length) {
3963 return alert('No layouts could be pasted');
3964 }
3965
3966 // Add layouts
3967 $.each(validated_layouts, function() {
3968
3969 var $layout = $(this);
3970 var search = source + '[' + $layout.attr('data-id') + ']';
3971 var target = flexible.$control().find('> input[type=hidden]').attr('name');
3972
3973 flexible.acfeDuplicate({
3974 layout: $layout,
3975 before: false,
3976 search: search,
3977 parent: target
3978 });
3979
3980 });
3981
3982 } catch (e) {
3983
3984 console.log(e);
3985 alert('Invalid data');
3986
3987 }
3988
3989 },
3990 acfeDuplicate: function(args) {
3991
3992 // Arguments
3993 args = acf.parseArgs(args, {
3994 layout: '',
3995 before: false,
3996 parent: false,
3997 search: '',
3998 replace: '',
3999 });
4000
4001 // Validate
4002 if (!this.allowAdd()) {
4003 return false;
4004 }
4005
4006 var uniqid = acf.uniqid();
4007
4008 if (args.parent) {
4009
4010 if (!args.search) {
4011 args.search = args.parent + '[' + args.layout.attr('data-id') + ']';
4012 }
4013
4014 args.replace = args.parent + '[' + uniqid + ']';
4015
4016 }
4017
4018 var duplicate_args = {
4019 target: args.layout,
4020 search: args.search,
4021 replace: args.replace,
4022 append: this.proxy(function($el, $el2) {
4023
4024 // Add class to duplicated layout
4025 $el2.addClass('acfe-layout-duplicated');
4026
4027 // Reset UniqID
4028 $el2.attr('data-id', uniqid);
4029
4030 // append before
4031 if (args.before) {
4032 args.before.after($el2); // Fix clone: Use after() instead of native before()
4033
4034 // append end
4035 } else {
4036 this.$layoutsWrap().append($el2);
4037 }
4038
4039 // enable
4040 acf.enable($el2, this.cid);
4041
4042 // render
4043 this.render();
4044
4045 })
4046 }
4047
4048 // pre ACF 5.9
4049 if (!acfe.isACF('5.9')) {
4050 var $el = acf.duplicate(duplicate_args);
4051
4052 // newest ACF
4053 } else {
4054 var $el = this.acfeNewAcfDuplicate(duplicate_args); // fix for ACF 5.9
4055 }
4056
4057 // trigger change for validation errors
4058 this.$input().trigger('change');
4059
4060 // Fix tabs conditionally hidden
4061 var tabs = acf.getFields({
4062 type: 'tab',
4063 parent: $el,
4064 });
4065
4066 if (tabs.length) {
4067 $.each(tabs, function() {
4068 if (this.$el.hasClass('acf-hidden')) {
4069 this.tab.$el.addClass('acf-hidden');
4070 }
4071 });
4072 }
4073
4074
4075 // return
4076 return $el;
4077
4078 },
4079 /**
4080 * Based on acf.duplicate (5.9)
4081 *
4082 * doAction('duplicate) has been commented out
4083 * This fix an issue with the WYSIWYG editor field during copy/paste since ACF 5.9
4084 */
4085 acfeNewAcfDuplicate: function(args) {
4086
4087 // allow jQuery
4088 if (args instanceof jQuery) {
4089 args = {
4090 target: args
4091 };
4092 }
4093
4094 // defaults
4095 args = acf.parseArgs(args, {
4096 target: false,
4097 search: '',
4098 replace: '',
4099 rename: true,
4100 before: function($el) {},
4101 after: function($el, $el2) {},
4102 append: function($el, $el2) {
4103 $el.after($el2);
4104 }
4105 });
4106
4107 // compatibility
4108 args.target = args.target || args.$el;
4109
4110 // vars
4111 var $el = args.target;
4112
4113 // search
4114 args.search = args.search || $el.attr('data-id');
4115 args.replace = args.replace || acf.uniqid();
4116
4117 // before
4118 // - allow acf to modify DOM
4119 // - fixes bug where select field option is not selected
4120 args.before($el);
4121 acf.doAction('before_duplicate', $el);
4122
4123 // clone
4124 var $el2 = $el.clone();
4125
4126 // rename
4127 if (args.rename) {
4128 acf.rename({
4129 target: $el2,
4130 search: args.search,
4131 replace: args.replace,
4132 replacer: (typeof args.rename === 'function' ? args.rename : null)
4133 });
4134 }
4135
4136 // remove classes
4137 $el2.removeClass('acf-clone');
4138 $el2.find('.ui-sortable').removeClass('ui-sortable');
4139
4140 // after
4141 // - allow acf to modify DOM
4142 args.after($el, $el2);
4143 acf.doAction('after_duplicate', $el, $el2);
4144
4145 // append
4146 args.append($el, $el2);
4147
4148 /**
4149 * Fires after an element has been duplicated and appended to the DOM.
4150 *
4151 * @date 30/10/19
4152 * @since 5.8.7
4153 *
4154 * @param jQuery $el The original element.
4155 * @param jQuery $el2 The duplicated element.
4156 */
4157 //acf.doAction('duplicate', $el, $el2 );
4158
4159 // append
4160 acf.doAction('append', $el2);
4161
4162 // return
4163 return $el2;
4164 },
4165 acfeFixInputs: function($layout) {
4166
4167 $layout.find('input').each(function() {
4168 $(this).attr('value', this.value);
4169 });
4170
4171 $layout.find('textarea').each(function() {
4172 $(this).html(this.value);
4173 });
4174
4175 $layout.find('input:radio,input:checkbox').each(function() {
4176 if (this.checked) {
4177 $(this).attr('checked', 'checked');
4178 } else {
4179 $(this).attr('checked', false);
4180 }
4181 });
4182
4183 $layout.find('option').each(function() {
4184 if (this.selected) {
4185 $(this).attr('selected', 'selected');
4186 } else {
4187 $(this).attr('selected', false);
4188 }
4189 });
4190
4191 },
4192 acfeCleanLayouts: function($layout) {
4193
4194 // Clean WP Editor
4195 $layout.find('.acf-editor-wrap').each(function() {
4196
4197 var $input = $(this);
4198 $input.find('.wp-editor-container div').remove();
4199 $input.find('.wp-editor-container textarea').css('display', '');
4200
4201 });
4202
4203 // Clean Block Editor
4204 $layout.find('.acfe-block-editor-wrapper').each(function() {
4205
4206 var $editor = $(this);
4207 $editor.find('.editor').remove();
4208
4209 });
4210
4211 // Clean Date
4212 $layout.find('.acf-date-picker').each(function() {
4213
4214 var $input = $(this);
4215 $input.find('input.input').removeClass('hasDatepicker').removeAttr('id');
4216
4217 });
4218
4219 // Clean Time
4220 $layout.find('.acf-time-picker').each(function() {
4221
4222 var $input = $(this);
4223 $input.find('input.input').removeClass('hasDatepicker').removeAttr('id');
4224
4225 });
4226
4227 // Clean DateTime
4228 $layout.find('.acf-date-time-picker').each(function() {
4229
4230 var $input = $(this);
4231 $input.find('input.input').removeClass('hasDatepicker').removeAttr('id');
4232
4233 });
4234
4235 // Clean Code Editor
4236 $layout.find('.acfe-field-code-editor').each(function() {
4237
4238 var $input = $(this);
4239 $input.find('.CodeMirror').remove();
4240
4241 });
4242
4243 // Clean Color Picker
4244 $layout.find('.acf-color-picker').each(function() {
4245
4246 var $input = $(this);
4247
4248 var $color_picker = $input.find('> input');
4249 var $color_picker_proxy = $input.find('.wp-picker-container input.wp-color-picker').clone();
4250
4251 if ($input.find('.acf-color-picker-palette').length) {
4252 $input.find('.acf-color-picker-palette').append($color_picker_proxy);
4253 } else {
4254 $color_picker.after($color_picker_proxy);
4255 }
4256
4257
4258 $input.find('.wp-picker-container').remove();
4259
4260 });
4261
4262 // Clean Post Object
4263 $layout.find('.acf-field-post-object').each(function() {
4264
4265 var $input = $(this);
4266 $input.find('> .acf-input span').remove();
4267 $input.find('> .acf-input select').removeAttr('tabindex aria-hidden').removeClass();
4268
4269 });
4270
4271 // Clean Page Link
4272 $layout.find('.acf-field-page-link').each(function() {
4273
4274 var $input = $(this);
4275 $input.find('> .acf-input span').remove();
4276 $input.find('> .acf-input select').removeAttr('tabindex aria-hidden').removeClass();
4277
4278 });
4279
4280 // Clean Select2
4281 $layout.find('.acf-field-select').each(function() {
4282
4283 var $input = $(this);
4284 $input.find('> .acf-input span').remove();
4285 $input.find('> .acf-input select').removeAttr('tabindex aria-hidden').removeClass();
4286 $input.find('> .acf-input select').removeAttr('data-select2-id'); // fix select2 multiple values
4287 $input.find('> .acf-input input[type=hidden], select').removeAttr('id'); // fix select2 multiple values
4288
4289 });
4290
4291 // Clean FontAwesome
4292 $layout.find('.acf-field-font-awesome').each(function() {
4293
4294 var $input = $(this);
4295 $input.find('> .acf-input span').remove();
4296 $input.find('> .acf-input select').removeAttr('tabindex aria-hidden');
4297
4298 });
4299
4300
4301 // Clean Tab
4302 $layout.find('.acf-tab-wrap').each(function() {
4303
4304 var $wrap = $(this);
4305 var $content = $wrap.closest('.acf-fields');
4306
4307 var tabs = [];
4308 $.each($wrap.find('li a'), function() {
4309 tabs.push($(this));
4310 });
4311
4312 $content.find('> .acf-field-tab').each(function() {
4313
4314 $current_tab = $(this);
4315
4316 $.each(tabs, function() {
4317
4318 var $this = $(this);
4319 if ($this.attr('data-key') !== $current_tab.attr('data-key')) {
4320 return;
4321 }
4322
4323 $current_tab.find('> .acf-input').append($this);
4324
4325 });
4326
4327 });
4328
4329 $wrap.remove();
4330
4331 });
4332
4333 // Clean Accordion
4334 $layout.find('.acf-field-accordion').each(function() {
4335
4336 var $input = $(this);
4337
4338 $input.find('> .acf-accordion-title > .acf-accordion-icon').remove();
4339
4340 // Append virtual endpoint after each accordion
4341 $input.after('<div class="acf-field acf-field-accordion" data-type="accordion"><div class="acf-input"><div class="acf-fields" data-endpoint="1"></div></div></div>');
4342
4343 });
4344
4345 }
4346 });
4347
4348 })(jQuery);
4349 (function($) {
4350
4351 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4352 return;
4353 }
4354
4355 /**
4356 * Flexible Content: Events
4357 */
4358 var eventManager = new acf.Model({
4359
4360 actions: {
4361 'new_field/type=flexible_content': 'newField',
4362 'show': 'onShow',
4363 'hide': 'onHide',
4364 'append': 'onAppend',
4365 },
4366
4367 newField: function(field) {
4368
4369 // placeholder
4370 field.addEvents({
4371 'click .acfe-fc-placeholder': 'onClickCollapse'
4372 });
4373
4374 // inline close button
4375 field.addEvents({
4376 'click .acfe-flexible-opened-actions > a': 'onClickCollapse'
4377 });
4378
4379 if (field.has('acfeFlexibleModalEdition')) {
4380
4381 // collapse action
4382 field.removeEvents({
4383 'click [data-name="collapse-layout"]': 'onClickCollapse'
4384 });
4385
4386 if (field.has('acfeFlexiblePlaceholder') || field.has('acfeFlexiblePreview')) {
4387
4388 // placeholder collapse Action
4389 field.removeEvents({
4390 'click .acfe-fc-placeholder': 'onClickCollapse'
4391 });
4392
4393 }
4394
4395 }
4396
4397 // lock
4398 if (field.has('acfeFlexibleLock')) {
4399 field.removeEvents({
4400 'mouseover': 'onHover'
4401 });
4402 }
4403
4404 field.$layouts().each(function() {
4405 field.trigger('newLayout', [$(this)]);
4406 });
4407
4408 },
4409
4410 onShow: function($el, context) {
4411
4412 // validate
4413 if (context === 'collapse' && $el.is('.layout')) {
4414
4415 // get field
4416 var field = acf.getClosestField($el);
4417
4418 // trigger
4419 field.trigger('showLayout', [$el]);
4420
4421 }
4422
4423 },
4424
4425 onHide: function($el, context) {
4426
4427 // validate
4428 if (context === 'collapse' && $el.is('.layout') && !$el.is('.acf-clone')) {
4429
4430 // get field
4431 var field = acf.getClosestField($el);
4432
4433 // trigger
4434 field.trigger('hideLayout', [$el]);
4435
4436 }
4437
4438 },
4439
4440 onAppend: function($el) {
4441
4442 // check element is a jQuery object with .layout class
4443 if ($el?.[0]?.classList?.contains('layout')) {
4444
4445 // get field
4446 var field = acf.getClosestField($el);
4447
4448 // trigger
4449 field.trigger('newLayout', [$el]);
4450 field.trigger('appendLayout', [$el]);
4451
4452 }
4453
4454 },
4455
4456 });
4457
4458 })(jQuery);
4459 (function($) {
4460
4461 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4462 return;
4463 }
4464
4465 /**
4466 * Flexible Content: Modal Edit
4467 */
4468 var Field = acfe.FieldExtender({
4469 id: 'fc_modal_edit',
4470 type: 'flexible_content',
4471 condition: function() {
4472 return this.has('acfeFlexibleModalEdition');
4473 },
4474 events: {
4475 'click [data-action="acfe-flexible-modal-edit"]': 'acfeModalEdit',
4476 },
4477 /**
4478 * Set Active Layout
4479 *
4480 * ACF 6.5: Nullify set active focus css
4481 *
4482 * @param e
4483 */
4484 setActiveLayout: function(e) {
4485 // nullify "active focus css" class when modal edit
4486 },
4487 acfeModalEdit: function(e, $el) {
4488
4489 // layout
4490 var $layout = $el.closest('.layout');
4491
4492 // modal
4493 var $modal = $layout.find('> .acfe-modal.-fields');
4494
4495 // vars
4496 var $handle = $layout.find('> .acf-fc-layout-actions-wrap > .acf-fc-layout-handle');
4497 var order = $handle.find('> .acf-fc-layout-order').outerHTML();
4498 var title = acfe.getTextNode($handle.find('.acf-fc-layout-title'));
4499
4500 var modal = acfe.getModal($modal, {
4501 open: true,
4502 title: order + title,
4503 onOpen: this.proxy(function() {
4504 this.openLayout($layout);
4505 }),
4506 onClose: this.proxy(function() {
4507 this.closeLayout($layout);
4508 }),
4509 });
4510 }
4511
4512 });
4513
4514 })(jQuery);
4515 (function($) {
4516
4517 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4518 return;
4519 }
4520
4521
4522 /**
4523 * Flexible Content: Modal Select
4524 */
4525 var Field = acfe.FieldExtender({
4526 id: 'fc_modal_select',
4527 type: 'flexible_content',
4528 condition: function() {
4529 return this.has('acfeFlexibleModal') && this.$clones().length > 1; // make sure there's more than 1 layout available
4530 },
4531 onClickAdd: function(e, $el) {
4532
4533 // get flexible
4534 var flexible = this;
4535
4536 // validate
4537 if (!flexible.validateAdd()) {
4538 return false;
4539 }
4540
4541 // get "add row" click context
4542 // this is later used in the flexible.add() method
4543 var $before = null;
4544 if ($el.data('context') === 'layout') {
4545 $before = $el.closest('.layout');
4546
4547 } else if ($el.data('context') === 'top-actions') {
4548 $before = $el.closest(".acf-flexible-content").find(".values .layout").first();
4549 }
4550
4551 // Open Modal
4552 acfe.newModal({
4553 destroy: true,
4554 modal: 'fc_select',
4555 title: flexible.get('acfeFlexibleModalTitle', flexible.get('buttonLabel')),
4556 class: '-select acfe-modal-select-' + flexible.get('name') + ' acfe-modal-select-' + flexible.get('key'),
4557 size: flexible.get('acfeFlexibleModalSize'),
4558 content: function() {
4559 var outerHtml = flexible.getPopupHTML();
4560 return $(outerHtml).children(); // get the first children element from outerHtml
4561 },
4562 events: {
4563 'click .acfe-fc-categories a': 'onClickCategory',
4564 'click a[data-layout]': 'onClickLayout',
4565 },
4566 onOpen: function() {
4567
4568 // add icon info class
4569 var icon = acfe.isWP('5.5') ? 'dashicons-info-outline' : 'dashicons-info';
4570 this.$('li a span.badge').addClass('acf-js-tooltip dashicons ' + icon).appendTo(this.$('li a span.badge').prev('.acfe-fc-layout-label'));
4571
4572 // autofocus fix
4573 this.$('li:first-of-type a').blur();
4574
4575 },
4576 $categoriesWrap: function() {
4577 return this.$('.acfe-fc-categories');
4578 },
4579 $categories: function() {
4580 return this.$categoriesWrap().find('a');
4581 },
4582 $category: function(category) {
4583 return this.$categories().filter('[data-category="' + category + '"]');
4584 },
4585 $activeCategory: function() {
4586 return this.$categories().filter('.-active');
4587 },
4588 onClickCategory: function(e, $el) {
4589
4590 // prevent default
4591 e.preventDefault();
4592
4593 // switch clicked category
4594 this.switchCategory($el.data('category'));
4595
4596 },
4597 switchCategory: function(category, silent = false) {
4598
4599 // remove all active
4600 this.$categories().removeClass('-active');
4601
4602 // set active on current
4603 this.$category(category).addClass('-active');
4604
4605 if (!silent) {
4606
4607 // show layouts
4608 this.showActiveCategoryLayouts();
4609
4610 // trigger event
4611 this.trigger('switch_category', [category]);
4612
4613 }
4614
4615 },
4616 hasCategories: function() {
4617 return this.$('.acfe-fc-categories').length > 0;
4618 },
4619 getCategories: function() {
4620 return this.$categories().map(function() {
4621 return $(this).data('category');
4622 }).get();
4623 },
4624 getActiveCategory: function() {
4625 return this.$activeCategory().data('category');
4626 },
4627 disableCategory: function(category) {
4628 this.$category(category).addClass('-disabled');
4629 },
4630 disableCategories: function() {
4631 this.$categories().addClass('-disabled');
4632 },
4633 enableCategory: function(category) {
4634 this.$category(category).removeClass('-disabled');
4635 },
4636 enableCategories: function() {
4637 this.$categories().removeClass('-disabled');
4638 },
4639 isCategoryDisabled: function(category) {
4640 return this.$category(category).hasClass('-disabled');
4641 },
4642 $layouts: function() {
4643 return this.$('a[data-layout]');
4644 },
4645 $categoryLayouts: function(category) {
4646
4647 if (category === 'acfe-all') {
4648 return this.$layouts(); // return all layouts
4649 }
4650
4651 return this.$layouts().filter('[data-category]').filter(function() {
4652 return $(this).data('category').includes(category);
4653 });
4654
4655 },
4656 $activeCategoryLayouts: function() {
4657
4658 // no categories
4659 if (!this.hasCategories()) {
4660 return this.$layouts(); // show all layouts
4661 }
4662
4663 // get active cateogry
4664 var activeCategory = this.getActiveCategory();
4665
4666 // filter layouts using active category
4667 return this.$categoryLayouts(activeCategory);
4668
4669 },
4670 getLayouts: function() {
4671 return this.$layouts().map(function() {
4672 return $(this).data('layout');
4673 });
4674 },
4675 getCategoryLayouts: function(category) {
4676 return this.$categoryLayouts(category).map(function() {
4677 return $(this).data('layout');
4678 }).get();
4679 },
4680 getActiveCategoryLayouts: function() {
4681 return this.$activeCategoryLayouts().map(function() {
4682 return $(this).data('layout');
4683 }).get();
4684 },
4685 hideLayouts: function(layouts = []) {
4686
4687 // convert to array
4688 layouts = acfe.getArray(layouts);
4689
4690 // hide specific layouts
4691 if (layouts.length) {
4692 this.$layouts().filter(function() {
4693 return acfe.inArray($(this).data('layout'), layouts);
4694 }).closest('li').hide();
4695 return;
4696 }
4697
4698 // hide all
4699 this.$layouts().closest('li').hide();
4700
4701 },
4702 showLayouts: function(layouts = []) {
4703
4704 // convert to array
4705 layouts = acfe.getArray(layouts);
4706
4707 // show specific layouts
4708 if (layouts.length) {
4709 this.$layouts().filter(function() {
4710 return acfe.inArray($(this).data('layout'), layouts);
4711 }).closest('li').show();
4712 return;
4713 }
4714
4715 // show all
4716 this.$layouts().closest('li').show();
4717
4718 },
4719 hideActiveCategoryLayouts: function() {
4720 this.$activeCategoryLayouts().closest('li').hide();
4721 },
4722 showActiveCategoryLayouts: function() {
4723 this.hideLayouts();
4724 this.$activeCategoryLayouts().closest('li').show();
4725 },
4726 hideCategoryLayouts: function(category) {
4727 this.$categoryLayouts(category).closest('li').hide();
4728 },
4729 showCategoryLayouts: function(category) {
4730 this.hideLayouts();
4731 this.$categoryLayouts(category).closest('li').show();
4732 },
4733 isLayoutHidden: function(layout) {
4734 return this.$layouts().filter(function() {
4735 return $(this).data('layout') === layout;
4736 }).closest('li').is(':hidden');
4737 },
4738 layoutHasCategory: function(layout, category) {
4739 return this.$layouts().filter(function() {
4740 return $(this).data('layout') === layout;
4741 }).data('category').includes(category);
4742 },
4743 onClickLayout: function(e, $el) {
4744
4745 e.preventDefault();
4746
4747 // close modal
4748 this.close();
4749
4750 // Add layout
4751 flexible.add({
4752 layout: $el.data('layout'),
4753 before: $before
4754 });
4755
4756 },
4757 });
4758
4759 },
4760
4761 });
4762
4763 })(jQuery);
4764 (function($) {
4765
4766 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4767 return;
4768 }
4769
4770 /**
4771 * Flexible Content: Modal Settings
4772 */
4773 var Field = acfe.FieldExtender({
4774 id: 'fc_modal_settings',
4775 type: 'flexible_content',
4776 events: {
4777 'click [data-name="acfe-settings"]': 'acfeLayoutSettings',
4778 },
4779 acfeLayoutSettings: function(e, $el) {
4780
4781 // layout
4782 var $layout = $el.closest('.layout');
4783
4784 // modal
4785 var $modal = $layout.find('> .acfe-modal.-settings');
4786
4787 // vars
4788 var $handle = $layout.find('> .acf-fc-layout-actions-wrap > .acf-fc-layout-handle');
4789 var order = $handle.find('> .acf-fc-layout-order').outerHTML();
4790 var title = acfe.getTextNode($handle.find('.acf-fc-layout-title'));
4791
4792 var modal = acfe.getModal($modal, {
4793 open: true,
4794 title: order + title,
4795 onClose: this.proxy(function() {
4796 if (this.has('acfeFlexiblePreview')) {
4797 this.closeLayout($layout);
4798 }
4799 })
4800 });
4801
4802 }
4803 });
4804
4805 })(jQuery);
4806 (function($) {
4807
4808 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4809 return;
4810 }
4811
4812 /**
4813 * Flexible Content: One Click
4814 */
4815 var Field = acfe.FieldExtender({
4816 id: 'fc_one_click',
4817 type: 'flexible_content',
4818 condition: function() {
4819 return this.$clones().length === 1;
4820 },
4821 onClickAdd: function(e, $el) {
4822
4823 // validate
4824 if (!this.validateAdd()) {
4825 return false;
4826 }
4827
4828 // get "add row" click context
4829 var $before = null;
4830 if ($el.data('context') === 'layout') {
4831 $before = $el.closest('.layout');
4832
4833 } else if ($el.data('context') === 'top-actions') {
4834 $before = $el.closest(".acf-flexible-content").find(".values .layout").first();
4835 }
4836
4837 // add layout
4838 this.add({
4839 layout: $(this.$clones()[0]).data('layout'), // add the first (and only) layout
4840 before: $before
4841 });
4842
4843 // hide popup just in case
4844 var $popup = $('.acf-fc-popup');
4845
4846 if ($popup.length) {
4847 $popup.hide();
4848 }
4849
4850 }
4851 });
4852
4853 })(jQuery);
4854 (function($) {
4855
4856 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4857 return;
4858 }
4859
4860 /**
4861 * Flexible Content: Placeholder
4862 */
4863 var Field = acfe.FieldExtender({
4864 id: 'fc_placeholder',
4865 type: 'flexible_content',
4866 condition: function() {
4867 return this.has('acfeFlexiblePlaceholder');
4868 },
4869 initialize: function() {
4870
4871 // initialize
4872 this.getParent(Field).initialize.apply(this, arguments);
4873
4874 // add events
4875 this.addEvents({
4876 'showLayout': 'acfePlaceholderShowLayout',
4877 'hideLayout': 'acfePlaceholderHideLayout',
4878 'newLayout': 'acfePlaceholderNewLayout',
4879 });
4880
4881 },
4882 acfePlaceholderShowLayout: function(e, $el, $layout) {
4883
4884 if (!this.has('acfeFlexibleModalEdition')) {
4885 acf.hide($layout.find('> .acfe-fc-placeholder')); // hide placeholder
4886 }
4887
4888 },
4889 acfePlaceholderHideLayout: function(e, $el, $layout) {
4890
4891 acf.show($layout.find('> .acfe-fc-placeholder')); // show placeholder
4892
4893 },
4894 acfePlaceholderNewLayout: function(e, $el, $layout) {
4895
4896 if (this.isLayoutClosed($layout)) {
4897 acf.show($layout.find('> .acfe-fc-placeholder')); // show placeholder
4898 }
4899
4900 },
4901
4902 });
4903
4904 })(jQuery);
4905 (function($) {
4906
4907 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
4908 return;
4909 }
4910
4911 /**
4912 * Flexible Content: Preview
4913 */
4914 var Field = acfe.FieldExtender({
4915
4916 id: 'fc_preview',
4917
4918 type: 'flexible_content',
4919
4920 condition: function() {
4921 return this.has('acfeFlexiblePreview');
4922 },
4923
4924 events: {
4925 'hideLayout': 'acfePreviewHideLayout',
4926 'appendLayout': 'acfePreviewAppendLayout',
4927 },
4928
4929 acfePreviewHideLayout: function(e, $el, $layout) {
4930 this.acfeLayoutPreview($layout);
4931 },
4932
4933 acfePreviewAppendLayout: function(e, $el, $layout) {
4934 this.acfeLayoutPreview($layout);
4935 },
4936
4937 acfeLayoutPreview: function($layout) {
4938
4939 // validate
4940 if (!this.isLayoutClosed($layout) || $layout.find('> .acfe-fc-placeholder').hasClass('-loading')) {
4941 return;
4942 }
4943
4944 // vars
4945 var key = this.get('key');
4946 var name = this.get('name');
4947 var $el = this.$el;
4948 var layout = $layout.data('layout');
4949 var index = $layout.index();
4950 var $placeholder = $layout.find('> .acfe-fc-placeholder');
4951
4952 $placeholder.addClass('acfe-fc-preview -loading').find('> .acfe-flexible-placeholder').prepend('<span class="spinner"></span>');
4953 $placeholder.find('> .acfe-fc-overlay').addClass('-hover');
4954
4955 // vars
4956 var $input = $layout.children('input');
4957 var prefix = $input.attr('name').replace('[acf_fc_layout]', '');
4958
4959 // ajax data
4960 var ajaxData = {
4961 action: 'acfe/flexible/layout_preview',
4962 field_key: key,
4963 i: index,
4964 layout: layout,
4965 value: acf.serialize($layout, prefix)
4966 };
4967
4968 ajaxData = acf.applyFilters('acfe/fields/flexible_content/preview_data', ajaxData, $el, $layout);
4969 ajaxData = acf.applyFilters('acfe/fields/flexible_content/preview_data/name=' + name, ajaxData, $el, $layout);
4970 ajaxData = acf.applyFilters('acfe/fields/flexible_content/preview_data/key=' + key, ajaxData, $el, $layout);
4971 ajaxData = acf.applyFilters('acfe/fields/flexible_content/preview_data/layout=' + layout, ajaxData, $el, $layout);
4972 ajaxData = acf.applyFilters('acfe/fields/flexible_content/preview_data/name=' + name + '&layout=' + layout, ajaxData, $el, $layout);
4973 ajaxData = acf.applyFilters('acfe/fields/flexible_content/preview_data/key=' + key + '&layout=' + layout, ajaxData, $el, $layout);
4974
4975 acf.doAction('acfe/fields/flexible_content/before_preview', $el, $layout, ajaxData);
4976 acf.doAction('acfe/fields/flexible_content/before_preview/name=' + name, $el, $layout, ajaxData);
4977 acf.doAction('acfe/fields/flexible_content/before_preview/key=' + key, $el, $layout, ajaxData);
4978 acf.doAction('acfe/fields/flexible_content/before_preview/layout=' + layout, $el, $layout, ajaxData);
4979 acf.doAction('acfe/fields/flexible_content/before_preview/name=' + name + '&layout=' + layout, $el, $layout, ajaxData);
4980 acf.doAction('acfe/fields/flexible_content/before_preview/key=' + key + '&layout=' + layout, $el, $layout, ajaxData);
4981
4982 // ajax
4983 $.ajax({
4984 url: acf.get('ajaxurl'),
4985 data: acf.prepareForAjax(ajaxData),
4986 dataType: 'html',
4987 type: 'post',
4988 context: this,
4989 success: function(response) {
4990
4991 if (response) {
4992 $placeholder.find('> .acfe-flexible-placeholder').html(response);
4993 } else {
4994 $placeholder.removeClass('acfe-fc-preview');
4995 }
4996
4997 acf.doAction('acfe/fields/flexible_content/preview', response, $el, $layout, ajaxData);
4998 acf.doAction('acfe/fields/flexible_content/preview/name=' + name, response, $el, $layout, ajaxData);
4999 acf.doAction('acfe/fields/flexible_content/preview/key=' + key, response, $el, $layout, ajaxData);
5000 acf.doAction('acfe/fields/flexible_content/preview/layout=' + layout, response, $el, $layout, ajaxData);
5001 acf.doAction('acfe/fields/flexible_content/preview/name=' + name + '&layout=' + layout, response, $el, $layout, ajaxData);
5002 acf.doAction('acfe/fields/flexible_content/preview/key=' + key + '&layout=' + layout, response, $el, $layout, ajaxData);
5003
5004 },
5005 complete: function() {
5006
5007 $placeholder.find('> .acfe-fc-overlay').removeClass('-hover');
5008 $placeholder.removeClass('-loading').find('> .acfe-flexible-placeholder > .spinner').remove();
5009
5010 }
5011 });
5012
5013 },
5014
5015 });
5016
5017 })(jQuery);
5018 (function($) {
5019
5020 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5021 return;
5022 }
5023
5024 /**
5025 * Flexible Content: State
5026 */
5027 var Field = acfe.FieldExtender({
5028 id: 'fc_state',
5029 type: 'flexible_content',
5030 condition: function() {
5031 return this.has('acfeFlexibleOpen');
5032 },
5033 addCollapsed: function() {
5034 // nullify "addCollapsed" to prevent layouts from being added as collapsed
5035 }
5036 });
5037
5038 })(jQuery);
5039 (function($) {
5040
5041 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5042 return;
5043 }
5044
5045 /**
5046 * Flexible Content: Title Ajax
5047 */
5048 var Field = acfe.FieldExtender({
5049 id: 'fc_title_ajax',
5050 type: 'flexible_content',
5051 condition: function() {
5052 return this.has('acfeFlexibleRemoveAjaxTitle');
5053 },
5054 renderLayout: function() {
5055 // nullify "renderLayout" that run ajax query "acf/fields/flexible_content/layout_title"
5056 }
5057 });
5058
5059 })(jQuery);
5060 (function($) {
5061
5062 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5063 return;
5064 }
5065
5066 /**
5067 * Flexible Content: Title Inline
5068 */
5069 var Field = acfe.FieldExtender({
5070
5071 id: 'fc_title_inline',
5072
5073 type: 'flexible_content',
5074
5075 condition: function() {
5076 return this.has('acfeFlexibleTitleEdition');
5077 },
5078
5079 events: {
5080 'click .acf-fc-layout-handle': 'acfeEditLayoutTitleToggleHandle',
5081 'click .acf-fc-layout-title': 'acfeEditLayoutTitle',
5082 'blur input.acfe-flexible-control-title': 'acfeEditLayoutTitleToggle',
5083 'click input.acfe-flexible-control-title': 'acfeEditLayoutTitlePropagation',
5084 'input [data-acfe-flexible-control-title-input]': 'acfeEditLayoutTitleInput',
5085 'keypress [data-acfe-flexible-control-title-input]': 'acfeEditLayoutTitleInputEnter',
5086 },
5087
5088 acfeEditLayoutTitleToggleHandle: function(e, $el) {
5089
5090 // layout
5091 var $layout = $el.closest('.layout');
5092
5093 if ($layout.hasClass('acfe-flexible-title-edition')) {
5094 $layout.find('> .acf-fc-layout-actions-wrap > .acf-fc-layout-handle > input.acfe-flexible-control-title').trigger('blur');
5095 }
5096
5097 },
5098
5099 acfeEditLayoutTitle: function(e, $el) {
5100
5101 e.stopPropagation();
5102 this.acfeEditLayoutTitleToggle(e, $el);
5103
5104 },
5105
5106 acfeEditLayoutTitleToggle: function(e, $el) {
5107
5108 // vars
5109 var $layout = $el.closest('.layout');
5110 var $handle = $layout.find('> .acf-fc-layout-actions-wrap > .acf-fc-layout-handle');
5111 var $title = $handle.find('.acf-fc-layout-title');
5112
5113 if ($layout.hasClass('acfe-flexible-title-edition')) {
5114
5115 var $input = $handle.find('> input[data-acfe-flexible-control-title-input]');
5116
5117 if ($input.val() === '') {
5118 $input.val($input.attr('placeholder')).trigger('input');
5119 }
5120
5121 $layout.removeClass('acfe-flexible-title-edition');
5122 $input.insertAfter($layout.find('> .acf-fc-layout-actions-wrap'));
5123
5124 } else {
5125
5126 var $input = $layout.find('> input[data-acfe-flexible-control-title-input]');
5127 var $input = $input.appendTo($handle);
5128
5129 $layout.addClass('acfe-flexible-title-edition');
5130 $input.focus().attr('size', $input.val().length);
5131
5132 }
5133
5134 },
5135
5136 acfeEditLayoutTitlePropagation: function(e, $el) {
5137 e.stopPropagation();
5138 },
5139
5140 acfeEditLayoutTitleInput: function(e, $el) {
5141
5142 // vars
5143 var $layout = $el.closest('.layout');
5144 var $title = $layout.find('> .acf-fc-layout-actions-wrap > .acf-fc-layout-handle .acf-fc-layout-title');
5145
5146 var val = $el.val();
5147
5148 $el.attr('size', val.length);
5149 $title.html(val);
5150
5151 },
5152
5153 acfeEditLayoutTitleInputEnter: function(e, $el) {
5154
5155 // 'enter'
5156 if (e.keyCode === 13) {
5157 e.preventDefault();
5158 $el.blur();
5159 }
5160
5161 }
5162
5163 });
5164
5165 })(jQuery);
5166 (function($) {
5167
5168 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5169 return;
5170 }
5171
5172 /**
5173 * Flexible Content: Toggle
5174 */
5175 var Field = acfe.FieldExtender({
5176 id: 'fc_toggle',
5177 type: 'flexible_content',
5178 condition: function() {
5179 return this.has('acfeFlexibleToggle');
5180 },
5181 events: {
5182 'click [data-name="acfe-toggle-layout"]': 'acfeToggleLayout',
5183 },
5184 acfeToggleLayout: function(e, $el) {
5185
5186 // vars
5187 var $layout = $el.closest('.layout');
5188 var $input = $layout.find('> .acfe-flexible-layout-toggle');
5189
5190 if ($input.length) {
5191
5192 if ($input.val() === '1') {
5193
5194 $layout.removeClass('acfe-flexible-layout-hidden');
5195 $input.val('');
5196
5197 } else {
5198
5199 $layout.addClass('acfe-flexible-layout-hidden');
5200 $input.val('1');
5201
5202 }
5203
5204 }
5205
5206 }
5207 });
5208
5209 })(jQuery);
5210 (function($) {
5211
5212 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5213 return;
5214 }
5215
5216 /**
5217 * Field: Group
5218 */
5219 var Group = acf.Field.extend({
5220
5221 wait: false,
5222
5223 type: 'group',
5224
5225 events: {
5226 'duplicateField': 'onDuplicate'
5227 },
5228
5229 initialize: function() {
5230
5231 if (this.has('acfeGroupModal')) {
5232
5233 this.$inputWrap().find('> .acf-fields, > .acf-table').wrapAll('<div class="acfe-modal"><div class="acfe-modal-wrapper"><div class="acfe-modal-content"></div></div></div>');
5234 this.$inputWrap().append('<a href="#" class="acf-button button" data-modal>' + this.get('acfeGroupModalButton') + '</a>');
5235
5236 this.initializeModal();
5237
5238 }
5239
5240 },
5241
5242 initializeModal: function() {
5243
5244 // normal title
5245 var title = this.$labelWrap().find('label').text().trim();
5246
5247 // inside table
5248 if (this.$el.is('td')) {
5249
5250 title = this.get('acfeGroupModalButton');
5251 var $th = this.$el.closest('table').find(' > thead th[data-key="' + this.get('key') + '"]');
5252
5253 if ($th.length) {
5254 title = acfe.getTextNode($th);
5255 }
5256
5257 }
5258
5259 // fallback to button text
5260 if (!title.length) {
5261 title = this.get('acfeGroupModalButton');
5262 }
5263
5264 // modal
5265 this.getModal({
5266 title: title,
5267 size: this.has('acfeGroupModalSize') ? this.get('acfeGroupModalSize') : 'large',
5268 footer: this.has('acfeGroupModalClose') ? acf.__('Close') : false,
5269 class: 'acfe-modal-edit-' + this.get('name') + ' acfe-modal-edit-' + this.get('key')
5270 });
5271
5272 },
5273
5274 onDuplicate: function(e, $el, $duplicate) {
5275 $duplicate.find('.acf-input:first > a[data-modal]').remove();
5276 }
5277
5278 });
5279
5280 acf.registerFieldType(Group);
5281
5282 })(jQuery);
5283 (function($) {
5284
5285 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5286 return;
5287 }
5288
5289 // fix icon picker field
5290 // in alignMediaLibraryTabToCurrentValue(), the field update the img src attribute with this.get('mediaLibraryPreviewUrl')
5291 // but this will return a value only when an image is actually selected
5292 // otherwise, it returns 'undefined' and thus never update the src, because $.attr() ignore 'undefined' values
5293 // when using acfe.get() extension, it returns 'null' instead of 'undefined', and $.attr() update the src attribute as 'empty'
5294 // alignMediaLibraryTabToCurrentValue() is executed both on field render and when a user select an image (weird design)
5295 if (typeof acf.models.IconPickerField !== 'undefined') {
5296
5297 // rollback to legacy acf.Model.get()
5298 acf.models.IconPickerField.prototype.get = function(name) {
5299 return this.data[name];
5300 };
5301
5302 }
5303
5304 })(jQuery);
5305 (function($) {
5306
5307 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5308 return;
5309 }
5310
5311 /**
5312 * Field: Radio
5313 */
5314 var Radio = acf.models.RadioField;
5315
5316 acf.models.RadioField = Radio.extend({
5317
5318 // add setValue method
5319 // this allows to use field.val('new_value') to assign a new value to the field
5320 setValue: function(val) {
5321
5322 // clear value
5323 if (!val) {
5324 return this.clearValue();
5325 }
5326
5327 // get option with value
5328 var $option = this.$(':radio[value="' + val + '"]');
5329
5330 // option exists and is not already selected
5331 if ($option.length && !$option.is(':checked')) {
5332
5333 // select the option
5334 $option.prop('checked', true).trigger('change');
5335 this.onClick(null, $option);
5336
5337 }
5338
5339 },
5340
5341 // add clearValue method
5342 // this allows to set the value to the first radio or if allow_null is enabled, to null
5343 clearValue: function() {
5344
5345 // if allow_null is enabled, get selected option and click it
5346 if (this.get('allow_null')) {
5347
5348 if (this.$input().length) {
5349 this.onClick(null, this.$input());
5350 }
5351
5352 // otherwise use first radio value as default value
5353 } else {
5354 this.val(this.$(':radio').first().val());
5355 }
5356
5357 }
5358
5359 });
5360
5361 })(jQuery);
5362 (function($) {
5363
5364 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5365 return;
5366 }
5367
5368 /**
5369 * Field: reCaptcha
5370 */
5371 var reCaptcha = acf.Field.extend({
5372
5373 type: 'acfe_recaptcha',
5374
5375 wait: 'load',
5376
5377 widgetID: 0,
5378
5379 events: {
5380 'invalidField': 'onInvalidField'
5381 },
5382
5383 $control: function() {
5384 return this.$('.acf-input-wrap');
5385 },
5386
5387 $input: function() {
5388 return this.$('input[type="hidden"]');
5389 },
5390
5391 initialize: function() {
5392 reCaptchaAPI.load(this, this.render);
5393 },
5394
5395 render: function() {
5396
5397 if (this.get('version') === 'v2') {
5398 this.renderV2();
5399
5400 } else if (this.get('version') === 'v3') {
5401 this.renderV3();
5402 }
5403 },
5404
5405 renderV2: function() {
5406
5407 // request
5408 this.widgetID = grecaptcha.render(this.$control().find('> div')[0], {
5409 'sitekey': this.get('siteKey'),
5410 'theme': this.get('theme'),
5411 'size': this.get('size'),
5412
5413 'callback': this.proxy(function(response) {
5414
5415 acf.val(this.$input(), response, true);
5416 this.removeError();
5417
5418 }),
5419
5420 'error-callback': this.proxy(function() {
5421
5422 // add custom error
5423 // this avoid multiple requests with onInvalidField() if keys are wrong
5424 this.$el.addClass('acf-error');
5425
5426 this.showNotice({
5427 text: 'An error has occured',
5428 type: 'error',
5429 dismiss: false
5430 });
5431
5432 }),
5433
5434 'expired-callback': this.proxy(function() {
5435 this.showError('reCaptcha has expired');
5436 })
5437 });
5438
5439 },
5440
5441 renderV3: function() {
5442
5443 // vars
5444 var $input = this.$input();
5445 var sitekey = this.get('siteKey');
5446
5447 // request
5448 var request = function() {
5449
5450 grecaptcha.execute(sitekey, {
5451 action: 'homepage'
5452 }).then(function(response) {
5453 acf.val($input, response, true);
5454 });
5455
5456 // refresh every 80sec
5457 // this avoid an issue where token becomes invalid after 2min
5458 setTimeout(request, 80 * 1000);
5459
5460 }
5461
5462 // execute request
5463 request();
5464
5465 },
5466
5467 reset: function() {
5468
5469 // reset v2
5470 if (this.get('version') === 'v2') {
5471 grecaptcha.reset(this.widgetID);
5472 acf.val(this.$input(), '', true);
5473
5474 // reset v3
5475 } else if (this.get('version') === 'v3') {
5476 this.renderV3();
5477
5478 }
5479
5480 },
5481
5482 onInvalidField: function(e, $el) {
5483 this.reset();
5484 },
5485
5486 });
5487
5488 acf.registerFieldType(reCaptcha);
5489
5490
5491 /**
5492 * recpatchaAPI
5493 *
5494 * @type {acf.Model}
5495 */
5496 var reCaptchaAPI = new acf.Model({
5497
5498 busy: false,
5499
5500 load: function(field, callback) {
5501
5502 // defaults
5503 callback = field.proxy(callback);
5504
5505 // vars
5506 var url_v2 = 'https://www.google.com/recaptcha/api.js?render=explicit';
5507 var url_v3 = 'https://www.google.com/recaptcha/api.js?render=' + field.get('siteKey');
5508 var url = field.get('version') === 'v2' ? url_v2 : url_v3;
5509
5510 // check if recaptcha exists
5511 if (typeof grecaptcha !== 'undefined' || acf.isset(window, 'grecaptcha')) {
5512 return callback();
5513 }
5514
5515 acf.addAction('acfe/recpatcha_loaded', callback);
5516
5517 // already busy
5518 if (this.busy) {
5519 return;
5520 }
5521
5522 // set busy
5523 this.busy = true;
5524
5525 // load api
5526 $.ajax({
5527 url: url,
5528 dataType: 'script',
5529 cache: true,
5530 context: this,
5531 success: function() {
5532
5533 grecaptcha.ready(this.proxy(function() {
5534 acf.doAction('acfe/recpatcha_loaded');
5535 this.busy = false;
5536 }));
5537
5538 }
5539 });
5540
5541 }
5542
5543 });
5544
5545 })(jQuery);
5546 (function($) {
5547
5548 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5549 return;
5550 }
5551
5552 /**
5553 * Init
5554 */
5555 var repeater = acf.getFieldType('repeater');
5556 var model = repeater.prototype;
5557
5558 // Repeater: Lock Layouts
5559 model.acfeOnHover = function() {
5560
5561 var repeater = this;
5562
5563 // remove event
5564 repeater.off('mouseover');
5565
5566 }
5567
5568 /**
5569 * Spawn
5570 */
5571 acf.addAction('new_field/type=repeater', function(repeater) {
5572
5573 // ACFE: Lock
5574 if (repeater.has('acfeRepeaterLock')) {
5575
5576 repeater.removeEvents({
5577 'mouseover': 'onHover'
5578 });
5579
5580 repeater.addEvents({
5581 'mouseover': 'acfeOnHover'
5582 });
5583
5584 }
5585
5586 // ACFE: Remove Actions
5587 if (repeater.has('acfeRepeaterRemoveActions')) {
5588
5589 repeater.$actions().remove();
5590
5591 repeater.$el.find('thead:first > tr > th.acf-row-handle:last').remove();
5592 repeater.$rows().find('> .acf-row-handle:last').remove();
5593
5594
5595 }
5596
5597 // ACFE: Stylised button
5598 if (repeater.has('acfeRepeaterStylisedButton')) {
5599
5600 repeater.$button().removeClass('button-primary');
5601 repeater.$actions().addClass('acfe-repeater-stylised-button');
5602
5603 }
5604
5605 });
5606
5607 })(jQuery);
5608 (function($) {
5609
5610 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5611 return;
5612 }
5613
5614
5615 /**
5616 * Field: Select
5617 */
5618 new acf.Model({
5619
5620 actions: {
5621 'new_field/type=select': 'newSelect',
5622 'select2_init': 'init',
5623 },
5624
5625 filters: {
5626 'select2_args': 'args',
5627 },
5628
5629 newSelect: function(field) {
5630
5631 // inherit properties
5632 field.inherit(field.$input());
5633
5634 // remove "- -" characters from placeholder
5635 // acf already apply this to all select2
5636 if (!field.get('ui') && field.get('allow_null')) {
5637
5638 field.$input().find('option').each(function(i, option) {
5639
5640 if (!option.value && option.text.startsWith('- ') && option.text.endsWith(' -')) {
5641
5642 option.text = option.text.substring(2); // remove starting "- "
5643 option.text = option.text.substring(0, option.text.length - 2); // remove ending " -"
5644
5645 }
5646
5647 });
5648
5649 }
5650
5651 // prepend / append
5652 if (field.has('acfePrepend') || field.has('acfeAppend')) {
5653
5654 if (!field.$input().parent('.acf-input-wrap').length) {
5655
5656 field.$input().wrapAll('<div class="acf-input-wrap"></div>');
5657
5658 if (field.get('ui')) {
5659 field.$('.acf-input-wrap:first').append(field.$('.select2'));
5660 }
5661
5662 if (field.has('acfePrepend')) {
5663 field.$('.acf-input-wrap:first').before('<div class="acf-input-prepend">' + field.get('acfePrepend') + '</div>');
5664 field.$input().addClass('acf-is-prepended');
5665 }
5666
5667 if (field.has('acfeAppend')) {
5668 field.$('.acf-input-wrap:first').before('<div class="acf-input-append">' + field.get('acfeAppend') + '</div>');
5669 field.$input().addClass('acf-is-appended');
5670 }
5671
5672 }
5673
5674 }
5675
5676 },
5677
5678 init: function($select, options, data, field, instance) {
5679
5680 // close dropdown on clear
5681 $select.on('select2:clear', function(e) {
5682 $(this).on('select2:opening.cancelOpen', function(e) {
5683 e.preventDefault();
5684 $(this).off("select2:opening.cancelOpen");
5685 });
5686 });
5687
5688 // bail early
5689 if (!field) {
5690 return;
5691 }
5692
5693 // add css class to dropdown with field name + key for developers <3
5694 if ($select.data('select2')) {
5695
5696 $select.data('select2').$dropdown
5697 .addClass('select2-dropdown-acf')
5698 .addClass('select2-dropdown-acf-field-' + field.get('name'))
5699 .addClass('select2-dropdown-acf-field-' + field.get('key'));
5700
5701 }
5702
5703 // search placeholder
5704 // only in single mode
5705 if (!field.get('multiple') && field.get('acfeSearchPlaceholder')) {
5706
5707 $select.on('select2:open', function(e) {
5708 $('.select2-search.select2-search--dropdown > .select2-search__field').attr('placeholder', field.get('acfeSearchPlaceholder'));
5709 });
5710
5711 }
5712
5713 },
5714
5715 args: function(options, $select, data, field, instance) {
5716
5717 // bail early
5718 if (!field) {
5719 return options;
5720 }
5721
5722 // custom tags disallowed
5723 if (!field.get('acfeAllowCustom')) {
5724 return options;
5725 }
5726
5727 // allow custom tags
5728 options.tags = true;
5729
5730 // create tag
5731 options.createTag = function(params) {
5732
5733 var term = $.trim(params.term);
5734
5735 if (term === '') {
5736 return null;
5737 }
5738
5739 // vars
5740 var foundTerm;
5741 var ajaxResults = acf.isget(this, '_request', 'responseJSON', 'results');
5742
5743 // ajax results
5744 if (ajaxResults) {
5745
5746 loop: for (var item of ajaxResults) {
5747
5748 if (item.children) {
5749 for (var child of item.children) {
5750
5751 if (typeof child.id === 'string' && child.id.toLowerCase() === term.toLowerCase()) {
5752 foundTerm = true;
5753 break loop;
5754 }
5755
5756 }
5757 }
5758
5759 }
5760
5761 // normal results
5762 }
5763 else {
5764
5765 for (var option of this.$element.find('option')) {
5766 if (option.value.toLowerCase() === term.toLowerCase()) {
5767 foundTerm = true;
5768 break;
5769 }
5770 }
5771
5772 }
5773
5774 // found term
5775 if (foundTerm) {
5776 return null;
5777 }
5778
5779 // create tag
5780 return {
5781 id: term,
5782 text: term
5783 };
5784
5785 };
5786
5787 // insert tag
5788 options.insertTag = function(results, tag) {
5789
5790 var found;
5791
5792 for (var result of results) {
5793 if ($.trim(tag.text).toUpperCase() === $.trim(result.text).toUpperCase()) {
5794 found = true;
5795 break;
5796 }
5797 }
5798
5799 if (!found) {
5800 results.unshift(tag);
5801 }
5802
5803 };
5804
5805 return options;
5806
5807 },
5808
5809 });
5810
5811 })(jQuery);
5812 (function($) {
5813
5814 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5815 return;
5816 }
5817
5818 /**
5819 * Field: Slug
5820 */
5821 var ACFE_Slug = acf.Field.extend({
5822
5823 type: 'acfe_slug',
5824
5825 events: {
5826 'input input': 'onInput',
5827 'focusout input': 'onFocusOut',
5828 },
5829
5830 onInput: function(e, $el) {
5831
5832 $el.val($el.val().toLowerCase()
5833 .replace(/\s+/g, '-') // Replace spaces with -
5834 .replace(/[^\w\-]+/g, '') // Remove all non-word chars
5835 .replace(/\-\-+/g, '-') // Replace multiple - with single -
5836 .replace(/\_\_+/g, '_') // Replace multiple _ with single _
5837 .replace(/^-+/, '')); // Trim - from start of text
5838
5839 },
5840
5841 onFocusOut: function(e, $el) {
5842
5843 $el.val($el.val().toLowerCase()
5844 .replace(/-+$/, '') // Trim - from end of text
5845 .replace(/_+$/, '')); // Trim _ from end of text
5846
5847 },
5848
5849 });
5850
5851 acf.registerFieldType(ACFE_Slug);
5852
5853 })(jQuery);
5854 (function($) {
5855
5856 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5857 return;
5858 }
5859
5860 /**
5861 * Field: Tab
5862 */
5863 new acf.Model({
5864
5865 actions: {
5866 'prepare_field/type=tab': 'prepareField',
5867 },
5868
5869 prepareField: function(field) {
5870
5871 if (!field.has('noPreference')) return;
5872
5873 var $tabs = field.findTabs();
5874 var tabs = acf.getInstances($tabs);
5875 var key = field.get('key');
5876
5877 if (tabs.length) {
5878
5879 var preference = acf.getPreference('this.tabs');
5880
5881 if (!preference) return;
5882
5883 $.each(tabs, function(i, group) {
5884
5885 var groupIndex = group.get('index');
5886
5887 if (group.data.key !== key)
5888 return;
5889
5890 preference[groupIndex] = 0;
5891
5892 });
5893
5894 // update
5895 acf.setPreference('this.tabs', preference);
5896
5897 }
5898
5899 }
5900
5901 });
5902
5903 })(jQuery);
5904 (function($) {
5905
5906 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5907 return;
5908 }
5909
5910 /**
5911 * Field: Textarea
5912 */
5913 var Textarea = acf.Field.extend({
5914
5915 type: 'textarea',
5916
5917 events: {
5918 'keydown textarea': 'onInput',
5919 },
5920
5921 onInput: function(e, $el) {
5922
5923 //check for mode
5924 if (!this.has('acfeTextareaCode')) return;
5925
5926 // check for tab input
5927 if (e.keyCode !== 9) return;
5928
5929 e.preventDefault();
5930
5931 var input = this.$el.find('textarea')[0];
5932
5933 var s = input.selectionStart;
5934
5935 this.$el.find('textarea').val(function(i, v) {
5936 return v.substring(0, s) + " " + v.substring(input.selectionEnd)
5937 });
5938
5939 input.selectionEnd = s + 4;
5940
5941 },
5942
5943 });
5944
5945 acf.registerFieldType(Textarea);
5946
5947 })(jQuery);
5948 (function($) {
5949
5950 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5951 return;
5952 }
5953
5954 /**
5955 * Field: True/False
5956 */
5957 var TrueFalse = acf.models.TrueFalseField;
5958
5959 acf.models.TrueFalseField = TrueFalse.extend({
5960
5961 // add setValue method
5962 // this allows to use field.val('new_value') to assign a new value to the field
5963 setValue: function(val) {
5964
5965 // clear value
5966 if (!val) {
5967 return this.clearValue();
5968 }
5969
5970 this.switchOn();
5971 this.trigger('change'); // trigger change for conditional logic
5972
5973 },
5974
5975 // add clearValue method
5976 // this allows to set the value to the first radio or if allow_null is enabled, to null
5977 clearValue: function() {
5978
5979 this.switchOff();
5980 this.trigger('change'); // trigger change for conditional logic
5981
5982 }
5983
5984 });
5985
5986 })(jQuery);
5987 (function($) {
5988
5989 if (typeof acf === 'undefined' || typeof acfe === 'undefined') {
5990 return;
5991 }
5992
5993 /**
5994 * Field: WYSIWYG Overwrite
5995 */
5996 var Wysiwyg = acf.models.WysiwygField;
5997
5998 acf.models.WysiwygField = Wysiwyg.extend({
5999
6000 initialize: function() {
6001
6002 // initialize Editor if no delay and not already initialized
6003 if (!this.has('id') && !this.$control().hasClass('delay')) {
6004 this.initializeEditor();
6005 }
6006
6007 },
6008
6009 /**
6010 * Fix an issue when we apply field.val('my value'), it add the value to all textarea within the same .acf-field > .acf-input
6011 *
6012 * @returns {*}
6013 */
6014 $input: function() {
6015 return this.$('textarea:first');
6016 }
6017
6018 });
6019
6020 /**
6021 * Field: WYSIWYG
6022 */
6023 new acf.Model({
6024
6025 actions: {
6026 'append_field/type=wysiwyg': 'appendField',
6027 'show_field/type=wysiwyg': 'showField',
6028 'ready_field/type=wysiwyg': 'showField',
6029 },
6030
6031 appendField: function(field) {
6032
6033 // initialize editor when inside flexible content > repeater
6034 // on click repeater add row
6035 this.setTimeout(function() {
6036 this.showField(field);
6037 }, 1);
6038
6039 },
6040
6041 showField: function(field) {
6042
6043 if (field.has('acfeWysiwygAutoInit') && field.$el.is(':visible') && !field.has('id') && !acfe.isFilterEnabled('acfeFlexibleOpen')) {
6044 this.initializeEditor(field);
6045 }
6046
6047 },
6048
6049 initializeEditor: function(field) {
6050
6051 if (field.$control().hasClass('delay')) {
6052
6053 field.$control().removeClass('delay');
6054 field.$control().find('.acf-editor-toolbar').remove();
6055
6056 // initialize
6057 field.initializeEditor();
6058
6059 }
6060
6061 },
6062
6063 });
6064
6065 })(jQuery);