13533 lines
261 KiB
JavaScript
13533 lines
261 KiB
JavaScript
(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(data) !== 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] || 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 $('<textarea/>').html( string ).text();
|
||
};
|
||
|
||
/**
|
||
* acf.strEscape
|
||
*
|
||
* description
|
||
*
|
||
* @date 3/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.strEscape = function( string ){
|
||
|
||
var entityMap = {
|
||
'&': '&',
|
||
'<': '<',
|
||
'>': '>',
|
||
'"': '"',
|
||
"'": ''',
|
||
'/': '/',
|
||
'`': '`',
|
||
'=': '='
|
||
};
|
||
|
||
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
|
||
return entityMap[s];
|
||
});
|
||
};
|
||
|
||
/**
|
||
* parseArgs
|
||
*
|
||
* Merges together defaults and args much like the WP wp_parse_args function
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object args
|
||
* @param object defaults
|
||
* @return object
|
||
*/
|
||
|
||
acf.parseArgs = function( args, defaults ){
|
||
if( typeof args !== 'object' ) args = {};
|
||
if( typeof defaults !== 'object' ) defaults = {};
|
||
return $.extend({}, defaults, args);
|
||
}
|
||
|
||
/**
|
||
* __
|
||
*
|
||
* Retrieve the translation of $text.
|
||
*
|
||
* @date 16/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param string text Text to translate.
|
||
* @return string Translated text.
|
||
*/
|
||
|
||
if( window.acfL10n == undefined ) {
|
||
acfL10n = {};
|
||
}
|
||
|
||
acf.__ = function( text ){
|
||
return acfL10n[ text ] || text;
|
||
};
|
||
|
||
/**
|
||
* _x
|
||
*
|
||
* Retrieve translated string with gettext context.
|
||
*
|
||
* @date 16/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param string text Text to translate.
|
||
* @param string context Context information for the translators.
|
||
* @return string Translated text.
|
||
*/
|
||
|
||
acf._x = function( text, context ){
|
||
return acfL10n[ text + '.' + context ] || acfL10n[ text ] || text;
|
||
};
|
||
|
||
/**
|
||
* _n
|
||
*
|
||
* Retrieve the plural or single form based on the amount.
|
||
*
|
||
* @date 16/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param string single Single text to translate.
|
||
* @param string plural Plural text to translate.
|
||
* @param int number The number to compare against.
|
||
* @return string Translated text.
|
||
*/
|
||
|
||
acf._n = function( single, plural, number ){
|
||
if( number == 1 ) {
|
||
return acf.__(single);
|
||
} else {
|
||
return acf.__(plural);
|
||
}
|
||
};
|
||
|
||
acf.isArray = function( a ){
|
||
return Array.isArray(a);
|
||
};
|
||
|
||
acf.isObject = function( a ){
|
||
return ( typeof a === 'object' );
|
||
}
|
||
|
||
/**
|
||
* serialize
|
||
*
|
||
* description
|
||
*
|
||
* @date 24/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
var buildObject = function( obj, name, value ){
|
||
//console.log('buildObject', obj, name);
|
||
// replace [] with placeholder
|
||
name = name.replace('[]', '[%%index%%]');
|
||
|
||
// vars
|
||
var keys = name.match(/([^\[\]])+/g);
|
||
if( !keys ) return;
|
||
var length = keys.length;
|
||
var ref = obj;
|
||
|
||
// loop
|
||
for( var i = 0; i < length; i++ ) {
|
||
|
||
// vars
|
||
var key = String( keys[i] );
|
||
|
||
// value
|
||
if( i == length - 1 ) {
|
||
|
||
// %%index%%
|
||
if( key === '%%index%%' ) {
|
||
ref.push( value );
|
||
|
||
// default
|
||
} else {
|
||
ref[ key ] = value;
|
||
}
|
||
|
||
// path
|
||
} else {
|
||
|
||
// array
|
||
if( keys[i+1] === '%%index%%' ) {
|
||
if( !acf.isArray(ref[ key ]) ) {
|
||
ref[ key ] = [];
|
||
}
|
||
|
||
// object
|
||
} else {
|
||
if( !acf.isObject(ref[ key ]) ) {
|
||
ref[ key ] = {};
|
||
}
|
||
}
|
||
|
||
// crawl
|
||
ref = ref[ key ];
|
||
}
|
||
//console.log('ref:', ref);
|
||
}
|
||
};
|
||
|
||
acf.serialize = function( $el, prefix ){
|
||
//console.time('serialize');
|
||
// vars
|
||
var obj = {};
|
||
var inputs = $el.find('select, textarea, input').serializeArray();
|
||
|
||
// prefix
|
||
if( prefix !== undefined ) {
|
||
|
||
// filter and modify
|
||
inputs = inputs.filter(function( item ){
|
||
return item.name.indexOf(prefix) === 0;
|
||
}).map(function( item ){
|
||
item.name = item.name.slice(prefix.length);
|
||
return item;
|
||
});
|
||
}
|
||
|
||
// loop
|
||
for( var i = 0; i < inputs.length; i++ ) {
|
||
buildObject( obj, inputs[i].name, inputs[i].value );
|
||
}
|
||
//console.timeEnd('serialize');
|
||
|
||
// return
|
||
return obj;
|
||
};
|
||
|
||
|
||
/**
|
||
* addAction
|
||
*
|
||
* Wrapper for acf.hooks.addAction
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
/*
|
||
var prefixAction = function( action ){
|
||
return 'acf_' + action;
|
||
}
|
||
*/
|
||
|
||
acf.addAction = function( action, callback, priority, context ){
|
||
//action = prefixAction(action);
|
||
acf.hooks.addAction.apply(this, arguments);
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* removeAction
|
||
*
|
||
* Wrapper for acf.hooks.removeAction
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
acf.removeAction = function( action, callback ){
|
||
//action = prefixAction(action);
|
||
acf.hooks.removeAction.apply(this, arguments);
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* doAction
|
||
*
|
||
* Wrapper for acf.hooks.doAction
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
var actionHistory = {};
|
||
//var currentAction = false;
|
||
acf.doAction = function( action ){
|
||
//action = prefixAction(action);
|
||
//currentAction = action;
|
||
actionHistory[ action ] = 1;
|
||
acf.hooks.doAction.apply(this, arguments);
|
||
actionHistory[ action ] = 0;
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* doingAction
|
||
*
|
||
* Return true if doing action
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
acf.doingAction = function( action ){
|
||
//action = prefixAction(action);
|
||
return (actionHistory[ action ] === 1);
|
||
};
|
||
|
||
|
||
/**
|
||
* didAction
|
||
*
|
||
* Wrapper for acf.hooks.doAction
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
acf.didAction = function( action ){
|
||
//action = prefixAction(action);
|
||
return (actionHistory[ action ] !== undefined);
|
||
};
|
||
|
||
/**
|
||
* currentAction
|
||
*
|
||
* Wrapper for acf.hooks.doAction
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
acf.currentAction = function(){
|
||
for( var k in actionHistory ) {
|
||
if( actionHistory[k] ) {
|
||
return k;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* addFilter
|
||
*
|
||
* Wrapper for acf.hooks.addFilter
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
acf.addFilter = function( action ){
|
||
//action = prefixAction(action);
|
||
acf.hooks.addFilter.apply(this, arguments);
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* removeFilter
|
||
*
|
||
* Wrapper for acf.hooks.removeFilter
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
acf.removeFilter = function( action ){
|
||
//action = prefixAction(action);
|
||
acf.hooks.removeFilter.apply(this, arguments);
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* applyFilters
|
||
*
|
||
* Wrapper for acf.hooks.applyFilters
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return this
|
||
*/
|
||
|
||
acf.applyFilters = function( action ){
|
||
//action = prefixAction(action);
|
||
return acf.hooks.applyFilters.apply(this, arguments);
|
||
};
|
||
|
||
|
||
/**
|
||
* getArgs
|
||
*
|
||
* description
|
||
*
|
||
* @date 15/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.arrayArgs = function( args ){
|
||
return Array.prototype.slice.call( args );
|
||
};
|
||
|
||
|
||
/**
|
||
* extendArgs
|
||
*
|
||
* description
|
||
*
|
||
* @date 15/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
/*
|
||
acf.extendArgs = function( ){
|
||
var args = Array.prototype.slice.call( arguments );
|
||
var realArgs = args.shift();
|
||
|
||
Array.prototype.push.call(arguments, 'bar')
|
||
return Array.prototype.push.apply( args, arguments );
|
||
};
|
||
*/
|
||
|
||
|
||
// Preferences
|
||
var preferences = localStorage.getItem('acf');
|
||
preferences = preferences ? JSON.parse(preferences) : {};
|
||
|
||
|
||
/**
|
||
* getPreferenceName
|
||
*
|
||
* Gets the true preference name.
|
||
* Converts "this.thing" to "thing-123" if editing post 123.
|
||
*
|
||
* @date 11/11/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @return string
|
||
*/
|
||
|
||
var getPreferenceName = function( name ){
|
||
if( name.substr(0, 5) === 'this.' ) {
|
||
name = name.substr(5) + '-' + acf.get('post_id');
|
||
}
|
||
return name;
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.getPreference
|
||
*
|
||
* Gets a preference setting or null if not set.
|
||
*
|
||
* @date 11/11/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @return mixed
|
||
*/
|
||
|
||
acf.getPreference = function( name ){
|
||
name = getPreferenceName( name );
|
||
return preferences[ name ] || null;
|
||
}
|
||
|
||
|
||
/**
|
||
* acf.setPreference
|
||
*
|
||
* Sets a preference setting.
|
||
*
|
||
* @date 11/11/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param mixed value
|
||
* @return n/a
|
||
*/
|
||
|
||
acf.setPreference = function( name, value ){
|
||
name = getPreferenceName( name );
|
||
if( value === null ) {
|
||
delete preferences[ name ];
|
||
} else {
|
||
preferences[ name ] = value;
|
||
}
|
||
localStorage.setItem('acf', JSON.stringify(preferences));
|
||
}
|
||
|
||
|
||
/**
|
||
* acf.removePreference
|
||
*
|
||
* Removes a preference setting.
|
||
*
|
||
* @date 11/11/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @return n/a
|
||
*/
|
||
|
||
acf.removePreference = function( name ){
|
||
acf.setPreference(name, null);
|
||
};
|
||
|
||
|
||
/**
|
||
* remove
|
||
*
|
||
* Removes an element with fade effect
|
||
*
|
||
* @date 1/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.remove = function( props ){
|
||
|
||
// allow jQuery
|
||
if( props instanceof jQuery ) {
|
||
props = {
|
||
target: props
|
||
};
|
||
}
|
||
|
||
// defaults
|
||
props = acf.parseArgs(props, {
|
||
target: false,
|
||
endHeight: 0,
|
||
complete: function(){}
|
||
});
|
||
|
||
// action
|
||
acf.doAction('remove', props.target);
|
||
|
||
// tr
|
||
if( props.target.is('tr') ) {
|
||
removeTr( props );
|
||
|
||
// div
|
||
} else {
|
||
removeDiv( props );
|
||
}
|
||
|
||
};
|
||
|
||
/**
|
||
* removeDiv
|
||
*
|
||
* description
|
||
*
|
||
* @date 16/2/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
var removeDiv = function( props ){
|
||
|
||
// vars
|
||
var $el = props.target;
|
||
var height = $el.height();
|
||
var width = $el.width();
|
||
var margin = $el.css('margin');
|
||
var outerHeight = $el.outerHeight(true);
|
||
var style = $el.attr('style') + ''; // needed to copy
|
||
|
||
// wrap
|
||
$el.wrap('<div class="acf-temp-remove" style="height:' + outerHeight + 'px"></div>');
|
||
var $wrap = $el.parent();
|
||
|
||
// set pos
|
||
$el.css({
|
||
height: height,
|
||
width: width,
|
||
margin: margin,
|
||
position: 'absolute'
|
||
});
|
||
|
||
// fade wrap
|
||
setTimeout(function(){
|
||
|
||
$wrap.css({
|
||
opacity: 0,
|
||
height: props.endHeight
|
||
});
|
||
|
||
}, 50);
|
||
|
||
// remove
|
||
setTimeout(function(){
|
||
|
||
$el.attr('style', style);
|
||
$wrap.remove();
|
||
props.complete();
|
||
|
||
}, 301);
|
||
};
|
||
|
||
/**
|
||
* removeTr
|
||
*
|
||
* description
|
||
*
|
||
* @date 16/2/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
var removeTr = function( props ){
|
||
|
||
// vars
|
||
var $tr = props.target;
|
||
var height = $tr.height();
|
||
var children = $tr.children().length;
|
||
|
||
// create dummy td
|
||
var $td = $('<td class="acf-temp-remove" style="padding:0; height:' + height + 'px" colspan="' + children + '"></td>');
|
||
|
||
// fade away tr
|
||
$tr.addClass('acf-remove-element');
|
||
|
||
// update HTML after fade animation
|
||
setTimeout(function(){
|
||
$tr.html( $td );
|
||
}, 251);
|
||
|
||
// allow .acf-temp-remove to exist before changing CSS
|
||
setTimeout(function(){
|
||
|
||
// remove class
|
||
$tr.removeClass('acf-remove-element');
|
||
|
||
// collapse
|
||
$td.css({
|
||
height: props.endHeight
|
||
});
|
||
|
||
}, 300);
|
||
|
||
// remove
|
||
setTimeout(function(){
|
||
|
||
$tr.remove();
|
||
props.complete();
|
||
|
||
}, 451);
|
||
};
|
||
|
||
/**
|
||
* duplicate
|
||
*
|
||
* description
|
||
*
|
||
* @date 3/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.duplicate = function( args ){
|
||
|
||
// allow jQuery
|
||
if( args instanceof jQuery ) {
|
||
args = {
|
||
target: args
|
||
};
|
||
}
|
||
|
||
// vars
|
||
var timeout = 0;
|
||
|
||
// defaults
|
||
args = acf.parseArgs(args, {
|
||
target: false,
|
||
search: '',
|
||
replace: '',
|
||
before: function( $el ){},
|
||
after: function( $el, $el2 ){},
|
||
append: function( $el, $el2 ){
|
||
$el.after( $el2 );
|
||
timeout = 1;
|
||
}
|
||
});
|
||
|
||
// compatibility
|
||
args.target = args.target || args.$el;
|
||
|
||
// vars
|
||
var $el = args.target;
|
||
|
||
// search
|
||
args.search = args.search || $el.attr('data-id');
|
||
args.replace = args.replace || acf.uniqid();
|
||
|
||
// before
|
||
// - allow acf to modify DOM
|
||
// - fixes bug where select field option is not selected
|
||
args.before( $el );
|
||
acf.doAction('before_duplicate', $el);
|
||
|
||
// clone
|
||
var $el2 = $el.clone();
|
||
|
||
// rename
|
||
acf.rename({
|
||
target: $el2,
|
||
search: args.search,
|
||
replace: args.replace,
|
||
});
|
||
|
||
// remove classes
|
||
$el2.removeClass('acf-clone');
|
||
$el2.find('.ui-sortable').removeClass('ui-sortable');
|
||
|
||
// after
|
||
// - allow acf to modify DOM
|
||
args.after( $el, $el2 );
|
||
acf.doAction('after_duplicate', $el, $el2 );
|
||
|
||
// append
|
||
args.append( $el, $el2 );
|
||
|
||
// append
|
||
// - allow element to be moved into a visible position before fire action
|
||
//var callback = function(){
|
||
acf.doAction('append', $el2);
|
||
//};
|
||
//if( timeout ) {
|
||
// setTimeout(callback, timeout);
|
||
//} else {
|
||
// callback();
|
||
//}
|
||
|
||
// return
|
||
return $el2;
|
||
};
|
||
|
||
/**
|
||
* rename
|
||
*
|
||
* description
|
||
*
|
||
* @date 7/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.rename = function( args ){
|
||
|
||
// allow jQuery
|
||
if( args instanceof jQuery ) {
|
||
args = {
|
||
target: args
|
||
};
|
||
}
|
||
|
||
// defaults
|
||
args = acf.parseArgs(args, {
|
||
target: false,
|
||
destructive: false,
|
||
search: '',
|
||
replace: '',
|
||
});
|
||
|
||
// vars
|
||
var $el = args.target;
|
||
var search = args.search || $el.attr('data-id');
|
||
var replace = args.replace || acf.uniqid('acf');
|
||
var replaceAttr = function(i, value){
|
||
return value.replace( search, replace );
|
||
}
|
||
|
||
// replace (destructive)
|
||
if( args.destructive ) {
|
||
var html = $el.outerHTML();
|
||
html = acf.strReplace( search, replace, html );
|
||
$el.replaceWith( html );
|
||
|
||
// replace
|
||
} else {
|
||
$el.attr('data-id', replace);
|
||
$el.find('[id*="' + search + '"]').attr('id', replaceAttr);
|
||
$el.find('[for*="' + search + '"]').attr('for', replaceAttr);
|
||
$el.find('[name*="' + search + '"]').attr('name', replaceAttr);
|
||
}
|
||
|
||
// return
|
||
return $el;
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.prepareForAjax
|
||
*
|
||
* description
|
||
*
|
||
* @date 4/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.prepareForAjax = function( data ){
|
||
|
||
// required
|
||
data.nonce = acf.get('nonce');
|
||
data.post_id = acf.get('post_id');
|
||
|
||
// filter for 3rd party customization
|
||
data = acf.applyFilters('prepare_for_ajax', data);
|
||
|
||
// return
|
||
return data;
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.startButtonLoading
|
||
*
|
||
* description
|
||
*
|
||
* @date 5/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.startButtonLoading = function( $el ){
|
||
$el.prop('disabled', true);
|
||
$el.after(' <i class="acf-loading"></i>');
|
||
}
|
||
|
||
acf.stopButtonLoading = function( $el ){
|
||
$el.prop('disabled', false);
|
||
$el.next('.acf-loading').remove();
|
||
}
|
||
|
||
|
||
/**
|
||
* acf.showLoading
|
||
*
|
||
* description
|
||
*
|
||
* @date 12/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.showLoading = function( $el ){
|
||
$el.append('<div class="acf-loading-overlay"><i class="acf-loading"></i></div>');
|
||
};
|
||
|
||
acf.hideLoading = function( $el ){
|
||
$el.children('.acf-loading-overlay').remove();
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.updateUserSetting
|
||
*
|
||
* description
|
||
*
|
||
* @date 5/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.updateUserSetting = function( name, value ){
|
||
|
||
var ajaxData = {
|
||
action: 'acf/update_user_setting',
|
||
name: name,
|
||
value: value
|
||
};
|
||
|
||
$.ajax({
|
||
url: acf.get('ajaxurl'),
|
||
data: acf.prepareForAjax(ajaxData),
|
||
type: 'post',
|
||
dataType: 'html'
|
||
});
|
||
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.val
|
||
*
|
||
* description
|
||
*
|
||
* @date 8/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.val = function( $input, value, silent ){
|
||
|
||
// vars
|
||
var prevValue = $input.val();
|
||
|
||
// bail if no change
|
||
if( value === prevValue ) {
|
||
return false
|
||
}
|
||
|
||
// bail if select option does not exist
|
||
if( $input.is('select') && !$input.find('option[value="'+value+'"]').length ) {
|
||
return false;
|
||
}
|
||
|
||
// update value
|
||
$input.val( value );
|
||
|
||
// update with trigger
|
||
if( silent !== true ) {
|
||
$input.trigger('change');
|
||
}
|
||
|
||
// return
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* acf.show
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.show = function( $el, lockKey ){
|
||
|
||
// unlock
|
||
if( lockKey ) {
|
||
acf.unlock($el, 'hidden', lockKey);
|
||
}
|
||
|
||
// bail early if $el is still locked
|
||
if( acf.isLocked($el, 'hidden') ) {
|
||
//console.log( 'still locked', getLocks( $el, 'hidden' ));
|
||
return false;
|
||
}
|
||
|
||
// $el is hidden, remove class and return true due to change in visibility
|
||
if( $el.hasClass('acf-hidden') ) {
|
||
$el.removeClass('acf-hidden');
|
||
return true;
|
||
|
||
// $el is visible, return false due to no change in visibility
|
||
} else {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.hide
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.hide = function( $el, lockKey ){
|
||
|
||
// lock
|
||
if( lockKey ) {
|
||
acf.lock($el, 'hidden', lockKey);
|
||
}
|
||
|
||
// $el is hidden, return false due to no change in visibility
|
||
if( $el.hasClass('acf-hidden') ) {
|
||
return false;
|
||
|
||
// $el is visible, add class and return true due to change in visibility
|
||
} else {
|
||
$el.addClass('acf-hidden');
|
||
return true;
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.isHidden
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.isHidden = function( $el ){
|
||
return $el.hasClass('acf-hidden');
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.isVisible
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.isVisible = function( $el ){
|
||
return !acf.isHidden( $el );
|
||
};
|
||
|
||
|
||
/**
|
||
* enable
|
||
*
|
||
* description
|
||
*
|
||
* @date 12/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
var enable = function( $el, lockKey ){
|
||
|
||
// check class. Allow .acf-disabled to overrule all JS
|
||
if( $el.hasClass('acf-disabled') ) {
|
||
return false;
|
||
}
|
||
|
||
// unlock
|
||
if( lockKey ) {
|
||
acf.unlock($el, 'disabled', lockKey);
|
||
}
|
||
|
||
// bail early if $el is still locked
|
||
if( acf.isLocked($el, 'disabled') ) {
|
||
return false;
|
||
}
|
||
|
||
// $el is disabled, remove prop and return true due to change
|
||
if( $el.prop('disabled') ) {
|
||
$el.prop('disabled', false);
|
||
return true;
|
||
|
||
// $el is enabled, return false due to no change
|
||
} else {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* acf.enable
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.enable = function( $el, lockKey ){
|
||
|
||
// enable single input
|
||
if( $el.attr('name') ) {
|
||
return enable( $el, lockKey );
|
||
}
|
||
|
||
// find and enable child inputs
|
||
// return true if any inputs have changed
|
||
var results = false;
|
||
$el.find('[name]').each(function(){
|
||
var result = enable( $(this), lockKey );
|
||
if( result ) {
|
||
results = true;
|
||
}
|
||
});
|
||
return results;
|
||
};
|
||
|
||
|
||
/**
|
||
* disable
|
||
*
|
||
* description
|
||
*
|
||
* @date 12/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
var disable = function( $el, lockKey ){
|
||
|
||
// lock
|
||
if( lockKey ) {
|
||
acf.lock($el, 'disabled', lockKey);
|
||
}
|
||
|
||
// $el is disabled, return false due to no change
|
||
if( $el.prop('disabled') ) {
|
||
return false;
|
||
|
||
// $el is enabled, add prop and return true due to change
|
||
} else {
|
||
$el.prop('disabled', true);
|
||
return true;
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.disable
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.disable = function( $el, lockKey ){
|
||
|
||
// disable single input
|
||
if( $el.attr('name') ) {
|
||
return disable( $el, lockKey );
|
||
}
|
||
|
||
// find and enable child inputs
|
||
// return true if any inputs have changed
|
||
var results = false;
|
||
$el.find('[name]').each(function(){
|
||
var result = disable( $(this), lockKey );
|
||
if( result ) {
|
||
results = true;
|
||
}
|
||
});
|
||
return results;
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.isset
|
||
*
|
||
* description
|
||
*
|
||
* @date 10/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.isset = function( obj /*, level1, level2, ... */ ) {
|
||
for( var i = 1; i < arguments.length; i++ ) {
|
||
if( !obj.hasOwnProperty(arguments[i]) ) {
|
||
return false;
|
||
}
|
||
obj = obj[ arguments[i] ];
|
||
}
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* acf.isget
|
||
*
|
||
* description
|
||
*
|
||
* @date 10/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.isget = function( obj /*, level1, level2, ... */ ) {
|
||
for( var i = 1; i < arguments.length; i++ ) {
|
||
if( !obj.hasOwnProperty(arguments[i]) ) {
|
||
return null;
|
||
}
|
||
obj = obj[ arguments[i] ];
|
||
}
|
||
return obj;
|
||
};
|
||
|
||
/**
|
||
* acf.getFileInputData
|
||
*
|
||
* description
|
||
*
|
||
* @date 10/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.getFileInputData = function( $input, callback ){
|
||
|
||
// vars
|
||
var value = $input.val();
|
||
|
||
// bail early if no value
|
||
if( !value ) {
|
||
return false;
|
||
}
|
||
|
||
// data
|
||
var data = {
|
||
url: value
|
||
};
|
||
|
||
// modern browsers
|
||
var file = acf.isget( $input[0], 'files', 0);
|
||
if( file ){
|
||
|
||
// update data
|
||
data.size = file.size;
|
||
data.type = file.type;
|
||
|
||
// image
|
||
if( file.type.indexOf('image') > -1 ) {
|
||
|
||
// vars
|
||
var windowURL = window.URL || window.webkitURL;
|
||
var img = new Image();
|
||
|
||
img.onload = function() {
|
||
|
||
// update
|
||
data.width = this.width;
|
||
data.height = this.height;
|
||
|
||
callback( data );
|
||
};
|
||
img.src = windowURL.createObjectURL( file );
|
||
} else {
|
||
callback( data );
|
||
}
|
||
} else {
|
||
callback( data );
|
||
}
|
||
};
|
||
|
||
/**
|
||
* acf.isAjaxSuccess
|
||
*
|
||
* description
|
||
*
|
||
* @date 18/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.isAjaxSuccess = function( json ){
|
||
return ( json && json.success );
|
||
};
|
||
|
||
/**
|
||
* acf.getAjaxMessage
|
||
*
|
||
* description
|
||
*
|
||
* @date 18/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.getAjaxMessage = function( json ){
|
||
return acf.isget( json, 'data', 'message' );
|
||
};
|
||
|
||
/**
|
||
* acf.getAjaxError
|
||
*
|
||
* description
|
||
*
|
||
* @date 18/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.getAjaxError = function( json ){
|
||
return acf.isget( json, 'data', 'error' );
|
||
};
|
||
|
||
|
||
/**
|
||
* acf.renderSelect
|
||
*
|
||
* Renders the innter html for a select field.
|
||
*
|
||
* @date 19/2/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param jQuery $select The select element.
|
||
* @param array choices An array of choices.
|
||
* @return void
|
||
*/
|
||
|
||
acf.renderSelect = function( $select, choices ){
|
||
|
||
// vars
|
||
var value = $select.val();
|
||
var values = [];
|
||
|
||
// callback
|
||
var crawl = function( items ){
|
||
|
||
// vars
|
||
var itemsHtml = '';
|
||
|
||
// loop
|
||
items.map(function( item ){
|
||
|
||
// vars
|
||
var text = item.text || item.label || '';
|
||
var id = item.id || item.value || '';
|
||
|
||
// append
|
||
values.push(id);
|
||
|
||
// optgroup
|
||
if( item.children ) {
|
||
itemsHtml += '<optgroup label="' + acf.strEscape(text) + '">' + crawl( item.children ) + '</optgroup>';
|
||
|
||
// option
|
||
} else {
|
||
itemsHtml += '<option value="' + id + '"' + (item.disabled ? ' disabled="disabled"' : '') + '>' + acf.strEscape(text) + '</option>';
|
||
}
|
||
});
|
||
|
||
// return
|
||
return itemsHtml;
|
||
};
|
||
|
||
// update HTML
|
||
$select.html( crawl(choices) );
|
||
|
||
// update value
|
||
if( values.indexOf(value) > -1 ){
|
||
$select.val( value );
|
||
}
|
||
|
||
// return selected value
|
||
return $select.val();
|
||
};
|
||
|
||
/**
|
||
* acf.lock
|
||
*
|
||
* Creates a "lock" on an element for a given type and key
|
||
*
|
||
* @date 22/2/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param jQuery $el The element to lock.
|
||
* @param string type The type of lock such as "condition" or "visibility".
|
||
* @param string key The key that will be used to unlock.
|
||
* @return void
|
||
*/
|
||
|
||
var getLocks = function( $el, type ){
|
||
return $el.data('acf-lock-'+type) || [];
|
||
};
|
||
|
||
var setLocks = function( $el, type, locks ){
|
||
$el.data('acf-lock-'+type, locks);
|
||
}
|
||
|
||
acf.lock = function( $el, type, key ){
|
||
var locks = getLocks( $el, type );
|
||
var i = locks.indexOf(key);
|
||
if( i < 0 ) {
|
||
locks.push( key );
|
||
setLocks( $el, type, locks );
|
||
}
|
||
};
|
||
|
||
/**
|
||
* acf.unlock
|
||
*
|
||
* Unlocks a "lock" on an element for a given type and key
|
||
*
|
||
* @date 22/2/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param jQuery $el The element to lock.
|
||
* @param string type The type of lock such as "condition" or "visibility".
|
||
* @param string key The key that will be used to unlock.
|
||
* @return void
|
||
*/
|
||
|
||
acf.unlock = function( $el, type, key ){
|
||
var locks = getLocks( $el, type );
|
||
var i = locks.indexOf(key);
|
||
if( i > -1 ) {
|
||
locks.splice(i, 1);
|
||
setLocks( $el, type, locks );
|
||
}
|
||
|
||
// return true if is unlocked (no locks)
|
||
return (locks.length === 0);
|
||
};
|
||
|
||
/**
|
||
* acf.isLocked
|
||
*
|
||
* Returns true if a lock exists for a given type
|
||
*
|
||
* @date 22/2/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param jQuery $el The element to lock.
|
||
* @param string type The type of lock such as "condition" or "visibility".
|
||
* @return void
|
||
*/
|
||
|
||
acf.isLocked = function( $el, type ){
|
||
return ( getLocks( $el, type ).length > 0 );
|
||
};
|
||
|
||
/*
|
||
* exists
|
||
*
|
||
* This function will return true if a jQuery selection exists
|
||
*
|
||
* @type function
|
||
* @date 8/09/2014
|
||
* @since 5.0.0
|
||
*
|
||
* @param n/a
|
||
* @return (boolean)
|
||
*/
|
||
|
||
$.fn.exists = function() {
|
||
return $(this).length>0;
|
||
};
|
||
|
||
|
||
/*
|
||
* outerHTML
|
||
*
|
||
* This function will return a string containing the HTML of the selected element
|
||
*
|
||
* @type function
|
||
* @date 19/11/2013
|
||
* @since 5.0.0
|
||
*
|
||
* @param $.fn
|
||
* @return (string)
|
||
*/
|
||
|
||
$.fn.outerHTML = function() {
|
||
return $(this).get(0).outerHTML;
|
||
};
|
||
|
||
/*
|
||
* indexOf
|
||
*
|
||
* This function will provide compatibility for ie8
|
||
*
|
||
* @type function
|
||
* @date 5/3/17
|
||
* @since 5.5.10
|
||
*
|
||
* @param n/a
|
||
* @return n/a
|
||
*/
|
||
|
||
if( !Array.prototype.indexOf ) {
|
||
|
||
Array.prototype.indexOf = function(val) {
|
||
return $.inArray(val, this);
|
||
};
|
||
|
||
}
|
||
|
||
|
||
// Set up actions from events
|
||
$(document).ready(function(){
|
||
acf.doAction('ready');
|
||
});
|
||
|
||
$(window).on('load', function(){
|
||
acf.doAction('load');
|
||
});
|
||
|
||
$(window).on('unload', function(){
|
||
acf.doAction('unload');
|
||
});
|
||
|
||
$(window).on('resize', function(){
|
||
acf.doAction('resize');
|
||
});
|
||
|
||
$(document).on('sortstart', function( event, ui ) {
|
||
acf.doAction('sortstart', ui.item, ui.placeholder);
|
||
});
|
||
|
||
$(document).on('sortstop', function( event, ui ) {
|
||
acf.doAction('sortstop', ui.item, ui.placeholder);
|
||
});
|
||
|
||
})(jQuery);
|
||
|
||
( function( window, undefined ) {
|
||
"use strict";
|
||
|
||
/**
|
||
* Handles managing all events for whatever you plug it into. Priorities for hooks are based on lowest to highest in
|
||
* that, lowest priority hooks are fired first.
|
||
*/
|
||
var EventManager = function() {
|
||
/**
|
||
* Maintain a reference to the object scope so our public methods never get confusing.
|
||
*/
|
||
var MethodsAvailable = {
|
||
removeFilter : removeFilter,
|
||
applyFilters : applyFilters,
|
||
addFilter : addFilter,
|
||
removeAction : removeAction,
|
||
doAction : doAction,
|
||
addAction : addAction,
|
||
storage : getStorage
|
||
};
|
||
|
||
/**
|
||
* Contains the hooks that get registered with this EventManager. The array for storage utilizes a "flat"
|
||
* object literal such that looking up the hook utilizes the native object literal hash.
|
||
*/
|
||
var STORAGE = {
|
||
actions : {},
|
||
filters : {}
|
||
};
|
||
|
||
function getStorage() {
|
||
|
||
return STORAGE;
|
||
|
||
};
|
||
|
||
/**
|
||
* Adds an action to the event manager.
|
||
*
|
||
* @param action Must contain namespace.identifier
|
||
* @param callback Must be a valid callback function before this action is added
|
||
* @param [priority=10] Used to control when the function is executed in relation to other callbacks bound to the same hook
|
||
* @param [context] Supply a value to be used for this
|
||
*/
|
||
function addAction( action, callback, priority, context ) {
|
||
if( typeof action === 'string' && typeof callback === 'function' ) {
|
||
priority = parseInt( ( priority || 10 ), 10 );
|
||
_addHook( 'actions', action, callback, priority, context );
|
||
}
|
||
|
||
return MethodsAvailable;
|
||
}
|
||
|
||
/**
|
||
* Performs an action if it exists. You can pass as many arguments as you want to this function; the only rule is
|
||
* that the first argument must always be the action.
|
||
*/
|
||
function doAction( /* action, arg1, arg2, ... */ ) {
|
||
var args = Array.prototype.slice.call( arguments );
|
||
var action = args.shift();
|
||
|
||
if( typeof action === 'string' ) {
|
||
_runHook( 'actions', action, args );
|
||
}
|
||
|
||
return MethodsAvailable;
|
||
}
|
||
|
||
/**
|
||
* Removes the specified action if it contains a namespace.identifier & exists.
|
||
*
|
||
* @param action The action to remove
|
||
* @param [callback] Callback function to remove
|
||
*/
|
||
function removeAction( action, callback ) {
|
||
if( typeof action === 'string' ) {
|
||
_removeHook( 'actions', action, callback );
|
||
}
|
||
|
||
return MethodsAvailable;
|
||
}
|
||
|
||
/**
|
||
* Adds a filter to the event manager.
|
||
*
|
||
* @param filter Must contain namespace.identifier
|
||
* @param callback Must be a valid callback function before this action is added
|
||
* @param [priority=10] Used to control when the function is executed in relation to other callbacks bound to the same hook
|
||
* @param [context] Supply a value to be used for this
|
||
*/
|
||
function addFilter( filter, callback, priority, context ) {
|
||
if( typeof filter === 'string' && typeof callback === 'function' ) {
|
||
priority = parseInt( ( priority || 10 ), 10 );
|
||
_addHook( 'filters', filter, callback, priority, context );
|
||
}
|
||
|
||
return MethodsAvailable;
|
||
}
|
||
|
||
/**
|
||
* Performs a filter if it exists. You should only ever pass 1 argument to be filtered. The only rule is that
|
||
* the first argument must always be the filter.
|
||
*/
|
||
function applyFilters( /* filter, filtered arg, arg2, ... */ ) {
|
||
var args = Array.prototype.slice.call( arguments );
|
||
var filter = args.shift();
|
||
|
||
if( typeof filter === 'string' ) {
|
||
return _runHook( 'filters', filter, args );
|
||
}
|
||
|
||
return MethodsAvailable;
|
||
}
|
||
|
||
/**
|
||
* Removes the specified filter if it contains a namespace.identifier & exists.
|
||
*
|
||
* @param filter The action to remove
|
||
* @param [callback] Callback function to remove
|
||
*/
|
||
function removeFilter( filter, callback ) {
|
||
if( typeof filter === 'string') {
|
||
_removeHook( 'filters', filter, callback );
|
||
}
|
||
|
||
return MethodsAvailable;
|
||
}
|
||
|
||
/**
|
||
* Removes the specified hook by resetting the value of it.
|
||
*
|
||
* @param type Type of hook, either 'actions' or 'filters'
|
||
* @param hook The hook (namespace.identifier) to remove
|
||
* @private
|
||
*/
|
||
function _removeHook( type, hook, callback, context ) {
|
||
if ( !STORAGE[ type ][ hook ] ) {
|
||
return;
|
||
}
|
||
if ( !callback ) {
|
||
STORAGE[ type ][ hook ] = [];
|
||
} else {
|
||
var handlers = STORAGE[ type ][ hook ];
|
||
var i;
|
||
if ( !context ) {
|
||
for ( i = handlers.length; i--; ) {
|
||
if ( handlers[i].callback === callback ) {
|
||
handlers.splice( i, 1 );
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
for ( i = handlers.length; i--; ) {
|
||
var handler = handlers[i];
|
||
if ( handler.callback === callback && handler.context === context) {
|
||
handlers.splice( i, 1 );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Adds the hook to the appropriate storage container
|
||
*
|
||
* @param type 'actions' or 'filters'
|
||
* @param hook The hook (namespace.identifier) to add to our event manager
|
||
* @param callback The function that will be called when the hook is executed.
|
||
* @param priority The priority of this hook. Must be an integer.
|
||
* @param [context] A value to be used for this
|
||
* @private
|
||
*/
|
||
function _addHook( type, hook, callback, priority, context ) {
|
||
var hookObject = {
|
||
callback : callback,
|
||
priority : priority,
|
||
context : context
|
||
};
|
||
|
||
// Utilize 'prop itself' : http://jsperf.com/hasownproperty-vs-in-vs-undefined/19
|
||
var hooks = STORAGE[ type ][ hook ];
|
||
if( hooks ) {
|
||
hooks.push( hookObject );
|
||
hooks = _hookInsertSort( hooks );
|
||
}
|
||
else {
|
||
hooks = [ hookObject ];
|
||
}
|
||
|
||
STORAGE[ type ][ hook ] = hooks;
|
||
}
|
||
|
||
/**
|
||
* Use an insert sort for keeping our hooks organized based on priority. This function is ridiculously faster
|
||
* than bubble sort, etc: http://jsperf.com/javascript-sort
|
||
*
|
||
* @param hooks The custom array containing all of the appropriate hooks to perform an insert sort on.
|
||
* @private
|
||
*/
|
||
function _hookInsertSort( hooks ) {
|
||
var tmpHook, j, prevHook;
|
||
for( var i = 1, len = hooks.length; i < len; i++ ) {
|
||
tmpHook = hooks[ i ];
|
||
j = i;
|
||
while( ( prevHook = hooks[ j - 1 ] ) && prevHook.priority > tmpHook.priority ) {
|
||
hooks[ j ] = hooks[ j - 1 ];
|
||
--j;
|
||
}
|
||
hooks[ j ] = tmpHook;
|
||
}
|
||
|
||
return hooks;
|
||
}
|
||
|
||
/**
|
||
* Runs the specified hook. If it is an action, the value is not modified but if it is a filter, it is.
|
||
*
|
||
* @param type 'actions' or 'filters'
|
||
* @param hook The hook ( namespace.identifier ) to be ran.
|
||
* @param args Arguments to pass to the action/filter. If it's a filter, args is actually a single parameter.
|
||
* @private
|
||
*/
|
||
function _runHook( type, hook, args ) {
|
||
var handlers = STORAGE[ type ][ hook ];
|
||
|
||
if ( !handlers ) {
|
||
return (type === 'filters') ? args[0] : false;
|
||
}
|
||
|
||
var i = 0, len = handlers.length;
|
||
if ( type === 'filters' ) {
|
||
for ( ; i < len; i++ ) {
|
||
args[ 0 ] = handlers[ i ].callback.apply( handlers[ i ].context, args );
|
||
}
|
||
} else {
|
||
for ( ; i < len; i++ ) {
|
||
handlers[ i ].callback.apply( handlers[ i ].context, args );
|
||
}
|
||
}
|
||
|
||
return ( type === 'filters' ) ? args[ 0 ] : true;
|
||
}
|
||
|
||
// return all of the publicly available methods
|
||
return MethodsAvailable;
|
||
|
||
};
|
||
|
||
// instantiate
|
||
acf.hooks = new EventManager();
|
||
|
||
} )( window );
|
||
|
||
(function($, undefined){
|
||
|
||
// Cached regex to split keys for `addEvent`.
|
||
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
|
||
|
||
/**
|
||
* extend
|
||
*
|
||
* Helper function to correctly set up the prototype chain for subclasses
|
||
* Heavily inspired by backbone.js
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object protoProps New properties for this object.
|
||
* @return function.
|
||
*/
|
||
|
||
var extend = function( protoProps ) {
|
||
|
||
// vars
|
||
var Parent = this;
|
||
var Child;
|
||
|
||
// The constructor function for the new subclass is either defined by you
|
||
// (the "constructor" property in your `extend` definition), or defaulted
|
||
// by us to simply call the parent constructor.
|
||
if( protoProps && protoProps.hasOwnProperty('constructor') ) {
|
||
Child = protoProps.constructor;
|
||
} else {
|
||
Child = function(){ return Parent.apply(this, arguments); };
|
||
}
|
||
|
||
// Add static properties to the constructor function, if supplied.
|
||
$.extend(Child, Parent);
|
||
|
||
// Set the prototype chain to inherit from `parent`, without calling
|
||
// `parent`'s constructor function and add the prototype properties.
|
||
Child.prototype = Object.create(Parent.prototype);
|
||
$.extend(Child.prototype, protoProps);
|
||
Child.prototype.constructor = Child;
|
||
|
||
// Set a convenience property in case the parent's prototype is needed later.
|
||
//Child.prototype.__parent__ = Parent.prototype;
|
||
|
||
// return
|
||
return Child;
|
||
|
||
};
|
||
|
||
|
||
/**
|
||
* Model
|
||
*
|
||
* Base class for all inheritence
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object props
|
||
* @return function.
|
||
*/
|
||
|
||
var Model = acf.Model = function(){
|
||
|
||
// generate uique client id
|
||
this.cid = acf.uniqueId('acf');
|
||
|
||
// set vars to avoid modifying prototype
|
||
this.data = $.extend(true, {}, this.data);
|
||
|
||
// pass props to setup function
|
||
this.setup.apply(this, arguments);
|
||
|
||
// store on element (allow this.setup to create this.$el)
|
||
if( this.$el && !this.$el.data('acf') ) {
|
||
this.$el.data('acf', this);
|
||
}
|
||
|
||
// initialize
|
||
var initialize = function(){
|
||
this.initialize();
|
||
this.addEvents();
|
||
this.addActions();
|
||
this.addFilters();
|
||
};
|
||
|
||
// initialize on action
|
||
if( this.wait && !acf.didAction(this.wait) ) {
|
||
this.addAction(this.wait, initialize);
|
||
|
||
// initialize now
|
||
} else {
|
||
initialize.apply(this);
|
||
}
|
||
};
|
||
|
||
// Attach all inheritable methods to the Model prototype.
|
||
$.extend(Model.prototype, {
|
||
|
||
// Unique model id
|
||
id: '',
|
||
|
||
// Unique client id
|
||
cid: '',
|
||
|
||
// jQuery element
|
||
$el: null,
|
||
|
||
// Data specific to this instance
|
||
data: {},
|
||
|
||
// toggle used when changing data
|
||
busy: false,
|
||
changed: false,
|
||
|
||
// Setup events hooks
|
||
events: {},
|
||
actions: {},
|
||
filters: {},
|
||
|
||
// class used to avoid nested event triggers
|
||
eventScope: '',
|
||
|
||
// action to wait until initialize
|
||
wait: false,
|
||
|
||
// action priority default
|
||
priority: 10,
|
||
|
||
/**
|
||
* get
|
||
*
|
||
* Gets a specific data value
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @return mixed
|
||
*/
|
||
|
||
get: function( name ) {
|
||
return this.data[name];
|
||
},
|
||
|
||
/**
|
||
* has
|
||
*
|
||
* Returns `true` if the data exists and is not null
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @return boolean
|
||
*/
|
||
|
||
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
|
||
*/
|
||
|
||
set: function( name, value, silent ) {
|
||
|
||
// bail if unchanged
|
||
var prevValue = this.get(name);
|
||
if( prevValue == value ) {
|
||
return this;
|
||
}
|
||
|
||
// set data
|
||
this.data[ name ] = value;
|
||
|
||
// trigger events
|
||
if( !silent ) {
|
||
this.changed = true;
|
||
this.trigger('changed:' + name, [value]);
|
||
this.trigger('changed', [name, value]);
|
||
}
|
||
|
||
// return
|
||
return this;
|
||
},
|
||
|
||
/**
|
||
* inherit
|
||
*
|
||
* Inherits the data from a jQuery element
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param jQuery $el
|
||
* @return this
|
||
*/
|
||
|
||
inherit: function( data ){
|
||
|
||
// allow jQuery
|
||
if( data instanceof jQuery ) {
|
||
data = data.data();
|
||
}
|
||
|
||
// extend
|
||
$.extend(this.data, data);
|
||
|
||
// return
|
||
return this;
|
||
},
|
||
|
||
/**
|
||
* prop
|
||
*
|
||
* mimics the jQuery prop function
|
||
*
|
||
* @date 4/6/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
prop: function(){
|
||
return this.$el.prop.apply(this.$el, arguments);
|
||
},
|
||
|
||
/**
|
||
* setup
|
||
*
|
||
* Run during constructor function
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return n/a
|
||
*/
|
||
|
||
setup: function( props ){
|
||
$.extend(this, props);
|
||
},
|
||
|
||
/**
|
||
* initialize
|
||
*
|
||
* Also run during constructor function
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param n/a
|
||
* @return n/a
|
||
*/
|
||
|
||
initialize: function(){},
|
||
|
||
/**
|
||
* addElements
|
||
*
|
||
* Adds multiple jQuery elements to this object
|
||
*
|
||
* @date 9/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
addElements: function( elements ){
|
||
elements = elements || this.elements || null;
|
||
if( !elements || !Object.keys(elements).length ) return false;
|
||
for( var i in elements ) {
|
||
this.addElement( i, elements[i] );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* addElement
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
addElement: function( name, selector){
|
||
this[ '$' + name ] = this.$( selector );
|
||
},
|
||
|
||
/**
|
||
* addEvents
|
||
*
|
||
* Adds multiple event handlers
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object events {event1 : callback, event2 : callback, etc }
|
||
* @return n/a
|
||
*/
|
||
|
||
addEvents: function( events ){
|
||
events = events || this.events || null;
|
||
if( !events ) return false;
|
||
for( var key in events ) {
|
||
var match = key.match(delegateEventSplitter);
|
||
this.on(match[1], match[2], events[key]);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* removeEvents
|
||
*
|
||
* Removes multiple event handlers
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object events {event1 : callback, event2 : callback, etc }
|
||
* @return n/a
|
||
*/
|
||
|
||
removeEvents: function( events ){
|
||
events = events || this.events || null;
|
||
if( !events ) return false;
|
||
for( var key in events ) {
|
||
var match = key.match(delegateEventSplitter);
|
||
this.off(match[1], match[2], events[key]);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* getEventTarget
|
||
*
|
||
* Returns a jQUery element to tigger an event on
|
||
*
|
||
* @date 5/6/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param jQuery $el The default jQuery element. Optional.
|
||
* @param string event The event name. Optional.
|
||
* @return jQuery
|
||
*/
|
||
|
||
getEventTarget: function( $el, event ){
|
||
return $el || this.$el || $(document);
|
||
},
|
||
|
||
/**
|
||
* validateEvent
|
||
*
|
||
* Returns true if the event target's closest $el is the same as this.$el
|
||
* Requires both this.el and this.$el to be defined
|
||
*
|
||
* @date 5/6/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
validateEvent: function( e ){
|
||
if( this.eventScope ) {
|
||
return $( e.target ).closest( this.eventScope ).is( this.$el );
|
||
} else {
|
||
return true;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* proxyEvent
|
||
*
|
||
* Returns a new event callback function scoped to this model
|
||
*
|
||
* @date 29/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param function callback
|
||
* @return function
|
||
*/
|
||
|
||
proxyEvent: function( callback ){
|
||
return this.proxy(function(e){
|
||
if( !this.validateEvent(e) ) {
|
||
return;
|
||
}
|
||
var args = acf.arrayArgs(arguments);
|
||
args.push( $(e.currentTarget) );
|
||
callback.apply(this, args);
|
||
});
|
||
},
|
||
|
||
/**
|
||
* on
|
||
*
|
||
* Adds an event handler similar to jQuery
|
||
* Uses the instance 'cid' to namespace event
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param string callback
|
||
* @return n/a
|
||
*/
|
||
|
||
on: function( a1, a2, a3, a4 ){
|
||
|
||
// vars
|
||
var $el, event, selector, callback, args;
|
||
|
||
// find args
|
||
if( a1 instanceof jQuery ) {
|
||
|
||
// 1. args( $el, event, selector, callback )
|
||
if( a4 ) {
|
||
$el = a1; event = a2; selector = a3; callback = a4;
|
||
|
||
// 2. args( $el, event, callback )
|
||
} else {
|
||
$el = a1; event = a2; callback = a3;
|
||
}
|
||
} else {
|
||
|
||
// 3. args( event, selector, callback )
|
||
if( a3 ) {
|
||
event = a1; selector = a2; callback = a3;
|
||
|
||
// 4. args( event, callback )
|
||
} else {
|
||
event = a1; callback = a2;
|
||
}
|
||
}
|
||
|
||
// element
|
||
$el = this.getEventTarget( $el );
|
||
|
||
// modify callback
|
||
if( typeof callback === 'string' ) {
|
||
callback = this.proxyEvent( this[callback] );
|
||
}
|
||
|
||
// modify event
|
||
event = event + '.' + this.cid;
|
||
|
||
// args
|
||
if( selector ) {
|
||
args = [ event, selector, callback ];
|
||
} else {
|
||
args = [ event, callback ];
|
||
}
|
||
|
||
// on()
|
||
$el.on.apply($el, args);
|
||
},
|
||
|
||
/**
|
||
* off
|
||
*
|
||
* Removes an event handler similar to jQuery
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param string callback
|
||
* @return n/a
|
||
*/
|
||
|
||
off: function( a1, a2 ,a3 ){
|
||
|
||
// vars
|
||
var $el, event, selector, args;
|
||
|
||
// find args
|
||
if( a1 instanceof jQuery ) {
|
||
|
||
// 1. args( $el, event, selector )
|
||
if( a3 ) {
|
||
$el = a1; event = a2; selector = a3;
|
||
|
||
// 2. args( $el, event )
|
||
} else {
|
||
$el = a1; event = a2;
|
||
}
|
||
} else {
|
||
|
||
// 3. args( event, selector )
|
||
if( a2 ) {
|
||
event = a1; selector = a2;
|
||
|
||
// 4. args( event )
|
||
} else {
|
||
event = a1;
|
||
}
|
||
}
|
||
|
||
// element
|
||
$el = this.getEventTarget( $el );
|
||
|
||
// modify event
|
||
event = event + '.' + this.cid;
|
||
|
||
// args
|
||
if( selector ) {
|
||
args = [ event, selector ];
|
||
} else {
|
||
args = [ event ];
|
||
}
|
||
|
||
// off()
|
||
$el.off.apply($el, args);
|
||
},
|
||
|
||
/**
|
||
* trigger
|
||
*
|
||
* Triggers an event similar to jQuery
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param string callback
|
||
* @return n/a
|
||
*/
|
||
|
||
trigger: function( name, args, bubbles ){
|
||
var $el = this.getEventTarget();
|
||
if( bubbles ) {
|
||
$el.trigger.apply( $el, arguments );
|
||
} else {
|
||
$el.triggerHandler.apply( $el, arguments );
|
||
}
|
||
return this;
|
||
},
|
||
|
||
/**
|
||
* addActions
|
||
*
|
||
* Adds multiple action handlers
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object actions {action1 : callback, action2 : callback, etc }
|
||
* @return n/a
|
||
*/
|
||
|
||
addActions: function( actions ){
|
||
actions = actions || this.actions || null;
|
||
if( !actions ) return false;
|
||
for( var i in actions ) {
|
||
this.addAction( i, actions[i] );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* removeActions
|
||
*
|
||
* Removes multiple action handlers
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object actions {action1 : callback, action2 : callback, etc }
|
||
* @return n/a
|
||
*/
|
||
|
||
removeActions: function( actions ){
|
||
actions = actions || this.actions || null;
|
||
if( !actions ) return false;
|
||
for( var i in actions ) {
|
||
this.removeAction( i, actions[i] );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* addAction
|
||
*
|
||
* Adds an action using the wp.hooks library
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param string callback
|
||
* @return n/a
|
||
*/
|
||
|
||
addAction: function( name, callback, priority ){
|
||
//console.log('addAction', name, priority);
|
||
// defaults
|
||
priority = priority || this.priority;
|
||
|
||
// modify callback
|
||
if( typeof callback === 'string' ) {
|
||
callback = this[ callback ];
|
||
}
|
||
|
||
// add
|
||
acf.addAction(name, callback, priority, this);
|
||
|
||
},
|
||
|
||
/**
|
||
* removeAction
|
||
*
|
||
* Remove an action using the wp.hooks library
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param string callback
|
||
* @return n/a
|
||
*/
|
||
|
||
removeAction: function( name, callback ){
|
||
acf.removeAction(name, this[ callback ]);
|
||
},
|
||
|
||
/**
|
||
* addFilters
|
||
*
|
||
* Adds multiple filter handlers
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object filters {filter1 : callback, filter2 : callback, etc }
|
||
* @return n/a
|
||
*/
|
||
|
||
addFilters: function( filters ){
|
||
filters = filters || this.filters || null;
|
||
if( !filters ) return false;
|
||
for( var i in filters ) {
|
||
this.addFilter( i, filters[i] );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* addFilter
|
||
*
|
||
* Adds a filter using the wp.hooks library
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param string callback
|
||
* @return n/a
|
||
*/
|
||
|
||
addFilter: function( name, callback, priority ){
|
||
|
||
// defaults
|
||
priority = priority || this.priority;
|
||
|
||
// modify callback
|
||
if( typeof callback === 'string' ) {
|
||
callback = this[ callback ];
|
||
}
|
||
|
||
// add
|
||
acf.addFilter(name, callback, priority, this);
|
||
|
||
},
|
||
|
||
/**
|
||
* removeFilters
|
||
*
|
||
* Removes multiple filter handlers
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object filters {filter1 : callback, filter2 : callback, etc }
|
||
* @return n/a
|
||
*/
|
||
|
||
removeFilters: function( filters ){
|
||
filters = filters || this.filters || null;
|
||
if( !filters ) return false;
|
||
for( var i in filters ) {
|
||
this.removeFilter( i, filters[i] );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* removeFilter
|
||
*
|
||
* Remove a filter using the wp.hooks library
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param string callback
|
||
* @return n/a
|
||
*/
|
||
|
||
removeFilter: function( name, callback ){
|
||
acf.removeFilter(name, this[ callback ]);
|
||
},
|
||
|
||
/**
|
||
* $
|
||
*
|
||
* description
|
||
*
|
||
* @date 16/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
$: function( selector ){
|
||
return this.$el.find( selector );
|
||
},
|
||
|
||
/**
|
||
* remove
|
||
*
|
||
* Removes the element and listenters
|
||
*
|
||
* @date 19/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
remove: function(){
|
||
this.removeEvents();
|
||
this.removeActions();
|
||
this.removeFilters();
|
||
this.$el.remove();
|
||
},
|
||
|
||
/**
|
||
* setTimeout
|
||
*
|
||
* description
|
||
*
|
||
* @date 16/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
setTimeout: function( callback, milliseconds ){
|
||
return setTimeout( this.proxy(callback), milliseconds );
|
||
},
|
||
|
||
/**
|
||
* time
|
||
*
|
||
* used for debugging
|
||
*
|
||
* @date 7/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
time: function(){
|
||
console.time( this.id || this.cid );
|
||
},
|
||
|
||
/**
|
||
* timeEnd
|
||
*
|
||
* used for debugging
|
||
*
|
||
* @date 7/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
timeEnd: function(){
|
||
console.timeEnd( this.id || this.cid );
|
||
},
|
||
|
||
/**
|
||
* show
|
||
*
|
||
* description
|
||
*
|
||
* @date 15/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
show: function(){
|
||
acf.show( this.$el );
|
||
},
|
||
|
||
|
||
/**
|
||
* hide
|
||
*
|
||
* description
|
||
*
|
||
* @date 15/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
hide: function(){
|
||
acf.hide( this.$el );
|
||
},
|
||
|
||
/**
|
||
* proxy
|
||
*
|
||
* Returns a new function scoped to this model
|
||
*
|
||
* @date 29/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param function callback
|
||
* @return function
|
||
*/
|
||
|
||
proxy: function( callback ){
|
||
return $.proxy( callback, this );
|
||
}
|
||
|
||
|
||
});
|
||
|
||
// Set up inheritance for the model
|
||
Model.extend = extend;
|
||
|
||
// Global model storage
|
||
acf.models = {};
|
||
|
||
/**
|
||
* acf.getInstance
|
||
*
|
||
* This function will get an instance from an element
|
||
*
|
||
* @date 5/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.getInstance = function( $el ){
|
||
return $el.data('acf');
|
||
};
|
||
|
||
/**
|
||
* acf.getInstances
|
||
*
|
||
* This function will get an array of instances from multiple elements
|
||
*
|
||
* @date 5/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.getInstances = function( $el ){
|
||
var instances = [];
|
||
$el.each(function(){
|
||
instances.push( acf.getInstance( $(this) ) );
|
||
});
|
||
return instances;
|
||
};
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
acf.models.Popup = acf.Model.extend({
|
||
|
||
data: {
|
||
title: '',
|
||
content: '',
|
||
width: 0,
|
||
height: 0,
|
||
loading: false,
|
||
},
|
||
|
||
events: {
|
||
'click [data-event="close"]': 'onClickClose',
|
||
'click .acf-close-popup': 'onClickClose',
|
||
},
|
||
|
||
setup: function( props ){
|
||
$.extend(this.data, props);
|
||
this.$el = $(this.tmpl());
|
||
},
|
||
|
||
initialize: function(){
|
||
this.render();
|
||
this.open();
|
||
},
|
||
|
||
tmpl: function(){
|
||
return [
|
||
'<div id="acf-popup">',
|
||
'<div class="acf-popup-box acf-box">',
|
||
'<div class="title"><h3></h3><a href="#" class="acf-icon -cancel grey" data-event="close"></a></div>',
|
||
'<div class="inner"></div>',
|
||
'<div class="loading"><i class="acf-loading"></i></div>',
|
||
'</div>',
|
||
'<div class="bg" data-event="close"></div>',
|
||
'</div>'
|
||
].join('');
|
||
},
|
||
|
||
render: function(){
|
||
|
||
// vars
|
||
var title = this.get('title');
|
||
var content = this.get('content');
|
||
var loading = this.get('loading');
|
||
var width = this.get('width');
|
||
var height = this.get('height');
|
||
|
||
// html
|
||
this.title( title );
|
||
this.content( content );
|
||
|
||
// width
|
||
if( width ) {
|
||
this.$('.acf-popup-box').css('width', width);
|
||
}
|
||
|
||
// height
|
||
if( height ) {
|
||
this.$('.acf-popup-box').css('min-height', height);
|
||
}
|
||
|
||
// loading
|
||
this.loading( loading );
|
||
|
||
// action
|
||
acf.doAction('append', this.$el);
|
||
|
||
},
|
||
|
||
update: function( props ){
|
||
this.data = acf.parseArgs(props, this.data);
|
||
this.render();
|
||
},
|
||
|
||
title: function( title ){
|
||
this.$('.title:first h3').html( title );
|
||
},
|
||
|
||
content: function( content ){
|
||
this.$('.inner:first').html( content );
|
||
},
|
||
|
||
loading: function( show ){
|
||
var $loading = this.$('.loading:first');
|
||
show ? $loading.show() : $loading.hide();
|
||
},
|
||
|
||
open: function(){
|
||
$('body').append( this.$el );
|
||
},
|
||
|
||
close: function(){
|
||
this.remove();
|
||
},
|
||
|
||
onClickClose: function( e, $el ){
|
||
e.preventDefault();
|
||
this.close();
|
||
}
|
||
|
||
});
|
||
|
||
/**
|
||
* newPopup
|
||
*
|
||
* Creates a new Popup with the supplied props
|
||
*
|
||
* @date 17/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object props
|
||
* @return object
|
||
*/
|
||
|
||
acf.newPopup = function( props ){
|
||
return new acf.models.Popup( props );
|
||
};
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
acf.unload = new acf.Model({
|
||
|
||
wait: 'load',
|
||
active: true,
|
||
changed: false,
|
||
|
||
actions: {
|
||
'change_field': 'startListening',
|
||
'validation_failure': 'startListening'
|
||
},
|
||
|
||
events: {
|
||
'submit form': 'stopListening'
|
||
},
|
||
|
||
reset: function(){
|
||
this.stopListening();
|
||
},
|
||
|
||
startListening: function(){
|
||
|
||
// bail ealry if already changed, not active
|
||
if( this.changed || !this.active ) {
|
||
return;
|
||
}
|
||
|
||
// update
|
||
this.changed = true;
|
||
|
||
// add event
|
||
$(window).on('beforeunload', this.onUnload);
|
||
|
||
},
|
||
|
||
stopListening: function(){
|
||
|
||
// update
|
||
this.changed = false;
|
||
|
||
// remove event
|
||
$(window).off('beforeunload', this.onUnload);
|
||
|
||
},
|
||
|
||
onUnload: function(){
|
||
return acf.__('The changes you made will be lost if you navigate away from this page');
|
||
}
|
||
|
||
});
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var panel = new acf.Model({
|
||
|
||
events: {
|
||
'click .acf-panel-title': 'onClick',
|
||
},
|
||
|
||
onClick: function( e, $el ){
|
||
e.preventDefault();
|
||
this.toggle( $el.parent() );
|
||
},
|
||
|
||
isOpen: function( $el ) {
|
||
return $el.hasClass('-open');
|
||
},
|
||
|
||
toggle: function( $el ){
|
||
this.isOpen($el) ? this.close( $el ) : this.open( $el );
|
||
},
|
||
|
||
open: function( $el ){
|
||
$el.addClass('-open');
|
||
$el.find('.acf-panel-title i').attr('class', 'dashicons dashicons-arrow-down');
|
||
},
|
||
|
||
close: function( $el ){
|
||
$el.removeClass('-open');
|
||
$el.find('.acf-panel-title i').attr('class', 'dashicons dashicons-arrow-right');
|
||
}
|
||
|
||
});
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Notice = acf.Model.extend({
|
||
|
||
data: {
|
||
text: '',
|
||
type: '',
|
||
timeout: 0,
|
||
dismiss: true,
|
||
target: false,
|
||
close: function(){}
|
||
},
|
||
|
||
events: {
|
||
'click .acf-notice-dismiss': 'onClickClose',
|
||
},
|
||
|
||
tmpl: function(){
|
||
return '<div class="acf-notice"></div>';
|
||
},
|
||
|
||
setup: function( props ){
|
||
$.extend(this.data, props);
|
||
this.$el = $(this.tmpl());
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// render
|
||
this.render();
|
||
|
||
// show
|
||
this.show();
|
||
},
|
||
|
||
render: function(){
|
||
|
||
// class
|
||
this.type( this.get('type') );
|
||
|
||
// text
|
||
this.html( '<p>' + this.get('text') + '</p>' );
|
||
|
||
// close
|
||
if( this.get('dismiss') ) {
|
||
this.$el.append('<a href="#" class="acf-notice-dismiss acf-icon -cancel small"></a>');
|
||
this.$el.addClass('-dismiss');
|
||
}
|
||
|
||
// timeout
|
||
var timeout = this.get('timeout');
|
||
if( timeout ) {
|
||
this.away( timeout );
|
||
}
|
||
},
|
||
|
||
update: function( props ){
|
||
|
||
// update
|
||
$.extend(this.data, props);
|
||
|
||
// re-initialize
|
||
this.initialize();
|
||
},
|
||
|
||
show: function(){
|
||
var $target = this.get('target');
|
||
if( $target ) {
|
||
$target.prepend( this.$el );
|
||
}
|
||
},
|
||
|
||
hide: function(){
|
||
this.$el.remove();
|
||
},
|
||
|
||
away: function( timeout ){
|
||
this.setTimeout(function(){
|
||
acf.remove( this.$el );
|
||
}, timeout );
|
||
},
|
||
|
||
type: function( type ){
|
||
|
||
// remove prev type
|
||
var prevType = this.get('type');
|
||
if( prevType ) {
|
||
this.$el.removeClass('-' + prevType);
|
||
}
|
||
|
||
// add new type
|
||
this.$el.addClass('-' + type);
|
||
|
||
// backwards compatibility
|
||
if( type == 'error' ) {
|
||
this.$el.addClass('acf-error-message');
|
||
}
|
||
},
|
||
|
||
html: function( html ){
|
||
this.$el.html( html );
|
||
},
|
||
|
||
text: function( text ){
|
||
this.$('p').html( text );
|
||
},
|
||
|
||
onClickClose: function( e, $el ){
|
||
e.preventDefault();
|
||
this.get('close').apply(this, arguments);
|
||
this.remove();
|
||
}
|
||
});
|
||
|
||
acf.newNotice = function( props ){
|
||
|
||
// ensure object
|
||
if( typeof props !== 'object' ) {
|
||
props = { text: props };
|
||
}
|
||
|
||
// instantiate
|
||
return new Notice( props );
|
||
};
|
||
|
||
var noticeManager = new acf.Model({
|
||
wait: 'prepare',
|
||
priority: 1,
|
||
initialize: function(){
|
||
|
||
// vars
|
||
var $notice = $('.acf-admin-notice');
|
||
|
||
// move to avoid WP flicker
|
||
if( $notice.length ) {
|
||
$('h1:first').after( $notice );
|
||
}
|
||
}
|
||
});
|
||
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
acf.models.Postbox = acf.Model.extend({
|
||
|
||
data: {
|
||
id: '',
|
||
key: '',
|
||
style: 'default',
|
||
label: 'top',
|
||
editLink: '',
|
||
editTitle: '',
|
||
visibility: true
|
||
},
|
||
|
||
setup: function( props ){
|
||
$.extend(this.data, props);
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// vars
|
||
var id = this.get('id');
|
||
var $postbox = $('#' + id);
|
||
var $toggle = $('#' + id + '-hide');
|
||
var $label = $toggle.parent();
|
||
|
||
// add class
|
||
$postbox.addClass('acf-postbox');
|
||
$label.addClass('acf-postbox-toggle');
|
||
|
||
// remove class
|
||
$postbox.removeClass('hide-if-js');
|
||
$label.removeClass('hide-if-js');
|
||
|
||
// field group style
|
||
var style = this.get('style');
|
||
if( style !== 'default' ) {
|
||
$postbox.addClass( style );
|
||
}
|
||
|
||
// .inside class
|
||
$postbox.children('.inside').addClass('acf-fields').addClass('-' + this.get('label'));
|
||
|
||
|
||
// visibility
|
||
if( this.get('visibility') ) {
|
||
$toggle.prop('checked', true);
|
||
} else {
|
||
$postbox.addClass('acf-hidden');
|
||
$label.addClass('acf-hidden');
|
||
}
|
||
|
||
// edit link
|
||
var editLink = this.get('editLink');
|
||
var editTitle = this.get('editTitle');
|
||
if( editLink ) {
|
||
|
||
$postbox.children('.hndle').append('<a href="' + editLink + '" class="dashicons dashicons-admin-generic acf-hndle-cog acf-js-tooltip" title="' + editTitle + '"></a>');
|
||
}
|
||
}
|
||
});
|
||
|
||
acf.newPostbox = function( props ){
|
||
return new acf.models.Postbox( props );
|
||
};
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
acf.newTooltip = function( props ){
|
||
|
||
// ensure object
|
||
if( typeof props !== 'object' ) {
|
||
props = { text: props };
|
||
}
|
||
|
||
// confirmRemove
|
||
if( props.confirmRemove !== undefined ) {
|
||
|
||
props.textConfirm = acf.__('Remove');
|
||
props.textCancel = acf.__('Cancel');
|
||
return new TooltipConfirm( props );
|
||
|
||
// confirm
|
||
} else if( props.confirm !== undefined ) {
|
||
|
||
return new TooltipConfirm( props );
|
||
|
||
// default
|
||
} else {
|
||
return new Tooltip( props );
|
||
}
|
||
|
||
};
|
||
|
||
var Tooltip = acf.Model.extend({
|
||
|
||
data: {
|
||
text: '',
|
||
timeout: 0,
|
||
target: null
|
||
},
|
||
|
||
tmpl: function(){
|
||
return '<div class="acf-tooltip"></div>';
|
||
},
|
||
|
||
setup: function( props ){
|
||
$.extend(this.data, props);
|
||
this.$el = $(this.tmpl());
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// render
|
||
this.render();
|
||
|
||
// append
|
||
this.show();
|
||
|
||
// position
|
||
this.position();
|
||
|
||
// timeout
|
||
var timeout = this.get('timeout');
|
||
if( timeout ) {
|
||
setTimeout( $.proxy(this.fade, this), timeout );
|
||
}
|
||
},
|
||
|
||
update: function( props ){
|
||
$.extend(this.data, props);
|
||
this.initialize();
|
||
},
|
||
|
||
render: function(){
|
||
this.html( this.get('text') );
|
||
},
|
||
|
||
show: function(){
|
||
$('body').append( this.$el );
|
||
},
|
||
|
||
hide: function(){
|
||
this.$el.remove();
|
||
},
|
||
|
||
fade: function(){
|
||
|
||
// add class
|
||
this.$el.addClass('acf-fade-up');
|
||
|
||
// remove
|
||
this.setTimeout(function(){
|
||
this.remove();
|
||
}, 250);
|
||
},
|
||
|
||
html: function( html ){
|
||
this.$el.html( html );
|
||
},
|
||
|
||
position: function(){
|
||
|
||
// vars
|
||
var $tooltip = this.$el;
|
||
var $target = this.get('target');
|
||
if( !$target ) return;
|
||
|
||
// reset class
|
||
$tooltip.removeClass('right left bottom top');
|
||
|
||
// position
|
||
var tolerance = 10;
|
||
var target_w = $target.outerWidth();
|
||
var target_h = $target.outerHeight();
|
||
var target_t = $target.offset().top;
|
||
var target_l = $target.offset().left;
|
||
var tooltip_w = $tooltip.outerWidth();
|
||
var tooltip_h = $tooltip.outerHeight();
|
||
|
||
// calculate top
|
||
var top = target_t - tooltip_h;
|
||
var left = target_l + (target_w / 2) - (tooltip_w / 2);
|
||
|
||
// too far left
|
||
if( left < tolerance ) {
|
||
|
||
$tooltip.addClass('right');
|
||
left = target_l + target_w;
|
||
top = target_t + (target_h / 2) - (tooltip_h / 2);
|
||
|
||
// too far right
|
||
} else if( (left + tooltip_w + tolerance) > $(window).width() ) {
|
||
|
||
$tooltip.addClass('left');
|
||
left = target_l - tooltip_w;
|
||
top = target_t + (target_h / 2) - (tooltip_h / 2);
|
||
|
||
// too far top
|
||
} else if( top - $(window).scrollTop() < tolerance ) {
|
||
|
||
$tooltip.addClass('bottom');
|
||
top = target_t + target_h;
|
||
|
||
} else {
|
||
|
||
$tooltip.addClass('top');
|
||
|
||
}
|
||
|
||
// update css
|
||
$tooltip.css({ 'top': top, 'left': left });
|
||
}
|
||
});
|
||
|
||
var TooltipConfirm = Tooltip.extend({
|
||
|
||
data: {
|
||
text: '',
|
||
textConfirm: '',
|
||
textCancel: '',
|
||
target: null,
|
||
targetConfirm: true,
|
||
confirm: function(){},
|
||
cancel: function(){},
|
||
context: false
|
||
},
|
||
|
||
events: {
|
||
'click [data-event="cancel"]': 'onCancel',
|
||
'click [data-event="confirm"]': 'onConfirm',
|
||
},
|
||
|
||
addEvents: function(){
|
||
|
||
// add events
|
||
acf.Model.prototype.addEvents.apply(this);
|
||
|
||
// vars
|
||
var $document = $(document);
|
||
var $target = this.get('target');
|
||
|
||
// add global 'cancel' click event
|
||
// - use timeout to avoid the current 'click' event triggering the onCancel function
|
||
this.setTimeout(function(){
|
||
this.on( $document, 'click', 'onCancel' );
|
||
});
|
||
|
||
// add target 'confirm' click event
|
||
// - allow setting to control this feature
|
||
if( this.get('targetConfirm') ) {
|
||
this.on( $target, 'click', 'onConfirm' );
|
||
}
|
||
},
|
||
|
||
removeEvents: function(){
|
||
|
||
// remove events
|
||
acf.Model.prototype.removeEvents.apply(this);
|
||
|
||
// vars
|
||
var $document = $(document);
|
||
var $target = this.get('target');
|
||
|
||
// remove custom events
|
||
this.off( $document, 'click' );
|
||
this.off( $target, 'click' );
|
||
},
|
||
|
||
render: function(){
|
||
|
||
// defaults
|
||
var text = this.get('text') || acf.__('Are you sure?');
|
||
var textConfirm = this.get('textConfirm') || acf.__('Yes');
|
||
var textCancel = this.get('textCancel') || acf.__('No');
|
||
|
||
// html
|
||
var html = [
|
||
text,
|
||
'<a href="#" data-event="confirm">' + textConfirm + '</a>',
|
||
'<a href="#" data-event="cancel">' + textCancel + '</a>'
|
||
].join(' ');
|
||
|
||
// html
|
||
this.html( html );
|
||
|
||
// class
|
||
this.$el.addClass('-confirm');
|
||
},
|
||
|
||
onCancel: function( e, $el ){
|
||
|
||
// prevent default
|
||
e.preventDefault();
|
||
e.stopImmediatePropagation();
|
||
|
||
// callback
|
||
var callback = this.get('cancel');
|
||
var context = this.get('context') || this;
|
||
callback.apply( context, arguments );
|
||
|
||
//remove
|
||
this.remove();
|
||
},
|
||
|
||
onConfirm: function( e, $el ){
|
||
|
||
// prevent default
|
||
e.preventDefault();
|
||
e.stopImmediatePropagation();
|
||
|
||
// callback
|
||
var callback = this.get('confirm');
|
||
var context = this.get('context') || this;
|
||
callback.apply( context, arguments );
|
||
|
||
//remove
|
||
this.remove();
|
||
}
|
||
});
|
||
|
||
// storage
|
||
acf.models.Tooltip = Tooltip;
|
||
acf.models.TooltipConfirm = TooltipConfirm;
|
||
|
||
|
||
/**
|
||
* tooltipManager
|
||
*
|
||
* description
|
||
*
|
||
* @date 17/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
var tooltipHoverHelper = new acf.Model({
|
||
|
||
tooltip: false,
|
||
|
||
events: {
|
||
'mouseenter .acf-js-tooltip': 'showTitle',
|
||
'mouseup .acf-js-tooltip': 'hideTitle',
|
||
'mouseleave .acf-js-tooltip': 'hideTitle'
|
||
},
|
||
|
||
showTitle: function( e, $el ){
|
||
|
||
// vars
|
||
var title = $el.attr('title');
|
||
|
||
// bail ealry if no title
|
||
if( !title ) {
|
||
return;
|
||
}
|
||
|
||
// clear title to avoid default browser tooltip
|
||
$el.attr('title', '');
|
||
|
||
// create
|
||
if( !this.tooltip ) {
|
||
this.tooltip = acf.newTooltip({
|
||
text: title,
|
||
target: $el
|
||
});
|
||
|
||
// update
|
||
} else {
|
||
this.tooltip.update({
|
||
text: title,
|
||
target: $el
|
||
});
|
||
}
|
||
|
||
},
|
||
|
||
hideTitle: function( e, $el ){
|
||
|
||
// hide tooltip
|
||
this.tooltip.hide();
|
||
|
||
// restore title
|
||
$el.attr('title', this.tooltip.get('text'));
|
||
}
|
||
});
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
// vars
|
||
var storage = [];
|
||
|
||
/**
|
||
* acf.Field
|
||
*
|
||
* description
|
||
*
|
||
* @date 23/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.Field = acf.Model.extend({
|
||
|
||
// field type
|
||
type: '',
|
||
|
||
// class used to avoid nested event triggers
|
||
eventScope: '.acf-field',
|
||
|
||
// initialize events on 'ready'
|
||
wait: 'ready',
|
||
|
||
/**
|
||
* setup
|
||
*
|
||
* Called during the constructor function to setup this field ready for initialization
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param jQuery $field The field element.
|
||
* @return void
|
||
*/
|
||
|
||
setup: function( $field ){
|
||
|
||
// set $el
|
||
this.$el = $field;
|
||
|
||
// inherit $field data
|
||
this.inherit( $field );
|
||
|
||
// inherit controll data
|
||
this.inherit( this.$control() );
|
||
},
|
||
|
||
/**
|
||
* val
|
||
*
|
||
* Sets or returns the field's value
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param mixed val Optional. The value to set
|
||
* @return mixed
|
||
*/
|
||
|
||
val: function( val ){
|
||
if( val !== undefined ) {
|
||
return this.setValue( val );
|
||
} else {
|
||
return this.prop('disabled') ? null : this.getValue();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* getValue
|
||
*
|
||
* returns the field's value
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param void
|
||
* @return mixed
|
||
*/
|
||
|
||
getValue: function(){
|
||
return this.$input().val();
|
||
},
|
||
|
||
/**
|
||
* setValue
|
||
*
|
||
* sets the field's value and returns true if changed
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param mixed val
|
||
* @return boolean. True if changed.
|
||
*/
|
||
|
||
setValue: function( val ){
|
||
return acf.val( this.$input(), val );
|
||
},
|
||
|
||
/**
|
||
* __
|
||
*
|
||
* i18n helper to be removed
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
__: function( string ){
|
||
return acf._e( this.type, string );
|
||
},
|
||
|
||
/**
|
||
* $control
|
||
*
|
||
* returns the control jQuery element used for inheriting data. Uses this.control setting.
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param void
|
||
* @return jQuery
|
||
*/
|
||
|
||
$control: function(){
|
||
return false;
|
||
},
|
||
|
||
/**
|
||
* $input
|
||
*
|
||
* returns the input jQuery element used for saving values. Uses this.input setting.
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param void
|
||
* @return jQuery
|
||
*/
|
||
|
||
$input: function(){
|
||
return this.$('[name]:first');
|
||
},
|
||
|
||
/**
|
||
* $inputWrap
|
||
*
|
||
* description
|
||
*
|
||
* @date 12/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
$inputWrap: function(){
|
||
return this.$('.acf-input:first');
|
||
},
|
||
|
||
/**
|
||
* $inputWrap
|
||
*
|
||
* description
|
||
*
|
||
* @date 12/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
$labelWrap: function(){
|
||
return this.$('.acf-label:first');
|
||
},
|
||
|
||
/**
|
||
* getInputName
|
||
*
|
||
* Returns the field's input name
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param void
|
||
* @return string
|
||
*/
|
||
|
||
getInputName: function(){
|
||
return this.$input().attr('name') || '';
|
||
},
|
||
|
||
/**
|
||
* parent
|
||
*
|
||
* returns the field's parent field or false on failure.
|
||
*
|
||
* @date 8/5/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param void
|
||
* @return object|false
|
||
*/
|
||
|
||
parent: function() {
|
||
|
||
// vars
|
||
var parents = this.parents();
|
||
|
||
// return
|
||
return parents.length ? parents[0] : false;
|
||
},
|
||
|
||
/**
|
||
* parents
|
||
*
|
||
* description
|
||
*
|
||
* @date 9/7/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
parents: function(){
|
||
|
||
// vars
|
||
var $parents = this.$el.parents('.acf-field');
|
||
|
||
// convert
|
||
var parents = acf.getFields( $parents );
|
||
|
||
// return
|
||
return parents;
|
||
},
|
||
|
||
show: function( lockKey, context ){
|
||
|
||
// show field and store result
|
||
var changed = acf.show( this.$el, lockKey );
|
||
|
||
// do action if visibility has changed
|
||
if( changed ) {
|
||
this.prop('hidden', false);
|
||
acf.doAction('show_field', this, context);
|
||
}
|
||
|
||
// return
|
||
return changed;
|
||
},
|
||
|
||
hide: function( lockKey, context ){
|
||
|
||
// hide field and store result
|
||
var changed = acf.hide( this.$el, lockKey );
|
||
|
||
// do action if visibility has changed
|
||
if( changed ) {
|
||
this.prop('hidden', true);
|
||
acf.doAction('hide_field', this, context);
|
||
}
|
||
|
||
// return
|
||
return changed;
|
||
},
|
||
|
||
enable: function( lockKey, context ){
|
||
|
||
// enable field and store result
|
||
var changed = acf.enable( this.$el, lockKey );
|
||
|
||
// do action if disabled has changed
|
||
if( changed ) {
|
||
this.prop('disabled', false);
|
||
acf.doAction('enable_field', this, context);
|
||
}
|
||
|
||
// return
|
||
return changed;
|
||
},
|
||
|
||
disable: function( lockKey, context ){
|
||
|
||
// disabled field and store result
|
||
var changed = acf.disable( this.$el, lockKey );
|
||
|
||
// do action if disabled has changed
|
||
if( changed ) {
|
||
this.prop('disabled', true);
|
||
acf.doAction('disable_field', this, context);
|
||
}
|
||
|
||
// return
|
||
return changed;
|
||
},
|
||
|
||
showEnable: function( lockKey, context ){
|
||
|
||
// enable
|
||
this.enable.apply(this, arguments);
|
||
|
||
// show and return true if changed
|
||
return this.show.apply(this, arguments);
|
||
},
|
||
|
||
hideDisable: function( lockKey, context ){
|
||
|
||
// disable
|
||
this.disable.apply(this, arguments);
|
||
|
||
// hide and return true if changed
|
||
return this.hide.apply(this, arguments);
|
||
},
|
||
|
||
showNotice: function( props ){
|
||
|
||
// ensure object
|
||
if( typeof props !== 'object' ) {
|
||
props = { text: props };
|
||
}
|
||
|
||
// remove old notice
|
||
if( this.notice ) {
|
||
this.notice.remove();
|
||
}
|
||
|
||
// create new notice
|
||
props.target = this.$inputWrap();
|
||
this.notice = acf.newNotice( props );
|
||
},
|
||
|
||
removeNotice: function( timeout ){
|
||
if( this.notice ) {
|
||
this.notice.away( timeout || 0 );
|
||
this.notice = false;
|
||
}
|
||
},
|
||
|
||
showError: function( message ){
|
||
|
||
// add class
|
||
this.$el.addClass('acf-error');
|
||
|
||
// add message
|
||
if( message !== undefined ) {
|
||
this.showNotice({
|
||
text: message,
|
||
type: 'error',
|
||
dismiss: false
|
||
});
|
||
}
|
||
|
||
// action
|
||
acf.doAction('invalid_field', this);
|
||
|
||
// add event
|
||
this.$el.one('focus change', 'input, select, textarea', $.proxy( this.removeError, this ));
|
||
},
|
||
|
||
removeError: function(){
|
||
|
||
// remove class
|
||
this.$el.removeClass('acf-error');
|
||
|
||
// remove notice
|
||
this.removeNotice( 250 );
|
||
|
||
// action
|
||
acf.doAction('valid_field', this);
|
||
},
|
||
|
||
trigger: function( name, args, bubbles ){
|
||
|
||
// allow some events to bubble
|
||
if( name == 'invalidField' ) {
|
||
bubbles = true;
|
||
}
|
||
|
||
// return
|
||
return acf.Model.prototype.trigger.apply(this, [name, args, bubbles]);
|
||
},
|
||
});
|
||
|
||
/**
|
||
* newField
|
||
*
|
||
* description
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.newField = function( $field ){
|
||
|
||
// vars
|
||
var type = $field.data('type');
|
||
var mid = modelId( type );
|
||
var model = acf.models[ mid ] || acf.Field;
|
||
|
||
// instantiate
|
||
var field = new model( $field );
|
||
|
||
// actions
|
||
acf.doAction('new_field', field);
|
||
|
||
// return
|
||
return field;
|
||
};
|
||
|
||
/**
|
||
* 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 || '' ) + 'Field';
|
||
};
|
||
|
||
/**
|
||
* registerFieldType
|
||
*
|
||
* description
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.registerFieldType = 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.getFieldType
|
||
*
|
||
* description
|
||
*
|
||
* @date 1/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.getFieldType = function( type ){
|
||
var mid = modelId( type );
|
||
return acf.models[ mid ] || false;
|
||
}
|
||
|
||
/**
|
||
* acf.getFieldTypes
|
||
*
|
||
* description
|
||
*
|
||
* @date 1/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.getFieldTypes = function( args ){
|
||
|
||
// defaults
|
||
args = acf.parseArgs(args, {
|
||
category: '',
|
||
// hasValue: true
|
||
});
|
||
|
||
// clonse available types
|
||
var types = [];
|
||
|
||
// loop
|
||
storage.map(function( type ){
|
||
|
||
// vars
|
||
var model = acf.getFieldType(type);
|
||
var proto = model.prototype;
|
||
|
||
// check operator
|
||
if( args.category && proto.category !== args.category ) {
|
||
return;
|
||
}
|
||
|
||
// append
|
||
types.push( model );
|
||
});
|
||
|
||
// return
|
||
return types;
|
||
};
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
/**
|
||
* findFields
|
||
*
|
||
* Returns a jQuery selection object of acf fields.
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param object $args {
|
||
* Optional. Arguments to find fields.
|
||
*
|
||
* @type string key The field's key (data-attribute).
|
||
* @type string name The field's name (data-attribute).
|
||
* @type string type The field's type (data-attribute).
|
||
* @type string is jQuery selector to compare against.
|
||
* @type jQuery parent jQuery element to search within.
|
||
* @type jQuery sibling jQuery element to search alongside.
|
||
* @type limit int The number of fields to find.
|
||
* @type suppressFilters bool Whether to allow filters to add/remove results. Default behaviour will ignore clone fields.
|
||
* }
|
||
* @return jQuery
|
||
*/
|
||
|
||
acf.findFields = function( args ){
|
||
|
||
// vars
|
||
var selector = '.acf-field';
|
||
var $fields = false;
|
||
|
||
// args
|
||
args = acf.parseArgs(args, {
|
||
key: '',
|
||
name: '',
|
||
type: '',
|
||
is: '',
|
||
parent: false,
|
||
sibling: false,
|
||
limit: false,
|
||
visible: false,
|
||
suppressFilters: false,
|
||
});
|
||
|
||
// filter args
|
||
if( !args.suppressFilters ) {
|
||
args = acf.applyFilters('find_fields_args', args);
|
||
}
|
||
|
||
// key
|
||
if( args.key ) {
|
||
selector += '[data-key="' + args.key + '"]';
|
||
}
|
||
|
||
// type
|
||
if( args.type ) {
|
||
selector += '[data-type="' + args.type + '"]';
|
||
}
|
||
|
||
// name
|
||
if( args.name ) {
|
||
selector += '[data-name="' + args.name + '"]';
|
||
}
|
||
|
||
// is
|
||
if( args.is ) {
|
||
selector += args.is;
|
||
}
|
||
|
||
// visibility
|
||
if( args.visible ) {
|
||
selector += ':visible';
|
||
}
|
||
|
||
// query
|
||
if( args.parent ) {
|
||
$fields = args.parent.find( selector );
|
||
} else if( args.sibling ) {
|
||
$fields = args.sibling.siblings( selector );
|
||
} else {
|
||
$fields = $( selector );
|
||
}
|
||
|
||
// filter
|
||
if( !args.suppressFilters ) {
|
||
$fields = $fields.not('.acf-clone .acf-field');
|
||
$fields = acf.applyFilters('find_fields', $fields);
|
||
}
|
||
|
||
// limit
|
||
if( args.limit ) {
|
||
$fields = $fields.slice( 0, args.limit );
|
||
}
|
||
|
||
// return
|
||
return $fields;
|
||
|
||
};
|
||
|
||
/**
|
||
* findField
|
||
*
|
||
* Finds a specific field with jQuery
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string key The field's key.
|
||
* @param jQuery $parent jQuery element to search within.
|
||
* @return jQuery
|
||
*/
|
||
|
||
acf.findField = function( key, $parent ){
|
||
return acf.findFields({
|
||
key: key,
|
||
limit: 1,
|
||
parent: $parent,
|
||
suppressFilters: true
|
||
});
|
||
};
|
||
|
||
/**
|
||
* getField
|
||
*
|
||
* Returns a field instance
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param jQuery|string $field jQuery element or field key.
|
||
* @return object
|
||
*/
|
||
|
||
acf.getField = function( $field ){
|
||
|
||
// allow jQuery
|
||
if( $field instanceof jQuery ) {
|
||
|
||
// find fields
|
||
} else {
|
||
$field = acf.findField( $field );
|
||
}
|
||
|
||
// instantiate
|
||
var field = $field.data('acf');
|
||
if( !field ) {
|
||
field = acf.newField( $field );
|
||
}
|
||
|
||
// return
|
||
return field;
|
||
};
|
||
|
||
/**
|
||
* getFields
|
||
*
|
||
* Returns multiple field instances
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param jQuery|object $fields jQuery elements or query args.
|
||
* @return array
|
||
*/
|
||
|
||
acf.getFields = function( $fields ){
|
||
|
||
// allow jQuery
|
||
if( $fields instanceof jQuery ) {
|
||
|
||
// find fields
|
||
} else {
|
||
$fields = acf.findFields( $fields );
|
||
}
|
||
|
||
// loop
|
||
var fields = [];
|
||
$fields.each(function(){
|
||
var field = acf.getField( $(this) );
|
||
fields.push( field );
|
||
});
|
||
|
||
// return
|
||
return fields;
|
||
};
|
||
|
||
/**
|
||
* findClosestField
|
||
*
|
||
* Returns the closest jQuery field element
|
||
*
|
||
* @date 9/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param jQuery $el
|
||
* @return jQuery
|
||
*/
|
||
|
||
acf.findClosestField = function( $el ){
|
||
return $el.closest('.acf-field');
|
||
};
|
||
|
||
/**
|
||
* getClosestField
|
||
*
|
||
* Returns the closest field instance
|
||
*
|
||
* @date 22/1/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param jQuery $el
|
||
* @return object
|
||
*/
|
||
|
||
acf.getClosestField = function( $el ){
|
||
var $field = acf.findClosestField( $el );
|
||
return this.getField( $field );
|
||
};
|
||
|
||
/**
|
||
* addGlobalFieldAction
|
||
*
|
||
* Sets up callback logic for global field actions
|
||
*
|
||
* @date 15/6/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param string action
|
||
* @return void
|
||
*/
|
||
|
||
var addGlobalFieldAction = function( action ){
|
||
|
||
// vars
|
||
var globalAction = action;
|
||
var pluralAction = action + '_fields'; // ready_fields
|
||
var singleAction = action + '_field'; // ready_field
|
||
|
||
// global action
|
||
var globalCallback = function( $el /*, arg1, arg2, etc*/ ){
|
||
//console.log( action, arguments );
|
||
|
||
// get args [$el, ...]
|
||
var args = acf.arrayArgs( arguments );
|
||
var extraArgs = args.slice(1);
|
||
|
||
// find fields
|
||
var fields = acf.getFields({ parent: $el });
|
||
|
||
// check
|
||
if( fields.length ) {
|
||
|
||
// pluralAction
|
||
var pluralArgs = [ pluralAction, fields ].concat( extraArgs );
|
||
acf.doAction.apply(null, pluralArgs);
|
||
}
|
||
};
|
||
|
||
// plural action
|
||
var pluralCallback = function( fields /*, arg1, arg2, etc*/ ){
|
||
//console.log( pluralAction, arguments );
|
||
|
||
// get args [fields, ...]
|
||
var args = acf.arrayArgs( arguments );
|
||
var extraArgs = args.slice(1);
|
||
|
||
// loop
|
||
fields.map(function( field, i ){
|
||
//setTimeout(function(){
|
||
// singleAction
|
||
var singleArgs = [ singleAction, field ].concat( extraArgs );
|
||
acf.doAction.apply(null, singleArgs);
|
||
//}, i * 100);
|
||
});
|
||
};
|
||
|
||
// add actions
|
||
acf.addAction(globalAction, globalCallback);
|
||
acf.addAction(pluralAction, pluralCallback);
|
||
|
||
// also add single action
|
||
addSingleFieldAction( action );
|
||
}
|
||
|
||
/**
|
||
* addSingleFieldAction
|
||
*
|
||
* Sets up callback logic for single field actions
|
||
*
|
||
* @date 15/6/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param string action
|
||
* @return void
|
||
*/
|
||
|
||
var addSingleFieldAction = function( action ){
|
||
|
||
// vars
|
||
var singleAction = action + '_field'; // ready_field
|
||
var singleEvent = action + 'Field'; // readyField
|
||
|
||
// single action
|
||
var singleCallback = function( field /*, arg1, arg2, etc*/ ){
|
||
//console.log( singleAction, arguments );
|
||
|
||
// get args [field, ...]
|
||
var args = acf.arrayArgs( arguments );
|
||
var extraArgs = args.slice(1);
|
||
|
||
// action variations (ready_field/type=image)
|
||
var variations = ['type', 'name', 'key'];
|
||
variations.map(function( variation ){
|
||
|
||
// vars
|
||
var prefix = '/' + variation + '=' + field.get(variation);
|
||
|
||
// singleAction
|
||
args = [ singleAction + prefix , field ].concat( extraArgs );
|
||
acf.doAction.apply(null, args);
|
||
});
|
||
|
||
// event
|
||
if( singleFieldEvents.indexOf(action) > -1 ) {
|
||
field.trigger(singleEvent, extraArgs);
|
||
}
|
||
};
|
||
|
||
// add actions
|
||
acf.addAction(singleAction, singleCallback);
|
||
}
|
||
|
||
// vars
|
||
var globalFieldActions = [ 'prepare', 'ready', 'load', 'append', 'remove', 'sortstart', 'sortstop', 'show', 'hide', 'unload' ];
|
||
var singleFieldActions = [ 'valid', 'invalid', 'enable', 'disable', 'new' ];
|
||
var singleFieldEvents = [ 'remove', 'sortstart', 'sortstop', 'show', 'hide', 'unload', 'valid', 'invalid', 'enable', 'disable' ];
|
||
|
||
// add
|
||
globalFieldActions.map( addGlobalFieldAction );
|
||
singleFieldActions.map( addSingleFieldAction );
|
||
|
||
/**
|
||
* fieldsEventManager
|
||
*
|
||
* Manages field actions and events
|
||
*
|
||
* @date 15/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param void
|
||
* @param void
|
||
*/
|
||
|
||
var fieldsEventManager = new acf.Model({
|
||
id: 'fieldsEventManager',
|
||
events: {
|
||
'click .acf-field a[href="#"]': 'onClick'
|
||
},
|
||
onClick: function( e ){
|
||
e.preventDefault();
|
||
}
|
||
});
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var i = 0;
|
||
|
||
var Field = acf.Field.extend({
|
||
|
||
type: 'accordion',
|
||
|
||
wait: '',
|
||
|
||
$control: function(){
|
||
return this.$('.acf-fields:first');
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// bail early if is cell
|
||
if( this.$el.is('td') ) return;
|
||
|
||
// enpoint
|
||
if( this.get('endpoint') ) {
|
||
return this.remove();
|
||
}
|
||
|
||
// vars
|
||
var $field = this.$el;
|
||
var $label = this.$labelWrap()
|
||
var $input = this.$inputWrap();
|
||
var $wrap = this.$control();
|
||
var $instructions = $input.children('.description');
|
||
|
||
// force description into label
|
||
if( $instructions.length ) {
|
||
$label.append( $instructions );
|
||
}
|
||
|
||
// table
|
||
if( this.$el.is('tr') ) {
|
||
|
||
// vars
|
||
var $table = this.$el.closest('table');
|
||
var $newLabel = $('<div class="acf-accordion-title"/>');
|
||
var $newInput = $('<div class="acf-accordion-content"/>');
|
||
var $newTable = $('<table class="' + $table.attr('class') + '"/>');
|
||
var $newWrap = $('<tbody/>');
|
||
|
||
// dom
|
||
$newLabel.append( $label.html() );
|
||
$newTable.append( $newWrap );
|
||
$newInput.append( $newTable );
|
||
$input.append( $newLabel );
|
||
$input.append( $newInput );
|
||
|
||
// modify
|
||
$label.remove();
|
||
$wrap.remove();
|
||
$input.attr('colspan', 2);
|
||
|
||
// update vars
|
||
$label = $newLabel;
|
||
$input = $newInput;
|
||
$wrap = $newWrap;
|
||
}
|
||
|
||
// add classes
|
||
$field.addClass('acf-accordion');
|
||
$label.addClass('acf-accordion-title');
|
||
$input.addClass('acf-accordion-content');
|
||
|
||
// index
|
||
i++;
|
||
|
||
// multi-expand
|
||
if( this.get('multi_expand') ) {
|
||
$field.attr('multi-expand', 1);
|
||
}
|
||
|
||
// open
|
||
var order = acf.getPreference('this.accordions') || [];
|
||
if( order[i-1] !== undefined ) {
|
||
this.set('open', order[i-1]);
|
||
}
|
||
|
||
if( this.get('open') ) {
|
||
$field.addClass('-open');
|
||
$input.css('display', 'block'); // needed for accordion to close smoothly
|
||
}
|
||
|
||
// add icon
|
||
$label.prepend('<i class="acf-accordion-icon dashicons dashicons-arrow-' + (this.get('open') ? 'down' : 'right') + '"></i>');
|
||
|
||
// classes
|
||
// - remove 'inside' which is a #poststuff WP class
|
||
var $parent = $field.parent();
|
||
$wrap.addClass( $parent.hasClass('-left') ? '-left' : '' );
|
||
$wrap.addClass( $parent.hasClass('-clear') ? '-clear' : '' );
|
||
|
||
// append
|
||
$wrap.append( $field.nextUntil('.acf-field-accordion', '.acf-field') );
|
||
|
||
// clean up
|
||
$wrap.removeAttr('data-open data-multi_expand data-endpoint');
|
||
},
|
||
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
|
||
/**
|
||
* accordionManager
|
||
*
|
||
* Events manager for the acf accordion
|
||
*
|
||
* @date 14/2/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param void
|
||
* @return void
|
||
*/
|
||
|
||
var accordionManager = new acf.Model({
|
||
|
||
actions: {
|
||
'unload': 'onUnload'
|
||
},
|
||
|
||
events: {
|
||
'click .acf-accordion-title': 'onClick',
|
||
'invalidField .acf-accordion': 'onInvalidField'
|
||
},
|
||
|
||
isOpen: function( $el ) {
|
||
return $el.hasClass('-open');
|
||
},
|
||
|
||
toggle: function( $el ){
|
||
if( this.isOpen($el) ) {
|
||
this.close( $el );
|
||
} else {
|
||
this.open( $el );
|
||
}
|
||
},
|
||
|
||
open: function( $el ){
|
||
|
||
// open
|
||
$el.find('.acf-accordion-content:first').slideDown().css('display', 'block');
|
||
$el.find('.acf-accordion-icon:first').removeClass('dashicons-arrow-right').addClass('dashicons-arrow-down');
|
||
$el.addClass('-open');
|
||
|
||
// action
|
||
acf.doAction('show', $el);
|
||
|
||
// close siblings
|
||
if( !$el.attr('multi-expand') ) {
|
||
$el.siblings('.acf-accordion.-open').each(function(){
|
||
accordionManager.close( $(this) );
|
||
});
|
||
}
|
||
},
|
||
|
||
close: function( $el ){
|
||
|
||
// close
|
||
$el.find('.acf-accordion-content:first').slideUp();
|
||
$el.find('.acf-accordion-icon:first').removeClass('dashicons-arrow-down').addClass('dashicons-arrow-right');
|
||
$el.removeClass('-open');
|
||
|
||
// action
|
||
acf.doAction('hide', $el);
|
||
},
|
||
|
||
onClick: function( e, $el ){
|
||
|
||
// prevent Defailt
|
||
e.preventDefault();
|
||
|
||
// open close
|
||
this.toggle( $el.parent() );
|
||
|
||
},
|
||
|
||
onInvalidField: function( e, $el ){
|
||
|
||
// bail early if already focused
|
||
if( this.busy ) {
|
||
return;
|
||
}
|
||
|
||
// disable functionality for 1sec (allow next validation to work)
|
||
this.busy = true;
|
||
this.setTimeout(function(){
|
||
this.busy = false;
|
||
}, 1000);
|
||
|
||
// open accordion
|
||
this.open( $el );
|
||
},
|
||
|
||
onUnload: function( e ){
|
||
|
||
// vars
|
||
var order = [];
|
||
|
||
// loop
|
||
$('.acf-accordion').each(function(){
|
||
var open = $(this).hasClass('-open') ? 1 : 0;
|
||
order.push(open);
|
||
});
|
||
|
||
// set
|
||
if( order.length ) {
|
||
acf.setPreference('this.accordions', order);
|
||
}
|
||
}
|
||
});
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.Field.extend({
|
||
|
||
type: 'button_group',
|
||
|
||
events: {
|
||
'click input[type="radio"]': 'onClick'
|
||
},
|
||
|
||
$control: function(){
|
||
return this.$('.acf-button-group');
|
||
},
|
||
|
||
$input: function(){
|
||
return this.$('input:checked');
|
||
},
|
||
|
||
setValue: function( val ){
|
||
this.$('input[value="' + val + '"]').prop('checked', true).trigger('change');
|
||
},
|
||
|
||
onClick: 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.Field.extend({
|
||
|
||
type: 'checkbox',
|
||
|
||
events: {
|
||
'change input': 'onChange',
|
||
'click .acf-add-checkbox': 'onClickAdd',
|
||
'click .acf-checkbox-toggle': 'onClickToggle',
|
||
'click .acf-checkbox-custom': 'onClickCustom'
|
||
},
|
||
|
||
$control: function(){
|
||
return this.$('.acf-checkbox-list');
|
||
},
|
||
|
||
$toggle: function(){
|
||
return this.$('.acf-checkbox-toggle');
|
||
},
|
||
|
||
$input: function(){
|
||
return this.$('input[type="hidden"]');
|
||
},
|
||
|
||
$inputs: function(){
|
||
return this.$('input[type="checkbox"]').not('.acf-checkbox-toggle');
|
||
},
|
||
|
||
getValue: function(){
|
||
var val = [];
|
||
this.$(':checked').each(function(){
|
||
val.push( $(this).val() );
|
||
});
|
||
return val.length ? val : false;
|
||
},
|
||
|
||
onChange: function( e, $el ){
|
||
|
||
// vars
|
||
var checked = $el.prop('checked');
|
||
var $toggle = this.$toggle();
|
||
|
||
// selected
|
||
if( checked ) {
|
||
$el.parent().addClass('selected');
|
||
} else {
|
||
$el.parent().removeClass('selected');
|
||
}
|
||
|
||
// determine if all inputs are checked
|
||
if( $toggle.length ) {
|
||
var $inputs = this.$inputs();
|
||
|
||
// all checked
|
||
if( $inputs.not(':checked').length == 0 ) {
|
||
$toggle.prop('checked', true);
|
||
} else {
|
||
$toggle.prop('checked', false);
|
||
}
|
||
}
|
||
},
|
||
|
||
onClickAdd: function( e, $el ){
|
||
var html = '<li><input class="acf-checkbox-custom" type="checkbox" checked="checked" /><input type="text" name="' + this.getInputName() + '[]" /></li>';
|
||
$el.parent('li').before( html );
|
||
},
|
||
|
||
onClickToggle: function( e, $el ){
|
||
var checked = $el.prop('checked');
|
||
var $inputs = this.$inputs();
|
||
$inputs.prop('checked', checked);
|
||
},
|
||
|
||
onClickCustom: function( e, $el ){
|
||
var checked = $el.prop('checked');
|
||
var $text = $el.next('input[type="text"]');
|
||
|
||
// checked
|
||
if( checked ) {
|
||
$text.prop('disabled', false);
|
||
|
||
// not checked
|
||
} else {
|
||
$text.prop('disabled', true);
|
||
|
||
// remove
|
||
if( $text.val() == '' ) {
|
||
$el.parent('li').remove();
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.Field.extend({
|
||
|
||
type: 'color_picker',
|
||
|
||
wait: 'load',
|
||
|
||
$control: function(){
|
||
return this.$('.acf-color-picker');
|
||
},
|
||
|
||
$input: function(){
|
||
return this.$('input[type="hidden"]');
|
||
},
|
||
|
||
$inputText: function(){
|
||
return this.$('input[type="text"]');
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// vars
|
||
var $input = this.$input();
|
||
var $inputText = this.$inputText();
|
||
|
||
// event
|
||
var onChange = function( e ){
|
||
|
||
// timeout is required to ensure the $input val is correct
|
||
setTimeout(function(){
|
||
acf.val( $input, $inputText.val() );
|
||
}, 1);
|
||
}
|
||
|
||
// args
|
||
var args = {
|
||
defaultColor: false,
|
||
palettes: true,
|
||
hide: true,
|
||
change: onChange,
|
||
clear: onChange
|
||
};
|
||
|
||
// filter
|
||
var args = acf.applyFilters('color_picker_args', args, this);
|
||
|
||
// initialize
|
||
$inputText.wpColorPicker( args );
|
||
}
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.Field.extend({
|
||
|
||
type: 'date_picker',
|
||
|
||
events: {
|
||
'blur input[type="text"]': 'onBlur'
|
||
},
|
||
|
||
$control: function(){
|
||
return this.$('.acf-date-picker');
|
||
},
|
||
|
||
$input: function(){
|
||
return this.$('input[type="hidden"]');
|
||
},
|
||
|
||
$inputText: function(){
|
||
return this.$('input[type="text"]');
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// save_format: compatibility with ACF < 5.0.0
|
||
if( this.has('save_format') ) {
|
||
return this.initializeCompatibility();
|
||
}
|
||
|
||
// vars
|
||
var $input = this.$input();
|
||
var $inputText = this.$inputText();
|
||
|
||
// args
|
||
var args = {
|
||
dateFormat: this.get('date_format'),
|
||
altField: $input,
|
||
altFormat: 'yymmdd',
|
||
changeYear: true,
|
||
yearRange: "-100:+100",
|
||
changeMonth: true,
|
||
showButtonPanel: true,
|
||
firstDay: this.get('first_day')
|
||
};
|
||
|
||
// filter
|
||
args = acf.applyFilters('date_picker_args', args, this);
|
||
|
||
// add date picker
|
||
acf.newDatePicker( $inputText, args );
|
||
|
||
// action
|
||
acf.doAction('date_picker_init', $inputText, args, this);
|
||
|
||
},
|
||
|
||
initializeCompatibility: function(){
|
||
|
||
// vars
|
||
var $input = this.$input();
|
||
var $inputText = this.$inputText();
|
||
|
||
// get and set value from alt field
|
||
$inputText.val( $input.val() );
|
||
|
||
// args
|
||
var args = {
|
||
dateFormat: this.get('date_format'),
|
||
altField: $input,
|
||
altFormat: this.get('save_format'),
|
||
changeYear: true,
|
||
yearRange: "-100:+100",
|
||
changeMonth: true,
|
||
showButtonPanel: true,
|
||
firstDay: this.get('first_day')
|
||
};
|
||
|
||
// filter for 3rd party customization
|
||
args = acf.applyFilters('date_picker_args', args, this);
|
||
|
||
// backup
|
||
var dateFormat = args.dateFormat;
|
||
|
||
// change args.dateFormat
|
||
args.dateFormat = this.get('save_format');
|
||
|
||
// add date picker
|
||
acf.newDatePicker( $inputText, args );
|
||
|
||
// now change the format back to how it should be.
|
||
$inputText.datepicker( 'option', 'dateFormat', dateFormat );
|
||
|
||
// action for 3rd party customization
|
||
acf.doAction('date_picker_init', $inputText, args, this);
|
||
},
|
||
|
||
onBlur: function(){
|
||
if( !this.$inputText().val() ) {
|
||
acf.val( this.$input(), '' );
|
||
}
|
||
}
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
|
||
// manager
|
||
var datePickerManager = new acf.Model({
|
||
priority: 5,
|
||
wait: 'ready',
|
||
initialize: function(){
|
||
|
||
// vars
|
||
var locale = acf.get('locale');
|
||
var rtl = acf.get('rtl');
|
||
var l10n = acf.get('datePickerL10n');
|
||
|
||
// bail ealry if no l10n
|
||
if( !l10n ) {
|
||
return false;
|
||
}
|
||
|
||
// bail ealry if no datepicker library
|
||
if( typeof $.datepicker === 'undefined' ) {
|
||
return false;
|
||
}
|
||
|
||
// rtl
|
||
l10n.isRTL = rtl;
|
||
|
||
// append
|
||
$.datepicker.regional[ locale ] = l10n;
|
||
$.datepicker.setDefaults(l10n);
|
||
}
|
||
});
|
||
|
||
// add
|
||
acf.newDatePicker = function( $input, args ){
|
||
|
||
// bail ealry if no datepicker library
|
||
if( typeof $.datepicker === 'undefined' ) {
|
||
return false;
|
||
}
|
||
|
||
// defaults
|
||
args = args || {};
|
||
|
||
// initialize
|
||
$input.datepicker( args );
|
||
|
||
// wrap the datepicker (only if it hasn't already been wrapped)
|
||
if( $('body > #ui-datepicker-div').exists() ) {
|
||
$('body > #ui-datepicker-div').wrap('<div class="acf-ui-datepicker" />');
|
||
}
|
||
};
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.models.DatePickerField.extend({
|
||
|
||
type: 'date_time_picker',
|
||
|
||
$control: function(){
|
||
return this.$('.acf-date-time-picker');
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// vars
|
||
var $input = this.$input();
|
||
var $inputText = this.$inputText();
|
||
|
||
// args
|
||
var args = {
|
||
dateFormat: this.get('date_format'),
|
||
timeFormat: this.get('time_format'),
|
||
altField: $input,
|
||
altFieldTimeOnly: false,
|
||
altFormat: 'yy-mm-dd',
|
||
altTimeFormat: 'HH:mm:ss',
|
||
changeYear: true,
|
||
yearRange: "-100:+100",
|
||
changeMonth: true,
|
||
showButtonPanel: true,
|
||
firstDay: this.get('first_day'),
|
||
controlType: 'select',
|
||
oneLine: true
|
||
};
|
||
|
||
// filter
|
||
args = acf.applyFilters('date_time_picker_args', args, this);
|
||
|
||
// add date time picker
|
||
acf.newDateTimePicker( $inputText, args );
|
||
|
||
// action
|
||
acf.doAction('date_time_picker_init', $inputText, args, this);
|
||
}
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
|
||
// manager
|
||
var dateTimePickerManager = new acf.Model({
|
||
priority: 5,
|
||
wait: 'ready',
|
||
initialize: function(){
|
||
|
||
// vars
|
||
var locale = acf.get('locale');
|
||
var rtl = acf.get('rtl');
|
||
var l10n = acf.get('dateTimePickerL10n');
|
||
|
||
// bail ealry if no l10n
|
||
if( !l10n ) {
|
||
return false;
|
||
}
|
||
|
||
// bail ealry if no datepicker library
|
||
if( typeof $.timepicker === 'undefined' ) {
|
||
return false;
|
||
}
|
||
|
||
// rtl
|
||
l10n.isRTL = rtl;
|
||
|
||
// append
|
||
$.timepicker.regional[ locale ] = l10n;
|
||
$.timepicker.setDefaults(l10n);
|
||
}
|
||
});
|
||
|
||
|
||
// add
|
||
acf.newDateTimePicker = function( $input, args ){
|
||
|
||
// bail ealry if no datepicker library
|
||
if( typeof $.timepicker === 'undefined' ) {
|
||
return false;
|
||
}
|
||
|
||
// defaults
|
||
args = args || {};
|
||
|
||
// initialize
|
||
$input.datetimepicker( args );
|
||
|
||
// wrap the datepicker (only if it hasn't already been wrapped)
|
||
if( $('body > #ui-datepicker-div').exists() ) {
|
||
$('body > #ui-datepicker-div').wrap('<div class="acf-ui-datepicker" />');
|
||
}
|
||
};
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.Field.extend({
|
||
|
||
type: 'google_map',
|
||
|
||
map: false,
|
||
|
||
wait: 'load',
|
||
|
||
events: {
|
||
'click a[data-name="clear"]': 'onClickClear',
|
||
'click a[data-name="locate"]': 'onClickLocate',
|
||
'click a[data-name="search"]': 'onClickSearch',
|
||
'keydown .search': 'onKeydownSearch',
|
||
'keyup .search': 'onKeyupSearch',
|
||
'focus .search': 'onFocusSearch',
|
||
'blur .search': 'onBlurSearch',
|
||
'showField': 'onShow'
|
||
},
|
||
|
||
$control: function(){
|
||
return this.$('.acf-google-map');
|
||
},
|
||
|
||
$input: function( name ){
|
||
return this.$('input[data-name="' + (name || 'address') + '"]');
|
||
},
|
||
|
||
$search: function(){
|
||
return this.$('.search');
|
||
},
|
||
|
||
addClass: function( name ){
|
||
this.$control().addClass( name );
|
||
},
|
||
|
||
removeClass: function( name ){
|
||
this.$control().removeClass( name );
|
||
},
|
||
|
||
getValue: function(){
|
||
|
||
// defaults
|
||
var val = {
|
||
lat: '',
|
||
lng: '',
|
||
address: ''
|
||
};
|
||
|
||
// loop
|
||
this.$('input[type="hidden"]').each(function(){
|
||
val[ $(this).data('name') ] = $(this).val();
|
||
});
|
||
|
||
// return false if no address
|
||
if( !val.address ) {
|
||
val = false;
|
||
}
|
||
|
||
// return
|
||
return val;
|
||
},
|
||
|
||
setValue: function( val ){
|
||
|
||
// defaults
|
||
val = acf.parseArgs(val, {
|
||
lat: '',
|
||
lng: '',
|
||
address: ''
|
||
});
|
||
|
||
// loop
|
||
for( var name in val ) {
|
||
acf.val( this.$input(name), val[name] );
|
||
}
|
||
|
||
// return false if no address
|
||
if( !val.address ) {
|
||
val = false;
|
||
}
|
||
|
||
// render
|
||
this.renderVal( val );
|
||
},
|
||
|
||
renderVal: function( val ){
|
||
|
||
// has value
|
||
if( val ) {
|
||
this.addClass('-value');
|
||
this.setPosition( val.lat, val.lng );
|
||
this.map.marker.setVisible( true );
|
||
|
||
// no value
|
||
} else {
|
||
this.removeClass('-value');
|
||
this.map.marker.setVisible( false );
|
||
}
|
||
|
||
// search
|
||
this.$search().val( val.address );
|
||
},
|
||
|
||
setPosition: function( lat, lng ){
|
||
|
||
// vars
|
||
var latLng = this.newLatLng( lat, lng );
|
||
|
||
// update marker
|
||
this.map.marker.setPosition( latLng );
|
||
|
||
// show marker
|
||
this.map.marker.setVisible( true );
|
||
|
||
// action
|
||
acf.doAction('google_map_change', latLng, this.map, this);
|
||
|
||
// center
|
||
this.center();
|
||
|
||
// return
|
||
return this;
|
||
},
|
||
|
||
center: function(){
|
||
|
||
// vars
|
||
var position = this.map.marker.getPosition();
|
||
var lat = this.get('lat');
|
||
var lng = this.get('lng');
|
||
|
||
// if marker exists, center on the marker
|
||
if( position ) {
|
||
lat = position.lat();
|
||
lng = position.lng();
|
||
}
|
||
|
||
// latlng
|
||
var latLng = this.newLatLng( lat, lng );
|
||
|
||
// set center of map
|
||
this.map.setCenter( latLng );
|
||
},
|
||
|
||
getSearchVal: function(){
|
||
return this.$search().val();
|
||
},
|
||
|
||
getCanvas: function(){
|
||
return this.$('.canvas');
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// bail early if too early
|
||
if( !api.isReady() ) {
|
||
api.ready( this.initializeMap, this );
|
||
return;
|
||
}
|
||
|
||
// initializeMap
|
||
this.initializeMap();
|
||
},
|
||
|
||
newLatLng: function( lat, lng ){
|
||
return new google.maps.LatLng( parseFloat(lat), parseFloat(lng) );
|
||
},
|
||
|
||
initializeMap: function(){
|
||
|
||
// vars
|
||
var zoom = this.get('zoom');
|
||
var lat = this.get('lat');
|
||
var lng = this.get('lng');
|
||
|
||
|
||
// map
|
||
var mapArgs = {
|
||
scrollwheel: false,
|
||
zoom: parseInt( zoom ),
|
||
center: this.newLatLng(lat, lng),
|
||
mapTypeId: google.maps.MapTypeId.ROADMAP,
|
||
marker: {
|
||
draggable: true,
|
||
raiseOnDrag: true
|
||
},
|
||
autocomplete: {}
|
||
};
|
||
mapArgs = acf.applyFilters('google_map_args', mapArgs, this);
|
||
var map = new google.maps.Map( this.getCanvas()[0], mapArgs );
|
||
this.addMapEvents( map, this );
|
||
|
||
|
||
// marker
|
||
var markerArgs = acf.parseArgs(mapArgs.marker, {
|
||
draggable: true,
|
||
raiseOnDrag: true,
|
||
map: map
|
||
});
|
||
markerArgs = acf.applyFilters('google_map_marker_args', markerArgs, this);
|
||
var marker = new google.maps.Marker( markerArgs );
|
||
this.addMarkerEvents( marker, this );
|
||
|
||
|
||
// reference
|
||
map.acf = this;
|
||
map.marker = marker;
|
||
this.map = map;
|
||
|
||
// action for 3rd party customization
|
||
acf.doAction('google_map_init', map, marker, this);
|
||
|
||
// set position
|
||
var val = this.getValue();
|
||
this.renderVal( val );
|
||
},
|
||
|
||
addMapEvents: function( map, field ){
|
||
|
||
// autocomplete
|
||
if( acf.isset(window, 'google', 'maps', 'places', 'Autocomplete') ) {
|
||
|
||
// vars
|
||
var autocompleteArgs = map.autocomplete || {};
|
||
var autocomplete = new google.maps.places.Autocomplete( this.$search()[0], autocompleteArgs );
|
||
|
||
// bind
|
||
autocomplete.bindTo('bounds', map);
|
||
|
||
// event
|
||
google.maps.event.addListener(autocomplete, 'place_changed', function() {
|
||
field.setPlace( this.getPlace() );
|
||
});
|
||
}
|
||
|
||
// click
|
||
google.maps.event.addListener( map, 'click', function( e ) {
|
||
|
||
// vars
|
||
var lat = e.latLng.lat();
|
||
var lng = e.latLng.lng();
|
||
|
||
// search
|
||
field.searchPosition( lat, lng );
|
||
});
|
||
},
|
||
|
||
addMarkerEvents: function( marker, field ){
|
||
|
||
// dragend
|
||
google.maps.event.addListener( marker, 'dragend', function(){
|
||
|
||
// vars
|
||
var position = this.getPosition();
|
||
var lat = position.lat();
|
||
var lng = position.lng();
|
||
|
||
// search
|
||
field.searchPosition( lat, lng );
|
||
});
|
||
},
|
||
|
||
searchPosition: function( lat, lng ){
|
||
|
||
// vars
|
||
var latLng = this.newLatLng( lat, lng );
|
||
var $wrap = this.$control();
|
||
|
||
// set position
|
||
this.setPosition( lat, lng );
|
||
|
||
// add class
|
||
$wrap.addClass('-loading');
|
||
|
||
// callback
|
||
var callback = $.proxy(function( results, status ){
|
||
|
||
// remove class
|
||
$wrap.removeClass('-loading');
|
||
|
||
// vars
|
||
var address = '';
|
||
|
||
// validate
|
||
if( status != google.maps.GeocoderStatus.OK ) {
|
||
console.log('Geocoder failed due to: ' + status);
|
||
} else if( !results[0] ) {
|
||
console.log('No results found');
|
||
} else {
|
||
address = results[0].formatted_address;
|
||
}
|
||
|
||
// update val
|
||
this.val({
|
||
lat: lat,
|
||
lng: lng,
|
||
address: address
|
||
});
|
||
|
||
}, this);
|
||
|
||
// query
|
||
api.geocoder.geocode({ 'latLng' : latLng }, callback);
|
||
},
|
||
|
||
setPlace: function( place ){
|
||
|
||
// bail if no place
|
||
if( !place ) return this;
|
||
|
||
// search name if no geometry
|
||
// - possible when hitting enter in search address
|
||
if( place.name && !place.geometry ) {
|
||
this.searchAddress(place.name);
|
||
return this;
|
||
}
|
||
|
||
// vars
|
||
var lat = place.geometry.location.lat();
|
||
var lng = place.geometry.location.lng();
|
||
var address = place.formatted_address;
|
||
|
||
// update
|
||
this.setValue({
|
||
lat: lat,
|
||
lng: lng,
|
||
address: address
|
||
});
|
||
|
||
// return
|
||
return this;
|
||
},
|
||
|
||
searchAddress: function( address ){
|
||
|
||
// is address latLng?
|
||
var latLng = address.split(',');
|
||
if( latLng.length == 2 ) {
|
||
|
||
// vars
|
||
var lat = latLng[0];
|
||
var lng = latLng[1];
|
||
|
||
// check
|
||
if( $.isNumeric(lat) && $.isNumeric(lng) ) {
|
||
return this.searchPosition( lat, lng );
|
||
}
|
||
}
|
||
|
||
// vars
|
||
var $wrap = this.$control();
|
||
|
||
// add class
|
||
$wrap.addClass('-loading');
|
||
|
||
// callback
|
||
var callback = $.proxy(function( results, status ){
|
||
|
||
// remove class
|
||
$wrap.removeClass('-loading');
|
||
|
||
// vars
|
||
var lat = '';
|
||
var lng = '';
|
||
|
||
// validate
|
||
if( status != google.maps.GeocoderStatus.OK ) {
|
||
console.log('Geocoder failed due to: ' + status);
|
||
} else if( !results[0] ) {
|
||
console.log('No results found');
|
||
} else {
|
||
lat = results[0].geometry.location.lat();
|
||
lng = results[0].geometry.location.lng();
|
||
address = results[0].formatted_address;
|
||
}
|
||
|
||
// update val
|
||
this.val({
|
||
lat: lat,
|
||
lng: lng,
|
||
address: address
|
||
});
|
||
|
||
//acf.doAction('google_map_geocode_results', results, status, this.$el, this);
|
||
|
||
}, this);
|
||
|
||
// query
|
||
api.geocoder.geocode({ 'address' : address }, callback);
|
||
},
|
||
|
||
searchLocation: function(){
|
||
|
||
// Try HTML5 geolocation
|
||
if( !navigator.geolocation ) {
|
||
return alert( acf.__('Sorry, this browser does not support geolocation') );
|
||
}
|
||
|
||
// vars
|
||
var $wrap = this.$control();
|
||
|
||
// add class
|
||
$wrap.addClass('-loading');
|
||
|
||
// callback
|
||
var onSuccess = $.proxy(function( results, status ){
|
||
|
||
// remove class
|
||
$wrap.removeClass('-loading');
|
||
|
||
// vars
|
||
var lat = results.coords.latitude;
|
||
var lng = results.coords.longitude;
|
||
|
||
// search;
|
||
this.searchPosition( lat, lng );
|
||
|
||
}, this);
|
||
|
||
var onFailure = function( error ){
|
||
$wrap.removeClass('-loading');
|
||
}
|
||
|
||
// try query
|
||
navigator.geolocation.getCurrentPosition( onSuccess, onFailure );
|
||
},
|
||
|
||
onClickClear: function( e, $el ){
|
||
this.val( false );
|
||
},
|
||
|
||
onClickLocate: function( e, $el ){
|
||
this.searchLocation();
|
||
},
|
||
|
||
onClickSearch: function( e, $el ){
|
||
this.searchAddress( this.$search().val() );
|
||
},
|
||
|
||
onFocusSearch: function( e, $el ){
|
||
this.removeClass('-value');
|
||
this.onKeyupSearch.apply(this, arguments);
|
||
},
|
||
|
||
onBlurSearch: function( e, $el ){
|
||
|
||
// timeout to allow onClickLocate event
|
||
this.setTimeout(function(){
|
||
this.removeClass('-search');
|
||
if( $el.val() ) {
|
||
this.addClass('-value');
|
||
}
|
||
}, 100);
|
||
},
|
||
|
||
onKeyupSearch: function( e, $el ){
|
||
if( $el.val() ) {
|
||
this.addClass('-search');
|
||
} else {
|
||
this.removeClass('-search');
|
||
}
|
||
},
|
||
|
||
onKeydownSearch: function( e, $el ){
|
||
|
||
// prevent form from submitting
|
||
if( e.which == 13 ) {
|
||
e.preventDefault();
|
||
}
|
||
},
|
||
|
||
onMousedown: function(){
|
||
|
||
/*
|
||
// clear timeout in 1ms (onMousedown will run before onBlurSearch)
|
||
this.setTimeout(function(){
|
||
clearTimeout( this.get('timeout') );
|
||
}, 1);
|
||
*/
|
||
},
|
||
|
||
onShow: function(){
|
||
|
||
// bail early if no map
|
||
// - possible if JS API was not loaded
|
||
if( !this.map ) {
|
||
return false;
|
||
}
|
||
|
||
// center map when it is shown (by a tab / collapsed row)
|
||
// - use delay to avoid rendering issues with browsers (ensures div is visible)
|
||
this.setTimeout( this.center, 10 );
|
||
}
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
var api = new acf.Model({
|
||
|
||
geocoder: false,
|
||
|
||
data: {
|
||
status: false,
|
||
},
|
||
|
||
getStatus: function(){
|
||
return this.get('status');
|
||
},
|
||
|
||
setStatus: function( status ){
|
||
return this.set('status', status);
|
||
},
|
||
|
||
isReady: function(){
|
||
|
||
// loaded
|
||
if( this.getStatus() == 'ready' ) {
|
||
return true;
|
||
}
|
||
|
||
// loading
|
||
if( this.getStatus() == 'loading' ) {
|
||
return false;
|
||
}
|
||
|
||
// check exists (optimal)
|
||
if( acf.isset(window, 'google', 'maps', 'places') ) {
|
||
this.setStatus('ready');
|
||
return true;
|
||
}
|
||
|
||
// load api
|
||
var url = acf.get('google_map_api');
|
||
if( url ) {
|
||
this.setStatus('loading');
|
||
|
||
// enqueue
|
||
$.ajax({
|
||
url: url,
|
||
dataType: 'script',
|
||
cache: true,
|
||
context: this,
|
||
success: function(){
|
||
|
||
// ready
|
||
this.setStatus('ready');
|
||
|
||
// geocoder
|
||
this.geocoder = new google.maps.Geocoder();
|
||
|
||
// action
|
||
acf.doAction('google_map_api_loaded');
|
||
}
|
||
});
|
||
}
|
||
|
||
// return
|
||
return false;
|
||
},
|
||
|
||
ready: function( callback, context ){
|
||
acf.addAction('google_map_api_loaded', callback, 10, context);
|
||
}
|
||
});
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.Field.extend({
|
||
|
||
type: 'image',
|
||
|
||
$control: function(){
|
||
return this.$('.acf-image-uploader');
|
||
},
|
||
|
||
$input: function(){
|
||
return this.$('input[type="hidden"]');
|
||
},
|
||
|
||
events: {
|
||
'click a[data-name="add"]': 'onClickAdd',
|
||
'click a[data-name="edit"]': 'onClickEdit',
|
||
'click a[data-name="remove"]': 'onClickRemove',
|
||
'change input[type="file"]': 'onChange'
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// add attribute to form
|
||
if( this.get('uploader') === 'basic' ) {
|
||
this.$el.closest('form').attr('enctype', 'multipart/form-data');
|
||
}
|
||
},
|
||
|
||
validateAttachment: function( attachment ){
|
||
|
||
// defaults
|
||
attachment = attachment || {};
|
||
|
||
// WP attachment
|
||
if( attachment.id !== undefined ) {
|
||
attachment = attachment.attributes;
|
||
}
|
||
|
||
// args
|
||
attachment = acf.parseArgs(attachment, {
|
||
url: '',
|
||
alt: '',
|
||
title: '',
|
||
caption: '',
|
||
description: '',
|
||
width: 0,
|
||
height: 0
|
||
});
|
||
|
||
// preview size
|
||
var url = acf.isget(attachment, 'sizes', this.get('preview_size'), 'url');
|
||
if( url !== null ) {
|
||
attachment.url = url;
|
||
}
|
||
|
||
// return
|
||
return attachment;
|
||
},
|
||
|
||
render: function( attachment ){
|
||
|
||
// vars
|
||
attachment = this.validateAttachment( attachment );
|
||
|
||
// update image
|
||
this.$('img').attr({
|
||
src: attachment.url,
|
||
alt: attachment.alt,
|
||
title: attachment.title
|
||
});
|
||
|
||
// vars
|
||
var val = attachment.id || '';
|
||
|
||
// update val
|
||
this.val( val );
|
||
|
||
// update class
|
||
if( val ) {
|
||
this.$control().addClass('has-value');
|
||
} else {
|
||
this.$control().removeClass('has-value');
|
||
}
|
||
},
|
||
|
||
// create a new repeater row and render value
|
||
append: function( attachment, parent ){
|
||
|
||
// create function to find next available field within parent
|
||
var getNext = function( field, parent ){
|
||
|
||
// find existing file fields within parent
|
||
var fields = acf.getFields({
|
||
key: field.get('key'),
|
||
parent: parent.$el
|
||
});
|
||
|
||
// find the first field with no value
|
||
for( var i = 0; i < fields.length; i++ ) {
|
||
if( !fields[i].val() ) {
|
||
return fields[i];
|
||
}
|
||
}
|
||
|
||
// return
|
||
return false;
|
||
}
|
||
|
||
// find existing file fields within parent
|
||
var field = getNext( this, parent );
|
||
|
||
// add new row if no available field
|
||
if( !field ) {
|
||
parent.$('.acf-button:last').trigger('click');
|
||
field = getNext( this, parent );
|
||
}
|
||
|
||
// render
|
||
if( field ) {
|
||
field.render( attachment );
|
||
}
|
||
},
|
||
|
||
selectAttachment: function(){
|
||
|
||
// vars
|
||
var parent = this.parent();
|
||
var multiple = (parent && parent.get('type') === 'repeater');
|
||
|
||
// new frame
|
||
var frame = acf.newMediaPopup({
|
||
mode: 'select',
|
||
type: 'image',
|
||
title: acf.__('Select Image'),
|
||
field: this.get('key'),
|
||
multiple: multiple,
|
||
library: this.get('library'),
|
||
allowedTypes: this.get('mime_types'),
|
||
select: $.proxy(function( attachment, i ) {
|
||
if( i > 0 ) {
|
||
this.append( attachment, parent );
|
||
} else {
|
||
this.render( attachment );
|
||
}
|
||
}, this)
|
||
});
|
||
},
|
||
|
||
editAttachment: function(){
|
||
|
||
// vars
|
||
var val = this.val();
|
||
|
||
// bail early if no val
|
||
if( !val ) return;
|
||
|
||
// popup
|
||
var frame = acf.newMediaPopup({
|
||
mode: 'edit',
|
||
title: acf.__('Edit Image'),
|
||
button: acf.__('Update Image'),
|
||
attachment: val,
|
||
field: this.get('key'),
|
||
select: $.proxy(function( attachment, i ) {
|
||
this.render( attachment );
|
||
}, this)
|
||
});
|
||
},
|
||
|
||
removeAttachment: function(){
|
||
this.render( false );
|
||
},
|
||
|
||
onClickAdd: function( e, $el ){
|
||
this.selectAttachment();
|
||
},
|
||
|
||
onClickEdit: function( e, $el ){
|
||
this.editAttachment();
|
||
},
|
||
|
||
onClickRemove: function( e, $el ){
|
||
this.removeAttachment();
|
||
},
|
||
|
||
onChange: function( e, $el ){
|
||
var $hiddenInput = this.$input();
|
||
|
||
acf.getFileInputData($el, function( data ){
|
||
$hiddenInput.val( $.param(data) );
|
||
});
|
||
}
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.models.ImageField.extend({
|
||
|
||
type: 'file',
|
||
|
||
$control: function(){
|
||
return this.$('.acf-file-uploader');
|
||
},
|
||
|
||
$input: function(){
|
||
return this.$('input[type="hidden"]');
|
||
},
|
||
|
||
validateAttachment: function( attachment ){
|
||
|
||
// defaults
|
||
attachment = attachment || {};
|
||
|
||
// WP attachment
|
||
if( attachment.id !== undefined ) {
|
||
attachment = attachment.attributes;
|
||
}
|
||
|
||
// args
|
||
attachment = acf.parseArgs(attachment, {
|
||
url: '',
|
||
alt: '',
|
||
title: '',
|
||
filename: '',
|
||
filesizeHumanReadable: '',
|
||
icon: '/wp-includes/images/media/default.png'
|
||
});
|
||
|
||
// return
|
||
return attachment;
|
||
},
|
||
|
||
render: function( attachment ){
|
||
|
||
// vars
|
||
attachment = this.validateAttachment( attachment );
|
||
|
||
// update image
|
||
this.$('img').attr({
|
||
src: attachment.icon,
|
||
alt: attachment.alt,
|
||
title: attachment.title
|
||
});
|
||
|
||
// update elements
|
||
this.$('[data-name="title"]').text( attachment.title );
|
||
this.$('[data-name="filename"]').text( attachment.filename ).attr( 'href', attachment.url );
|
||
this.$('[data-name="filesize"]').text( attachment.filesizeHumanReadable );
|
||
|
||
// vars
|
||
var val = attachment.id || '';
|
||
|
||
// update val
|
||
acf.val( this.$input(), val );
|
||
|
||
// update class
|
||
if( val ) {
|
||
this.$control().addClass('has-value');
|
||
} else {
|
||
this.$control().removeClass('has-value');
|
||
}
|
||
},
|
||
|
||
selectAttachment: function(){
|
||
|
||
// vars
|
||
var parent = this.parent();
|
||
var multiple = (parent && parent.get('type') === 'repeater');
|
||
|
||
// new frame
|
||
var frame = acf.newMediaPopup({
|
||
mode: 'select',
|
||
title: acf.__('Select File'),
|
||
field: this.get('key'),
|
||
multiple: multiple,
|
||
library: this.get('library'),
|
||
allowedTypes: this.get('mime_types'),
|
||
select: $.proxy(function( attachment, i ) {
|
||
if( i > 0 ) {
|
||
this.append( attachment, parent );
|
||
} else {
|
||
this.render( attachment );
|
||
}
|
||
}, this)
|
||
});
|
||
},
|
||
|
||
editAttachment: function(){
|
||
|
||
// vars
|
||
var val = this.val();
|
||
|
||
// bail early if no val
|
||
if( !val ) {
|
||
return false;
|
||
}
|
||
|
||
// popup
|
||
var frame = acf.newMediaPopup({
|
||
mode: 'edit',
|
||
title: acf.__('Edit File'),
|
||
button: acf.__('Update File'),
|
||
attachment: val,
|
||
field: this.get('key'),
|
||
select: $.proxy(function( attachment, i ) {
|
||
this.render( attachment );
|
||
}, this)
|
||
});
|
||
}
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
})(jQuery);
|
||
|
||
(function($, undefined){
|
||
|
||
var Field = acf.Field.extend({
|
||
|
||
type: 'link',
|
||
|
||
events: {
|
||
'click a[data-name="add"]': 'onClickEdit',
|
||
'click a[data-name="edit"]': 'onClickEdit',
|
||
'click a[data-name="remove"]': 'onClickRemove',
|
||
'change .link-node': 'onChange',
|
||
},
|
||
|
||
$control: function(){
|
||
return this.$('.acf-link');
|
||
},
|
||
|
||
$node: function(){
|
||
return this.$('.link-node');
|
||
},
|
||
|
||
getValue: function(){
|
||
|
||
// vars
|
||
var $node = this.$node();
|
||
|
||
// return false if empty
|
||
if( !$node.attr('href') ) {
|
||
return false;
|
||
}
|
||
|
||
// return
|
||
return {
|
||
title: $node.html(),
|
||
url: $node.attr('href'),
|
||
target: $node.attr('target')
|
||
};
|
||
},
|
||
|
||
setValue: function( val ){
|
||
|
||
// default
|
||
val = acf.parseArgs(val, {
|
||
title: '',
|
||
url: '',
|
||
target: ''
|
||
});
|
||
|
||
// vars
|
||
var $div = this.$control();
|
||
var $node = this.$node();
|
||
|
||
// remove class
|
||
$div.removeClass('-value -external');
|
||
|
||
// add class
|
||
if( val.url ) $div.addClass('-value');
|
||
if( val.target === '_blank' ) $div.addClass('-external');
|
||
|
||
// update text
|
||
this.$('.link-title').html( val.title );
|
||
this.$('.link-url').attr('href', val.url).html( val.url );
|
||
|
||
// update node
|
||
$node.html(val.title);
|
||
$node.attr('href', val.url);
|
||
$node.attr('target', val.target);
|
||
|
||
// update inputs
|
||
this.$('.input-title').val( val.title );
|
||
this.$('.input-target').val( val.target );
|
||
this.$('.input-url').val( val.url ).trigger('change');
|
||
},
|
||
|
||
onClickEdit: function( e, $el ){
|
||
acf.wpLink.open( this.$node() );
|
||
},
|
||
|
||
onClickRemove: function( e, $el ){
|
||
this.setValue( false );
|
||
},
|
||
|
||
onChange: function( e, $el ){
|
||
|
||
// get the changed value
|
||
var val = this.getValue();
|
||
|
||
// update inputs
|
||
this.setValue(val);
|
||
}
|
||
|
||
});
|
||
|
||
acf.registerFieldType( Field );
|
||
|
||
|
||
// manager
|
||
acf.wpLink = new acf.Model({
|
||
|
||
getNodeValue: function(){
|
||
var $node = this.get('node');
|
||
return {
|
||
title: $node.html(),
|
||
url: $node.attr('href'),
|
||
target: $node.attr('target')
|
||
};
|
||
},
|
||
|
||
setNodeValue: function( val ){
|
||
var $node = this.get('node');
|
||
$node.html( val.title );
|
||
$node.attr('href', val.url);
|
||
$node.attr('target', val.target);
|
||
$node.trigger('change');
|
||
},
|
||
|
||
getInputValue: function(){
|
||
return {
|
||
title: $('#wp-link-text').val(),
|
||
url: $('#wp-link-url').val(),
|
||
target: $('#wp-link-target').prop('checked') ? '_blank' : ''
|
||
};
|
||
},
|
||
|
||
setInputValue: function( val ){
|
||
$('#wp-link-text').val( val.title );
|
||
$('#wp-link-url').val( val.url );
|
||
$('#wp-link-target').prop('checked', val.target === '_blank' );
|
||
},
|
||
|
||
open: function( $node ){
|
||
|
||
// add events
|
||
this.on('wplink-open', 'onOpen');
|
||
this.on('wplink-close', 'onClose');
|
||
|
||
// set node
|
||
this.set('node', $node);
|
||
|
||
// create textarea
|
||
var $textarea = $('<textarea id="acf-link-textarea" style="display:none;"></textarea>');
|
||
$('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' ) {
|
||
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 [
|
||
'<li>',
|
||
'<span data-id="' + props.id + '" class="acf-rel-item">' + props.text + '</span>',
|
||
'</li>'
|
||
].join('');
|
||
},
|
||
|
||
newValue: function( props ){
|
||
return [
|
||
'<li>',
|
||
'<input type="hidden" name="' + this.getInputName() + '[]" value="' + props.id + '" />',
|
||
'<span data-id="' + props.id + '" class="acf-rel-item">' + props.text,
|
||
'<a href="#" class="acf-icon -minus small dark" data-name="remove_item"></a>',
|
||
'</span>',
|
||
'</li>'
|
||
].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 = $('<li><i class="acf-loading"></i> ' + acf.__('Loading') + '</li>');
|
||
$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('<li>' + acf.__('No matches found') + '</li>');
|
||
}
|
||
|
||
// 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 += '<li><span class="acf-rel-label">' + data.text + '</span><ul class="acf-bl">';
|
||
html += walk( data.children );
|
||
html += '</ul></li>';
|
||
|
||
// single
|
||
} else {
|
||
html += '<li><span class="acf-rel-item" data-id="' + data.id + '">' + data.text + '</span></li>';
|
||
}
|
||
}
|
||
|
||
// 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 = $('<tr class="acf-tab-wrap"><td colspan="2"><ul class="acf-hl acf-tab-group"></ul></td></tr>');
|
||
} else {
|
||
this.$el = $('<div class="acf-tab-wrap -' + placement + '"><ul class="acf-hl acf-tab-group"></ul></div>');
|
||
}
|
||
|
||
// 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 <li>
|
||
var $li = $('<li></li>');
|
||
|
||
// append <a>
|
||
$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();
|
||
|
||
// 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 = $('<option value="' + term.term_id + '">' + term.term_label + '</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 = $([
|
||
'<li data-id="' + term.term_id + '">',
|
||
'<label>',
|
||
'<input type="' + this.get('ftype') + '" value="' + term.term_id + '" name="' + name + '" /> ',
|
||
'<span>' + term.term_name + '</span>',
|
||
'</label>',
|
||
'</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 = $('<ul class="children acf-bl"></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('<div class="acf-ui-datepicker" />');
|
||
}
|
||
};
|
||
|
||
})(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-');
|
||
|
||
// rename
|
||
acf.rename({
|
||
target: $wrap,
|
||
search: oldId,
|
||
replace: newId,
|
||
destructive: true
|
||
});
|
||
|
||
// update id
|
||
this.set('id', newId, true);
|
||
|
||
// initialize
|
||
acf.tinymce.initialize( newId, args );
|
||
},
|
||
|
||
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 '<intput type="text" />';
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 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 '<input type="text" disabled="" />';
|
||
}
|
||
});
|
||
|
||
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 '<input type="text" />';
|
||
}
|
||
});
|
||
|
||
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 '<input type="text" placeholder="[a-z0-9]" />';
|
||
}
|
||
});
|
||
|
||
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' ],
|
||
match: function( rule, field ){
|
||
return containsString( field.val(), rule.value );
|
||
},
|
||
choices: function( fieldObject ){
|
||
return '<input type="text" />';
|
||
}
|
||
});
|
||
|
||
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 '<input type="number" />';
|
||
}
|
||
});
|
||
|
||
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 '<input type="number" />';
|
||
}
|
||
});
|
||
|
||
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.dispose();
|
||
},
|
||
|
||
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(wp, 'media', 'view') ) {
|
||
return;
|
||
}
|
||
|
||
// 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 = $([
|
||
'<a href="#" class="acf-expand-details">',
|
||
'<span class="is-closed"><span class="acf-icon -left small grey"></span>' + acf.__('Expand Details') + '</span>',
|
||
'<span class="is-open"><span class="acf-icon -right small grey"></span>' + acf.__('Collapse Details') + '</span>',
|
||
'</a>'
|
||
].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 `<option>` elements.
|
||
this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
|
||
return {
|
||
el: $( '<option></option>' ).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 ) {
|
||
//console.log('ignore render', this.cid);
|
||
return this;
|
||
}
|
||
this.rendered = true;
|
||
|
||
// render
|
||
//console.log('render', this.cid);
|
||
AttachmentCompat.prototype.render.apply( this, arguments );
|
||
|
||
// clear timeout
|
||
clearTimeout( timeout );
|
||
|
||
// setTimeout
|
||
timeout = setTimeout($.proxy(function(){
|
||
|
||
// check if element is visible to avoid logic on previous instances (which are hidden)
|
||
if( this.$el.is(':visible') ) {
|
||
//console.log('append', this.cid);
|
||
acf.doAction('append', this.$el);
|
||
}
|
||
|
||
}, this), 50);
|
||
|
||
// return
|
||
return this;
|
||
},
|
||
|
||
// commented out function causing JS errors when navigating through media grid
|
||
// dispose (and remove) are called after the element has been detached, so this only causes extra JS initialization
|
||
dispose: function(){
|
||
|
||
// remove
|
||
if( this.$el.is(':visible') ) {
|
||
//acf.doAction('remove', this.$el);
|
||
console.log('removed visible');
|
||
}
|
||
// dispose
|
||
return AttachmentCompat.prototype.dispose.apply( this, arguments );
|
||
}
|
||
|
||
});
|
||
|
||
},
|
||
|
||
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([
|
||
'<div class="acf-selection-error">',
|
||
'<span class="selection-error-label">' + acf.__('Restricted') +'</span>',
|
||
'<span class="selection-error-filename">' + filename + '</span>',
|
||
'<span class="selection-error-message">' + errors + '</span>',
|
||
'</div>'
|
||
].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,
|
||
|
||
wait: 'ready',
|
||
|
||
events: {
|
||
'change #page_template': 'onChangeTemplate',
|
||
'change #parent_id': 'onChangeParent',
|
||
'change #post-formats-select input': 'onChangeFormat',
|
||
'change .categorychecklist input': 'onChangeTerm',
|
||
'change .categorychecklist select': 'onChangeTerm',
|
||
'change .acf-taxonomy-field[data-save="1"] input': 'onChangeTerm',
|
||
'change .acf-taxonomy-field[data-save="1"] select': 'onChangeTerm'
|
||
},
|
||
|
||
data: {
|
||
//'post_id': 0,
|
||
//'page_template': 0,
|
||
//'page_parent': 0,
|
||
//'page_type': 0,
|
||
//'post_format': 0,
|
||
//'post_taxonomy': 0
|
||
},
|
||
|
||
fetch: function(){
|
||
|
||
// bail early if not active
|
||
if( !this.active ) {
|
||
return;
|
||
}
|
||
|
||
// 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, {
|
||
post_id: acf.get('post_id')
|
||
});
|
||
|
||
// add action url
|
||
ajaxData.action = 'acf/post/get_field_groups';
|
||
|
||
// add ignore
|
||
ajaxData.exists = [];
|
||
$('.acf-postbox').not('.acf-hidden').each(function(){
|
||
ajaxData.exists.push( $(this).attr('id').substr(4) );
|
||
});
|
||
|
||
// success
|
||
var onSuccess = function( json ){
|
||
|
||
// bail early if not success
|
||
if( !acf.isAjaxSuccess(json) ) {
|
||
return;
|
||
}
|
||
|
||
// hide
|
||
$('.acf-postbox').addClass('acf-hidden');
|
||
$('.acf-postbox-toggle').addClass('acf-hidden');
|
||
|
||
// reset style
|
||
$('#acf-style').html('');
|
||
|
||
// loop
|
||
json.data.map(function( fieldGroup, i ){
|
||
|
||
// vars
|
||
var $postbox = $('#acf-' + fieldGroup.key);
|
||
var $toggle = $('#acf-' + fieldGroup.key + '-hide');
|
||
var $label = $toggle.parent();
|
||
|
||
// show
|
||
// use show() to force display when postbox has been hidden by 'Show on screen' toggle
|
||
$postbox.removeClass('acf-hidden hide-if-js').show();
|
||
$label.removeClass('acf-hidden hide-if-js').show();
|
||
$toggle.prop('checked', true);
|
||
|
||
// replace HTML if needed
|
||
var $replace = $postbox.find('.acf-replace-with-fields');
|
||
if( $replace.exists() ) {
|
||
$replace.replaceWith( fieldGroup.html );
|
||
acf.doAction('append', $postbox);
|
||
}
|
||
|
||
// update style if needed
|
||
if( i === 0 ) {
|
||
$('#acf-style').html( fieldGroup.style );
|
||
}
|
||
|
||
// enable inputs
|
||
acf.enable( $postbox, 'postbox' );
|
||
});
|
||
};
|
||
|
||
// complete
|
||
var onComplete = function( json ){
|
||
|
||
// disable inputs
|
||
$('.acf-postbox.acf-hidden').each(function(){
|
||
acf.disable( $(this), 'postbox' );
|
||
});
|
||
};
|
||
|
||
// ajax
|
||
this.xhr = $.ajax({
|
||
url: acf.get('ajaxurl'),
|
||
data: acf.prepareForAjax( ajaxData ),
|
||
type: 'post',
|
||
dataType: 'json',
|
||
context: this,
|
||
success: onSuccess,
|
||
complete: onComplete
|
||
});
|
||
},
|
||
|
||
syncTaxonomyTerms: function(){
|
||
|
||
// vars
|
||
var values = [''];
|
||
|
||
// loop over term lists
|
||
$('.categorychecklist, .acf-taxonomy-field').each(function(){
|
||
|
||
// vars
|
||
var $el = $(this),
|
||
$checkbox = $el.find('input[type="checkbox"]').not(':disabled'),
|
||
$radio = $el.find('input[type="radio"]').not(':disabled'),
|
||
$select = $el.find('select').not(':disabled'),
|
||
$hidden = $el.find('input[type="hidden"]').not(':disabled');
|
||
|
||
|
||
// bail early if not a field which saves taxonomy terms to post
|
||
if( $el.is('.acf-taxonomy-field') && $el.attr('data-save') != '1' ) {
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
// bail early if in attachment
|
||
if( $el.closest('.media-frame').exists() ) {
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
// checkbox
|
||
if( $checkbox.exists() ) {
|
||
|
||
$checkbox.filter(':checked').each(function(){
|
||
|
||
values.push( $(this).val() );
|
||
|
||
});
|
||
|
||
} else if( $radio.exists() ) {
|
||
|
||
$radio.filter(':checked').each(function(){
|
||
|
||
values.push( $(this).val() );
|
||
|
||
});
|
||
|
||
} else if( $select.exists() ) {
|
||
|
||
$select.find('option:selected').each(function(){
|
||
|
||
values.push( $(this).val() );
|
||
|
||
});
|
||
|
||
} else if( $hidden.exists() ) {
|
||
|
||
$hidden.each(function(){
|
||
|
||
// ignor blank values
|
||
if( ! $(this).val() ) {
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
values.push( $(this).val() );
|
||
|
||
});
|
||
|
||
}
|
||
|
||
});
|
||
|
||
|
||
// filter duplicates
|
||
values = values.filter(function(item, pos, self) {
|
||
return self.indexOf(item) == pos;
|
||
});
|
||
|
||
|
||
// update screen
|
||
this.set( 'post_taxonomy', values ).fetch();
|
||
},
|
||
|
||
onChangeTemplate: function( e, $el ){
|
||
|
||
// update & fetch
|
||
this.set('page_template', $el.val()).fetch();
|
||
},
|
||
|
||
onChangeParent: function( e, $el ){
|
||
|
||
// vars
|
||
var pageType = 'parent';
|
||
var pageParent = 0;
|
||
|
||
// if is child
|
||
if( $el.val() != "" ) {
|
||
pageType = 'child';
|
||
pageParent = $el.val();
|
||
}
|
||
|
||
// update & fetch
|
||
this.set('page_type', pageType).set('page_parent', pageParent).fetch();
|
||
},
|
||
|
||
onChangeFormat: function( e, $el ){
|
||
|
||
// vars
|
||
var postFormat = $el.val();
|
||
|
||
// default
|
||
if( postFormat == '0' ) {
|
||
postFormat = 'standard';
|
||
}
|
||
|
||
// update & fetch
|
||
this.set('post_format', postFormat).fetch();
|
||
},
|
||
|
||
onChangeTerm: function( e, $el ){
|
||
|
||
// bail early if within media popup
|
||
if( $el.closest('.media-frame').exists() ) {
|
||
return;
|
||
}
|
||
|
||
// set timeout to fix issue with chrome which does not register the change has yet happened
|
||
this.setTimeout(this.syncTaxonomyTerms, 1);
|
||
}
|
||
});
|
||
|
||
})(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></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 = $('<input type="hidden" />');
|
||
$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 = $('<option value="' + item.id + '">' + item.text + '</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');
|
||
|
||
// bail ealry if no l10n
|
||
if( !l10n ) {
|
||
return false;
|
||
}
|
||
|
||
// bail early if 'en'
|
||
if( locale.indexOf('en') === 0 ) {
|
||
return false;
|
||
}
|
||
|
||
// initialize
|
||
if( getVersion() == 4 ) {
|
||
this.addTranslations4();
|
||
} else {
|
||
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 && typeof toolbars[toolbar] !== 'undefined' ) {
|
||
|
||
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){
|
||
|
||
/**
|
||
* acf.validation
|
||
*
|
||
* Global validation logic
|
||
*
|
||
* @date 4/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param void
|
||
* @return void
|
||
*/
|
||
|
||
acf.validation = new acf.Model({
|
||
|
||
// enable / disable validation logic
|
||
active: true,
|
||
|
||
// temp ignore flag allowing bypass of validation
|
||
ignore: false,
|
||
|
||
// errors
|
||
errors: [],
|
||
|
||
// active form
|
||
form: false,
|
||
|
||
// wait
|
||
wait: 'prepare',
|
||
|
||
actions: {
|
||
'ready': 'addInputEvents',
|
||
'append': 'addInputEvents'
|
||
},
|
||
|
||
events: {
|
||
'click #publish': 'onClickPublish',
|
||
'click #submit': 'onClickPublish',
|
||
'click #save-post': 'onClickSave',
|
||
'submit form': 'onSubmit',
|
||
},
|
||
|
||
initialize: function(){
|
||
|
||
// load global setting
|
||
if( !acf.get('validation') ) {
|
||
this.disable();
|
||
this.actions = {};
|
||
this.events = {};
|
||
}
|
||
},
|
||
|
||
getForm: function( $form ){
|
||
|
||
// instantiate
|
||
var form = $form.data('acf');
|
||
if( !form ) {
|
||
form = new Form( $form );
|
||
}
|
||
|
||
// store
|
||
this.form = form;
|
||
|
||
// return
|
||
return form;
|
||
},
|
||
|
||
enable: function(){
|
||
this.active = true;
|
||
},
|
||
|
||
disable: function(){
|
||
this.active = false;
|
||
},
|
||
|
||
pass: function(){
|
||
this.ignore = true;
|
||
this.setTimeout(function(){
|
||
this.ignore = false;
|
||
}, 100);
|
||
},
|
||
|
||
reset: function(){
|
||
this.ignore = false;
|
||
this.errors = [];
|
||
this.form = false;
|
||
},
|
||
|
||
getErrors: function(){
|
||
return this.errors;
|
||
},
|
||
|
||
hasErrors: function(){
|
||
return this.errors.length;
|
||
},
|
||
|
||
addErrors: function( errors ){
|
||
errors.map( this.addError, this );
|
||
},
|
||
|
||
addError: function( error ){
|
||
this.errors.push( error );
|
||
},
|
||
|
||
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: function(){
|
||
|
||
// return array of errors that contain no input
|
||
return this.getErrors().filter(function(error){
|
||
return !error.input;
|
||
});
|
||
},
|
||
|
||
showErrors: function( $form ){
|
||
|
||
// bail early if no errors
|
||
if( !this.hasErrors() ) {
|
||
return;
|
||
}
|
||
|
||
// vars
|
||
var form = this.getForm( $form );
|
||
var fieldErrors = this.getFieldErrors();
|
||
var globalErrors = this.getGlobalErrors();
|
||
|
||
// vars
|
||
var errorCount = 0;
|
||
var $scrollTo = false;
|
||
|
||
// loop
|
||
fieldErrors.map(function( error ){
|
||
|
||
// get input
|
||
var $input = $form.find('[name="' + error.input + '"]').first();
|
||
|
||
// if $_POST value was an array, this $input may not exist
|
||
if( !$input.exists() ) {
|
||
$input = $form.find('[name^="' + error.input + '"]').first();
|
||
}
|
||
|
||
// bail early if input doesn't exist
|
||
if( !$input.exists() ) {
|
||
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');
|
||
if( errorCount == 1 ) {
|
||
errorMessage += '. ' + acf.__('1 field requires attention');
|
||
} else if( errorCount > 1 ) {
|
||
errorMessage += '. ' + acf.__('%d fields require attention').replace('%d', errorCount);
|
||
}
|
||
|
||
// notice
|
||
if( form.notice ) {
|
||
form.notice.update({
|
||
type: 'error',
|
||
text: errorMessage
|
||
});
|
||
} else {
|
||
form.notice = acf.newNotice({
|
||
type: 'error',
|
||
text: errorMessage,
|
||
target: $form
|
||
});
|
||
}
|
||
|
||
// if no $scrollTo, set to message
|
||
if( !$scrollTo ) {
|
||
$scrollTo = form.notice.$el;
|
||
}
|
||
|
||
// timeout
|
||
setTimeout(function(){
|
||
$("html, body").animate({ scrollTop: $scrollTo.offset().top - ( $(window).height() / 2 ) }, 500);
|
||
}, 10);
|
||
},
|
||
|
||
fetch: function( args ){
|
||
|
||
// bail early if busy
|
||
if( this.busy ) {
|
||
return;
|
||
}
|
||
|
||
// set busy
|
||
this.busy = 1;
|
||
|
||
// vars
|
||
args = acf.parseArgs(args, {
|
||
|
||
// form element
|
||
form: false,
|
||
|
||
// trigger event
|
||
event: false,
|
||
|
||
// lock form on success
|
||
lock: true,
|
||
|
||
// loading callback
|
||
loading: function(){},
|
||
|
||
// complete callback
|
||
complete: function(){},
|
||
|
||
// failure callback
|
||
failure: function(){},
|
||
|
||
// success callback
|
||
success: function( $form ){
|
||
$form.submit();
|
||
}
|
||
});
|
||
|
||
// vars
|
||
var $form = args.form;
|
||
var form = this.getForm( $form );
|
||
|
||
// create event specific success callback
|
||
if( args.event ) {
|
||
var event = $.Event(null, args.event);
|
||
args.success = function(){
|
||
$(event.target).trigger( event );
|
||
}
|
||
}
|
||
|
||
// action for 3rd party
|
||
acf.doAction('validation_begin', $form);
|
||
|
||
// data
|
||
var data = acf.serialize( $form );
|
||
data.action = 'acf/validate_save_post';
|
||
|
||
// lock form
|
||
this.lockForm( $form );
|
||
|
||
// loading callback
|
||
args.loading( $form );
|
||
|
||
// success
|
||
var onSuccess = function( json ){
|
||
|
||
// validate
|
||
if( !acf.isAjaxSuccess(json) ) {
|
||
return;
|
||
}
|
||
|
||
// filter
|
||
data = acf.applyFilters('validation_complete', json.data, $form);
|
||
|
||
// add errors
|
||
if( !data.valid ) {
|
||
this.addErrors( data.errors );
|
||
}
|
||
};
|
||
|
||
// complete
|
||
var onComplete = function(){
|
||
|
||
// set busy
|
||
this.busy = 0;
|
||
|
||
// unlock form
|
||
this.unlockForm( $form );
|
||
|
||
// failure
|
||
if( this.hasErrors() ) {
|
||
|
||
// action
|
||
acf.doAction('validation_failure', $form);
|
||
|
||
// display errors
|
||
this.showErrors( $form );
|
||
|
||
// failure callback
|
||
args.failure( $form );
|
||
|
||
// success
|
||
} else {
|
||
|
||
// allow for to pass
|
||
this.pass();
|
||
|
||
// remove previous error message
|
||
if( form.notice ) {
|
||
form.notice.update({
|
||
type: 'success',
|
||
text: acf.__('Validation successful'),
|
||
timeout: 1000
|
||
});
|
||
}
|
||
|
||
// action
|
||
acf.doAction('validation_success', $form);
|
||
acf.doAction('submit', $form);
|
||
|
||
// success callback (submit form)
|
||
args.success( $form );
|
||
|
||
// lock form
|
||
if( args.lock ) {
|
||
this.lockForm( $form );
|
||
}
|
||
}
|
||
|
||
// reset
|
||
this.reset();
|
||
|
||
// complete callback
|
||
args.complete( $form );
|
||
};
|
||
|
||
// ajax
|
||
$.ajax({
|
||
url: acf.get('ajaxurl'),
|
||
data: acf.prepareForAjax(data),
|
||
type: 'post',
|
||
dataType: 'json',
|
||
context: this,
|
||
success: onSuccess,
|
||
complete: onComplete
|
||
});
|
||
},
|
||
|
||
addInputEvents: function( $el ){
|
||
|
||
// vars
|
||
var $inputs = $('.acf-field [name]');
|
||
|
||
// check
|
||
if( $inputs.length ) {
|
||
this.on( $inputs, 'invalid', 'onInvalid' );
|
||
}
|
||
},
|
||
|
||
onInvalid: function( e, $el ){
|
||
|
||
// vars
|
||
var $form = $el.closest('form');
|
||
|
||
// add error
|
||
this.addError({
|
||
input: $el.attr('name'),
|
||
message: e.target.validationMessage
|
||
});
|
||
|
||
// prevent default
|
||
// - prevents browser error message
|
||
// - also fixes chrome bug where 'hidden-by-tab' field throws focus error
|
||
e.preventDefault();
|
||
|
||
// trigger submit on $form
|
||
// - allows for "save", "preview" and "publish" to work
|
||
$form.submit();
|
||
},
|
||
|
||
// fixes bug on User Profile edit form
|
||
// - WP prevents $form.submit() events for unknown reason
|
||
// - temp store 'click event' and use later in onSubmit
|
||
onClickPublish: function( e, $el ){
|
||
this.set('originalEvent', e);
|
||
this.setTimeout(function(){
|
||
this.set('originalEvent', null);
|
||
}, 100);
|
||
},
|
||
|
||
onClickSave: function( e, $el ) {
|
||
|
||
// ignore errors
|
||
this.pass();
|
||
},
|
||
|
||
onSubmit: function( e, $form ){
|
||
|
||
// validate
|
||
var valid = acf.validateForm({
|
||
form: $form,
|
||
event: this.get('originalEvent') || e
|
||
});
|
||
|
||
// if not valid, stop event and allow validation to continue
|
||
if( !valid ) {
|
||
e.preventDefault();
|
||
}
|
||
},
|
||
|
||
showSpinner: function( $spinner ){
|
||
$spinner.addClass('is-active'); // add class (WP > 4.2)
|
||
$spinner.css('display', 'inline-block'); // css (WP < 4.2)
|
||
},
|
||
|
||
hideSpinner: function( $spinner ){
|
||
$spinner.removeClass('is-active'); // add class (WP > 4.2)
|
||
$spinner.css('display', 'none'); // css (WP < 4.2)
|
||
},
|
||
|
||
disableSubmit: function( $submit ){
|
||
$submit.prop('disabled', true).addClass('disabled');
|
||
},
|
||
|
||
enableSubmit: function( $submit ){
|
||
$submit.prop('disabled', false).removeClass('disabled');
|
||
},
|
||
|
||
findSubmitWrap: function( $form ){
|
||
|
||
// default post submit div
|
||
var $wrap = $('#submitdiv');
|
||
if( $wrap.length ) {
|
||
return $wrap;
|
||
}
|
||
|
||
// 3rd party publish box
|
||
var $wrap = $('#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;
|
||
},
|
||
|
||
lockForm: function( $form ){
|
||
|
||
// vars
|
||
var $wrap = this.findSubmitWrap( $form );
|
||
var $submit = $wrap.find('.button, .acf-button');
|
||
var $spinner = $wrap.find('.spinner, .acf-spinner');
|
||
|
||
// hide all spinners (hides the preview spinner)
|
||
this.hideSpinner( $spinner );
|
||
|
||
// lock
|
||
this.disableSubmit( $submit );
|
||
this.showSpinner( $spinner.last() );
|
||
},
|
||
|
||
unlockForm: function( $form ){
|
||
|
||
// vars
|
||
var $wrap = this.findSubmitWrap( $form );
|
||
var $submit = $wrap.find('.button, .acf-button');
|
||
var $spinner = $wrap.find('.spinner, .acf-spinner');
|
||
|
||
// unlock
|
||
this.enableSubmit( $submit );
|
||
this.hideSpinner( $spinner );
|
||
}
|
||
|
||
});
|
||
|
||
/**
|
||
* Form
|
||
*
|
||
* description
|
||
*
|
||
* @date 5/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
var Form = acf.Model.extend({
|
||
notice: false,
|
||
setup: function( $form ){
|
||
this.$el = $form;
|
||
},
|
||
lock: function(){
|
||
acf.validation.lockForm( this.$el );
|
||
},
|
||
unlock: function(){
|
||
acf.validation.unlockForm( this.$el );
|
||
}
|
||
});
|
||
|
||
/**
|
||
* acf.validateForm
|
||
*
|
||
* description
|
||
*
|
||
* @date 4/4/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.validateForm = function( args ){
|
||
|
||
// bail early if no form
|
||
// - return true allowing form submit
|
||
if( !args.form ) {
|
||
return true;
|
||
}
|
||
|
||
// get form
|
||
var form = acf.validation.getForm( args.form );
|
||
|
||
// bail early if not active
|
||
// - return true allowing form submit
|
||
if( !acf.validation.active ) {
|
||
return true;
|
||
}
|
||
|
||
// bail early if ignore
|
||
// - return true allowing form submit
|
||
if( acf.validation.ignore ) {
|
||
return true;
|
||
}
|
||
|
||
// bail early if is preview
|
||
// - return true allowing form submit
|
||
if( form.$('#wp-preview').val() ) {
|
||
form.unlock();
|
||
return true;
|
||
}
|
||
|
||
// bail early if this form does not contain ACF data
|
||
// - return true allowing form submit
|
||
if( !form.$('#acf-form-data').length ) {
|
||
return true;
|
||
}
|
||
|
||
// validate
|
||
acf.validation.fetch( args );
|
||
|
||
// return false preventing form submit
|
||
return false;
|
||
};
|
||
|
||
})(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 <tr> 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('<td style="height:' + $item.height() + 'px; padding:0;" colspan="' + $item.children('td').length + '"></td>');
|
||
}
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 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 = $();
|
||
}
|
||
|
||
// 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
|
||
});
|
||
}
|
||
});
|
||
|
||
|
||
/**
|
||
* 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);
|
||
}
|
||
});
|
||
_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";
|
||
|
||
|