(function($, undefined){
/**
* fieldGroupManager
*
* Generic field group functionality
*
* @date 15/12/17
* @since 5.7.0
*
* @param void
* @return void
*/
var fieldGroupManager = new acf.Model({
id: 'fieldGroupManager',
events: {
'submit #post': 'onSubmit',
'click a[href="#"]': 'onClick',
'click .submitdelete': 'onClickTrash',
},
filters: {
'find_fields_args': 'filterFindFieldArgs'
},
onSubmit: function( e, $el ){
// vars
var $title = $('#titlewrap #title');
// empty
if( !$title.val() ) {
// prevent default
e.preventDefault();
// unlock form
acf.unlockForm( $el );
// alert
alert( acf.__('Field group title is required') );
// focus
$title.trigger('focus');
}
},
onClick: function( e ){
e.preventDefault();
},
onClickTrash: function( e ){
var result = confirm( acf.__('Move to trash. Are you sure?') );
if( !result ) {
e.preventDefault();
}
},
filterFindFieldArgs: function( args ){
args.visible = true;
return args;
}
});
/**
* screenOptionsManager
*
* Screen options functionality
*
* @date 15/12/17
* @since 5.7.0
*
* @param void
* @return void
*/
var screenOptionsManager = new acf.Model({
id: 'screenOptionsManager',
wait: 'prepare',
events: {
'change': 'onChange'
},
initialize: function(){
// vars
var $div = $('#adv-settings');
var $append = $('#acf-append-show-on-screen');
// append
$div.find('.metabox-prefs').append( $append.html() );
$div.find('.metabox-prefs br').remove();
// clean up
$append.remove();
// initialize
this.$el = $('#acf-field-key-hide');
// render
this.render();
},
isChecked: function(){
return this.$el.prop('checked');
},
onChange: function( e, $el ) {
var val = this.isChecked() ? 1 : 0;
acf.updateUserSetting('show_field_keys', val);
this.render();
},
render: function(){
if( this.isChecked() ) {
$('#acf-field-group-fields').addClass('show-field-keys');
} else {
$('#acf-field-group-fields').removeClass('show-field-keys');
}
}
});
/**
* appendFieldManager
*
* Appends fields together
*
* @date 15/12/17
* @since 5.7.0
*
* @param void
* @return void
*/
var appendFieldManager = new acf.Model({
actions: {
'new_field' : 'onNewField'
},
onNewField: function( field ){
// bail ealry if not append
if( !field.has('append') ) return;
// vars
var append = field.get('append');
var $sibling = field.$el.siblings('[data-name="' + append + '"]').first();
// bail early if no sibling
if( !$sibling.length ) return;
// ul
var $div = $sibling.children('.acf-input');
var $ul = $div.children('ul');
// create ul
if( !$ul.length ) {
$div.wrapInner('
');
$ul = $div.children('ul');
}
// li
var html = field.$('.acf-input').html();
var $li = $('' + html + '');
$ul.append( $li );
$ul.attr('data-cols', $ul.children().length );
// clean up
field.remove();
}
});
})(jQuery);
(function($, undefined){
acf.FieldObject = acf.Model.extend({
// class used to avoid nested event triggers
eventScope: '.acf-field-object',
// events
events: {
'click .edit-field': 'onClickEdit',
'click .delete-field': 'onClickDelete',
'click .duplicate-field': 'duplicate',
'click .move-field': 'move',
'change .field-type': 'onChangeType',
'change .field-required': 'onChangeRequired',
'blur .field-label': 'onChangeLabel',
'blur .field-name': 'onChangeName',
'change': 'onChange',
'changed': 'onChanged',
},
// data
data: {
// Similar to ID, but used for HTML puposes.
// It is possbile for a new field to have an ID of 0, but an id of 'field_123' */
id: 0,
// The field key ('field_123')
key: '',
// The field type (text, image, etc)
type: '',
// The $post->ID of this field
//ID: 0,
// The field's parent
//parent: 0,
// The menu order
//menu_order: 0
},
setup: function( $field ){
// set $el
this.$el = $field;
// inherit $field data (id, key, type)
this.inherit( $field );
// load additional props
// - this won't trigger 'changed'
this.prop('ID');
this.prop('parent');
this.prop('menu_order');
},
$input: function( name ){
return $('#' + this.getInputId() + '-' + name);
},
$meta: function(){
return this.$('.meta:first');
},
$handle: function(){
return this.$('.handle:first');
},
$settings: function(){
return this.$('.settings:first');
},
$setting: function( name ){
return this.$('.acf-field-settings:first > .acf-field-setting-' + name);
},
getParent: function(){
return acf.getFieldObjects({ child: this.$el, limit: 1 }).pop();
},
getParents: function(){
return acf.getFieldObjects({ child: this.$el });
},
getFields: function(){
return acf.getFieldObjects({ parent: this.$el });
},
getInputName: function(){
return 'acf_fields[' + this.get('id') + ']';
},
getInputId: function(){
return 'acf_fields-' + this.get('id');
},
newInput: function( name, value ){
// vars
var inputId = this.getInputId();
var inputName = this.getInputName();
// append name
if( name ) {
inputId += '-'+name;
inputName += '['+name+']';
}
// create input (avoid HTML + JSON value issues)
var $input = $('').attr({
id: inputId,
name: inputName,
value: value
});
this.$('> .meta').append( $input );
// return
return $input;
},
getProp: function( name ){
// check data
if( this.has(name) ) {
return this.get(name);
}
// get input value
var $input = this.$input( name );
var value = $input.length ? $input.val() : null;
// set data silently (cache)
this.set(name, value, true);
// return
return value;
},
setProp: function( name, value ) {
// get input
var $input = this.$input( name );
var prevVal = $input.val();
// create if new
if( !$input.length ) {
$input = this.newInput( name, value );
}
// remove
if( value === null ) {
$input.remove();
// update
} else {
$input.val( value );
}
//console.log('setProp', name, value, this);
// set data silently (cache)
if( !this.has(name) ) {
//console.log('setting silently');
this.set(name, value, true);
// set data allowing 'change' event to fire
} else {
//console.log('setting loudly!');
this.set(name, value);
}
// return
return this;
},
prop: function( name, value ){
if( value !== undefined ) {
return this.setProp( name, value );
} else {
return this.getProp( name );
}
},
props: function( props ){
Object.keys( props ).map(function( key ){
this.setProp( key, props[key] );
}, this);
},
getLabel: function(){
// get label with empty default
var label = this.prop('label');
if( label === '' ) {
label = acf.__('(no label)')
}
// return
return label;
},
getName: function(){
return this.prop('name');
},
getType: function(){
return this.prop('type');
},
getTypeLabel: function(){
var type = this.prop('type');
var types = acf.get('fieldTypes');
return ( types[type] ) ? types[type].label : type;
},
getKey: function(){
return this.prop('key');
},
initialize: function(){
this.addProFields();
},
addProFields: function() {
// Make sure we're only running this on free version.
if (acf.data.fieldTypes.hasOwnProperty('clone')) {
return;
}
// Make sure we haven't appended these fields before.
var $fieldTypeSelect = $('.field-type').not('.acf-free-field-type');
// Append pro fields to "Layout" group.
var $layoutGroup = $fieldTypeSelect.find('optgroup option[value="group"]').parent();
$layoutGroup.append(
'' +
'' +
''
);
// Add pro fields to "Content" group.
var $contentGroup = $fieldTypeSelect.find('optgroup option[value="image"]').parent();
$contentGroup.append(
''
);
$fieldTypeSelect.addClass('acf-free-field-type');
},
render: function(){
// vars
var $handle = this.$('.handle:first');
var menu_order = this.prop('menu_order');
var label = this.getLabel();
var name = this.prop('name');
var type = this.getTypeLabel();
var key = this.prop('key');
var required = this.$input('required').prop('checked');
// update menu order
$handle.find('.acf-icon').html( parseInt(menu_order) + 1 );
// update required
if( required ) {
label += ' *';
}
// update label
$handle.find('.li-field-label strong a').html( label );
// update name
$handle.find('.li-field-name').text( name );
// update type
$handle.find('.li-field-type').text( type );
// update key
$handle.find('.li-field-key').text( key );
// action for 3rd party customization
acf.doAction('render_field_object', this);
},
refresh: function(){
acf.doAction('refresh_field_object', this);
},
isOpen: function() {
return this.$el.hasClass('open');
},
onClickEdit: function( e ){
this.isOpen() ? this.close() : this.open();
},
open: function(){
// vars
var $settings = this.$el.children('.settings');
// open
$settings.slideDown();
this.$el.addClass('open');
// action (open)
acf.doAction('open_field_object', this);
this.trigger('openFieldObject');
// action (show)
acf.doAction('show', $settings);
},
close: function(){
// vars
var $settings = this.$el.children('.settings');
// close
$settings.slideUp();
this.$el.removeClass('open');
// action (close)
acf.doAction('close_field_object', this);
this.trigger('closeFieldObject');
// action (hide)
acf.doAction('hide', $settings);
},
serialize: function(){
return acf.serialize( this.$el, this.getInputName() );
},
save: function( type ){
// defaults
type = type || 'settings'; // meta, settings
// vars
var save = this.getProp('save');
// bail if already saving settings
if( save === 'settings' ) {
return;
}
// prop
this.setProp('save', type);
// debug
this.$el.attr('data-save', type);
// action
acf.doAction('save_field_object', this, type);
},
submit: function(){
// vars
var inputName = this.getInputName();
var save = this.get('save');
// close
if( this.isOpen() ) {
this.close();
}
// allow all inputs to save
if( save == 'settings' ) {
// do nothing
// allow only meta inputs to save
} else if( save == 'meta' ) {
this.$('> .settings [name^="' + inputName + '"]').remove();
// prevent all inputs from saving
} else {
this.$('[name^="' + inputName + '"]').remove();
}
// action
acf.doAction('submit_field_object', this);
},
onChange: function( e, $el ){
// save settings
this.save();
// action for 3rd party customization
acf.doAction('change_field_object', this);
},
onChanged: function( e, $el, name, value ){
// ignore 'save'
if( name == 'save' ) {
return;
}
// save meta
if( ['menu_order', 'parent'].indexOf(name) > -1 ) {
this.save('meta');
// save field
} else {
this.save();
}
// render
if( ['menu_order', 'label', 'required', 'name', 'type', 'key'].indexOf(name) > -1 ) {
this.render();
}
// action for 3rd party customization
acf.doAction('change_field_object_' + name, this, value);
},
onChangeLabel: function( e, $el ){
// set
var label = $el.val();
this.set('label', label);
// render name
if( this.prop('name') == '' ) {
var name = acf.applyFilters('generate_field_object_name', acf.strSanitize(label), this);
this.prop('name', name);
}
},
onChangeName: function( e, $el){
// set
var name = $el.val();
this.set('name', name);
// error
if( name.substr(0, 6) === 'field_' ) {
alert( acf.__('The string "field_" may not be used at the start of a field name') );
}
},
onChangeRequired: function( e, $el ){
// set
var required = $el.prop('checked') ? 1 : 0;
this.set('required', required);
},
delete: function( args ){
// defaults
args = acf.parseArgs(args, {
animate: true
});
// add to remove list
var id = this.prop('ID');
if( id ) {
var $input = $('#_acf_delete_fields');
var newVal = $input.val() + '|' + id;
$input.val( newVal );
}
// action
acf.doAction('delete_field_object', this);
// animate
if( args.animate ) {
this.removeAnimate();
} else {
this.remove();
}
},
onClickDelete: function( e, $el ){
// Bypass confirmation when holding down "shift" key.
if( e.shiftKey ) {
return this.delete();
}
// add class
this.$el.addClass('-hover');
// add tooltip
var tooltip = acf.newTooltip({
confirmRemove: true,
target: $el,
context: this,
confirm: function(){
this.delete();
},
cancel: function(){
this.$el.removeClass('-hover');
}
});
},
removeAnimate: function(){
// vars
var field = this;
var $list = this.$el.parent();
var $fields = acf.findFieldObjects({
sibling: this.$el
});
// remove
acf.remove({
target: this.$el,
endHeight: $fields.length ? 0 : 50,
complete: function(){
field.remove();
acf.doAction('removed_field_object', field, $list);
}
});
// action
acf.doAction('remove_field_object', field, $list);
},
duplicate: function(){
// vars
var newKey = acf.uniqid('field_');
// duplicate
var $newField = acf.duplicate({
target: this.$el,
search: this.get('id'),
replace: newKey,
});
// set new key
$newField.attr('data-key', newKey);
// get instance
var newField = acf.getFieldObject( $newField );
// open / close
if( this.isOpen() ) {
this.close();
} else {
newField.open();
}
// focus label
var $label = newField.$setting('label input');
setTimeout(function(){
$label.trigger('focus');
}, 251);
// update newField label / name
var label = newField.prop('label');
var name = newField.prop('name');
var end = name.split('_').pop();
var copy = acf.__('copy');
// increase suffix "1"
if( acf.isNumeric(end) ) {
var i = (end*1) + 1;
label = label.replace( end, i );
name = name.replace( end, i );
// increase suffix "(copy1)"
} else if( end.indexOf(copy) === 0 ) {
var i = end.replace(copy, '') * 1;
i = i ? i+1 : 2;
// replace
label = label.replace( end, copy + i );
name = name.replace( end, copy + i );
// add default "(copy)"
} else {
label += ' (' + copy + ')';
name += '_' + copy;
}
newField.prop('ID', 0);
newField.prop('label', label);
newField.prop('name', name);
newField.prop('key', newKey);
// action
acf.doAction('duplicate_field_object', this, newField);
acf.doAction('append_field_object', newField);
},
wipe: function(){
// vars
var prevId = this.get('id');
var prevKey = this.get('key');
var newKey = acf.uniqid('field_');
// rename
acf.rename({
target: this.$el,
search: prevId,
replace: newKey,
});
// data
this.set('id', newKey);
this.set('prevId', prevId);
this.set('prevKey', prevKey);
// props
this.prop('key', newKey);
this.prop('ID', 0);
// attr
this.$el.attr('data-key', newKey);
this.$el.attr('data-id', newKey);
// action
acf.doAction('wipe_field_object', this);
},
move: function(){
// helper
var hasChanged = function( field ){
return (field.get('save') == 'settings');
};
// vars
var changed = hasChanged(this);
// has sub fields changed
if( !changed ) {
acf.getFieldObjects({
parent: this.$el
}).map(function( field ){
changed = hasChanged(field) || field.changed;
});
}
// bail early if changed
if( changed ) {
alert( acf.__('This field cannot be moved until its changes have been saved') );
return;
}
// step 1.
var id = this.prop('ID');
var field = this;
var popup = false;
var step1 = function(){
// popup
popup = acf.newPopup({
title: acf.__('Move Custom Field'),
loading: true,
width: '300px'
});
// ajax
var ajaxData = {
action: 'acf/field_group/move_field',
field_id: id
};
// get HTML
$.ajax({
url: acf.get('ajaxurl'),
data: acf.prepareForAjax(ajaxData),
type: 'post',
dataType: 'html',
success: step2
});
};
var step2 = function( html ){
// update popup
popup.loading(false);
popup.content(html);
// submit form
popup.on('submit', 'form', step3);
};
var step3 = function( e, $el ){
// prevent
e.preventDefault();
// disable
acf.startButtonLoading( popup.$('.button') );
// ajax
var ajaxData = {
action: 'acf/field_group/move_field',
field_id: id,
field_group_id: popup.$('select').val()
};
// get HTML
$.ajax({
url: acf.get('ajaxurl'),
data: acf.prepareForAjax(ajaxData),
type: 'post',
dataType: 'html',
success: step4
});
};
var step4 = function( html ){
// update popup
popup.content(html);
// remove element
field.removeAnimate();
};
// start
step1();
},
onChangeType: function( e, $el ){
// clea previous timout
if( this.changeTimeout ) {
clearTimeout(this.changeTimeout);
}
// set new timeout
// - prevents changing type multiple times whilst user types in newType
this.changeTimeout = this.setTimeout(function(){
this.changeType( $el.val() );
}, 300);
},
changeType: function( newType ){
// vars
var prevType = this.prop('type');
var prevClass = acf.strSlugify( 'acf-field-object-' + prevType );
var newClass = acf.strSlugify( 'acf-field-object-' + newType );
// update props
this.$el.removeClass(prevClass).addClass(newClass);
this.$el.attr('data-type', newType);
this.$el.data('type', newType);
// abort XHR if this field is already loading AJAX data
if( this.has('xhr') ) {
this.get('xhr').abort();
}
// store settings
var $tbody = this.$('> .settings > table > tbody');
var $settings = $tbody.children('[data-setting="' + prevType + '"]');
this.set( 'settings-' + prevType, $settings );
$settings.detach();
// show settings
if( this.has('settings-' + newType) ) {
var $newSettings = this.get('settings-' + newType);
this.$setting('conditional_logic').before( $newSettings );
this.set('type', newType);
//this.refresh();
return;
}
// load settings
var $loading = $(' | |
');
this.$setting('conditional_logic').before( $loading );
// ajax
var ajaxData = {
action: 'acf/field_group/render_field_settings',
field: this.serialize(),
prefix: this.getInputName()
};
// ajax
var xhr = $.ajax({
url: acf.get('ajaxurl'),
data: acf.prepareForAjax(ajaxData),
type: 'post',
dataType: 'html',
context: this,
success: function( html ){
// bail early if no settings
if( !html ) return;
// append settings
$loading.after( html );
// events
acf.doAction('append', $tbody);
},
complete: function(){
// also triggered by xhr.abort();
$loading.remove();
this.set('type', newType);
//this.refresh();
}
});
// set
this.set('xhr', xhr);
},
updateParent: function(){
// vars
var ID = acf.get('post_id');
// check parent
var parent = this.getParent();
if( parent ) {
ID = parseInt(parent.prop('ID')) || parent.prop('key');
}
// update
this.prop('parent', ID);
}
});
})(jQuery);
(function($, undefined){
/**
* mid
*
* Calculates the model ID for a field type
*
* @date 15/12/17
* @since 5.6.5
*
* @param string type
* @return string
*/
var modelId = function( type ) {
return acf.strPascalCase( type || '' ) + 'FieldSetting';
};
/**
* registerFieldType
*
* description
*
* @date 14/12/17
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
acf.registerFieldSetting = function( model ){
var proto = model.prototype;
var mid = modelId(proto.type + ' ' + proto.name);
this.models[ mid ] = model;
};
/**
* newField
*
* description
*
* @date 14/12/17
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
acf.newFieldSetting = function( field ){
// vars
var type = field.get('setting') || '';
var name = field.get('name') || '';
var mid = modelId( type + ' ' + name );
var model = acf.models[ mid ] || null;
// bail ealry if no setting
if( model === null ) return false;
// instantiate
var setting = new model( field );
// return
return setting;
};
/**
* acf.getFieldSetting
*
* description
*
* @date 19/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
acf.getFieldSetting = function( field ) {
// allow jQuery
if( field instanceof jQuery ) {
field = acf.getField(field);
}
// return
return field.setting;
};
/**
* settingsManager
*
* description
*
* @date 6/1/18
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
var settingsManager = new acf.Model({
actions: {
'new_field': 'onNewField'
},
onNewField: function( field ){
field.setting = acf.newFieldSetting( field );
}
});
/**
* acf.FieldSetting
*
* description
*
* @date 6/1/18
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
acf.FieldSetting = acf.Model.extend({
field: false,
type: '',
name: '',
wait: 'ready',
eventScope: '.acf-field',
events: {
'change': 'render'
},
setup: function( field ){
// vars
var $field = field.$el;
// set props
this.$el = $field;
this.field = field;
this.$fieldObject = $field.closest('.acf-field-object');
this.fieldObject = acf.getFieldObject( this.$fieldObject );
// inherit data
$.extend(this.data, field.data);
},
initialize: function(){
this.render();
},
render: function(){
// do nothing
}
});
/*
* Date Picker
*
* This field type requires some extra logic for its settings
*
* @type function
* @date 24/10/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
var DisplayFormatFieldSetting = acf.FieldSetting.extend({
type: '',
name: '',
render: function(){
var $input = this.$('input[type="radio"]:checked');
if( $input.val() != 'other' ) {
this.$('input[type="text"]').val( $input.val() );
}
}
});
var DatePickerDisplayFormatFieldSetting = DisplayFormatFieldSetting.extend({
type: 'date_picker',
name: 'display_format'
});
var DatePickerReturnFormatFieldSetting = DisplayFormatFieldSetting.extend({
type: 'date_picker',
name: 'return_format'
});
acf.registerFieldSetting( DatePickerDisplayFormatFieldSetting );
acf.registerFieldSetting( DatePickerReturnFormatFieldSetting );
/*
* Date Time Picker
*
* This field type requires some extra logic for its settings
*
* @type function
* @date 24/10/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
var DateTimePickerDisplayFormatFieldSetting = DisplayFormatFieldSetting.extend({
type: 'date_time_picker',
name: 'display_format'
});
var DateTimePickerReturnFormatFieldSetting = DisplayFormatFieldSetting.extend({
type: 'date_time_picker',
name: 'return_format'
});
acf.registerFieldSetting( DateTimePickerDisplayFormatFieldSetting );
acf.registerFieldSetting( DateTimePickerReturnFormatFieldSetting );
/*
* Time Picker
*
* This field type requires some extra logic for its settings
*
* @type function
* @date 24/10/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
var TimePickerDisplayFormatFieldSetting = DisplayFormatFieldSetting.extend({
type: 'time_picker',
name: 'display_format'
});
var TimePickerReturnFormatFieldSetting = DisplayFormatFieldSetting.extend({
name: 'time_picker',
name: 'return_format'
});
acf.registerFieldSetting( TimePickerDisplayFormatFieldSetting );
acf.registerFieldSetting( TimePickerReturnFormatFieldSetting );
/**
* Color Picker Settings.
*
* @date 16/12/20
* @since 5.9.4
*
* @param type $var Description. Default.
* @return type Description.
*/
var ColorPickerReturnFormat = acf.FieldSetting.extend({
type: 'color_picker',
name: 'enable_opacity',
render: function(){
var $return_format_setting = this.fieldObject.$setting('return_format');
var $default_value_setting = this.fieldObject.$setting('default_value');
var $labelText = $return_format_setting.find('input[type="radio"][value="string"]').parent('label').contents().last();
var $defaultPlaceholder = $default_value_setting.find('input[type="text"]');
var l10n = acf.get('colorPickerL10n');
if( this.field.val() ) {
$labelText.replaceWith( l10n.rgba_string );
$defaultPlaceholder.attr('placeholder', 'rgba(255,255,255,0.8)');
} else {
$labelText.replaceWith( l10n.hex_string );
$defaultPlaceholder.attr('placeholder', '#FFFFFF');
}
}
});
acf.registerFieldSetting( ColorPickerReturnFormat );
})(jQuery);
(function($, undefined){
/**
* ConditionalLogicFieldSetting
*
* description
*
* @date 3/2/18
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
var ConditionalLogicFieldSetting = acf.FieldSetting.extend({
type: '',
name: 'conditional_logic',
events: {
'change .conditions-toggle': 'onChangeToggle',
'click .add-conditional-group': 'onClickAddGroup',
'focus .condition-rule-field': 'onFocusField',
'change .condition-rule-field': 'onChangeField',
'change .condition-rule-operator': 'onChangeOperator',
'click .add-conditional-rule': 'onClickAdd',
'click .remove-conditional-rule': 'onClickRemove'
},
$rule: false,
scope: function( $rule ){
this.$rule = $rule;
return this;
},
ruleData: function( name, value ){
return this.$rule.data.apply( this.$rule, arguments );
},
$input: function( name ){
return this.$rule.find('.condition-rule-' + name);
},
$td: function( name ){
return this.$rule.find('td.' + name);
},
$toggle: function(){
return this.$('.conditions-toggle');
},
$control: function(){
return this.$('.rule-groups');
},
$groups: function(){
return this.$('.rule-group');
},
$rules: function(){
return this.$('.rule');
},
open: function(){
var $div = this.$control();
$div.show();
acf.enable( $div );
},
close: function(){
var $div = this.$control();
$div.hide();
acf.disable( $div );
},
render: function(){
// show
if( this.$toggle().prop('checked') ) {
this.renderRules();
this.open();
// hide
} else {
this.close();
}
},
renderRules: function(){
// vars
var self = this;
// loop
this.$rules().each(function(){
self.renderRule( $(this) );
});
},
renderRule: function( $rule ){
this.scope( $rule );
this.renderField();
this.renderOperator();
this.renderValue();
},
renderField: function(){
// vars
var choices = [];
var validFieldTypes = [];
var cid = this.fieldObject.cid;
var $select = this.$input('field');
// loop
acf.getFieldObjects().map(function( fieldObject ){
// vars
var choice = {
id: fieldObject.getKey(),
text: fieldObject.getLabel()
};
// bail early if is self
if( fieldObject.cid === cid ) {
choice.text += acf.__('(this field)');
choice.disabled = true;
}
// get selected field conditions
var conditionTypes = acf.getConditionTypes({
fieldType: fieldObject.getType()
});
// bail early if no types
if( !conditionTypes.length ) {
choice.disabled = true;
}
// calulate indents
var indents = fieldObject.getParents().length;
choice.text = '- '.repeat(indents) + choice.text;
// append
choices.push(choice);
});
// allow for scenario where only one field exists
if( !choices.length ) {
choices.push({
id: '',
text: acf.__('No toggle fields available'),
});
}
// render
acf.renderSelect( $select, choices );
// set
this.ruleData('field', $select.val());
},
renderOperator: function(){
// bail early if no field selected
if( !this.ruleData('field') ) {
return;
}
// vars
var $select = this.$input('operator');
var val = $select.val();
var choices = [];
// set saved value on first render
// - this allows the 2nd render to correctly select an option
if( $select.val() === null ) {
acf.renderSelect($select, [{
id: this.ruleData('operator'),
text: ''
}]);
}
// get selected field
var $field = acf.findFieldObject( this.ruleData('field') );
var field = acf.getFieldObject( $field );
// get selected field conditions
var conditionTypes = acf.getConditionTypes({
fieldType: field.getType()
});
// html
conditionTypes.map(function( model ){
choices.push({
id: model.prototype.operator,
text: model.prototype.label
});
});
// render
acf.renderSelect( $select, choices );
// set
this.ruleData('operator', $select.val());
},
renderValue: function(){
// bail early if no field selected
if( !this.ruleData('field') || !this.ruleData('operator') ) {
return;
}
// vars
var $select = this.$input('value');
var $td = this.$td('value');
var val = $select.val();
// get selected field
var $field = acf.findFieldObject( this.ruleData('field') );
var field = acf.getFieldObject( $field );
// get selected field conditions
var conditionTypes = acf.getConditionTypes({
fieldType: field.getType(),
operator: this.ruleData('operator')
});
// html
var conditionType = conditionTypes[0].prototype;
var choices = conditionType.choices( field );
// create html: array
if( choices instanceof Array ) {
var $newSelect = $('');
acf.renderSelect( $newSelect, choices );
// create html: string ()
} else {
var $newSelect = $(choices);
}
// append
$select.detach();
$td.html( $newSelect );
// copy attrs
// timeout needed to avoid browser bug where "disabled" attribute is not applied
setTimeout(function(){
['class', 'name', 'id'].map(function( attr ){
$newSelect.attr( attr, $select.attr(attr));
});
}, 0);
// select existing value (if not a disabled input)
if( !$newSelect.prop('disabled') ) {
acf.val( $newSelect, val, true );
}
// set
this.ruleData('value', $newSelect.val());
},
onChangeToggle: function(){
this.render();
},
onClickAddGroup: function( e, $el ){
this.addGroup();
},
addGroup: function(){
// vars
var $group = this.$('.rule-group:last');
// duplicate
var $group2 = acf.duplicate( $group );
// update h4
$group2.find('h4').text( acf.__('or') );
// remove all tr's except the first one
$group2.find('tr').not(':first').remove();
// save field
this.fieldObject.save();
},
onFocusField: function( e, $el ){
this.renderField();
},
onChangeField: function( e, $el ){
// scope
this.scope( $el.closest('.rule') );
// set data
this.ruleData('field', $el.val());
// render
this.renderOperator();
this.renderValue();
},
onChangeOperator: function( e, $el ){
// scope
this.scope( $el.closest('.rule') );
// set data
this.ruleData('operator', $el.val());
// render
this.renderValue();
},
onClickAdd: function( e, $el ){
// duplciate
var $rule = acf.duplicate( $el.closest('.rule') );
// render
this.renderRule( $rule );
},
onClickRemove: function( e, $el ){
// vars
var $rule = $el.closest('.rule');
// save field
this.fieldObject.save();
// remove group
if( $rule.siblings('.rule').length == 0 ) {
$rule.closest('.rule-group').remove();
}
// remove
$rule.remove();
}
});
acf.registerFieldSetting( ConditionalLogicFieldSetting );
/**
* conditionalLogicHelper
*
* description
*
* @date 20/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
var conditionalLogicHelper = new acf.Model({
actions: {
'duplicate_field_objects': 'onDuplicateFieldObjects',
},
onDuplicateFieldObjects: function( children, newField, prevField ){
// vars
var data = {};
var $selects = $();
// reference change in key
children.map(function( child ){
// store reference of changed key
data[ child.get('prevKey') ] = child.get('key');
// append condition select
$selects = $selects.add( child.$('.condition-rule-field') );
});
// loop
$selects.each(function(){
// vars
var $select = $(this);
var val = $select.val();
// bail early if val is not a ref key
if( !val || !data[val] ) {
return;
}
// modify selected option
$select.find('option:selected').attr('value', data[val]);
// set new val
$select.val( data[val] );
});
},
});
})(jQuery);
(function($, undefined){
/**
* acf.findFieldObject
*
* Returns a single fieldObject $el for a given field key
*
* @date 1/2/18
* @since 5.7.0
*
* @param string key The field key
* @return jQuery
*/
acf.findFieldObject = function( key ){
return acf.findFieldObjects({
key: key,
limit: 1
});
};
/**
* acf.findFieldObjects
*
* Returns an array of fieldObject $el for the given args
*
* @date 1/2/18
* @since 5.7.0
*
* @param object args
* @return jQuery
*/
acf.findFieldObjects = function( args ){
// vars
args = args || {};
var selector = '.acf-field-object';
var $fields = false;
// args
args = acf.parseArgs(args, {
id: '',
key: '',
type: '',
limit: false,
list: null,
parent: false,
sibling: false,
child: false,
});
// id
if( args.id ) {
selector += '[data-id="' + args.id + '"]';
}
// key
if( args.key ) {
selector += '[data-key="' + args.key + '"]';
}
// type
if( args.type ) {
selector += '[data-type="' + args.type + '"]';
}
// query
if( args.list ) {
$fields = args.list.children( selector );
} else if( args.parent ) {
$fields = args.parent.find( selector );
} else if( args.sibling ) {
$fields = args.sibling.siblings( selector );
} else if( args.child ) {
$fields = args.child.parents( selector );
} else {
$fields = $( selector );
}
// limit
if( args.limit ) {
$fields = $fields.slice( 0, args.limit );
}
// return
return $fields;
};
/**
* acf.getFieldObject
*
* Returns a single fieldObject instance for a given $el|key
*
* @date 1/2/18
* @since 5.7.0
*
* @param string|jQuery $field The field $el or key
* @return jQuery
*/
acf.getFieldObject = function( $field ){
// allow key
if( typeof $field === 'string' ) {
$field = acf.findFieldObject( $field );
}
// instantiate
var field = $field.data('acf');
if( !field ) {
field = acf.newFieldObject( $field );
}
// return
return field;
};
/**
* acf.getFieldObjects
*
* Returns an array of fieldObject instances for the given args
*
* @date 1/2/18
* @since 5.7.0
*
* @param object args
* @return array
*/
acf.getFieldObjects = function( args ){
// query
var $fields = acf.findFieldObjects( args );
// loop
var fields = [];
$fields.each(function(){
var field = acf.getFieldObject( $(this) );
fields.push( field );
});
// return
return fields;
};
/**
* acf.newFieldObject
*
* Initializes and returns a new FieldObject instance
*
* @date 1/2/18
* @since 5.7.0
*
* @param jQuery $field The field $el
* @return object
*/
acf.newFieldObject = function( $field ){
// instantiate
var field = new acf.FieldObject( $field );
// action
acf.doAction('new_field_object', field);
// return
return field;
};
/**
* actionManager
*
* description
*
* @date 15/12/17
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
var eventManager = new acf.Model({
priority: 5,
initialize: function(){
// actions
var actions = [
'prepare',
'ready',
'append',
'remove'
];
// loop
actions.map(function( action ){
this.addFieldActions( action );
}, this);
},
addFieldActions: function( action ){
// vars
var pluralAction = action + '_field_objects'; // ready_field_objects
var singleAction = action + '_field_object'; // ready_field_object
var singleEvent = action + 'FieldObject'; // readyFieldObject
// global action
var callback = function( $el /*, arg1, arg2, etc*/ ){
// vars
var fieldObjects = acf.getFieldObjects({ parent: $el });
// call plural
if( fieldObjects.length ) {
/// get args [$el, arg1]
var args = acf.arrayArgs( arguments );
// modify args [pluralAction, fields, arg1]
args.splice(0, 1, pluralAction, fieldObjects);
acf.doAction.apply(null, args);
}
};
// plural action
var pluralCallback = function( fieldObjects /*, arg1, arg2, etc*/ ){
/// get args [fields, arg1]
var args = acf.arrayArgs( arguments );
// modify args [singleAction, fields, arg1]
args.unshift(singleAction);
// loop
fieldObjects.map(function( fieldObject ){
// modify args [singleAction, field, arg1]
args[1] = fieldObject;
acf.doAction.apply(null, args);
});
};
// single action
var singleCallback = function( fieldObject /*, arg1, arg2, etc*/ ){
/// get args [$field, arg1]
var args = acf.arrayArgs( arguments );
// modify args [singleAction, $field, arg1]
args.unshift(singleAction);
// action variations (ready_field/type=image)
var variations = ['type', 'name', 'key'];
variations.map(function( variation ){
args[0] = singleAction + '/' + variation + '=' + fieldObject.get(variation);
acf.doAction.apply(null, args);
});
// modify args [arg1]
args.splice(0, 2);
// event
fieldObject.trigger(singleEvent, args);
};
// add actions
acf.addAction(action, callback, 5);
acf.addAction(pluralAction, pluralCallback, 5);
acf.addAction(singleAction, singleCallback, 5);
}
});
/**
* fieldManager
*
* description
*
* @date 4/1/18
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
var fieldManager = new acf.Model({
id: 'fieldManager',
events: {
'submit #post': 'onSubmit',
'mouseenter .acf-field-list': 'onHoverSortable',
'click .add-field': 'onClickAdd',
},
actions: {
'removed_field_object': 'onRemovedField',
'sortstop_field_object': 'onReorderField',
'delete_field_object': 'onDeleteField',
'change_field_object_type': 'onChangeFieldType',
'duplicate_field_object': 'onDuplicateField'
},
onSubmit: function( e, $el ){
// vars
var fields = acf.getFieldObjects();
// loop
fields.map(function( field ){
field.submit();
});
},
setFieldMenuOrder: function( field ){
this.renderFields( field.$el.parent() );
},
onHoverSortable: function( e, $el ){
// bail early if already sortable
if( $el.hasClass('ui-sortable') ) return;
// sortable
$el.sortable({
handle: '.acf-sortable-handle',
connectWith: '.acf-field-list',
start: function( e, ui ){
var field = acf.getFieldObject( ui.item );
ui.placeholder.height( ui.item.height() );
acf.doAction('sortstart_field_object', field, $el);
},
update: function( e, ui ){
var field = acf.getFieldObject( ui.item );
acf.doAction('sortstop_field_object', field, $el);
}
});
},
onRemovedField: function( field, $list ){
this.renderFields( $list );
},
onReorderField: function( field, $list ){
field.updateParent();
this.renderFields( $list );
},
onDeleteField: function( field ){
// delete children
field.getFields().map(function( child ){
child.delete({ animate: false });
});
},
onChangeFieldType: function( field ){
// this caused sub fields to disapear if changing type back...
//this.onDeleteField( field );
},
onDuplicateField: function( field, newField ){
// check for children
var children = newField.getFields();
if( children.length ) {
// loop
children.map(function( child ){
// wipe field
child.wipe();
// update parent
child.updateParent();
});
// action
acf.doAction('duplicate_field_objects', children, newField, field);
}
// set menu order
this.setFieldMenuOrder( newField );
},
renderFields: function( $list ){
// vars
var fields = acf.getFieldObjects({
list: $list
});
// no fields
if( !fields.length ) {
$list.addClass('-empty');
return;
}
// has fields
$list.removeClass('-empty');
// prop
fields.map(function( field, i ){
field.prop('menu_order', i);
});
},
onClickAdd: function( e, $el ){
var $list = $el.closest('.acf-tfoot').siblings('.acf-field-list');
this.addField( $list );
},
addField: function( $list ){
// vars
var html = $('#tmpl-acf-field').html();
var $el = $(html);
var prevId = $el.data('id');
var newKey = acf.uniqid('field_');
// duplicate
var $newField = acf.duplicate({
target: $el,
search: prevId,
replace: newKey,
append: function( $el, $el2 ){
$list.append( $el2 );
}
});
// get instance
var newField = acf.getFieldObject( $newField );
// props
newField.prop('key', newKey);
newField.prop('ID', 0);
newField.prop('label', '');
newField.prop('name', '');
// attr
$newField.attr('data-key', newKey);
$newField.attr('data-id', newKey);
// update parent prop
newField.updateParent();
// focus label
var $label = newField.$input('label');
setTimeout(function(){
$label.trigger('focus');
}, 251);
// open
newField.open();
// set menu order
this.renderFields( $list );
// action
acf.doAction('add_field_object', newField);
acf.doAction('append_field_object', newField);
}
});
})(jQuery);
(function($, undefined){
/**
* locationManager
*
* Field group location rules functionality
*
* @date 15/12/17
* @since 5.7.0
*
* @param void
* @return void
*/
var locationManager = new acf.Model({
id: 'locationManager',
wait: 'ready',
events: {
'click .add-location-rule': 'onClickAddRule',
'click .add-location-group': 'onClickAddGroup',
'click .remove-location-rule': 'onClickRemoveRule',
'change .refresh-location-rule': 'onChangeRemoveRule'
},
initialize: function(){
this.$el = $('#acf-field-group-locations');
this.updateGroupsClass();
},
onClickAddRule: function( e, $el ){
this.addRule( $el.closest('tr') );
},
onClickRemoveRule: function( e, $el ){
this.removeRule( $el.closest('tr') );
},
onChangeRemoveRule: function( e, $el ){
this.changeRule( $el.closest('tr') );
},
onClickAddGroup: function( e, $el ){
this.addGroup();
},
addRule: function( $tr ){
acf.duplicate( $tr );
this.updateGroupsClass();
},
removeRule: function( $tr ){
if( $tr.siblings('tr').length == 0 ) {
$tr.closest('.rule-group').remove();
} else {
$tr.remove();
}
// Update h4
var $group = this.$('.rule-group:first');
$group.find('h4').text( acf.__('Show this field group if') );
this.updateGroupsClass();
},
changeRule: function( $rule ){
// vars
var $group = $rule.closest('.rule-group');
var prefix = $rule.find('td.param select').attr('name').replace('[param]', '');
// ajaxdata
var ajaxdata = {};
ajaxdata.action = 'acf/field_group/render_location_rule';
ajaxdata.rule = acf.serialize( $rule, prefix );
ajaxdata.rule.id = $rule.data('id');
ajaxdata.rule.group = $group.data('id');
// temp disable
acf.disable( $rule.find('td.value') );
// ajax
$.ajax({
url: acf.get('ajaxurl'),
data: acf.prepareForAjax(ajaxdata),
type: 'post',
dataType: 'html',
success: function( html ){
if( !html ) return;
$rule.replaceWith( html );
}
});
},
addGroup: function(){
// vars
var $group = this.$('.rule-group:last');
// duplicate
$group2 = acf.duplicate( $group );
// update h4
$group2.find('h4').text( acf.__('or') );
// remove all tr's except the first one
$group2.find('tr').not(':first').remove();
// update the groups class
this.updateGroupsClass();
},
updateGroupsClass: function () {
var $group = this.$(".rule-group:last");
var $ruleGroups = $group.closest(".rule-groups");
var rows_count = $ruleGroups.find(".acf-table tr").length;
if (rows_count > 1) {
$ruleGroups.addClass("rule-groups-multiple");
} else {
$ruleGroups.removeClass("rule-groups-multiple");
}
},
});
})(jQuery);
(function($, undefined){
var _acf = acf.getCompatibility( acf );
/**
* fieldGroupCompatibility
*
* Compatibility layer for extinct acf.field_group
*
* @date 15/12/17
* @since 5.7.0
*
* @param void
* @return void
*/
_acf.field_group = {
save_field: function( $field, type ){
type = (type !== undefined) ? type : 'settings';
acf.getFieldObject( $field ).save( type );
},
delete_field: function( $field, animate ){
animate = (animate !== undefined) ? animate : true;
acf.getFieldObject( $field ).delete({
animate: animate
});
},
update_field_meta: function( $field, name, value ){
acf.getFieldObject( $field ).prop( name, value );
},
delete_field_meta: function( $field, name ){
acf.getFieldObject( $field ).prop( name, null );
}
};
/**
* fieldGroupCompatibility.field_object
*
* Compatibility layer for extinct acf.field_group.field_object
*
* @date 15/12/17
* @since 5.7.0
*
* @param void
* @return void
*/
_acf.field_group.field_object = acf.model.extend({
// vars
type: '',
o: {},
$field: null,
$settings: null,
tag: function( tag ) {
// vars
var type = this.type;
// explode, add 'field' and implode
// - open => open_field
// - change_type => change_field_type
var tags = tag.split('_');
tags.splice(1, 0, 'field');
tag = tags.join('_');
// add type
if( type ) {
tag += '/type=' + type;
}
// return
return tag;
},
selector: function(){
// vars
var selector = '.acf-field-object';
var type = this.type;
// add type
if( type ) {
selector += '-' + type;
selector = acf.str_replace('_', '-', selector);
}
// return
return selector;
},
_add_action: function( name, callback ) {
// vars
var model = this;
// add action
acf.add_action( this.tag(name), function( $field ){
// focus
model.set('$field', $field);
// callback
model[ callback ].apply(model, arguments);
});
},
_add_filter: function( name, callback ) {
// vars
var model = this;
// add action
acf.add_filter( this.tag(name), function( $field ){
// focus
model.set('$field', $field);
// callback
model[ callback ].apply(model, arguments);
});
},
_add_event: function( name, callback ) {
// vars
var model = this;
var event = name.substr(0,name.indexOf(' '));
var selector = name.substr(name.indexOf(' ')+1);
var context = this.selector();
// add event
$(document).on(event, context + ' ' + selector, function( e ){
// append $el to event object
e.$el = $(this);
e.$field = e.$el.closest('.acf-field-object');
// focus
model.set('$field', e.$field);
// callback
model[ callback ].apply(model, [e]);
});
},
_set_$field: function(){
// vars
this.o = this.$field.data();
// els
this.$settings = this.$field.find('> .settings > table > tbody');
// focus
this.focus();
},
focus: function(){
// do nothing
},
setting: function( name ) {
return this.$settings.find('> .acf-field-setting-' + name);
}
});
/*
* field
*
* This model fires actions and filters for registered fields
*
* @type function
* @date 21/02/2014
* @since 3.5.1
*
* @param n/a
* @return n/a
*/
var actionManager = new acf.Model({
actions: {
'open_field_object': 'onOpenFieldObject',
'close_field_object': 'onCloseFieldObject',
'add_field_object': 'onAddFieldObject',
'duplicate_field_object': 'onDuplicateFieldObject',
'delete_field_object': 'onDeleteFieldObject',
'change_field_object_type': 'onChangeFieldObjectType',
'change_field_object_label': 'onChangeFieldObjectLabel',
'change_field_object_name': 'onChangeFieldObjectName',
'change_field_object_parent': 'onChangeFieldObjectParent',
'sortstop_field_object': 'onChangeFieldObjectParent'
},
onOpenFieldObject: function( field ){
acf.doAction('open_field', field.$el);
acf.doAction('open_field/type=' + field.get('type'), field.$el);
acf.doAction('render_field_settings', field.$el);
acf.doAction('render_field_settings/type=' + field.get('type'), field.$el);
},
onCloseFieldObject: function( field ){
acf.doAction('close_field', field.$el);
acf.doAction('close_field/type=' + field.get('type'), field.$el);
},
onAddFieldObject: function( field ){
acf.doAction('add_field', field.$el);
acf.doAction('add_field/type=' + field.get('type'), field.$el);
},
onDuplicateFieldObject: function( field ){
acf.doAction('duplicate_field', field.$el);
acf.doAction('duplicate_field/type=' + field.get('type'), field.$el);
},
onDeleteFieldObject: function( field ){
acf.doAction('delete_field', field.$el);
acf.doAction('delete_field/type=' + field.get('type'), field.$el);
},
onChangeFieldObjectType: function( field ){
acf.doAction('change_field_type', field.$el);
acf.doAction('change_field_type/type=' + field.get('type'), field.$el);
acf.doAction('render_field_settings', field.$el);
acf.doAction('render_field_settings/type=' + field.get('type'), field.$el);
},
onChangeFieldObjectLabel: function( field ){
acf.doAction('change_field_label', field.$el);
acf.doAction('change_field_label/type=' + field.get('type'), field.$el);
},
onChangeFieldObjectName: function( field ){
acf.doAction('change_field_name', field.$el);
acf.doAction('change_field_name/type=' + field.get('type'), field.$el);
},
onChangeFieldObjectParent: function( field ){
acf.doAction('update_field_parent', field.$el);
}
});
})(jQuery);