(function($, undefined){ /** * acf * * description * * @date 14/12/17 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ // The global acf object var acf = {}; // Set as a browser global window.acf = acf; /** @var object Data sent from PHP */ acf.data = {}; /** * get * * Gets a specific data value * * @date 14/12/17 * @since 5.6.5 * * @param string name * @return mixed */ acf.get = function( name ){ return this.data[name] || null; }; /** * has * * Returns `true` if the data exists and is not null * * @date 14/12/17 * @since 5.6.5 * * @param string name * @return boolean */ acf.has = function( name ){ return this.get(name) !== null; }; /** * set * * Sets a specific data value * * @date 14/12/17 * @since 5.6.5 * * @param string name * @param mixed value * @return this */ acf.set = function( name, value ){ this.data[ name ] = value; return this; }; /** * uniqueId * * Returns a unique ID * * @date 9/11/17 * @since 5.6.3 * * @param string prefix Optional prefix. * @return string */ var idCounter = 0; acf.uniqueId = function(prefix){ var id = ++idCounter + ''; return prefix ? prefix + id : id; }; /** * acf.uniqueArray * * Returns a new array with only unique values * Credit: https://stackoverflow.com/questions/1960473/get-all-unique-values-in-an-array-remove-duplicates * * @date 23/3/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ acf.uniqueArray = function( array ){ function onlyUnique(value, index, self) { return self.indexOf(value) === index; } return array.filter( onlyUnique ); }; /** * uniqid * * Returns a unique ID (PHP version) * * @date 9/11/17 * @since 5.6.3 * @source http://locutus.io/php/misc/uniqid/ * * @param string prefix Optional prefix. * @return string */ var uniqidSeed = ''; acf.uniqid = function(prefix, moreEntropy){ // discuss at: http://locutus.io/php/uniqid/ // original by: Kevin van Zonneveld (http://kvz.io) // revised by: Kankrelune (http://www.webfaktory.info/) // note 1: Uses an internal counter (in locutus global) to avoid collision // example 1: var $id = uniqid() // example 1: var $result = $id.length === 13 // returns 1: true // example 2: var $id = uniqid('foo') // example 2: var $result = $id.length === (13 + 'foo'.length) // returns 2: true // example 3: var $id = uniqid('bar', true) // example 3: var $result = $id.length === (23 + 'bar'.length) // returns 3: true if (typeof prefix === 'undefined') { prefix = ''; } var retId; var formatSeed = function(seed, reqWidth) { seed = parseInt(seed, 10).toString(16); // to hex str if (reqWidth < seed.length) { // so long we split return seed.slice(seed.length - reqWidth); } if (reqWidth > seed.length) { // so short we pad return Array(1 + (reqWidth - seed.length)).join('0') + seed; } return seed; }; if (!uniqidSeed) { // init seed with big random int uniqidSeed = Math.floor(Math.random() * 0x75bcd15); } uniqidSeed++; retId = prefix; // start with prefix, add current milliseconds hex string retId += formatSeed(parseInt(new Date().getTime() / 1000, 10), 8); retId += formatSeed(uniqidSeed, 5); // add seed hex string if (moreEntropy) { // for more entropy we add a float lower to 10 retId += (Math.random() * 10).toFixed(8).toString(); } return retId; }; /** * strReplace * * Performs a string replace * * @date 14/12/17 * @since 5.6.5 * * @param string search * @param string replace * @param string subject * @return string */ acf.strReplace = function( search, replace, subject ){ return subject.split(search).join(replace); }; /** * strCamelCase * * Converts a string into camelCase * Thanks to https://stackoverflow.com/questions/2970525/converting-any-string-into-camel-case * * @date 14/12/17 * @since 5.6.5 * * @param string str * @return string */ acf.strCamelCase = function( str ){ // replace [_-] characters with space str = str.replace(/[_-]/g, ' '); // camelCase str = str.replace(/(?:^\w|\b\w|\s+)/g, function(match, index) { if (+match === 0) return ""; // or if (/\s+/.test(match)) for white spaces return index == 0 ? match.toLowerCase() : match.toUpperCase(); }); // return return str; }; /** * strPascalCase * * Converts a string into PascalCase * Thanks to https://stackoverflow.com/questions/1026069/how-do-i-make-the-first-letter-of-a-string-uppercase-in-javascript * * @date 14/12/17 * @since 5.6.5 * * @param string str * @return string */ acf.strPascalCase = function( str ){ var camel = acf.strCamelCase( str ); return camel.charAt(0).toUpperCase() + camel.slice(1); }; /** * acf.strSlugify * * Converts a string into a HTML class friendly slug * * @date 21/3/18 * @since 5.6.9 * * @param string str * @return string */ acf.strSlugify = function( str ){ return acf.strReplace( '_', '-', str.toLowerCase() ); }; acf.strSanitize = function( str ){ // chars (https://jsperf.com/replace-foreign-characters) var map = { "À": "A", "Á": "A", "Â": "A", "Ã": "A", "Ä": "A", "Å": "A", "Æ": "AE", "Ç": "C", "È": "E", "É": "E", "Ê": "E", "Ë": "E", "Ì": "I", "Í": "I", "Î": "I", "Ï": "I", "Ð": "D", "Ñ": "N", "Ò": "O", "Ó": "O", "Ô": "O", "Õ": "O", "Ö": "O", "Ø": "O", "Ù": "U", "Ú": "U", "Û": "U", "Ü": "U", "Ý": "Y", "ß": "s", "à": "a", "á": "a", "â": "a", "ã": "a", "ä": "a", "å": "a", "æ": "ae", "ç": "c", "è": "e", "é": "e", "ê": "e", "ë": "e", "ì": "i", "í": "i", "î": "i", "ï": "i", "ñ": "n", "ò": "o", "ó": "o", "ô": "o", "õ": "o", "ö": "o", "ø": "o", "ù": "u", "ú": "u", "û": "u", "ü": "u", "ý": "y", "ÿ": "y", "Ā": "A", "ā": "a", "Ă": "A", "ă": "a", "Ą": "A", "ą": "a", "Ć": "C", "ć": "c", "Ĉ": "C", "ĉ": "c", "Ċ": "C", "ċ": "c", "Č": "C", "č": "c", "Ď": "D", "ď": "d", "Đ": "D", "đ": "d", "Ē": "E", "ē": "e", "Ĕ": "E", "ĕ": "e", "Ė": "E", "ė": "e", "Ę": "E", "ę": "e", "Ě": "E", "ě": "e", "Ĝ": "G", "ĝ": "g", "Ğ": "G", "ğ": "g", "Ġ": "G", "ġ": "g", "Ģ": "G", "ģ": "g", "Ĥ": "H", "ĥ": "h", "Ħ": "H", "ħ": "h", "Ĩ": "I", "ĩ": "i", "Ī": "I", "ī": "i", "Ĭ": "I", "ĭ": "i", "Į": "I", "į": "i", "İ": "I", "ı": "i", "IJ": "IJ", "ij": "ij", "Ĵ": "J", "ĵ": "j", "Ķ": "K", "ķ": "k", "Ĺ": "L", "ĺ": "l", "Ļ": "L", "ļ": "l", "Ľ": "L", "ľ": "l", "Ŀ": "L", "ŀ": "l", "Ł": "l", "ł": "l", "Ń": "N", "ń": "n", "Ņ": "N", "ņ": "n", "Ň": "N", "ň": "n", "ʼn": "n", "Ō": "O", "ō": "o", "Ŏ": "O", "ŏ": "o", "Ő": "O", "ő": "o", "Œ": "OE", "œ": "oe", "Ŕ": "R", "ŕ": "r", "Ŗ": "R", "ŗ": "r", "Ř": "R", "ř": "r", "Ś": "S", "ś": "s", "Ŝ": "S", "ŝ": "s", "Ş": "S", "ş": "s", "Š": "S", "š": "s", "Ţ": "T", "ţ": "t", "Ť": "T", "ť": "t", "Ŧ": "T", "ŧ": "t", "Ũ": "U", "ũ": "u", "Ū": "U", "ū": "u", "Ŭ": "U", "ŭ": "u", "Ů": "U", "ů": "u", "Ű": "U", "ű": "u", "Ų": "U", "ų": "u", "Ŵ": "W", "ŵ": "w", "Ŷ": "Y", "ŷ": "y", "Ÿ": "Y", "Ź": "Z", "ź": "z", "Ż": "Z", "ż": "z", "Ž": "Z", "ž": "z", "ſ": "s", "ƒ": "f", "Ơ": "O", "ơ": "o", "Ư": "U", "ư": "u", "Ǎ": "A", "ǎ": "a", "Ǐ": "I", "ǐ": "i", "Ǒ": "O", "ǒ": "o", "Ǔ": "U", "ǔ": "u", "Ǖ": "U", "ǖ": "u", "Ǘ": "U", "ǘ": "u", "Ǚ": "U", "ǚ": "u", "Ǜ": "U", "ǜ": "u", "Ǻ": "A", "ǻ": "a", "Ǽ": "AE", "ǽ": "ae", "Ǿ": "O", "ǿ": "o", // extra ' ': '_', "'": '', '?': '', '/': '', '\\': '', '.': '', ',': '', '`': '', '>': '', '<': '', '"': '', '[': '', ']': '', '|': '', '{': '', '}': '', '(': '', ')': '' }; // vars var nonWord = /\W/g; var mapping = function (c) { return (map[c] !== undefined) ? map[c] : c; }; // replace str = str.replace(nonWord, mapping); // lowercase str = str.toLowerCase(); // return return str; }; /** * acf.strMatch * * Returns the number of characters that match between two strings * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.strMatch = function( s1, s2 ){ // vars var val = 0; var min = Math.min( s1.length, s2.length ); // loop for( var i = 0; i < min; i++ ) { if( s1[i] !== s2[i] ) { break; } val++; } // return return val; }; /** * acf.decode * * description * * @date 13/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.decode = function( string ){ return $(''); $('body').append( $textarea ); // vars var val = this.getNodeValue(); // open popup wpLink.open( 'acf-link-textarea', val.url, val.title, null ); }, onOpen: function(){ // always show title (WP will hide title if empty) $('#wp-link-wrap').addClass('has-text-field'); // set inputs var val = this.getNodeValue(); this.setInputValue( val ); }, close: function(){ wpLink.close(); }, onClose: function(){ // bail early if no node // needed due to WP triggering this event twice if( !this.has('node') ) { return false; } // remove events this.off('wplink-open'); this.off('wplink-close'); // set value var val = this.getInputValue(); this.setNodeValue( val ); // remove textarea $('#acf-link-textarea').remove(); // reset this.set('node', null); } }); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'oembed', events: { 'click [data-name="clear-button"]': 'onClickClear', 'keypress .input-search': 'onKeypressSearch', 'keyup .input-search': 'onKeyupSearch', 'change .input-search': 'onChangeSearch' }, $control: function(){ return this.$('.acf-oembed'); }, $input: function(){ return this.$('.input-value'); }, $search: function(){ return this.$('.input-search'); }, getValue: function(){ return this.$input().val(); }, getSearchVal: function(){ return this.$search().val(); }, setValue: function( val ){ // class if( val ) { this.$control().addClass('has-value'); } else { this.$control().removeClass('has-value'); } acf.val( this.$input(), val ); }, showLoading: function( show ){ acf.showLoading( this.$('.canvas') ); }, hideLoading: function(){ acf.hideLoading( this.$('.canvas') ); }, maybeSearch: function(){ // vars var prevUrl = this.val(); var url = this.getSearchVal(); // no value if( !url ) { return this.clear(); } // fix missing 'http://' - causes the oembed code to error and fail if( url.substr(0, 4) != 'http' ) { url = 'http://' + url; } // bail early if no change if( url === prevUrl ) return; // clear existing timeout var timeout = this.get('timeout'); if( timeout ) { clearTimeout( timeout ); } // set new timeout var callback = $.proxy(this.search, this, url); this.set('timeout', setTimeout(callback, 300)); }, search: function( url ){ // ajax var ajaxData = { action: 'acf/fields/oembed/search', s: url, field_key: this.get('key') }; // clear existing timeout var xhr = this.get('xhr'); if( xhr ) { xhr.abort(); } // loading this.showLoading(); // query var xhr = $.ajax({ url: acf.get('ajaxurl'), data: acf.prepareForAjax(ajaxData), type: 'post', dataType: 'json', context: this, success: function( json ){ // error if( !json || !json.html ) { json = { url: false, html: '' } } // update vars this.val( json.url ); this.$('.canvas-media').html( json.html ); }, complete: function(){ this.hideLoading(); } }); this.set('xhr', xhr); }, clear: function(){ this.val(''); this.$search().val(''); this.$('.canvas-media').html(''); }, onClickClear: function( e, $el ){ this.clear(); }, onKeypressSearch: function( e, $el ){ if( e.which == 13 ) { e.preventDefault(); this.maybeSearch(); } }, onKeyupSearch: function( e, $el ){ if( $el.val() ) { this.maybeSearch(); } }, onChangeSearch: function( e, $el ){ this.maybeSearch(); } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'radio', events: { 'click input[type="radio"]': 'onClick', }, $control: function(){ return this.$('.acf-radio-list'); }, $input: function(){ return this.$('input:checked'); }, $inputText: function(){ return this.$('input[type="text"]'); }, getValue: function(){ var val = this.$input().val(); if( val === 'other' && this.get('other_choice') ) { val = this.$inputText().val(); } return val; }, onClick: function( e, $el ){ // vars var $label = $el.parent('label'); var selected = $label.hasClass('selected'); var val = $el.val(); // remove previous selected this.$('.selected').removeClass('selected'); // add active class $label.addClass('selected'); // allow null if( this.get('allow_null') && selected ) { $label.removeClass('selected'); $el.prop('checked', false).trigger('change'); val = false; } // other if( this.get('other_choice') ) { // enable if( val === 'other' ) { this.$inputText().prop('disabled', false); // disable } else { this.$inputText().prop('disabled', true); } } } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'range', events: { 'input input[type="range"]': 'onChange', 'change input': 'onChange' }, $input: function(){ return this.$('input[type="range"]'); }, $inputAlt: function(){ return this.$('input[type="number"]'); }, setValue: function( val ){ this.busy = true; // update range input (with change) acf.val( this.$input(), val ); // update alt input (without change) acf.val( this.$inputAlt(), val, true ); this.busy = false; }, onChange: function( e, $el ){ if( !this.busy ) { this.setValue( $el.val() ); } } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'relationship', events: { 'keypress [data-filter]': 'onKeypressFilter', 'change [data-filter]': 'onChangeFilter', 'keyup [data-filter]': 'onChangeFilter', 'click .choices-list .acf-rel-item': 'onClickAdd', 'click [data-name="remove_item"]': 'onClickRemove', 'mouseover': 'onHover' }, $control: function(){ return this.$('.acf-relationship'); }, $list: function( list ) { return this.$('.' + list + '-list'); }, $listItems: function( list ) { return this.$list( list ).find('.acf-rel-item'); }, $listItem: function( list, id ) { return this.$list( list ).find('.acf-rel-item[data-id="' + id + '"]'); }, getValue: function(){ var val = []; this.$listItems('values').each(function(){ val.push( $(this).data('id') ); }); return val.length ? val : false; }, newChoice: function( props ){ return [ '
  • ', '' + props.text + '', '
  • ' ].join(''); }, newValue: function( props ){ return [ '
  • ', '', '' + props.text, '', '', '
  • ' ].join(''); }, addSortable: function( self ){ // sortable this.$list('values').sortable({ items: 'li', forceHelperSize: true, forcePlaceholderSize: true, scroll: true, update: function(){ self.$input().trigger('change'); } }); }, initialize: function(){ // scroll var onScroll = this.proxy(function(e){ // bail early if no more results if( this.get('loading') || !this.get('more') ) { return; } // Scrolled to bottom var $list = this.$list('choices'); var scrollTop = Math.ceil( $list.scrollTop() ); var scrollHeight = Math.ceil( $list[0].scrollHeight ); var innerHeight = Math.ceil( $list.innerHeight() ); var paged = this.get('paged') || 1; if( (scrollTop + innerHeight) >= scrollHeight ) { // update paged this.set('paged', (paged+1)); // fetch this.fetch(); } }); this.$list('choices').scrollTop(0).on('scroll', onScroll); // fetch this.fetch(); }, onHover: function( e ){ // only once $().off(e); // add sortable this.addSortable( this ); }, onKeypressFilter: function( e, $el ){ // don't submit form if( e.which == 13 ) { e.preventDefault(); } }, onChangeFilter: function( e, $el ){ // vars var val = $el.val(); var filter = $el.data('filter'); // Bail early if filter has not changed if( this.get(filter) === val ) { return; } // update attr this.set(filter, val); // reset paged this.set('paged', 1); // fetch if( $el.is('select') ) { this.fetch(); // search must go through timeout } else { this.maybeFetch(); } }, onClickAdd: function( e, $el ){ // vars var val = this.val(); var max = parseInt( this.get('max') ); // can be added? if( $el.hasClass('disabled') ) { return false; } // validate if( max > 0 && val && val.length >= max ) { // add notice this.showNotice({ text: acf.__('Maximum values reached ( {max} values )').replace('{max}', max), type: 'warning' }); return false; } // disable $el.addClass('disabled'); // add var html = this.newValue({ id: $el.data('id'), text: $el.html() }); this.$list('values').append( html ) // trigger change this.$input().trigger('change'); }, onClickRemove: function( e, $el ){ // vars var $span = $el.parent(); var $li = $span.parent(); var id = $span.data('id'); // remove value setTimeout(function(){ $li.remove(); }, 1); // show choice this.$listItem('choices', id).removeClass('disabled'); // trigger change this.$input().trigger('change'); }, maybeFetch: function(){ // vars var timeout = this.get('timeout'); // abort timeout if( timeout ) { clearTimeout( timeout ); } // fetch timeout = this.setTimeout(this.fetch, 300); this.set('timeout', timeout); }, getAjaxData: function(){ // load data based on element attributes var ajaxData = this.$control().data(); for( var name in ajaxData ) { ajaxData[ name ] = this.get( name ); } // extra ajaxData.action = 'acf/fields/relationship/query'; ajaxData.field_key = this.get('key'); // return return ajaxData; }, fetch: function(){ // abort XHR if this field is already loading AJAX data var xhr = this.get('xhr'); if( xhr ) { xhr.abort(); } // add to this.o var ajaxData = this.getAjaxData(); // clear html if is new query var $choiceslist = this.$list( 'choices' ); if( ajaxData.paged == 1 ) { $choiceslist.html(''); } // loading var $loading = $('
  • ' + acf.__('Loading') + '
  • '); $choiceslist.append($loading); this.set('loading', true); // callback var onComplete = function(){ this.set('loading', false); $loading.remove(); }; var onSuccess = function( json ){ // no results if( !json || !json.results || !json.results.length ) { // prevent pagination this.set('more', false); // add message if( this.get('paged') == 1 ) { this.$list('choices').append('
  • ' + acf.__('No matches found') + '
  • '); } // return return; } // set more (allows pagination scroll) this.set('more', json.more ); // get new results var html = this.walkChoices(json.results); var $html = $( html ); // apply .disabled to left li's var val = this.val(); if( val && val.length ) { val.map(function( id ){ $html.find('.acf-rel-item[data-id="' + id + '"]').addClass('disabled'); }); } // append $choiceslist.append( $html ); // merge together groups var $prevLabel = false; var $prevList = false; $choiceslist.find('.acf-rel-label').each(function(){ var $label = $(this); var $list = $label.siblings('ul'); if( $prevLabel && $prevLabel.text() == $label.text() ) { $prevList.append( $list.children() ); $(this).parent().remove(); return; } // update vars $prevLabel = $label; $prevList = $list; }); }; // get results var xhr = $.ajax({ url: acf.get('ajaxurl'), dataType: 'json', type: 'post', data: acf.prepareForAjax(ajaxData), context: this, success: onSuccess, complete: onComplete }); // set this.set('xhr', xhr); }, walkChoices: function( data ){ // walker var walk = function( data ){ // vars var html = ''; // is array if( $.isArray(data) ) { data.map(function(item){ html += walk( item ); }); // is item } else if( $.isPlainObject(data) ) { // group if( data.children !== undefined ) { html += '
  • ' + data.text + '
  • '; // single } else { html += '
  • ' + data.text + '
  • '; } } // return return html; }; return walk( data ); } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'select', select2: false, wait: 'load', events: { 'removeField': 'onRemove' }, $input: function(){ return this.$('select'); }, initialize: function(){ // vars var $select = this.$input(); // inherit data this.inherit( $select ); // select2 if( this.get('ui') ) { // populate ajax_data (allowing custom attribute to already exist) var ajaxAction = this.get('ajax_action'); if( !ajaxAction ) { ajaxAction = 'acf/fields/' + this.get('type') + '/query'; } // select2 this.select2 = acf.newSelect2($select, { field: this, ajax: this.get('ajax'), multiple: this.get('multiple'), placeholder: this.get('placeholder'), allowNull: this.get('allow_null'), ajaxAction: ajaxAction, }); } }, onRemove: function(){ if( this.select2 ) { this.select2.destroy(); } } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ // vars var CONTEXT = 'tab'; var Field = acf.Field.extend({ type: 'tab', wait: '', tabs: false, tab: false, findFields: function(){ return this.$el.nextUntil('.acf-field-tab', '.acf-field'); }, getFields: function(){ return acf.getFields( this.findFields() ); }, findTabs: function(){ return this.$el.prevAll('.acf-tab-wrap:first'); }, findTab: function(){ return this.$('.acf-tab-button'); }, initialize: function(){ // bail early if is td if( this.$el.is('td') ) { this.events = {}; return false; } // vars var $tabs = this.findTabs(); var $tab = this.findTab(); var settings = acf.parseArgs($tab.data(), { endpoint: false, placement: '', before: this.$el }); // create wrap if( !$tabs.length || settings.endpoint ) { this.tabs = new Tabs( settings ); } else { this.tabs = $tabs.data('acf'); } // add tab this.tab = this.tabs.addTab($tab, this); }, isActive: function(){ return this.tab.isActive(); }, showFields: function(){ // show fields this.getFields().map(function( field ){ field.show( this.cid, CONTEXT ); field.hiddenByTab = false; }, this); }, hideFields: function(){ // hide fields this.getFields().map(function( field ){ field.hide( this.cid, CONTEXT ); field.hiddenByTab = this.tab; }, this); }, show: function( lockKey ){ // show field and store result var visible = acf.Field.prototype.show.apply(this, arguments); // check if now visible if( visible ) { // show tab this.tab.show(); // check active tabs this.tabs.refresh(); } // return return visible; }, hide: function( lockKey ){ // hide field and store result var hidden = acf.Field.prototype.hide.apply(this, arguments); // check if now hidden if( hidden ) { // hide tab this.tab.hide(); // reset tabs if this was active if( this.isActive() ) { this.tabs.reset(); } } // return return hidden; }, enable: function( lockKey ){ // enable fields this.getFields().map(function( field ){ field.enable( CONTEXT ); }); }, disable: function( lockKey ){ // disable fields this.getFields().map(function( field ){ field.disable( CONTEXT ); }); } }); acf.registerFieldType( Field ); /** * tabs * * description * * @date 8/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var i = 0; var Tabs = acf.Model.extend({ tabs: [], active: false, actions: { 'refresh': 'onRefresh' }, data: { before: false, placement: 'top', index: 0, initialized: false, }, setup: function( settings ){ // data $.extend(this.data, settings); // define this prop to avoid scope issues this.tabs = []; this.active = false; // vars var placement = this.get('placement'); var $before = this.get('before'); var $parent = $before.parent(); // add sidebar for left placement if( placement == 'left' && $parent.hasClass('acf-fields') ) { $parent.addClass('-sidebar'); } // create wrap if( $before.is('tr') ) { this.$el = $(''); } else { this.$el = $('
    '); } // append $before.before( this.$el ); // set index this.set('index', i, true); i++; }, initializeTabs: function(){ // find first visible tab var tab = this.getVisible().shift(); // remember previous tab state var order = acf.getPreference('this.tabs') || []; var groupIndex = this.get('index'); var tabIndex = order[ groupIndex ]; if( this.tabs[ tabIndex ] && this.tabs[ tabIndex ].isVisible() ) { tab = this.tabs[ tabIndex ]; } // select if( tab ) { this.selectTab( tab ); } else { this.closeTabs(); } // set local variable used by tabsManager this.set('initialized', true); }, getVisible: function(){ return this.tabs.filter(function( tab ){ return tab.isVisible(); }); }, getActive: function(){ return this.active; }, setActive: function( tab ){ return this.active = tab; }, hasActive: function(){ return (this.active !== false); }, isActive: function( tab ){ var active = this.getActive(); return (active && active.cid === tab.cid); }, closeActive: function(){ if( this.hasActive() ) { this.closeTab( this.getActive() ); } }, openTab: function( tab ){ // close existing tab this.closeActive(); // open tab.open(); // set active this.setActive( tab ); }, closeTab: function( tab ){ // close tab.close(); // set active this.setActive( false ); }, closeTabs: function(){ this.tabs.map( this.closeTab, this ); }, selectTab: function( tab ){ // close other tabs this.tabs.map(function( t ){ if( tab.cid !== t.cid ) { this.closeTab( t ); } }, this); // open this.openTab( tab ); }, addTab: function( $a, field ){ // create
  • var $li = $('
  • '); // append $li.append( $a ); // append this.$('ul').append( $li ); // initialize var tab = new Tab({ $el: $li, field: field, group: this, }); // store this.tabs.push( tab ); // return return tab; }, reset: function(){ // close existing tab this.closeActive(); // find and active a tab return this.refresh(); }, refresh: function(){ // bail early if active already exists if( this.hasActive() ) { return false; } // find next active tab var tab = this.getVisible().shift(); // open tab if( tab ) { this.openTab( tab ); } // return return tab; }, onRefresh: function(){ // only for left placements if( this.get('placement') !== 'left' ) { return; } // vars var $parent = this.$el.parent(); var $list = this.$el.children('ul'); var attribute = $parent.is('td') ? 'height' : 'min-height'; // find height (minus 1 for border-bottom) var height = $list.position().top + $list.outerHeight(true) - 1; // add css $parent.css(attribute, height); } }); var Tab = acf.Model.extend({ group: false, field: false, events: { 'click a': 'onClick' }, index: function(){ return this.$el.index(); }, isVisible: function(){ return acf.isVisible( this.$el ); }, isActive: function(){ return this.$el.hasClass('active'); }, open: function(){ // add class this.$el.addClass('active'); // show field this.field.showFields(); }, close: function(){ // remove class this.$el.removeClass('active'); // hide field this.field.hideFields(); }, onClick: function( e, $el ){ // prevent default e.preventDefault(); // toggle this.toggle(); }, toggle: function(){ // bail early if already active if( this.isActive() ) { return; } // toggle this tab this.group.openTab( this ); } }); var tabsManager = new acf.Model({ priority: 50, actions: { 'prepare': 'render', 'append': 'render', 'unload': 'onUnload', 'invalid_field': 'onInvalidField' }, findTabs: function(){ return $('.acf-tab-wrap'); }, getTabs: function(){ return acf.getInstances( this.findTabs() ); }, render: function( $el ){ this.getTabs().map(function( tabs ){ if( !tabs.get('initialized') ) { tabs.initializeTabs(); } }); }, onInvalidField: function( field ){ // bail early if busy if( this.busy ) { return; } // ignore if not hidden by tab if( !field.hiddenByTab ) { return; } // toggle tab field.hiddenByTab.toggle(); // ignore other invalid fields this.busy = true; this.setTimeout(function(){ this.busy = false; }, 100); }, onUnload: function(){ // vars var order = []; // loop this.getTabs().map(function( group ){ var active = group.hasActive() ? group.getActive().index() : 0; order.push(active); }); // bail if no tabs if( !order.length ) { return; } // update acf.setPreference('this.tabs', order); } }); })(jQuery); (function($, undefined){ var Field = acf.models.SelectField.extend({ type: 'post_object', }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.models.SelectField.extend({ type: 'page_link', }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.models.SelectField.extend({ type: 'user', }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'taxonomy', data: { 'ftype': 'select' }, select2: false, wait: 'load', events: { 'click a[data-name="add"]': 'onClickAdd', 'click input[type="radio"]': 'onClickRadio', }, $control: function(){ return this.$('.acf-taxonomy-field'); }, $input: function(){ return this.getRelatedPrototype().$input.apply(this, arguments); }, getRelatedType: function(){ // vars var fieldType = this.get('ftype'); // normalize if( fieldType == 'multi_select' ) { fieldType = 'select'; } // return return fieldType; }, getRelatedPrototype: function(){ return acf.getFieldType( this.getRelatedType() ).prototype; }, getValue: function(){ return this.getRelatedPrototype().getValue.apply(this, arguments); }, setValue: function(){ return this.getRelatedPrototype().setValue.apply(this, arguments); }, initialize: function(){ this.getRelatedPrototype().initialize.apply(this, arguments); }, onRemove: function(){ if( this.select2 ) { this.select2.destroy(); } }, onClickAdd: function( e, $el ){ // vars var field = this; var popup = false; var $form = false; var $name = false; var $parent = false; var $button = false; var $message = false; var notice = false; // step 1. var step1 = function(){ // popup popup = acf.newPopup({ title: $el.attr('title'), loading: true, width: '300px' }); // ajax var ajaxData = { action: 'acf/fields/taxonomy/add_term', field_key: field.get('key') }; // get HTML $.ajax({ url: acf.get('ajaxurl'), data: acf.prepareForAjax(ajaxData), type: 'post', dataType: 'html', success: step2 }); }; // step 2. var step2 = function( html ){ // update popup popup.loading(false); popup.content(html); // vars $form = popup.$('form'); $name = popup.$('input[name="term_name"]'); $parent = popup.$('select[name="term_parent"]'); $button = popup.$('.acf-submit-button'); // focus $name.focus(); // submit form popup.on('submit', 'form', step3); }; // step 3. var step3 = function( e, $el ){ // prevent e.preventDefault(); e.stopImmediatePropagation(); // basic validation if( $name.val() === '' ) { $name.focus(); return false; } // disable acf.startButtonLoading( $button ); // ajax var ajaxData = { action: 'acf/fields/taxonomy/add_term', field_key: field.get('key'), term_name: $name.val(), term_parent: $parent.length ? $parent.val() : 0 }; $.ajax({ url: acf.get('ajaxurl'), data: acf.prepareForAjax(ajaxData), type: 'post', dataType: 'json', success: step4 }); }; // step 4. var step4 = function( json ){ // enable acf.stopButtonLoading( $button ); // remove prev notice if( notice ) { notice.remove(); } // success if( acf.isAjaxSuccess(json) ) { // clear name $name.val(''); // update term lists step5( json.data ); // notice notice = acf.newNotice({ type: 'success', text: acf.getAjaxMessage(json), target: $form, timeout: 2000, dismiss: false }); } else { // notice notice = acf.newNotice({ type: 'error', text: acf.getAjaxError(json), target: $form, timeout: 2000, dismiss: false }); } // focus $name.focus(); }; // step 5. var step5 = function( term ){ // update parent dropdown var $option = $(''); if( term.term_parent ) { $parent.children('option[value="' + term.term_parent + '"]').after( $option ); } else { $parent.append( $option ); } // add this new term to all taxonomy field var fields = acf.getFields({ type: 'taxonomy' }); fields.map(function( otherField ){ if( otherField.get('taxonomy') == field.get('taxonomy') ) { otherField.appendTerm( term ); } }); // select field.selectTerm( term.term_id ); }; // run step1(); }, appendTerm: function( term ){ if( this.getRelatedType() == 'select' ) { this.appendTermSelect( term ); } else { this.appendTermCheckbox( term ); } }, appendTermSelect: function( term ){ this.select2.addOption({ id: term.term_id, text: term.term_label }); }, appendTermCheckbox: function( term ){ // vars var name = this.$('[name]:first').attr('name'); var $ul = this.$('ul:first'); // allow multiple selection if( this.getRelatedType() == 'checkbox' ) { name += '[]'; } // create new li var $li = $([ '
  • ', '', '
  • ' ].join('')); // find parent if( term.term_parent ) { // vars var $parent = $ul.find('li[data-id="' + term.term_parent + '"]'); // update vars $ul = $parent.children('ul'); // create ul if( !$ul.exists() ) { $ul = $(''); $parent.append( $ul ); } } // append $ul.append( $li ); }, selectTerm: function( id ){ if( this.getRelatedType() == 'select' ) { this.select2.selectOption( id ); } else { var $input = this.$('input[value="' + id + '"]'); $input.prop('checked', true).trigger('change'); } }, onClickRadio: function( e, $el ){ // vars var $label = $el.parent('label'); var selected = $label.hasClass('selected'); // remove previous selected this.$('.selected').removeClass('selected'); // add active class $label.addClass('selected'); // allow null if( this.get('allow_null') && selected ) { $label.removeClass('selected'); $el.prop('checked', false).trigger('change'); } } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.models.DatePickerField.extend({ type: 'time_picker', $control: function(){ return this.$('.acf-time-picker'); }, initialize: function(){ // vars var $input = this.$input(); var $inputText = this.$inputText(); // args var args = { timeFormat: this.get('time_format'), altField: $input, altFieldTimeOnly: false, altTimeFormat: 'HH:mm:ss', showButtonPanel: true, controlType: 'select', oneLine: true, closeText: acf.get('dateTimePickerL10n').selectText, timeOnly: true, }; // add custom 'Close = Select' functionality args.onClose = function( value, dp_instance, t_instance ){ // vars var $close = dp_instance.dpDiv.find('.ui-datepicker-close'); // if clicking close button if( !value && $close.is(':hover') ) { t_instance._updateDateTime(); } }; // filter args = acf.applyFilters('time_picker_args', args, this); // add date time picker acf.newTimePicker( $inputText, args ); // action acf.doAction('time_picker_init', $inputText, args, this); } }); acf.registerFieldType( Field ); // add acf.newTimePicker = function( $input, args ){ // bail ealry if no datepicker library if( typeof $.timepicker === 'undefined' ) { return false; } // defaults args = args || {}; // initialize $input.timepicker( args ); // wrap the datepicker (only if it hasn't already been wrapped) if( $('body > #ui-datepicker-div').exists() ) { $('body > #ui-datepicker-div').wrap('
    '); } }; })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'true_false', events: { 'change .acf-switch-input': 'onChange', 'focus .acf-switch-input': 'onFocus', 'blur .acf-switch-input': 'onBlur', 'keypress .acf-switch-input': 'onKeypress' }, $input: function(){ return this.$('input[type="checkbox"]'); }, $switch: function(){ return this.$('.acf-switch'); }, getValue: function(){ return this.$input().prop('checked') ? 1 : 0; }, initialize: function(){ this.render(); }, render: function(){ // vars var $switch = this.$switch(); // bail ealry if no $switch if( !$switch.length ) return; // vars var $on = $switch.children('.acf-switch-on'); var $off = $switch.children('.acf-switch-off'); var width = Math.max( $on.width(), $off.width() ); // bail ealry if no width if( !width ) return; // set widths $on.css( 'min-width', width ); $off.css( 'min-width', width ); }, switchOn: function() { this.$input().prop('checked', true); this.$switch().addClass('-on'); }, switchOff: function() { this.$input().prop('checked', false); this.$switch().removeClass('-on'); }, onChange: function( e, $el ){ if( $el.prop('checked') ) { this.switchOn(); } else { this.switchOff(); } }, onFocus: function( e, $el ){ this.$switch().addClass('-focus'); }, onBlur: function( e, $el ){ this.$switch().removeClass('-focus'); }, onKeypress: function( e, $el ){ // left if( e.keyCode === 37 ) { return this.switchOff(); } // right if( e.keyCode === 39 ) { return this.switchOn(); } } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'url', events: { 'keyup input[type="url"]': 'onkeyup' }, $control: function(){ return this.$('.acf-input-wrap'); }, $input: function(){ return this.$('input[type="url"]'); }, initialize: function(){ this.render(); }, isValid: function(){ // vars var val = this.val(); // bail early if no val if( !val ) { return false; } // url if( val.indexOf('://') !== -1 ) { return true; } // protocol relative url if( val.indexOf('//') === 0 ) { return true; } // return return false; }, render: function(){ // add class if( this.isValid() ) { this.$control().addClass('-valid'); } else { this.$control().removeClass('-valid'); } }, onkeyup: function( e, $el ){ this.render(); } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ var Field = acf.Field.extend({ type: 'wysiwyg', wait: 'load', events: { 'mousedown .acf-editor-wrap.delay': 'onMousedown', 'sortstartField': 'disableEditor', 'sortstopField': 'enableEditor', 'removeField': 'disableEditor' }, $control: function(){ return this.$('.acf-editor-wrap'); }, $input: function(){ return this.$('textarea'); }, getMode: function(){ return this.$control().hasClass('tmce-active') ? 'visual' : 'text'; }, initialize: function(){ // initializeEditor if no delay if( !this.$control().hasClass('delay') ) { this.initializeEditor(); } }, initializeEditor: function(){ // vars var $wrap = this.$control(); var $textarea = this.$input(); var args = { tinymce: true, quicktags: true, toolbar: this.get('toolbar'), mode: this.getMode(), field: this }; // generate new id var oldId = $textarea.attr('id'); var newId = acf.uniqueId('acf-editor-'); // store copy of textarea data var data = $textarea.data(); // rename acf.rename({ target: $wrap, search: oldId, replace: newId, destructive: true }); // update id this.set('id', newId, true); // initialize acf.tinymce.initialize( newId, args ); // apply data to new textarea (acf.rename creates a new textarea element due to destructive mode) // fixes bug where conditional logic "disabled" is lost during "screen_check" this.$input().data(data); }, onMousedown: function( e ){ // prevent default e.preventDefault(); // remove delay class var $wrap = this.$control(); $wrap.removeClass('delay'); $wrap.find('.acf-editor-toolbar').remove(); // initialize this.initializeEditor(); }, enableEditor: function(){ if( this.getMode() == 'visual' ) { acf.tinymce.enable( this.get('id') ); } }, disableEditor: function(){ acf.tinymce.destroy( this.get('id') ); } }); acf.registerFieldType( Field ); })(jQuery); (function($, undefined){ // vars var storage = []; /** * acf.Condition * * description * * @date 23/3/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ acf.Condition = acf.Model.extend({ type: '', // used for model name operator: '==', // rule operator label: '', // label shown when editing fields choiceType: 'input', // input, select fieldTypes: [], // auto connect this conditions with these field types data: { conditions: false, // the parent instance field: false, // the field which we query against rule: {} // the rule [field, operator, value] }, events: { 'change': 'change', 'keyup': 'change', 'enableField': 'change', 'disableField': 'change' }, setup: function( props ){ $.extend(this.data, props); }, getEventTarget: function( $el, event ){ return $el || this.get('field').$el; }, change: function( e, $el ){ this.get('conditions').change( e ); }, match: function( rule, field ){ return false; }, calculate: function(){ return this.match( this.get('rule'), this.get('field') ); }, choices: function( field ){ return ''; } }); /** * acf.newCondition * * description * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.newCondition = function( rule, conditions ){ // currently setting up conditions for fieldX, this field is the 'target' var target = conditions.get('field'); // use the 'target' to find the 'trigger' field. // - this field is used to setup the conditional logic events var field = target.getField( rule.field ); // bail ealry if no target or no field (possible if field doesn't exist due to HTML error) if( !target || !field ) { return false; } // vars var args = { rule: rule, target: target, conditions: conditions, field: field }; // vars var fieldType = field.get('type'); var operator = rule.operator; // get avaibale conditions var conditionTypes = acf.getConditionTypes({ fieldType: fieldType, operator: operator, }); // instantiate var model = conditionTypes[0] || acf.Condition; // instantiate var condition = new model( args ); // return return condition; }; /** * 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 || '' ) + 'Condition'; }; /** * acf.registerConditionType * * description * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.registerConditionType = function( model ){ // vars var proto = model.prototype; var type = proto.type; var mid = modelId( type ); // store model acf.models[ mid ] = model; // store reference storage.push( type ); }; /** * acf.getConditionType * * description * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.getConditionType = function( type ){ var mid = modelId( type ); return acf.models[ mid ] || false; } /** * acf.registerConditionForFieldType * * description * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.registerConditionForFieldType = function( conditionType, fieldType ){ // get model var model = acf.getConditionType( conditionType ); // append if( model ) { model.prototype.fieldTypes.push( fieldType ); } }; /** * acf.getConditionTypes * * description * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.getConditionTypes = function( args ){ // defaults args = acf.parseArgs(args, { fieldType: '', operator: '' }); // clonse available types var types = []; // loop storage.map(function( type ){ // vars var model = acf.getConditionType(type); var ProtoFieldTypes = model.prototype.fieldTypes; var ProtoOperator = model.prototype.operator; // check fieldType if( args.fieldType && ProtoFieldTypes.indexOf( args.fieldType ) === -1 ) { return; } // check operator if( args.operator && ProtoOperator !== args.operator ) { return; } // append types.push( model ); }); // return return types; }; })(jQuery); (function($, undefined){ // vars var CONTEXT = 'conditional_logic'; /** * conditionsManager * * description * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var conditionsManager = new acf.Model({ id: 'conditionsManager', priority: 20, // run actions later actions: { 'new_field': 'onNewField', }, onNewField: function( field ){ if( field.has('conditions') ) { field.getConditions().render(); } }, }); /** * acf.Field.prototype.getField * * Finds a field that is related to another field * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var getSiblingField = function( field, key ){ // find sibling (very fast) var fields = acf.getFields({ key: key, sibling: field.$el, suppressFilters: true, }); // find sibling-children (fast) // needed for group fields, accordions, etc if( !fields.length ) { fields = acf.getFields({ key: key, parent: field.$el.parent(), suppressFilters: true, }); } // return if( fields.length ) { return fields[0]; } return false; }; acf.Field.prototype.getField = function( key ){ // get sibling field var field = getSiblingField( this, key ); // return early if( field ) { return field; } // move up through each parent and try again var parents = this.parents(); for( var i = 0; i < parents.length; i++ ) { // get sibling field field = getSiblingField( parents[i], key ); // return early if( field ) { return field; } } // return return false; }; /** * acf.Field.prototype.getConditions * * Returns the field's conditions instance * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.Field.prototype.getConditions = function(){ // instantiate if( !this.conditions ) { this.conditions = new Conditions( this ); } // return return this.conditions; }; /** * Conditions * * description * * @date 1/2/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var timeout = false; var Conditions = acf.Model.extend({ id: 'Conditions', data: { field: false, // The field with "data-conditions" (target). timeStamp: false, // Reference used during "change" event. groups: [], // The groups of condition instances. }, setup: function( field ){ // data this.data.field = field; // vars var conditions = field.get('conditions'); // detect groups if( conditions instanceof Array ) { // detect groups if( conditions[0] instanceof Array ) { // loop conditions.map(function(rules, i){ this.addRules( rules, i ); }, this); // detect rules } else { this.addRules( conditions ); } // detect rule } else { this.addRule( conditions ); } }, change: function( e ){ // this function may be triggered multiple times per event due to multiple condition classes // compare timestamp to allow only 1 trigger per event if( this.get('timeStamp') === e.timeStamp ) { return false; } else { this.set('timeStamp', e.timeStamp, true); } // render condition and store result var changed = this.render(); }, render: function(){ return this.calculate() ? this.show() : this.hide(); }, show: function(){ return this.get('field').showEnable(this.cid, CONTEXT); }, hide: function(){ return this.get('field').hideDisable(this.cid, CONTEXT); }, calculate: function(){ // vars var pass = false; // loop this.getGroups().map(function( group ){ // igrnore this group if another group passed if( pass ) return; // find passed var passed = group.filter(function(condition){ return condition.calculate(); }); // if all conditions passed, update the global var if( passed.length == group.length ) { pass = true; } }); return pass; }, hasGroups: function(){ return this.data.groups != null; }, getGroups: function(){ return this.data.groups; }, addGroup: function(){ var group = []; this.data.groups.push( group ); return group; }, hasGroup: function( i ){ return this.data.groups[i] != null; }, getGroup: function( i ){ return this.data.groups[i]; }, removeGroup: function( i ){ this.data.groups[i].delete; return this; }, addRules: function( rules, group ){ rules.map(function( rule ){ this.addRule( rule, group ); }, this); }, addRule: function( rule, group ){ // defaults group = group || 0; // vars var groupArray; // get group if( this.hasGroup(group) ) { groupArray = this.getGroup(group); } else { groupArray = this.addGroup(); } // instantiate var condition = acf.newCondition( rule, this ); // bail ealry if condition failed (field did not exist) if( !condition ) { return false; } // add rule groupArray.push(condition); }, hasRule: function(){ }, getRule: function( rule, group ){ // defaults rule = rule || 0; group = group || 0; return this.data.groups[ group ][ rule ]; }, removeRule: function(){ } }); })(jQuery); (function($, undefined){ var __ = acf.__; var parseString = function( val ){ return val ? '' + val : ''; }; var isEqualTo = function( v1, v2 ){ return ( parseString(v1).toLowerCase() === parseString(v2).toLowerCase() ); }; var isEqualToNumber = function( v1, v2 ){ return ( parseFloat(v1) === parseFloat(v2) ); }; var isGreaterThan = function( v1, v2 ){ return ( parseFloat(v1) > parseFloat(v2) ); }; var isLessThan = function( v1, v2 ){ return ( parseFloat(v1) < parseFloat(v2) ); }; var inArray = function( v1, array ){ // cast all values as string array = array.map(function(v2){ return parseString(v2); }); return (array.indexOf( v1 ) > -1); } var containsString = function( haystack, needle ){ return ( parseString(haystack).indexOf( parseString(needle) ) > -1 ); }; var matchesPattern = function( v1, pattern ){ var regexp = new RegExp(parseString(pattern), 'gi'); return parseString(v1).match( regexp ); }; /** * hasValue * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var HasValue = acf.Condition.extend({ type: 'hasValue', operator: '!=empty', label: __('Has any value'), fieldTypes: [ 'text', 'textarea', 'number', 'range', 'email', 'url', 'password', 'image', 'file', 'wysiwyg', 'oembed', 'select', 'checkbox', 'radio', 'button_group', 'link', 'post_object', 'page_link', 'relationship', 'taxonomy', 'user', 'google_map', 'date_picker', 'date_time_picker', 'time_picker', 'color_picker' ], match: function( rule, field ){ return (field.val() ? true : false); }, choices: function( fieldObject ){ return ''; } }); acf.registerConditionType( HasValue ); /** * hasValue * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var HasNoValue = HasValue.extend({ type: 'hasNoValue', operator: '==empty', label: __('Has no value'), match: function( rule, field ){ return !HasValue.prototype.match.apply(this, arguments); } }); acf.registerConditionType( HasNoValue ); /** * EqualTo * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var EqualTo = acf.Condition.extend({ type: 'equalTo', operator: '==', label: __('Value is equal to'), fieldTypes: [ 'text', 'textarea', 'number', 'range', 'email', 'url', 'password' ], match: function( rule, field ){ if( $.isNumeric(rule.value) ) { return isEqualToNumber( rule.value, field.val() ); } else { return isEqualTo( rule.value, field.val() ); } }, choices: function( fieldObject ){ return ''; } }); acf.registerConditionType( EqualTo ); /** * NotEqualTo * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var NotEqualTo = EqualTo.extend({ type: 'notEqualTo', operator: '!=', label: __('Value is not equal to'), match: function( rule, field ){ return !EqualTo.prototype.match.apply(this, arguments); } }); acf.registerConditionType( NotEqualTo ); /** * PatternMatch * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var PatternMatch = acf.Condition.extend({ type: 'patternMatch', operator: '==pattern', label: __('Value matches pattern'), fieldTypes: [ 'text', 'textarea', 'email', 'url', 'password', 'wysiwyg' ], match: function( rule, field ){ return matchesPattern( field.val(), rule.value ); }, choices: function( fieldObject ){ return ''; } }); acf.registerConditionType( PatternMatch ); /** * Contains * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var Contains = acf.Condition.extend({ type: 'contains', operator: '==contains', label: __('Value contains'), fieldTypes: [ 'text', 'textarea', 'number', 'email', 'url', 'password', 'wysiwyg', 'oembed', 'select' ], match: function( rule, field ){ return containsString( field.val(), rule.value ); }, choices: function( fieldObject ){ return ''; } }); acf.registerConditionType( Contains ); /** * TrueFalseEqualTo * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var TrueFalseEqualTo = EqualTo.extend({ type: 'trueFalseEqualTo', choiceType: 'select', fieldTypes: [ 'true_false' ], choices: function( field ){ return [ { id: 1, text: __('Checked') } ]; }, }); acf.registerConditionType( TrueFalseEqualTo ); /** * TrueFalseNotEqualTo * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var TrueFalseNotEqualTo = NotEqualTo.extend({ type: 'trueFalseNotEqualTo', choiceType: 'select', fieldTypes: [ 'true_false' ], choices: function( field ){ return [ { id: 1, text: __('Checked') } ]; }, }); acf.registerConditionType( TrueFalseNotEqualTo ); /** * SelectEqualTo * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var SelectEqualTo = acf.Condition.extend({ type: 'selectEqualTo', operator: '==', label: __('Value is equal to'), fieldTypes: [ 'select', 'checkbox', 'radio', 'button_group' ], match: function( rule, field ){ var val = field.val(); if( val instanceof Array ) { return inArray( rule.value, val ); } else { return isEqualTo( rule.value, val ); } }, choices: function( fieldObject ){ // vars var choices = []; var lines = fieldObject.$setting('choices textarea').val().split("\n"); // allow null if( fieldObject.$input('allow_null').prop('checked') ) { choices.push({ id: '', text: __('Null') }); } // loop lines.map(function( line ){ // split line = line.split(':'); // default label to value line[1] = line[1] || line[0]; // append choices.push({ id: $.trim( line[0] ), text: $.trim( line[1] ) }); }); // return return choices; }, }); acf.registerConditionType( SelectEqualTo ); /** * SelectNotEqualTo * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var SelectNotEqualTo = SelectEqualTo.extend({ type: 'selectNotEqualTo', operator: '!=', label: __('Value is not equal to'), match: function( rule, field ){ return !SelectEqualTo.prototype.match.apply(this, arguments); } }); acf.registerConditionType( SelectNotEqualTo ); /** * GreaterThan * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var GreaterThan = acf.Condition.extend({ type: 'greaterThan', operator: '>', label: __('Value is greater than'), fieldTypes: [ 'number', 'range' ], match: function( rule, field ){ var val = field.val(); if( val instanceof Array ) { val = val.length; } return isGreaterThan( val, rule.value ); }, choices: function( fieldObject ){ return ''; } }); acf.registerConditionType( GreaterThan ); /** * LessThan * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var LessThan = GreaterThan.extend({ type: 'lessThan', operator: '<', label: __('Value is less than'), match: function( rule, field ){ var val = field.val(); if( val instanceof Array ) { val = val.length; } return isLessThan( val, rule.value ); }, choices: function( fieldObject ){ return ''; } }); acf.registerConditionType( LessThan ); /** * SelectedGreaterThan * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var SelectionGreaterThan = GreaterThan.extend({ type: 'selectionGreaterThan', label: __('Selection is greater than'), fieldTypes: [ 'checkbox', 'select', 'post_object', 'page_link', 'relationship', 'taxonomy', 'user' ], }); acf.registerConditionType( SelectionGreaterThan ); /** * SelectedGreaterThan * * description * * @date 1/2/18 * @since 5.6.5 * * @param void * @return void */ var SelectionLessThan = LessThan.extend({ type: 'selectionLessThan', label: __('Selection is less than'), fieldTypes: [ 'checkbox', 'select', 'post_object', 'page_link', 'relationship', 'taxonomy', 'user' ], }); acf.registerConditionType( SelectionLessThan ); })(jQuery); (function($, undefined){ /** * acf.newMediaPopup * * description * * @date 10/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.newMediaPopup = function( args ){ // args var popup = null; var args = acf.parseArgs(args, { mode: 'select', // 'select', 'edit' title: '', // 'Upload Image' button: '', // 'Select Image' type: '', // 'image', '' field: false, // field instance allowedTypes: '', // '.jpg, .png, etc' library: 'all', // 'all', 'uploadedTo' multiple: false, // false, true, 'add' attachment: 0, // the attachment to edit autoOpen: true, // open the popup automatically open: function(){}, // callback after close select: function(){}, // callback after select close: function(){} // callback after close }); // initialize if( args.mode == 'edit' ) { popup = new acf.models.EditMediaPopup( args ); } else { popup = new acf.models.SelectMediaPopup( args ); } // open popup (allow frame customization before opening) if( args.autoOpen ) { setTimeout(function(){ popup.open(); }, 1); } // action acf.doAction('new_media_popup', popup); // return return popup; }; /** * getPostID * * description * * @date 10/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var getPostID = function() { var postID = acf.get('post_id'); return $.isNumeric(postID) ? postID : 0; } /** * acf.getMimeTypes * * description * * @date 11/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.getMimeTypes = function(){ return this.get('mimeTypes'); }; acf.getMimeType = function( name ){ // vars var allTypes = acf.getMimeTypes(); // search if( allTypes[name] !== undefined ) { return allTypes[name]; } // some types contain a mixed key such as "jpg|jpeg|jpe" for( var key in allTypes ) { if( key.indexOf(name) !== -1 ) { return allTypes[key]; } } // return return false; }; /** * MediaPopup * * description * * @date 10/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var MediaPopup = acf.Model.extend({ id: 'MediaPopup', data: {}, defaults: {}, frame: false, setup: function( props ){ $.extend(this.data, props); }, initialize: function(){ // vars var options = this.getFrameOptions(); // add states this.addFrameStates( options ); // create frame var frame = wp.media( options ); // add args reference frame.acf = this; // add events this.addFrameEvents( frame, options ); // strore frame this.frame = frame; }, open: function(){ this.frame.open(); }, close: function(){ this.frame.close(); }, remove: function(){ this.frame.detach(); this.frame.remove(); }, getFrameOptions: function(){ // vars var options = { title: this.get('title'), multiple: this.get('multiple'), library: {}, states: [] }; // type if( this.get('type') ) { options.library.type = this.get('type'); } // type if( this.get('library') === 'uploadedTo' ) { options.library.uploadedTo = getPostID(); } // attachment if( this.get('attachment') ) { options.library.post__in = [ this.get('attachment') ]; } // button if( this.get('button') ) { options.button = { text: this.get('button') }; } // return return options; }, addFrameStates: function( options ){ // create query var Query = wp.media.query( options.library ); // add _acfuploader // this is super wack! // if you add _acfuploader to the options.library args, new uploads will not be added to the library view. // this has been traced back to the wp.media.model.Query initialize function (which can't be overriden) // Adding any custom args will cause the Attahcments to not observe the uploader queue // To bypass this security issue, we add in the args AFTER the Query has been initialized // options.library._acfuploader = settings.field; if( this.get('field') && acf.isset(Query, 'mirroring', 'args') ) { Query.mirroring.args._acfuploader = this.get('field'); } // add states options.states.push( // main state new wp.media.controller.Library({ library: Query, multiple: this.get('multiple'), title: this.get('title'), priority: 20, filterable: 'all', editable: true, allowLocalEdits: true }) ); // edit image functionality (added in WP 3.9) if( acf.isset(wp, 'media', 'controller', 'EditImage') ) { options.states.push( new wp.media.controller.EditImage() ); } }, addFrameEvents: function( frame, options ){ // log all events //frame.on('all', function( e ) { // console.log( 'frame all: %o', e ); //}); // add class frame.on('open',function() { this.$el.closest('.media-modal').addClass('acf-media-modal -' + this.acf.get('mode') ); }, frame); // edit image view // source: media-views.js:2410 editImageContent() frame.on('content:render:edit-image', function(){ var image = this.state().get('image'); var view = new wp.media.view.EditImage({ model: image, controller: this }).render(); this.content.set( view ); // after creating the wrapper view, load the actual editor via an ajax call view.loadEditor(); }, frame); // update toolbar button /* frame.on( 'toolbar:create:select', function( toolbar ) { toolbar.view = new wp.media.view.Toolbar.Select({ text: frame.options._button, controller: this }); }, frame ); */ // on select frame.on('select', function() { // vars var selection = frame.state().get('selection'); // if selecting images if( selection ) { // loop selection.each(function( attachment, i ){ frame.acf.get('select').apply( frame.acf, [attachment, i] ); }); } }); // on close frame.on('close',function(){ // callback and remove setTimeout(function(){ frame.acf.get('close').apply( frame.acf ); frame.acf.remove(); }, 1); }); } }); /** * acf.models.SelectMediaPopup * * description * * @date 10/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.models.SelectMediaPopup = MediaPopup.extend({ id: 'SelectMediaPopup', setup: function( props ){ // default button if( !props.button ) { props.button = acf._x('Select', 'verb'); } // parent MediaPopup.prototype.setup.apply(this, arguments); }, addFrameEvents: function( frame, options ){ // plupload // adds _acfuploader param to validate uploads if( acf.isset(_wpPluploadSettings, 'defaults', 'multipart_params') ) { // add _acfuploader so that Uploader will inherit _wpPluploadSettings.defaults.multipart_params._acfuploader = this.get('field'); // remove acf_field so future Uploaders won't inherit frame.on('open', function(){ delete _wpPluploadSettings.defaults.multipart_params._acfuploader; }); } // browse frame.on('content:activate:browse', function(){ // vars var toolbar = false; // populate above vars making sure to allow for failure // perhaps toolbar does not exist because the frame open is Upload Files try { toolbar = frame.content.get().toolbar; } catch(e) { console.log(e); return; } // callback frame.acf.customizeFilters.apply(frame.acf, [toolbar]); }); // parent MediaPopup.prototype.addFrameEvents.apply(this, arguments); }, customizeFilters: function( toolbar ){ // vars var filters = toolbar.get('filters'); // image if( this.get('type') == 'image' ) { // update all filters.filters.all.text = acf.__('All images'); // remove some filters delete filters.filters.audio; delete filters.filters.video; delete filters.filters.image; // update all filters to show images $.each(filters.filters, function( i, filter ){ filter.props.type = filter.props.type || 'image'; }); } // specific types if( this.get('allowedTypes') ) { // convert ".jpg, .png" into ["jpg", "png"] var allowedTypes = this.get('allowedTypes').split(' ').join('').split('.').join('').split(','); // loop allowedTypes.map(function( name ){ // get type var mimeType = acf.getMimeType( name ); // bail early if no type if( !mimeType ) return; // create new filter var newFilter = { text: mimeType, props: { status: null, type: mimeType, uploadedTo: null, orderby: 'date', order: 'DESC' }, priority: 20 }; // append filters.filters[ mimeType ] = newFilter; }); } // uploaded to post if( this.get('library') === 'uploadedTo' ) { // vars var uploadedTo = this.frame.options.library.uploadedTo; // remove some filters delete filters.filters.unattached; delete filters.filters.uploaded; // add uploadedTo to filters $.each(filters.filters, function( i, filter ){ filter.text += ' (' + acf.__('Uploaded to this post') + ')'; filter.props.uploadedTo = uploadedTo; }); } // add _acfuploader to filters var field = this.get('field'); $.each(filters.filters, function( k, filter ){ filter.props._acfuploader = field; }); // add _acfuplaoder to search var search = toolbar.get('search'); search.model.attributes._acfuploader = field; // render (custom function added to prototype) if( filters.renderFilters ) { filters.renderFilters(); } } }); /** * acf.models.EditMediaPopup * * description * * @date 10/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.models.EditMediaPopup = MediaPopup.extend({ id: 'SelectMediaPopup', setup: function( props ){ // default button if( !props.button ) { props.button = acf._x('Update', 'verb'); } // parent MediaPopup.prototype.setup.apply(this, arguments); }, addFrameEvents: function( frame, options ){ // add class frame.on('open',function() { // add class this.$el.closest('.media-modal').addClass('acf-expanded'); // set to browse if( this.content.mode() != 'browse' ) { this.content.mode('browse'); } // set selection var state = this.state(); var selection = state.get('selection'); var attachment = wp.media.attachment( frame.acf.get('attachment') ); selection.add( attachment ); }, frame); // parent MediaPopup.prototype.addFrameEvents.apply(this, arguments); } }); /** * customizePrototypes * * description * * @date 11/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var customizePrototypes = new acf.Model({ id: 'customizePrototypes', wait: 'ready', initialize: function(){ // bail early if no media views if( !acf.isset(window, 'wp', 'media', 'view') ) { return; } // fix bug where CPT without "editor" does not set post.id setting which then prevents uploadedTo from working var postID = getPostID(); if( postID && acf.isset(wp, 'media', 'view', 'settings', 'post') ) { wp.media.view.settings.post.id = postID; } // customize this.customizeAttachmentsRouter(); this.customizeAttachmentFilters(); this.customizeAttachmentCompat(); this.customizeAttachmentLibrary(); }, customizeAttachmentsRouter: function(){ // validate if( !acf.isset(wp, 'media', 'view', 'Router') ) { return; } // vars var Parent = wp.media.view.Router; // extend wp.media.view.Router = Parent.extend({ addExpand: function(){ // vars var $a = $([ '', '' + acf.__('Expand Details') + '', '' + acf.__('Collapse Details') + '', '' ].join('')); // add events $a.on('click', function( e ){ e.preventDefault(); var $div = $(this).closest('.media-modal'); if( $div.hasClass('acf-expanded') ) { $div.removeClass('acf-expanded'); } else { $div.addClass('acf-expanded'); } }); // append this.$el.append( $a ); }, initialize: function(){ // initialize Parent.prototype.initialize.apply( this, arguments ); // add buttons this.addExpand(); // return return this; } }); }, customizeAttachmentFilters: function(){ // validate if( !acf.isset(wp, 'media', 'view', 'AttachmentFilters', 'All') ) { return; } // vars var Parent = wp.media.view.AttachmentFilters.All; // renderFilters // copied from media-views.js:6939 Parent.prototype.renderFilters = function(){ // Build `' ).val( value ).html( filter.text )[0], priority: filter.priority || 50 }; }, this ).sortBy('priority').pluck('el').value() ); }; }, customizeAttachmentCompat: function(){ // validate if( !acf.isset(wp, 'media', 'view', 'AttachmentCompat') ) { return; } // vars var AttachmentCompat = wp.media.view.AttachmentCompat; var timeout = false; // extend wp.media.view.AttachmentCompat = AttachmentCompat.extend({ render: function() { // WP bug // When multiple media frames exist on the same page (WP content, WYSIWYG, image, file ), // WP creates multiple instances of this AttachmentCompat view. // Each instance will attempt to render when a new modal is created. // Use a property to avoid this and only render once per instance. if( this.rendered ) { return this; } // render HTML AttachmentCompat.prototype.render.apply( this, arguments ); // when uploading, render is called twice. // ignore first render by checking for #acf-form-data element if( !this.$('#acf-form-data').length ) { return this; } // clear timeout clearTimeout( timeout ); // setTimeout timeout = setTimeout($.proxy(function(){ this.rendered = true; acf.doAction('append', this.$el); }, this), 50); // return return this; } }); }, customizeAttachmentLibrary: function(){ // validate if( !acf.isset(wp, 'media', 'view', 'Attachment', 'Library') ) { return; } // vars var AttachmentLibrary = wp.media.view.Attachment.Library; // extend wp.media.view.Attachment.Library = AttachmentLibrary.extend({ render: function() { // vars var popup = acf.isget(this, 'controller', 'acf'); var attributes = acf.isget(this, 'model', 'attributes'); // check vars exist to avoid errors if( popup && attributes ) { // show errors if( attributes.acf_errors ) { this.$el.addClass('acf-disabled'); } // disable selected var selected = popup.get('selected'); if( selected && selected.indexOf(attributes.id) > -1 ) { this.$el.addClass('acf-selected'); } } // render return AttachmentLibrary.prototype.render.apply( this, arguments ); }, /* * toggleSelection * * This function is called before an attachment is selected * A good place to check for errors and prevent the 'select' function from being fired * * @type function * @date 29/09/2016 * @since 5.4.0 * * @param options (object) * @return n/a */ toggleSelection: function( options ) { // vars // source: wp-includes/js/media-views.js:2880 var collection = this.collection, selection = this.options.selection, model = this.model, single = selection.single(); // vars var frame = this.controller; var errors = acf.isget(this, 'model', 'attributes', 'acf_errors'); var $sidebar = frame.$el.find('.media-frame-content .media-sidebar'); // remove previous error $sidebar.children('.acf-selection-error').remove(); // show attachment details $sidebar.children().removeClass('acf-hidden'); // add message if( frame && errors ) { // vars var filename = acf.isget(this, 'model', 'attributes', 'filename'); // hide attachment details // Gallery field continues to show previously selected attachment... $sidebar.children().addClass('acf-hidden'); // append message $sidebar.prepend([ '
    ', '' + acf.__('Restricted') +'', '' + filename + '', '' + errors + '', '
    ' ].join('')); // reset selection (unselects all attachments) selection.reset(); // set single (attachment displayed in sidebar) selection.single( model ); // return and prevent 'select' form being fired return; } // return return AttachmentLibrary.prototype.toggleSelection.apply( this, arguments ); } }); } }); })(jQuery); (function($, undefined){ acf.screen = new acf.Model({ active: true, xhr: false, timeout: false, wait: 'load', events: { 'change #page_template': 'onChange', 'change #parent_id': 'onChange', 'change #post-formats-select': 'onChange', 'change .categorychecklist': 'onChange', 'change .tagsdiv': 'onChange', 'change .acf-taxonomy-field[data-save="1"]': 'onChange', 'change #product-type': 'onChange' }, initialize: function(){ }, /* checkScreenEvents: function(){ // vars var events = [ 'change #page_template', 'change #parent_id', 'change #post-formats-select input', 'change .categorychecklist input', 'change .categorychecklist select', 'change .acf-taxonomy-field[data-save="1"] input', 'change .acf-taxonomy-field[data-save="1"] select', 'change #product-type' ]; acf.screen.on('change', '#product-type', 'fetch'); }, */ isPost: function(){ return acf.get('screen') === 'post'; }, isUser: function(){ return acf.get('screen') === 'user'; }, isTaxonomy: function(){ return acf.get('screen') === 'taxonomy'; }, isAttachment: function(){ return acf.get('screen') === 'attachment'; }, isNavMenu: function(){ return acf.get('screen') === 'nav_menu'; }, isWidget: function(){ return acf.get('screen') === 'widget'; }, isComment: function(){ return acf.get('screen') === 'comment'; }, getPageTemplate: function(){ var $el = $('#page_template'); return $el.length ? $el.val() : null; }, getPageParent: function( e, $el ){ var $el = $('#parent_id'); return $el.length ? $el.val() : null; }, getPageType: function( e, $el ){ return this.getPageParent() ? 'child' : 'parent'; }, getPostFormat: function( e, $el ){ var $el = $('#post-formats-select input:checked'); if( $el.length ) { var val = $el.val(); return (val == '0') ? 'standard' : val; } return null; }, getPostTerms: function(){ // vars var terms = {}; // serialize WP taxonomy postboxes var data = acf.serialize( $('.categorydiv, .tagsdiv') ); // use tax_input (tag, custom-taxonomy) when possible. // this data is already formatted in taxonomy => [terms]. if( data.tax_input ) { terms = data.tax_input; } // append "category" which uses a different name if( data.post_category ) { terms.category = data.post_category; } // convert any string values (tags) into array format for( var tax in terms ) { if( !acf.isArray(terms[tax]) ) { terms[tax] = terms[tax].split(', '); } } // loop over taxonomy fields and add their values acf.getFields({type: 'taxonomy'}).map(function( field ){ // ignore fields that don't save if( !field.get('save') ) { return; } // vars var val = field.val(); var tax = field.get('taxonomy'); // check val if( val ) { // ensure terms exists terms[ tax ] = terms[ tax ] || []; // ensure val is an array val = acf.isArray(val) ? val : [val]; // append terms[ tax ] = terms[ tax ].concat( val ); } }); // add WC product type if( (productType = this.getProductType()) !== null ) { terms.product_type = [productType]; } // remove duplicate values for( var tax in terms ) { terms[tax] = acf.uniqueArray(terms[tax]); } // return return terms; }, getProductType: function(){ var $el = $('#product-type'); return $el.length ? $el.val() : null; }, check: function(){ // bail early if not for post if( acf.get('screen') !== 'post' ) { return; } // abort XHR if is already loading AJAX data if( this.xhr ) { this.xhr.abort(); } // vars var ajaxData = acf.parseArgs(this.data, { action: 'acf/ajax/check_screen', screen: acf.get('screen'), exists: [] }); // post id if( this.isPost() ) { ajaxData.post_id = acf.get('post_id'); } // page template if( (pageTemplate = this.getPageTemplate()) !== null ) { ajaxData.page_template = pageTemplate; } // page parent if( (pageParent = this.getPageParent()) !== null ) { ajaxData.page_parent = pageParent; } // page type if( (pageType = this.getPageType()) !== null ) { ajaxData.page_type = pageType; } // post format if( (postFormat = this.getPostFormat()) !== null ) { ajaxData.post_format = postFormat; } // post terms if( (postTerms = this.getPostTerms()) !== null ) { ajaxData.post_terms = postTerms; } // add array of existing postboxes to increase performance and reduce JSON HTML acf.getPostboxes().map(function( postbox ){ if( postbox.hasHTML() ) { ajaxData.exists.push( postbox.get('key') ); } }); // filter ajaxData = acf.applyFilters('check_screen_args', ajaxData); // success var onSuccess = function( json ){ // bail early if not success if( !acf.isAjaxSuccess(json) ) { return; } // vars var visible = []; // loop json.data.results.map(function( fieldGroup, i ){ // vars var id = 'acf-' + fieldGroup.key; var postbox = acf.getPostbox( id ); // show postbox postbox.showEnable(); // append visible.push( id ); // update HTML if( !postbox.hasHTML() && fieldGroup.html ) { postbox.html( fieldGroup.html ); } }); // hide other postboxes acf.getPostboxes().map(function( postbox ){ if( visible.indexOf( postbox.get('id') ) === -1 ) { postbox.hideDisable(); } }); // reset style $('#acf-style').html( json.data.style ); // action acf.doAction('check_screen_complete', json.data, ajaxData); }; // ajax this.xhr = $.ajax({ url: acf.get('ajaxurl'), data: acf.prepareForAjax( ajaxData ), type: 'post', dataType: 'json', context: this, success: onSuccess }); }, onChange: function( e, $el ){ this.setTimeout(this.check, 1); } }); /* // tests acf.registerScreenChange('#page_template', function( e, $el ){ return $('#page_template').val(); }); acf.registerScreenData({ name: 'page_template', change: '#page_template', val: function(){ var $input = $(this.el); return $input.length ? $input.val() : null; } }); acf.registerScreenData({ name: 'post_terms', change: '.acf-taxonomy-field[data-save="1"]', val: function(){ var $input = $(this.el); return $input.length ? $input.val() : null; } }); acf.registerScreenData({ name: 'post_terms', change: '#product-type', val: function( terms ){ var $select = $('#product-type'); if( $select.length ) { terms.push('product_cat:'+$select.val()); } return terms; } }); acf.screen.get('post_terms'); acf.screen.getPostTerms(); */ })(jQuery); (function($, undefined){ /** * acf.newSelect2 * * description * * @date 13/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ acf.newSelect2 = function( $select, props ){ // defaults props = acf.parseArgs(props, { allowNull: false, placeholder: '', multiple: false, field: false, ajax: false, ajaxAction: '', ajaxData: function( data ){ return data; }, ajaxResults: function( json ){ return json; }, }); // initialize if( getVersion() == 4 ) { var select2 = new Select2_4( $select, props ); } else { var select2 = new Select2_3( $select, props ); } // actions acf.doAction('new_select2', select2); // return return select2; }; /** * getVersion * * description * * @date 13/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ function getVersion() { // v4 if( acf.isset(window, 'jQuery', 'fn', 'select2', 'amd') ) { return 4; } // v3 if( acf.isset(window, 'Select2') ) { return 3; } // return return false; } /** * Select2 * * description * * @date 13/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var Select2 = acf.Model.extend({ setup: function( $select, props ){ $.extend(this.data, props); this.$el = $select; }, initialize: function(){ }, selectOption: function( value ){ var $option = this.getOption( value ); if( !$option.prop('selected') ) { $option.prop('selected', true).trigger('change'); } }, unselectOption: function( value ){ var $option = this.getOption( value ); if( $option.prop('selected') ) { $option.prop('selected', false).trigger('change'); } }, getOption: function( value ){ return this.$('option[value="' + value + '"]'); }, addOption: function( option ){ // defaults option = acf.parseArgs(option, { id: '', text: '', selected: false }); // vars var $option = this.getOption( option.id ); // append if( !$option.length ) { $option = $(''); $option.html( option.text ); $option.attr('value', option.id); $option.prop('selected', option.selected); this.$el.append($option); } // chain return $option; }, getValue: function(){ // vars var val = []; var $options = this.$el.find('option:selected'); // bail early if no selected if( !$options.exists() ) { return val; } // sort by attribute $options = $options.sort(function(a, b) { return +a.getAttribute('data-i') - +b.getAttribute('data-i'); }); // loop $options.each(function(){ var $el = $(this); val.push({ $el: $el, id: $el.attr('value'), text: $el.text(), }); }); // return return val; }, mergeOptions: function(){ }, getChoices: function(){ // callback var crawl = function( $parent ){ // vars var choices = []; // loop $parent.children().each(function(){ // vars var $child = $(this); // optgroup if( $child.is('optgroup') ) { choices.push({ text: $child.attr('label'), children: crawl( $child ) }); // option } else { choices.push({ id: $child.attr('value'), text: $child.text() }); } }); // return return choices; }; // crawl return crawl( this.$el ); }, decodeChoices: function( choices ){ // callback var crawl = function( items ){ items.map(function( item ){ item.text = acf.decode( item.text ); if( item.children ) { item.children = crawl( item.children ); } return item; }); return items; }; // crawl return crawl( choices ); }, getAjaxData: function( params ){ // vars var ajaxData = { action: this.get('ajaxAction'), s: params.term || '', paged: params.page || 1 }; // field helper var field = this.get('field'); if( field ) { ajaxData.field_key = field.get('key'); } // callback var callback = this.get('ajaxData'); if( callback ) { ajaxData = callback.apply( this, [ajaxData, params] ); } // filter ajaxData = acf.applyFilters( 'select2_ajax_data', ajaxData, this.data, this.$el, (field || false), this ); // return return acf.prepareForAjax(ajaxData); }, getAjaxResults: function( json, params ){ // defaults json = acf.parseArgs(json, { results: false, more: false, }); // decode if( json.results ) { json.results = this.decodeChoices(json.results); } // callback var callback = this.get('ajaxResults'); if( callback ) { json = callback.apply( this, [json, params] ); } // filter json = acf.applyFilters( 'select2_ajax_results', json, params, this ); // return return json; }, processAjaxResults: function( json, params ){ // vars var json = this.getAjaxResults( json, params ); // change more to pagination if( json.more ) { json.pagination = { more: true }; } // merge together groups setTimeout($.proxy(this.mergeOptions, this), 1); // return return json; }, destroy: function(){ // destroy via api if( this.$el.data('select2') ) { this.$el.select2('destroy'); } // destory via HTML (duplicating HTML does not contain data) this.$el.siblings('.select2-container').remove(); } }); /** * Select2_4 * * description * * @date 13/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var Select2_4 = Select2.extend({ initialize: function(){ // vars var $select = this.$el; var options = { width: '100%', allowClear: this.get('allowNull'), placeholder: this.get('placeholder'), multiple: this.get('multiple'), data: [], escapeMarkup: function( m ){ return m; } }; // multiple if( options.multiple ) { // reorder options this.getValue().map(function( item ){ item.$el.detach().appendTo( $select ); }); } // remove conflicting atts $select.removeData('ajax'); $select.removeAttr('data-ajax'); // ajax if( this.get('ajax') ) { options.ajax = { url: acf.get('ajaxurl'), delay: 250, dataType: 'json', type: 'post', cache: false, data: $.proxy(this.getAjaxData, this), processResults: $.proxy(this.processAjaxResults, this), }; } // filter for 3rd party customization //options = acf.applyFilters( 'select2_args', options, $select, this ); var field = this.get('field'); options = acf.applyFilters( 'select2_args', options, $select, this.data, (field || false), this ); // add select2 $select.select2( options ); // get container (Select2 v4 does not return this from constructor) var $container = $select.next('.select2-container'); // multiple if( options.multiple ) { // vars var $ul = $container.find('ul'); // sortable $ul.sortable({ stop: function( e ) { // loop $ul.find('.select2-selection__choice').each(function() { // vars var $option = $( $(this).data('data').element ); // detach and re-append to end $option.detach().appendTo( $select ); }); // trigger change on input (JS error if trigger on select) $select.trigger('change'); } }); // on select, move to end $select.on('select2:select', this.proxy(function( e ){ this.getOption( e.params.data.id ).detach().appendTo( this.$el ); })); } // add class $container.addClass('-acf'); // action for 3rd party customization acf.doAction('select2_init', $select, options, this.data, (field || false), this); }, mergeOptions: function(){ // vars var $prevOptions = false; var $prevGroup = false; // loop $('.select2-results__option[role="group"]').each(function(){ // vars var $options = $(this).children('ul'); var $group = $(this).children('strong'); // compare to previous if( $prevGroup && $prevGroup.text() === $group.text() ) { $prevOptions.append( $options.children() ); $(this).remove(); return; } // update vars $prevOptions = $options; $prevGroup = $group; }); }, }); /** * Select2_3 * * description * * @date 13/1/18 * @since 5.6.5 * * @param type $var Description. Default. * @return type Description. */ var Select2_3 = Select2.extend({ initialize: function(){ // vars var $select = this.$el; var value = this.getValue(); var multiple = this.get('multiple'); var options = { width: '100%', allowClear: this.get('allowNull'), placeholder: this.get('placeholder'), separator: '||', multiple: this.get('multiple'), data: this.getChoices(), escapeMarkup: function( m ){ return m; }, dropdownCss: { 'z-index': '999999999' }, initSelection: function( element, callback ) { if( multiple ) { callback( value ); } else { callback( value.shift() ); } } }; // get hidden input var $input = $select.siblings('input'); if( !$input.length ) { $input = $(''); $select.before( $input ); } // set input value inputValue = value.map(function(item){ return item.id }).join('||'); $input.val( inputValue ); // multiple if( options.multiple ) { // reorder options value.map(function( item ){ item.$el.detach().appendTo( $select ); }); } // remove blank option as we have a clear all button if( options.allowClear ) { options.data = options.data.filter(function(item){ return item.id !== ''; }); } // remove conflicting atts $select.removeData('ajax'); $select.removeAttr('data-ajax'); // ajax if( this.get('ajax') ) { options.ajax = { url: acf.get('ajaxurl'), quietMillis: 250, dataType: 'json', type: 'post', cache: false, data: $.proxy(this.getAjaxData, this), results: $.proxy(this.processAjaxResults, this), }; } // filter for 3rd party customization var field = this.get('field'); options = acf.applyFilters( 'select2_args', options, $select, this.data, (field || false), this ); // add select2 $input.select2( options ); // get container var $container = $input.select2('container'); // helper to find this select's option var getOption = $.proxy(this.getOption, this); // multiple if( options.multiple ) { // vars var $ul = $container.find('ul'); // sortable $ul.sortable({ stop: function() { // loop $ul.find('.select2-search-choice').each(function() { // vars var data = $(this).data('select2Data'); var $option = getOption( data.id ); // detach and re-append to end $option.detach().appendTo( $select ); }); // trigger change on input (JS error if trigger on select) $select.trigger('change'); } }); } // on select, create option and move to end $input.on('select2-selecting', function( e ){ // vars var item = e.choice; var $option = getOption( item.id ); // create if doesn't exist if( !$option.length ) { $option = $(''); } // detach and re-append to end $option.detach().appendTo( $select ); }); // add class $container.addClass('-acf'); // action for 3rd party customization acf.doAction('select2_init', $select, options, this.data, (field || false), this); // change $input.on('change', function(){ var val = $input.val(); if( val.indexOf('||') ) { val = val.split('||'); } $select.val( val ).trigger('change'); }); // hide select $select.hide(); }, mergeOptions: function(){ // vars var $prevOptions = false; var $prevGroup = false; // loop $('#select2-drop .select2-result-with-children').each(function(){ // vars var $options = $(this).children('ul'); var $group = $(this).children('.select2-result-label'); // compare to previous if( $prevGroup && $prevGroup.text() === $group.text() ) { $prevGroup.append( $options.children() ); $(this).remove(); return; } // update vars $prevOptions = $options; $prevGroup = $group; }); }, getAjaxData: function( term, page ){ // create Select2 v4 params var params = { term: term, page: page } // return return Select2.prototype.getAjaxData.apply(this, [params]); }, }); // manager var select2Manager = new acf.Model({ priority: 5, wait: 'prepare', initialize: function(){ // vars var locale = acf.get('locale'); var rtl = acf.get('rtl'); var l10n = acf.get('select2L10n'); var version = getVersion(); // bail ealry if no l10n if( !l10n ) { return false; } // bail early if 'en' if( locale.indexOf('en') === 0 ) { return false; } // initialize if( version == 4 ) { this.addTranslations4(); } else if( version == 3 ) { this.addTranslations3(); } }, addTranslations4: function(){ // vars var l10n = acf.get('select2L10n'); var locale = acf.get('locale'); // modify local to match html[lang] attribute (used by Select2) locale = locale.replace('_', '-'); // select2L10n var select2L10n = { errorLoading: function () { return l10n.load_fail; }, inputTooLong: function (args) { var overChars = args.input.length - args.maximum; if( overChars > 1 ) { return l10n.input_too_long_n.replace( '%d', overChars ); } return l10n.input_too_long_1; }, inputTooShort: function( args ){ var remainingChars = args.minimum - args.input.length; if( remainingChars > 1 ) { return l10n.input_too_short_n.replace( '%d', remainingChars ); } return l10n.input_too_short_1; }, loadingMore: function () { return l10n.load_more; }, maximumSelected: function( args ) { var maximum = args.maximum; if( maximum > 1 ) { return l10n.selection_too_long_n.replace( '%d', maximum ); } return l10n.selection_too_long_1; }, noResults: function () { return l10n.matches_0; }, searching: function () { return l10n.searching; } }; // append jQuery.fn.select2.amd.define('select2/i18n/' + locale, [], function(){ return select2L10n; }); }, addTranslations3: function(){ // vars var l10n = acf.get('select2L10n'); var locale = acf.get('locale'); // modify local to match html[lang] attribute (used by Select2) locale = locale.replace('_', '-'); // select2L10n var select2L10n = { formatMatches: function( matches ) { if( matches > 1 ) { return l10n.matches_n.replace( '%d', matches ); } return l10n.matches_1; }, formatNoMatches: function() { return l10n.matches_0; }, formatAjaxError: function() { return l10n.load_fail; }, formatInputTooShort: function( input, min ) { var remainingChars = min - input.length; if( remainingChars > 1 ) { return l10n.input_too_short_n.replace( '%d', remainingChars ); } return l10n.input_too_short_1; }, formatInputTooLong: function( input, max ) { var overChars = input.length - max; if( overChars > 1 ) { return l10n.input_too_long_n.replace( '%d', overChars ); } return l10n.input_too_long_1; }, formatSelectionTooBig: function( maximum ) { if( maximum > 1 ) { return l10n.selection_too_long_n.replace( '%d', maximum ); } return l10n.selection_too_long_1; }, formatLoadMore: function() { return l10n.load_more; }, formatSearching: function() { return l10n.searching; } }; // ensure locales exists $.fn.select2.locales = $.fn.select2.locales || {}; // append $.fn.select2.locales[ locale ] = select2L10n; $.extend($.fn.select2.defaults, select2L10n); } }); })(jQuery); (function($, undefined){ acf.tinymce = { /* * defaults * * This function will return default mce and qt settings * * @type function * @date 18/8/17 * @since 5.6.0 * * @param $post_id (int) * @return $post_id (int) */ defaults: function(){ // bail early if no tinyMCEPreInit if( typeof tinyMCEPreInit === 'undefined' ) return false; // vars var defaults = { tinymce: tinyMCEPreInit.mceInit.acf_content, quicktags: tinyMCEPreInit.qtInit.acf_content }; // return return defaults; }, /* * initialize * * This function will initialize the tinymce and quicktags instances * * @type function * @date 18/8/17 * @since 5.6.0 * * @param $post_id (int) * @return $post_id (int) */ initialize: function( id, args ){ // defaults args = acf.parseArgs(args, { tinymce: true, quicktags: true, toolbar: 'full', mode: 'visual', // visual,text field: false }); // tinymce if( args.tinymce ) { this.initializeTinymce( id, args ); } // quicktags if( args.quicktags ) { this.initializeQuicktags( id, args ); } }, /* * initializeTinymce * * This function will initialize the tinymce instance * * @type function * @date 18/8/17 * @since 5.6.0 * * @param $post_id (int) * @return $post_id (int) */ initializeTinymce: function( id, args ){ // vars var $textarea = $('#'+id); var defaults = this.defaults(); var toolbars = acf.get('toolbars'); var field = args.field || false; var $field = field.$el || false; // bail early if( typeof tinymce === 'undefined' ) return false; if( !defaults ) return false; // check if exists if( tinymce.get(id) ) { return this.enable( id ); } // settings var init = $.extend( {}, defaults.tinymce, args.tinymce ); init.id = id; init.selector = '#' + id; // toolbar var toolbar = args.toolbar; if( toolbar && toolbars && toolbars[toolbar] ) { for( var i = 1; i <= 4; i++ ) { init[ 'toolbar' + i ] = toolbars[toolbar][i] || ''; } } // event init.setup = function( ed ){ ed.on('change', function(e) { ed.save(); // save to textarea $textarea.trigger('change'); }); $( ed.getWin() ).on('unload', function() { acf.tinymce.remove( id ); }); }; // disable wp_autoresize_on (no solution yet for fixed toolbar) init.wp_autoresize_on = false; // hook for 3rd party customization init = acf.applyFilters('wysiwyg_tinymce_settings', init, id, field); // z-index fix (caused too many conflicts) //if( acf.isset(tinymce,'ui','FloatPanel') ) { // tinymce.ui.FloatPanel.zIndex = 900000; //} // store settings tinyMCEPreInit.mceInit[ id ] = init; // visual tab is active if( args.mode == 'visual' ) { // init var result = tinymce.init( init ); // get editor var ed = tinymce.get( id ); // validate if( !ed ) { return false; } // add reference ed.acf = args.field; // action acf.doAction('wysiwyg_tinymce_init', ed, ed.id, init, field); } }, /* * initializeQuicktags * * This function will initialize the quicktags instance * * @type function * @date 18/8/17 * @since 5.6.0 * * @param $post_id (int) * @return $post_id (int) */ initializeQuicktags: function( id, args ){ // vars var defaults = this.defaults(); // bail early if( typeof quicktags === 'undefined' ) return false; if( !defaults ) return false; // settings var init = $.extend( {}, defaults.quicktags, args.quicktags ); init.id = id; // filter var field = args.field || false; var $field = field.$el || false; init = acf.applyFilters('wysiwyg_quicktags_settings', init, init.id, field); // store settings tinyMCEPreInit.qtInit[ id ] = init; // init var ed = quicktags( init ); // validate if( !ed ) { return false; } // generate HTML this.buildQuicktags( ed ); // action for 3rd party customization acf.doAction('wysiwyg_quicktags_init', ed, ed.id, init, field); }, /* * buildQuicktags * * This function will build the quicktags HTML * * @type function * @date 18/8/17 * @since 5.6.0 * * @param $post_id (int) * @return $post_id (int) */ buildQuicktags: function( ed ){ var canvas, name, settings, theButtons, html, ed, id, i, use, instanceId, defaults = ',strong,em,link,block,del,ins,img,ul,ol,li,code,more,close,'; canvas = ed.canvas; name = ed.name; settings = ed.settings; html = ''; theButtons = {}; use = ''; instanceId = ed.id; // set buttons if ( settings.buttons ) { use = ','+settings.buttons+','; } for ( i in edButtons ) { if ( ! edButtons[i] ) { continue; } id = edButtons[i].id; if ( use && defaults.indexOf( ',' + id + ',' ) !== -1 && use.indexOf( ',' + id + ',' ) === -1 ) { continue; } if ( ! edButtons[i].instance || edButtons[i].instance === instanceId ) { theButtons[id] = edButtons[i]; if ( edButtons[i].html ) { html += edButtons[i].html( name + '_' ); } } } if ( use && use.indexOf(',dfw,') !== -1 ) { theButtons.dfw = new QTags.DFWButton(); html += theButtons.dfw.html( name + '_' ); } if ( 'rtl' === document.getElementsByTagName( 'html' )[0].dir ) { theButtons.textdirection = new QTags.TextDirectionButton(); html += theButtons.textdirection.html( name + '_' ); } ed.toolbar.innerHTML = html; ed.theButtons = theButtons; if ( typeof jQuery !== 'undefined' ) { jQuery( document ).triggerHandler( 'quicktags-init', [ ed ] ); } }, disable: function( id ){ this.destroyTinymce( id ); }, remove: function( id ){ this.destroyTinymce( id ); }, destroy: function( id ){ this.destroyTinymce( id ); }, destroyTinymce: function( id ){ // bail early if( typeof tinymce === 'undefined' ) return false; // get editor var ed = tinymce.get( id ); // bail early if no editor if( !ed ) return false; // save ed.save(); // destroy editor ed.destroy(); // return return true; }, enable: function( id ){ this.enableTinymce( id ); }, enableTinymce: function( id ){ // bail early if( typeof switchEditors === 'undefined' ) return false; // bail ealry if not initialized if( typeof tinyMCEPreInit.mceInit[ id ] === 'undefined' ) return false; // toggle switchEditors.go( id, 'tmce'); // return return true; } }; var editorManager = new acf.Model({ // hook in before fieldsEventManager, conditions, etc priority: 5, actions: { 'prepare': 'onPrepare', 'ready': 'onReady', }, onPrepare: function(){ // find hidden editor which may exist within a field var $div = $('#acf-hidden-wp-editor'); // move to footer if( $div.exists() ) { $div.appendTo('body'); } }, onReady: function(){ // bail early if no tinymce if( !acf.isset(window,'tinymce','on') ) return; // restore default activeEditor tinymce.on('AddEditor', function( data ){ // vars var editor = data.editor; // bail early if not 'acf' if( editor.id.substr(0, 3) !== 'acf' ) return; // override if 'content' exists editor = tinymce.editors.content || editor; // update vars tinymce.activeEditor = editor; wpActiveEditor = editor.id; }); } }); })(jQuery); (function($, undefined){ /** * Validator * * The model for validating forms * * @date 4/9/18 * @since 5.7.5 * * @param void * @return void */ var Validator = acf.Model.extend({ /** @var string The model identifier. */ id: 'Validator', /** @var object The model data. */ data: { /** @var array The form errors. */ errors: [], /** @var object The form notice. */ notice: null, /** @var string The form status. loading, invalid, valid */ status: '' }, /** @var object The model events. */ events: { 'changed:status': 'onChangeStatus' }, /** * addErrors * * Adds errors to the form. * * @date 4/9/18 * @since 5.7.5 * * @param array errors An array of errors. * @return void */ addErrors: function( errors ){ errors.map( this.addError, this ); }, /** * addError * * Adds and error to the form. * * @date 4/9/18 * @since 5.7.5 * * @param object error An error object containing input and message. * @return void */ addError: function( error ){ this.data.errors.push( error ); }, /** * hasErrors * * Returns true if the form has errors. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return bool */ hasErrors: function(){ return this.data.errors.length; }, /** * clearErrors * * Removes any errors. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return void */ clearErrors: function(){ return this.data.errors = []; }, /** * getErrors * * Returns the forms errors. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return array */ getErrors: function(){ return this.data.errors; }, /** * getFieldErrors * * Returns the forms field errors. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return array */ getFieldErrors: function(){ // vars var errors = []; var inputs = []; // loop this.getErrors().map(function(error){ // bail early if global if( !error.input ) return; // update if exists var i = inputs.indexOf(error.input); if( i > -1 ) { errors[ i ] = error; // update } else { errors.push( error ); inputs.push( error.input ); } }); // return return errors; }, /** * getGlobalErrors * * Returns the forms global errors (errors without a specific input). * * @date 4/9/18 * @since 5.7.5 * * @param void * @return array */ getGlobalErrors: function(){ // return array of errors that contain no input return this.getErrors().filter(function(error){ return !error.input; }); }, /** * showErrors * * Displays all errors for this form. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return void */ showErrors: function(){ // bail early if no errors if( !this.hasErrors() ) { return; } // vars var fieldErrors = this.getFieldErrors(); var globalErrors = this.getGlobalErrors(); // vars var errorCount = 0; var $scrollTo = false; // loop fieldErrors.map(function( error ){ // get input var $input = this.$('[name="' + error.input + '"]').first(); // if $_POST value was an array, this $input may not exist if( !$input.length ) { $input = this.$('[name^="' + error.input + '"]').first(); } // bail early if input doesn't exist if( !$input.length ) { return; } // increase errorCount++; // get field var field = acf.getClosestField( $input ); // show error field.showError( error.message ); // set $scrollTo if( !$scrollTo ) { $scrollTo = field.$el; } }, this); // errorMessage var errorMessage = acf.__('Validation failed'); globalErrors.map(function( error ){ errorMessage += '. ' + error.message; }); if( errorCount == 1 ) { errorMessage += '. ' + acf.__('1 field requires attention'); } else if( errorCount > 1 ) { errorMessage += '. ' + acf.__('%d fields require attention').replace('%d', errorCount); } // notice if( this.has('notice') ) { this.get('notice').update({ type: 'error', text: errorMessage }); } else { var notice = acf.newNotice({ type: 'error', text: errorMessage, target: this.$el }); this.set('notice', notice); } // if no $scrollTo, set to message if( !$scrollTo ) { $scrollTo = this.get('notice').$el; } // timeout setTimeout(function(){ $("html, body").animate({ scrollTop: $scrollTo.offset().top - ( $(window).height() / 2 ) }, 500); }, 10); }, /** * onChangeStatus * * Update the form class when changing the 'status' data * * @date 4/9/18 * @since 5.7.5 * * @param object e The event object. * @param jQuery $el The form element. * @param string value The new status. * @param string prevValue The old status. * @return void */ onChangeStatus: function( e, $el, value, prevValue ){ this.$el.removeClass('is-'+prevValue).addClass('is-'+value); }, /** * validate * * Vaildates the form via AJAX. * * @date 4/9/18 * @since 5.7.5 * * @param object args A list of settings to customize the validation process. * @return bool True if the form is valid. */ validate: function( args ){ // default args args = acf.parseArgs(args, { // trigger event event: false, // reset the form after submit reset: false, // loading callback loading: function(){}, // complete callback complete: function(){}, // failure callback failure: function(){}, // success callback success: function( $form ){ $form.submit(); } }); // return true if is valid - allows form submit if( this.get('status') == 'valid' ) { return true; } // return false if is currently validating - prevents form submit if( this.get('status') == 'validating' ) { return false; } // return true if no ACF fields exist (no need to validate) if( !this.$('.acf-field').length ) { return true; } // if event is provided, create a new success callback. if( args.event ) { var event = $.Event(null, args.event); args.success = function(){ acf.enableSubmit( $(event.target) ).trigger( event ); } } // action for 3rd party acf.doAction('validation_begin', this.$el); // lock form acf.lockForm( this.$el ); // loading callback args.loading( this.$el ); // update status this.set('status', 'validating'); // success callback var onSuccess = function( json ){ // validate if( !acf.isAjaxSuccess(json) ) { return; } // filter var data = acf.applyFilters('validation_complete', json.data, this.$el); // add errors if( !data.valid ) { this.addErrors( data.errors ); } }; // complete var onComplete = function(){ // unlock form acf.unlockForm( this.$el ); // failure if( this.hasErrors() ) { // update status this.set('status', 'invalid'); // action acf.doAction('validation_failure', this.$el); // display errors this.showErrors(); // failure callback args.failure( this.$el ); // success } else { // update status this.set('status', 'valid'); // remove previous error message if( this.has('notice') ) { this.get('notice').update({ type: 'success', text: acf.__('Validation successful'), timeout: 1000 }); } // action acf.doAction('validation_success', this.$el); acf.doAction('submit', this.$el); // success callback (submit form) args.success( this.$el ); // lock form acf.lockForm( this.$el ); // reset if( args.reset ) { this.reset(); } } // complete callback args.complete( this.$el ); // clear errors this.clearErrors(); }; // serialize form data var data = acf.serialize( this.$el ); data.action = 'acf/validate_save_post'; // ajax $.ajax({ url: acf.get('ajaxurl'), data: acf.prepareForAjax(data), type: 'post', dataType: 'json', context: this, success: onSuccess, complete: onComplete }); }, /** * setup * * Called during the constructor function to setup this instance * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $form The form element. * @return void */ setup: function( $form ){ // set $el this.$el = $form; }, /** * reset * * Rests the validation to be used again. * * @date 6/9/18 * @since 5.7.5 * * @param void * @return void */ reset: function(){ // reset data this.set('errors', []); this.set('notice', null); this.set('status', ''); // unlock form acf.unlockForm( this.$el ); } }); /** * getValidator * * Returns the instance for a given form element. * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $el The form element. * @return object */ var getValidator = function( $el ){ // instantiate var validator = $el.data('acf'); if( !validator ) { validator = new Validator( $el ); } // return return validator; }; /** * acf.validateForm * * A helper function for the Validator.validate() function. * Returns true if form is valid, or fetches a validation request and returns false. * * @date 4/4/18 * @since 5.6.9 * * @param object args A list of settings to customize the validation process. * @return bool */ acf.validateForm = function( args ){ return getValidator( args.form ).validate( args ); }; /** * acf.enableSubmit * * Enables a submit button and returns the element. * * @date 30/8/18 * @since 5.7.4 * * @param jQuery $submit The submit button. * @return jQuery */ acf.enableSubmit = function( $submit ){ return $submit.removeClass('disabled'); }; /** * acf.disableSubmit * * Disables a submit button and returns the element. * * @date 30/8/18 * @since 5.7.4 * * @param jQuery $submit The submit button. * @return jQuery */ acf.disableSubmit = function( $submit ){ return $submit.addClass('disabled'); }; /** * acf.showSpinner * * Shows the spinner element. * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $spinner The spinner element. * @return jQuery */ acf.showSpinner = function( $spinner ){ $spinner.addClass('is-active'); // add class (WP > 4.2) $spinner.css('display', 'inline-block'); // css (WP < 4.2) return $spinner; }; /** * acf.hideSpinner * * Hides the spinner element. * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $spinner The spinner element. * @return jQuery */ acf.hideSpinner = function( $spinner ){ $spinner.removeClass('is-active'); // add class (WP > 4.2) $spinner.css('display', 'none'); // css (WP < 4.2) return $spinner; }; /** * acf.lockForm * * Locks a form by disabeling its primary inputs and showing a spinner. * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $form The form element. * @return jQuery */ acf.lockForm = function( $form ){ // vars var $wrap = findSubmitWrap( $form ); var $submit = $wrap.find('.button, [type="submit"]'); var $spinner = $wrap.find('.spinner, .acf-spinner'); // hide all spinners (hides the preview spinner) acf.hideSpinner( $spinner ); // lock acf.disableSubmit( $submit ); acf.showSpinner( $spinner.last() ); return $form; }; /** * acf.unlockForm * * Unlocks a form by enabeling its primary inputs and hiding all spinners. * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $form The form element. * @return jQuery */ acf.unlockForm = function( $form ){ // vars var $wrap = findSubmitWrap( $form ); var $submit = $wrap.find('.button, [type="submit"]'); var $spinner = $wrap.find('.spinner, .acf-spinner'); // unlock acf.enableSubmit( $submit ); acf.hideSpinner( $spinner ); return $form; }; /** * findSubmitWrap * * An internal function to find the 'primary' form submit wrapping element. * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $form The form element. * @return jQuery */ var findSubmitWrap = function( $form ){ // default post submit div var $wrap = $form.find('#submitdiv'); if( $wrap.length ) { return $wrap; } // 3rd party publish box var $wrap = $form.find('#submitpost'); if( $wrap.length ) { return $wrap; } // term, user var $wrap = $form.find('p.submit').last(); if( $wrap.length ) { return $wrap; } // front end form var $wrap = $form.find('.acf-form-submit'); if( $wrap.length ) { return $wrap; } // default return $form; }; /** * acf.validation * * Global validation logic * * @date 4/4/18 * @since 5.6.9 * * @param void * @return void */ acf.validation = new acf.Model({ /** @var string The model identifier. */ id: 'validation', /** @var bool The active state. Set to false before 'prepare' to prevent validation. */ active: true, /** @var string The model initialize time. */ wait: 'prepare', /** @var object The model actions. */ actions: { 'ready': 'addInputEvents', 'append': 'addInputEvents' }, /** @var object The model events. */ events: { 'click input[type="submit"]': 'onClickSubmit', 'click button[type="submit"]': 'onClickSubmit', 'click #save-post': 'onClickSave', 'mousedown #post-preview': 'onClickPreview', // use mousedown to hook in before WP click event 'submit form': 'onSubmit', }, /** * initialize * * Called when initializing the model. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return void */ initialize: function(){ // check 'validation' setting if( !acf.get('validation') ) { this.active = false; this.actions = {}; this.events = {}; } }, /** * enable * * Enables validation. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return void */ enable: function(){ this.active = true; }, /** * disable * * Disables validation. * * @date 4/9/18 * @since 5.7.5 * * @param void * @return void */ disable: function(){ this.active = false; }, /** * reset * * Rests the form validation to be used again * * @date 6/9/18 * @since 5.7.5 * * @param jQuery $form The form element. * @return void */ reset: function( $form ){ getValidator( $form ).reset(); }, /** * addInputEvents * * Adds 'invalid' event listeners to HTML inputs. * * @date 4/9/18 * @since 5.7.5 * * @param jQuery $el The element being added / readied. * @return void */ addInputEvents: function( $el ){ // vars var $inputs = $('.acf-field [name]', $el); // check if( $inputs.length ) { this.on( $inputs, 'invalid', 'onInvalid' ); } }, /** * onInvalid * * Callback for the 'invalid' event. * * @date 4/9/18 * @since 5.7.5 * * @param object e The event object. * @param jQuery $el The input element. * @return void */ onInvalid: function( e, $el ){ // prevent default // - prevents browser error message // - also fixes chrome bug where 'hidden-by-tab' field throws focus error e.preventDefault(); // vars var $form = $el.closest('form'); // check form exists if( $form.length ) { // add error to validator getValidator( $form ).addError({ input: $el.attr('name'), message: e.target.validationMessage }); // trigger submit on $form // - allows for "save", "preview" and "publish" to work $form.submit(); } }, /** * onClickSubmit * * Callback when clicking submit. * * @date 4/9/18 * @since 5.7.5 * * @param object e The event object. * @param jQuery $el The input element. * @return void */ onClickSubmit: function( e, $el ){ // store the "click event" for later use in this.onSubmit() this.set('originalEvent', e); }, /** * onClickSave * * Set ignore to true when saving a draft. * * @date 4/9/18 * @since 5.7.5 * * @param object e The event object. * @param jQuery $el The input element. * @return void */ onClickSave: function( e, $el ) { this.set('ignore', true); }, /** * onClickPreview * * Set ignore to true when previewing a post. * * @date 4/9/18 * @since 5.7.5 * * @param object e The event object. * @param jQuery $el The input element. * @return void */ onClickPreview: function( e, $el ) { this.set('ignore', true); // if post has previously been published but prevented by an error, WP core has // added a custom 'submit.edit-post' event which causes the input buttons to become disabled. // remove this event to prevent UX issues. $('form#post').off('submit.edit-post'); }, /** * onSubmit * * Callback when the form is submit. * * @date 4/9/18 * @since 5.7.5 * * @param object e The event object. * @param jQuery $el The input element. * @return void */ onSubmit: function( e, $el ){ // bail early if is disabled if( !this.active ) { return; } // bail early if is ignore if( this.get('ignore') ) { this.set('ignore', false); return; } // validate var valid = acf.validateForm({ form: $el, event: this.get('originalEvent') }); // if not valid, stop event and allow validation to continue if( !valid ) { e.preventDefault(); } } }); })(jQuery); (function($, undefined){ /** * refreshHelper * * description * * @date 1/7/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ var refreshHelper = new acf.Model({ priority: 90, timeout: 0, actions: { 'new_field': 'refresh', 'show_field': 'refresh', 'hide_field': 'refresh', 'remove_field': 'refresh' }, refresh: function(){ clearTimeout( this.timeout ); this.timeout = setTimeout(function(){ acf.doAction('refresh'); }, 0); } }); /** * sortableHelper * * Adds compatibility for sorting a element * * @date 6/3/18 * @since 5.6.9 * * @param void * @return void */ var sortableHelper = new acf.Model({ actions: { 'sortstart': 'onSortstart' }, onSortstart: function( $item, $placeholder ){ // if $item is a tr, apply some css to the elements if( $item.is('tr') ) { // temp set as relative to find widths $item.css('position', 'relative'); // set widths for td children $item.children().each(function(){ $(this).width($(this).width()); }); // revert position css $item.css('position', 'absolute'); // add markup to the placeholder $placeholder.html(''); } } }); /** * duplicateHelper * * Fixes browser bugs when duplicating an element * * @date 6/3/18 * @since 5.6.9 * * @param void * @return void */ var duplicateHelper = new acf.Model({ actions: { 'after_duplicate': 'onAfterDuplicate' }, onAfterDuplicate: function( $el, $el2 ){ // get original values var vals = []; $el.find('select').each(function(i){ vals.push( $(this).val() ); }); // set duplicate values $el2.find('select').each(function(i){ $(this).val( vals[i] ); }); } }); /** * tableHelper * * description * * @date 6/3/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ var tableHelper = new acf.Model({ id: 'tableHelper', priority: 20, actions: { 'refresh': 'renderTables' }, renderTables: function( $el ){ // loop var self = this; $('.acf-table:visible').each(function(){ self.renderTable( $(this) ); }); }, renderTable: function( $table ){ // vars var $ths = $table.find('> thead > tr:visible > th[data-key]'); var $tds = $table.find('> tbody > tr:visible > td[data-key]'); // bail early if no thead if( !$ths.length || !$tds.length ) { return false; } // visiblity $ths.each(function( i ){ // vars var $th = $(this); var key = $th.data('key'); var $cells = $tds.filter('[data-key="' + key + '"]'); var $hidden = $cells.filter('.acf-hidden'); // always remove empty and allow cells to be hidden $cells.removeClass('acf-empty'); // hide $th if all cells are hidden if( $cells.length === $hidden.length ) { acf.hide( $th ); // force all hidden cells to appear empty } else { acf.show( $th ); $hidden.addClass('acf-empty'); } }); // clear width $ths.css('width', 'auto'); // get visible $ths = $ths.not('.acf-hidden'); // vars var availableWidth = 100; var colspan = $ths.length; // set custom widths first var $fixedWidths = $ths.filter('[data-width]'); $fixedWidths.each(function(){ var width = $(this).data('width'); $(this).css('width', width + '%'); availableWidth -= width; }); // set auto widths var $auoWidths = $ths.not('[data-width]'); if( $auoWidths.length ) { var width = availableWidth / $auoWidths.length; $auoWidths.css('width', width + '%'); availableWidth = 0; } // avoid stretching issue if( availableWidth > 0 ) { $ths.last().css('width', 'auto'); } // update colspan on collapsed $tds.filter('.-collapsed-target').each(function(){ // vars var $td = $(this); // check if collapsed if( $td.parent().hasClass('-collapsed') ) { $td.attr('colspan', $ths.length); } else { $td.removeAttr('colspan'); } }); } }); /** * fieldsHelper * * description * * @date 6/3/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ var fieldsHelper = new acf.Model({ id: 'fieldsHelper', priority: 30, actions: { 'refresh': 'renderGroups' }, renderGroups: function(){ // loop var self = this; $('.acf-fields:visible').each(function(){ self.renderGroup( $(this) ); }); }, renderGroup: function( $el ){ // vars var top = 0; var height = 0; var $row = $(); // get fields var $fields = $el.children('.acf-field[data-width]:visible'); // bail early if no fields if( !$fields.length ) { return false; } // bail ealry if is .-left if( $el.hasClass('-left') ) { $fields.removeAttr('data-width'); $fields.css('width', 'auto'); return false; } // reset fields $fields.removeClass('-r0 -c0').css({'min-height': 0}); // loop $fields.each(function( i ){ // vars var $field = $(this); var position = $field.position(); var thisTop = Math.ceil( position.top ); var thisLeft = Math.ceil( position.left ); // detect change in row if( $row.length && thisTop > top ) { // set previous heights $row.css({'min-height': height+'px'}); // update position due to change in row above position = $field.position(); thisTop = Math.ceil( position.top ); thisLeft = Math.ceil( position.left ); // reset vars top = 0; height = 0; $row = $(); } // rtl if( acf.get('rtl') ) { thisLeft = Math.ceil( $field.parent().width() - (position.left + $field.outerWidth()) ); } // add classes if( thisTop == 0 ) { $field.addClass('-r0'); } else if( thisLeft == 0 ) { $field.addClass('-c0'); } // get height after class change // - add 1 for subpixel rendering var thisHeight = Math.ceil( $field.outerHeight() ) + 1; // set height height = Math.max( height, thisHeight ); // set y top = Math.max( top, thisTop ); // append $row = $row.add( $field ); }); // clean up if( $row.length ) { $row.css({'min-height': height+'px'}); } } }); })(jQuery); (function($, undefined){ /** * acf.newCompatibility * * Inserts a new __proto__ object compatibility layer * * @date 15/2/18 * @since 5.6.9 * * @param object instance The object to modify. * @param object compatibilty Optional. The compatibilty layer. * @return object compatibilty */ acf.newCompatibility = function( instance, compatibilty ){ // defaults compatibilty = compatibilty || {}; // inherit __proto_- compatibilty.__proto__ = instance.__proto__; // inject instance.__proto__ = compatibilty; // reference instance.compatibility = compatibilty; // return return compatibilty; }; /** * acf.getCompatibility * * Returns the compatibility layer for a given instance * * @date 13/3/18 * @since 5.6.9 * * @param object instance The object to look in. * @return object|null compatibility The compatibility object or null on failure. */ acf.getCompatibility = function( instance ) { return instance.compatibility || null; }; /** * acf (compatibility) * * Compatibility layer for the acf object * * @date 15/2/18 * @since 5.6.9 * * @param void * @return void */ var _acf = acf.newCompatibility(acf, { // storage l10n: {}, o: {}, fields: {}, // changed function names update: acf.set, add_action: acf.addAction, remove_action: acf.removeAction, do_action: acf.doAction, add_filter: acf.addFilter, remove_filter: acf.removeFilter, apply_filters: acf.applyFilters, parse_args: acf.parseArgs, disable_el: acf.disable, disable_form: acf.disable, enable_el: acf.enable, enable_form: acf.enable, update_user_setting: acf.updateUserSetting, prepare_for_ajax: acf.prepareForAjax, is_ajax_success: acf.isAjaxSuccess, remove_el: acf.remove, remove_tr: acf.remove, str_replace: acf.strReplace, render_select: acf.renderSelect, get_uniqid: acf.uniqid, serialize_form: acf.serialize, esc_html: acf.strEscape, str_sanitize: acf.strSanitize, }); _acf._e = function( k1, k2 ){ // defaults k1 = k1 || ''; k2 = k2 || ''; // compability var compatKey = k2 ? k1 + '.' + k2 : k1; var compats = { 'image.select': 'Select Image', 'image.edit': 'Edit Image', 'image.update': 'Update Image' }; if( compats[compatKey] ) { return acf.__(compats[compatKey]); } // try k1 var string = this.l10n[ k1 ] || ''; // try k2 if( k2 ) { string = string[ k2 ] || ''; } // return return string; }; _acf.get_selector = function( s ) { // vars var selector = '.acf-field'; // bail early if no search if( !s ) { return selector; } // compatibility with object if( $.isPlainObject(s) ) { if( $.isEmptyObject(s) ) { return selector; } else { for( var k in s ) { s = s[k]; break; } } } // append selector += '-' + s; // replace underscores (split/join replaces all and is faster than regex!) selector = acf.strReplace('_', '-', selector); // remove potential double up selector = acf.strReplace('field-field-', 'field-', selector); // return return selector; }; _acf.get_fields = function( s, $el, all ){ // args var args = { is: s || '', parent: $el || false, suppressFilters: all || false, }; // change 'field_123' to '.acf-field-123' if( args.is ) { args.is = this.get_selector( args.is ); } // return return acf.findFields(args); }; _acf.get_field = function( s, $el ){ // get fields var $fields = this.get_fields.apply(this, arguments); // return if( $fields.length ) { return $fields.first(); } else { return false; } }; _acf.get_closest_field = function( $el, s ){ return $el.closest( this.get_selector(s) ); }; _acf.get_field_wrap = function( $el ){ return $el.closest( this.get_selector() ); }; _acf.get_field_key = function( $field ){ return $field.data('key'); }; _acf.get_field_type = function( $field ){ return $field.data('type'); }; _acf.get_data = function( $el, defaults ){ return acf.parseArgs( $el.data(), defaults ); }; _acf.maybe_get = function( obj, key, value ){ // default if( value === undefined ) { value = null; } // get keys keys = String(key).split('.'); // acf.isget for( var i = 0; i < keys.length; i++ ) { if( !obj.hasOwnProperty(keys[i]) ) { return value; } obj = obj[ keys[i] ]; } return obj; }; /** * hooks * * Modify add_action and add_filter functions to add compatibility with changed $field parameter * Using the acf.add_action() or acf.add_filter() functions will interpret new field parameters as jQuery $field * * @date 12/5/18 * @since 5.6.9 * * @param void * @return void */ var compatibleArgument = function( arg ){ return ( arg instanceof acf.Field ) ? arg.$el : arg; }; var compatibleArguments = function( args ){ return acf.arrayArgs( args ).map( compatibleArgument ); } var compatibleCallback = function( origCallback ){ return function(){ // convert to compatible arguments if( arguments.length ) { var args = compatibleArguments(arguments); // add default argument for 'ready', 'append' and 'load' events } else { var args = [ $(document) ]; } // return return origCallback.apply(this, args); } } _acf.add_action = function( action, callback, priority, context ){ // handle multiple actions var actions = action.split(' '); var length = actions.length; if( length > 1 ) { for( var i = 0; i < length; i++) { action = actions[i]; _acf.add_action.apply(this, arguments); } return this; } // single var callback = compatibleCallback(callback); return acf.addAction.apply(this, arguments); }; _acf.add_filter = function( action, callback, priority, context ){ var callback = compatibleCallback(callback); return acf.addFilter.apply(this, arguments); }; /* * acf.model * * This model acts as a scafold for action.event driven modules * * @type object * @date 8/09/2014 * @since 5.0.0 * * @param (object) * @return (object) */ _acf.model = { actions: {}, filters: {}, events: {}, extend: function( args ){ // extend var model = $.extend( {}, this, args ); // setup actions $.each(model.actions, function( name, callback ){ model._add_action( name, callback ); }); // setup filters $.each(model.filters, function( name, callback ){ model._add_filter( name, callback ); }); // setup events $.each(model.events, function( name, callback ){ model._add_event( name, callback ); }); // return return model; }, _add_action: function( name, callback ) { // split var model = this, data = name.split(' '); // add missing priority var name = data[0] || '', priority = data[1] || 10; // add action acf.add_action(name, model[ callback ], priority, model); }, _add_filter: function( name, callback ) { // split var model = this, data = name.split(' '); // add missing priority var name = data[0] || '', priority = data[1] || 10; // add action acf.add_filter(name, model[ callback ], priority, model); }, _add_event: function( name, callback ) { // vars var model = this, i = name.indexOf(' '), event = (i > 0) ? name.substr(0,i) : name, selector = (i > 0) ? name.substr(i+1) : ''; // event var fn = function( e ){ // append $el to event object e.$el = $(this); // append $field to event object (used in field group) if( acf.field_group ) { e.$field = e.$el.closest('.acf-field-object'); } // event if( typeof model.event === 'function' ) { e = model.event( e ); } // callback model[ callback ].apply(model, arguments); }; // add event if( selector ) { $(document).on(event, selector, fn); } else { $(document).on(event, fn); } }, get: function( name, value ){ // defaults value = value || null; // get if( typeof this[ name ] !== 'undefined' ) { value = this[ name ]; } // return return value; }, set: function( name, value ){ // set this[ name ] = value; // function for 3rd party if( typeof this[ '_set_' + name ] === 'function' ) { this[ '_set_' + name ].apply(this); } // return for chaining return this; } }; /* * field * * This model sets up many of the field's interactions * * @type function * @date 21/02/2014 * @since 3.5.1 * * @param n/a * @return n/a */ _acf.field = acf.model.extend({ type: '', o: {}, $field: null, _add_action: function( name, callback ) { // vars var model = this; // update name name = name + '_field/type=' + model.type; // add action acf.add_action(name, function( $field ){ // focus model.set('$field', $field); // callback model[ callback ].apply(model, arguments); }); }, _add_filter: function( name, callback ) { // vars var model = this; // update name name = name + '_field/type=' + model.type; // add action acf.add_filter(name, function( $field ){ // focus model.set('$field', $field); // callback model[ callback ].apply(model, arguments); }); }, _add_event: function( name, callback ) { // vars var model = this, event = name.substr(0,name.indexOf(' ')), selector = name.substr(name.indexOf(' ')+1), context = acf.get_selector(model.type); // add event $(document).on(event, context + ' ' + selector, function( e ){ // vars var $el = $(this); var $field = acf.get_closest_field( $el, model.type ); // bail early if no field if( !$field.length ) return; // focus if( !$field.is(model.$field) ) { model.set('$field', $field); } // append to event e.$el = $el; e.$field = $field; // callback model[ callback ].apply(model, [e]); }); }, _set_$field: function(){ // callback if( typeof this.focus === 'function' ) { this.focus(); } }, // depreciated doFocus: function( $field ){ return this.set('$field', $field); } }); /** * validation * * description * * @date 15/2/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ var _validation = acf.newCompatibility(acf.validation, { remove_error: function( $field ){ acf.getField( $field ).removeError(); }, add_warning: function( $field, message ){ acf.getField( $field ).showNotice({ text: message, type: 'warning', timeout: 1000 }); }, fetch: acf.validateForm, enableSubmit: acf.enableSubmit, disableSubmit: acf.disableSubmit, showSpinner: acf.showSpinner, hideSpinner: acf.hideSpinner, unlockForm: acf.unlockForm, lockForm: acf.lockForm }); /** * tooltip * * description * * @date 15/2/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ _acf.tooltip = { tooltip: function( text, $el ){ var tooltip = acf.newTooltip({ text: text, target: $el }); // return return tooltip.$el; }, temp: function( text, $el ){ var tooltip = acf.newTooltip({ text: text, target: $el, timeout: 250 }); }, confirm: function( $el, callback, text, button_y, button_n ){ var tooltip = acf.newTooltip({ confirm: true, text: text, target: $el, confirm: function(){ callback(true); }, cancel: function(){ callback(false); } }); }, confirm_remove: function( $el, callback ){ var tooltip = acf.newTooltip({ confirmRemove: true, target: $el, confirm: function(){ callback(true); }, cancel: function(){ callback(false); } }); }, }; /** * tooltip * * description * * @date 15/2/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ _acf.media = new acf.Model({ activeFrame: false, actions: { 'new_media_popup': 'onNewMediaPopup' }, frame: function(){ return this.activeFrame; }, onNewMediaPopup: function( popup ){ this.activeFrame = popup.frame; }, popup: function( props ){ // update props if( props.mime_types ) { props.allowedTypes = props.mime_types; } if( props.id ) { props.attachment = props.id; } // new var popup = acf.newMediaPopup( props ); // append /* if( props.selected ) { popup.selected = props.selected; } */ // return return popup.frame; } }); /** * Select2 * * description * * @date 11/6/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ _acf.select2 = { init: function( $select, args, $field ){ // compatible args if( args.allow_null ) { args.allowNull = args.allow_null; } if( args.ajax_action ) { args.ajaxAction = args.ajax_action; } if( $field ) { args.field = acf.getField($field); } // return return acf.newSelect2( $select, args ); }, destroy: function( $select ){ return acf.getInstance( $select ).destroy(); }, }; /** * postbox * * description * * @date 11/6/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ _acf.postbox = { render: function( args ){ // compatible args if( args.edit_url ) { args.editLink = args.edit_url; } if( args.edit_title ) { args.editTitle = args.edit_title; } // return return acf.newPostbox( args ); } }; /** * acf.screen * * description * * @date 11/6/18 * @since 5.6.9 * * @param type $var Description. Default. * @return type Description. */ acf.newCompatibility(acf.screen, { update: function(){ return this.set.apply(this, arguments); }, fetch: acf.screen.check }); _acf.ajax = acf.screen; })(jQuery); // @codekit-prepend "../js/acf.js"; // @codekit-prepend "../js/acf-hooks.js"; // @codekit-prepend "../js/acf-model.js"; // @codekit-prepend "../js/acf-popup.js"; // @codekit-prepend "../js/acf-unload.js"; // @codekit-prepend "../js/acf-panel.js"; // @codekit-prepend "../js/acf-notice.js"; // @codekit-prepend "../js/acf-postbox.js"; // @codekit-prepend "../js/acf-tooltip.js"; // @codekit-prepend "../js/acf-field.js"; // @codekit-prepend "../js/acf-fields.js"; // @codekit-prepend "../js/acf-field-accordion.js"; // @codekit-prepend "../js/acf-field-button-group.js"; // @codekit-prepend "../js/acf-field-checkbox.js"; // @codekit-prepend "../js/acf-field-color-picker.js"; // @codekit-prepend "../js/acf-field-date-picker.js"; // @codekit-prepend "../js/acf-field-date-time-picker.js"; // @codekit-prepend "../js/acf-field-google-map.js"; // @codekit-prepend "../js/acf-field-image.js"; // @codekit-prepend "../js/acf-field-file.js"; // @codekit-prepend "../js/acf-field-link.js"; // @codekit-prepend "../js/acf-field-oembed.js"; // @codekit-prepend "../js/acf-field-radio.js"; // @codekit-prepend "../js/acf-field-range.js"; // @codekit-prepend "../js/acf-field-relationship.js"; // @codekit-prepend "../js/acf-field-select.js"; // @codekit-prepend "../js/acf-field-tab.js"; // @codekit-prepend "../js/acf-field-post-object.js"; // @codekit-prepend "../js/acf-field-page-link.js"; // @codekit-prepend "../js/acf-field-user.js"; // @codekit-prepend "../js/acf-field-taxonomy.js"; // @codekit-prepend "../js/acf-field-time-picker.js"; // @codekit-prepend "../js/acf-field-true-false.js"; // @codekit-prepend "../js/acf-field-url.js"; // @codekit-prepend "../js/acf-field-wysiwyg.js"; // @codekit-prepend "../js/acf-condition.js"; // @codekit-prepend "../js/acf-conditions.js"; // @codekit-prepend "../js/acf-condition-types.js"; // @codekit-prepend "../js/acf-media.js"; // @codekit-prepend "../js/acf-screen.js"; // @codekit-prepend "../js/acf-select2.js"; // @codekit-prepend "../js/acf-tinymce.js"; // @codekit-prepend "../js/acf-validation.js"; // @codekit-prepend "../js/acf-helpers.js"; // @codekit-prepend "../js/acf-compatibility";