4449 lines
86 KiB
JavaScript
4449 lines
86 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(name) !== null;
|
||
};
|
||
|
||
|
||
/**
|
||
* set
|
||
*
|
||
* Sets a specific data value
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string name
|
||
* @param mixed value
|
||
* @return this
|
||
*/
|
||
|
||
acf.set = function( name, value ){
|
||
this.data[ name ] = value;
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* uniqueId
|
||
*
|
||
* Returns a unique ID
|
||
*
|
||
* @date 9/11/17
|
||
* @since 5.6.3
|
||
*
|
||
* @param string prefix Optional prefix.
|
||
* @return string
|
||
*/
|
||
|
||
var idCounter = 0;
|
||
acf.uniqueId = function(prefix){
|
||
var id = ++idCounter + '';
|
||
return prefix ? prefix + id : id;
|
||
};
|
||
|
||
/**
|
||
* acf.uniqueArray
|
||
*
|
||
* Returns a new array with only unique values
|
||
* Credit: https://stackoverflow.com/questions/1960473/get-all-unique-values-in-an-array-remove-duplicates
|
||
*
|
||
* @date 23/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.uniqueArray = function( array ){
|
||
function onlyUnique(value, index, self) {
|
||
return self.indexOf(value) === index;
|
||
}
|
||
return array.filter( onlyUnique );
|
||
};
|
||
|
||
/**
|
||
* uniqid
|
||
*
|
||
* Returns a unique ID (PHP version)
|
||
*
|
||
* @date 9/11/17
|
||
* @since 5.6.3
|
||
* @source http://locutus.io/php/misc/uniqid/
|
||
*
|
||
* @param string prefix Optional prefix.
|
||
* @return string
|
||
*/
|
||
|
||
var uniqidSeed = '';
|
||
acf.uniqid = function(prefix, moreEntropy){
|
||
// discuss at: http://locutus.io/php/uniqid/
|
||
// original by: Kevin van Zonneveld (http://kvz.io)
|
||
// revised by: Kankrelune (http://www.webfaktory.info/)
|
||
// note 1: Uses an internal counter (in locutus global) to avoid collision
|
||
// example 1: var $id = uniqid()
|
||
// example 1: var $result = $id.length === 13
|
||
// returns 1: true
|
||
// example 2: var $id = uniqid('foo')
|
||
// example 2: var $result = $id.length === (13 + 'foo'.length)
|
||
// returns 2: true
|
||
// example 3: var $id = uniqid('bar', true)
|
||
// example 3: var $result = $id.length === (23 + 'bar'.length)
|
||
// returns 3: true
|
||
if (typeof prefix === 'undefined') {
|
||
prefix = '';
|
||
}
|
||
|
||
var retId;
|
||
var formatSeed = function(seed, reqWidth) {
|
||
seed = parseInt(seed, 10).toString(16); // to hex str
|
||
if (reqWidth < seed.length) { // so long we split
|
||
return seed.slice(seed.length - reqWidth);
|
||
}
|
||
if (reqWidth > seed.length) { // so short we pad
|
||
return Array(1 + (reqWidth - seed.length)).join('0') + seed;
|
||
}
|
||
return seed;
|
||
};
|
||
|
||
if (!uniqidSeed) { // init seed with big random int
|
||
uniqidSeed = Math.floor(Math.random() * 0x75bcd15);
|
||
}
|
||
uniqidSeed++;
|
||
|
||
retId = prefix; // start with prefix, add current milliseconds hex string
|
||
retId += formatSeed(parseInt(new Date().getTime() / 1000, 10), 8);
|
||
retId += formatSeed(uniqidSeed, 5); // add seed hex string
|
||
if (moreEntropy) {
|
||
// for more entropy we add a float lower to 10
|
||
retId += (Math.random() * 10).toFixed(8).toString();
|
||
}
|
||
|
||
return retId;
|
||
};
|
||
|
||
|
||
/**
|
||
* strReplace
|
||
*
|
||
* Performs a string replace
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string search
|
||
* @param string replace
|
||
* @param string subject
|
||
* @return string
|
||
*/
|
||
|
||
acf.strReplace = function( search, replace, subject ){
|
||
return subject.split(search).join(replace);
|
||
};
|
||
|
||
|
||
/**
|
||
* strCamelCase
|
||
*
|
||
* Converts a string into camelCase
|
||
* Thanks to https://stackoverflow.com/questions/2970525/converting-any-string-into-camel-case
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string str
|
||
* @return string
|
||
*/
|
||
|
||
acf.strCamelCase = function( str ){
|
||
var matches = str.match( /([a-zA-Z0-9]+)/g );
|
||
return matches ? matches.map(function( s, i ){
|
||
var c = s.charAt(0);
|
||
return ( i === 0 ? c.toLowerCase() : c.toUpperCase() ) + s.slice(1);
|
||
}).join('') : '';
|
||
};
|
||
|
||
/**
|
||
* strPascalCase
|
||
*
|
||
* Converts a string into PascalCase
|
||
* Thanks to https://stackoverflow.com/questions/1026069/how-do-i-make-the-first-letter-of-a-string-uppercase-in-javascript
|
||
*
|
||
* @date 14/12/17
|
||
* @since 5.6.5
|
||
*
|
||
* @param string str
|
||
* @return string
|
||
*/
|
||
|
||
acf.strPascalCase = function( str ){
|
||
var camel = acf.strCamelCase( str );
|
||
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
||
};
|
||
|
||
/**
|
||
* acf.strSlugify
|
||
*
|
||
* Converts a string into a HTML class friendly slug
|
||
*
|
||
* @date 21/3/18
|
||
* @since 5.6.9
|
||
*
|
||
* @param string str
|
||
* @return string
|
||
*/
|
||
|
||
acf.strSlugify = function( str ){
|
||
return acf.strReplace( '_', '-', str.toLowerCase() );
|
||
};
|
||
|
||
|
||
acf.strSanitize = function( str ){
|
||
|
||
// chars (https://jsperf.com/replace-foreign-characters)
|
||
var map = {
|
||
"À": "A",
|
||
"Á": "A",
|
||
"Â": "A",
|
||
"Ã": "A",
|
||
"Ä": "A",
|
||
"Å": "A",
|
||
"Æ": "AE",
|
||
"Ç": "C",
|
||
"È": "E",
|
||
"É": "E",
|
||
"Ê": "E",
|
||
"Ë": "E",
|
||
"Ì": "I",
|
||
"Í": "I",
|
||
"Î": "I",
|
||
"Ï": "I",
|
||
"Ð": "D",
|
||
"Ñ": "N",
|
||
"Ò": "O",
|
||
"Ó": "O",
|
||
"Ô": "O",
|
||
"Õ": "O",
|
||
"Ö": "O",
|
||
"Ø": "O",
|
||
"Ù": "U",
|
||
"Ú": "U",
|
||
"Û": "U",
|
||
"Ü": "U",
|
||
"Ý": "Y",
|
||
"ß": "s",
|
||
"à": "a",
|
||
"á": "a",
|
||
"â": "a",
|
||
"ã": "a",
|
||
"ä": "a",
|
||
"å": "a",
|
||
"æ": "ae",
|
||
"ç": "c",
|
||
"è": "e",
|
||
"é": "e",
|
||
"ê": "e",
|
||
"ë": "e",
|
||
"ì": "i",
|
||
"í": "i",
|
||
"î": "i",
|
||
"ï": "i",
|
||
"ñ": "n",
|
||
"ò": "o",
|
||
"ó": "o",
|
||
"ô": "o",
|
||
"õ": "o",
|
||
"ö": "o",
|
||
"ø": "o",
|
||
"ù": "u",
|
||
"ú": "u",
|
||
"û": "u",
|
||
"ü": "u",
|
||
"ý": "y",
|
||
"ÿ": "y",
|
||
"Ā": "A",
|
||
"ā": "a",
|
||
"Ă": "A",
|
||
"ă": "a",
|
||
"Ą": "A",
|
||
"ą": "a",
|
||
"Ć": "C",
|
||
"ć": "c",
|
||
"Ĉ": "C",
|
||
"ĉ": "c",
|
||
"Ċ": "C",
|
||
"ċ": "c",
|
||
"Č": "C",
|
||
"č": "c",
|
||
"Ď": "D",
|
||
"ď": "d",
|
||
"Đ": "D",
|
||
"đ": "d",
|
||
"Ē": "E",
|
||
"ē": "e",
|
||
"Ĕ": "E",
|
||
"ĕ": "e",
|
||
"Ė": "E",
|
||
"ė": "e",
|
||
"Ę": "E",
|
||
"ę": "e",
|
||
"Ě": "E",
|
||
"ě": "e",
|
||
"Ĝ": "G",
|
||
"ĝ": "g",
|
||
"Ğ": "G",
|
||
"ğ": "g",
|
||
"Ġ": "G",
|
||
"ġ": "g",
|
||
"Ģ": "G",
|
||
"ģ": "g",
|
||
"Ĥ": "H",
|
||
"ĥ": "h",
|
||
"Ħ": "H",
|
||
"ħ": "h",
|
||
"Ĩ": "I",
|
||
"ĩ": "i",
|
||
"Ī": "I",
|
||
"ī": "i",
|
||
"Ĭ": "I",
|
||
"ĭ": "i",
|
||
"Į": "I",
|
||
"į": "i",
|
||
"İ": "I",
|
||
"ı": "i",
|
||
"IJ": "IJ",
|
||
"ij": "ij",
|
||
"Ĵ": "J",
|
||
"ĵ": "j",
|
||
"Ķ": "K",
|
||
"ķ": "k",
|
||
"Ĺ": "L",
|
||
"ĺ": "l",
|
||
"Ļ": "L",
|
||
"ļ": "l",
|
||
"Ľ": "L",
|
||
"ľ": "l",
|
||
"Ŀ": "L",
|
||
"ŀ": "l",
|
||
"Ł": "l",
|
||
"ł": "l",
|
||
"Ń": "N",
|
||
"ń": "n",
|
||
"Ņ": "N",
|
||
"ņ": "n",
|
||
"Ň": "N",
|
||
"ň": "n",
|
||
"ʼn": "n",
|
||
"Ō": "O",
|
||
"ō": "o",
|
||
"Ŏ": "O",
|
||
"ŏ": "o",
|
||
"Ő": "O",
|
||
"ő": "o",
|
||
"Œ": "OE",
|
||
"œ": "oe",
|
||
"Ŕ": "R",
|
||
"ŕ": "r",
|
||
"Ŗ": "R",
|
||
"ŗ": "r",
|
||
"Ř": "R",
|
||
"ř": "r",
|
||
"Ś": "S",
|
||
"ś": "s",
|
||
"Ŝ": "S",
|
||
"ŝ": "s",
|
||
"Ş": "S",
|
||
"ş": "s",
|
||
"Š": "S",
|
||
"š": "s",
|
||
"Ţ": "T",
|
||
"ţ": "t",
|
||
"Ť": "T",
|
||
"ť": "t",
|
||
"Ŧ": "T",
|
||
"ŧ": "t",
|
||
"Ũ": "U",
|
||
"ũ": "u",
|
||
"Ū": "U",
|
||
"ū": "u",
|
||
"Ŭ": "U",
|
||
"ŭ": "u",
|
||
"Ů": "U",
|
||
"ů": "u",
|
||
"Ű": "U",
|
||
"ű": "u",
|
||
"Ų": "U",
|
||
"ų": "u",
|
||
"Ŵ": "W",
|
||
"ŵ": "w",
|
||
"Ŷ": "Y",
|
||
"ŷ": "y",
|
||
"Ÿ": "Y",
|
||
"Ź": "Z",
|
||
"ź": "z",
|
||
"Ż": "Z",
|
||
"ż": "z",
|
||
"Ž": "Z",
|
||
"ž": "z",
|
||
"ſ": "s",
|
||
"ƒ": "f",
|
||
"Ơ": "O",
|
||
"ơ": "o",
|
||
"Ư": "U",
|
||
"ư": "u",
|
||
"Ǎ": "A",
|
||
"ǎ": "a",
|
||
"Ǐ": "I",
|
||
"ǐ": "i",
|
||
"Ǒ": "O",
|
||
"ǒ": "o",
|
||
"Ǔ": "U",
|
||
"ǔ": "u",
|
||
"Ǖ": "U",
|
||
"ǖ": "u",
|
||
"Ǘ": "U",
|
||
"ǘ": "u",
|
||
"Ǚ": "U",
|
||
"ǚ": "u",
|
||
"Ǜ": "U",
|
||
"ǜ": "u",
|
||
"Ǻ": "A",
|
||
"ǻ": "a",
|
||
"Ǽ": "AE",
|
||
"ǽ": "ae",
|
||
"Ǿ": "O",
|
||
"ǿ": "o",
|
||
|
||
// extra
|
||
' ': '_',
|
||
"'": '',
|
||
'?': '',
|
||
'/': '',
|
||
'\\': '',
|
||
'.': '',
|
||
',': '',
|
||
'`': '',
|
||
'>': '',
|
||
'<': '',
|
||
'"': '',
|
||
'[': '',
|
||
']': '',
|
||
'|': '',
|
||
'{': '',
|
||
'}': '',
|
||
'(': '',
|
||
')': ''
|
||
};
|
||
|
||
// vars
|
||
var nonWord = /\W/g;
|
||
var mapping = function (c) {
|
||
return (map[c] !== undefined) ? map[c] : c;
|
||
};
|
||
|
||
// replace
|
||
str = str.replace(nonWord, mapping);
|
||
|
||
// lowercase
|
||
str = str.toLowerCase();
|
||
|
||
// return
|
||
return str;
|
||
};
|
||
|
||
/**
|
||
* acf.strMatch
|
||
*
|
||
* Returns the number of characters that match between two strings
|
||
*
|
||
* @date 1/2/18
|
||
* @since 5.6.5
|
||
*
|
||
* @param type $var Description. Default.
|
||
* @return type Description.
|
||
*/
|
||
|
||
acf.strMatch = function( s1, s2 ){
|
||
|
||
// vars
|
||
var val = 0;
|
||
var min = Math.min( s1.length, s2.length );
|
||
|
||
// loop
|
||
for( var i = 0; i < min; i++ ) {
|
||
if( s1[i] !== s2[i] ) {
|
||
break;
|
||
}
|
||
val++;
|
||
}
|
||
|
||
// return
|
||
return val;
|
||
};
|
||
|
||
/**
|
||
* Escapes HTML entities from a string.
|
||
*
|
||
* @date 08/06/2020
|
||
* @since 5.9.0
|
||
*
|
||
* @param string string The input string.
|
||
* @return string
|
||
*/
|
||
acf.strEscape = function( string ){
|
||
var htmlEscapes = {
|
||
'&': '&',
|
||
'<': '<',
|
||
'>': '>',
|
||
'"': '"',
|
||
"'": '''
|
||
};
|
||
return ('' + string).replace(/[&<>"']/g, function( chr ) {
|
||
return htmlEscapes[ chr ];
|
||
});
|
||
};
|
||
|
||
// Tests.
|
||
//console.log( acf.strEscape('Test 1') );
|
||
//console.log( acf.strEscape('Test & 1') );
|
||
//console.log( acf.strEscape('Test\'s & 1') );
|
||
//console.log( acf.strEscape('<script>js</script>') );
|
||
|
||
/**
|
||
* Unescapes HTML entities from a string.
|
||
*
|
||
* @date 08/06/2020
|
||
* @since 5.9.0
|
||
*
|
||
* @param string string The input string.
|
||
* @return string
|
||
*/
|
||
acf.strUnescape = function( string ){
|
||
var htmlUnescapes = {
|
||
'&': '&',
|
||
'<': '<',
|
||
'>': '>',
|
||
'"': '"',
|
||
''': "'"
|
||
};
|
||
return ('' + string).replace(/&|<|>|"|'/g, function( entity ) {
|
||
return htmlUnescapes[ entity ];
|
||
});
|
||
};
|
||
|
||
// Tests.
|
||
//console.log( acf.strUnescape( acf.strEscape('Test 1') ) );
|
||
//console.log( acf.strUnescape( acf.strEscape('Test & 1') ) );
|
||
//console.log( acf.strUnescape( acf.strEscape('Test\'s & 1') ) );
|
||
//console.log( acf.strUnescape( acf.strEscape('<script>js</script>') ) );
|
||
|
||
/**
|
||
* Escapes HTML entities from a string.
|
||
*
|
||
* @date 08/06/2020
|
||
* @since 5.9.0
|
||
*
|
||
* @param string string The input string.
|
||
* @return string
|
||
*/
|
||
acf.escAttr = acf.strEscape;
|
||
|
||
/**
|
||
* Encodes <script> tags for safe HTML output.
|
||
*
|
||
* @date 08/06/2020
|
||
* @since 5.9.0
|
||
*
|
||
* @param string string The input string.
|
||
* @return string
|
||
*/
|
||
acf.escHtml = function( string ){
|
||
return ('' + string).replace(/<script|<\/script/g, function( html ) {
|
||
return acf.strEscape( html );
|
||
});
|
||
};
|
||
|
||
// Tests.
|
||
//console.log( acf.escHtml('<script>js</script>') );
|
||
//console.log( acf.escHtml( acf.strEscape('<script>js</script>') ) );
|
||
//console.log( acf.escHtml( '<script>js1</script><script>js2</script>' ) );
|
||
|
||
/**
|
||
* 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();
|
||
};
|
||
|
||
|
||
|
||
/**
|
||
* 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 ){
|
||
|
||
// 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 ];
|
||
}
|
||
}
|
||
};
|
||
|
||
acf.serialize = function( $el, prefix ){
|
||
|
||
// vars
|
||
var obj = {};
|
||
var inputs = acf.serializeArray( $el );
|
||
|
||
// 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 );
|
||
}
|
||
|
||
// return
|
||
return obj;
|
||
};
|
||
|
||
/**
|
||
* acf.serializeArray
|
||
*
|
||
* Similar to $.serializeArray() but works with a parent wrapping element.
|
||
*
|
||
* @date 19/8/18
|
||
* @since 5.7.3
|
||
*
|
||
* @param jQuery $el The element or form to serialize.
|
||
* @return array
|
||
*/
|
||
|
||
acf.serializeArray = function( $el ){
|
||
return $el.find('select, textarea, input').serializeArray();
|
||
}
|
||
|
||
/**
|
||
* acf.serializeForAjax
|
||
*
|
||
* Returns an object containing name => value data ready to be encoded for Ajax.
|
||
*
|
||
* @date 17/12/18
|
||
* @since 5.8.0
|
||
*
|
||
* @param jQUery $el The element or form to serialize.
|
||
* @return object
|
||
*/
|
||
acf.serializeForAjax = function( $el ){
|
||
|
||
// vars
|
||
var data = {};
|
||
var index = {};
|
||
|
||
// Serialize inputs.
|
||
var inputs = acf.serializeArray( $el );
|
||
|
||
// Loop over inputs and build data.
|
||
inputs.map(function( item ){
|
||
|
||
// Append to array.
|
||
if( item.name.slice(-2) === '[]' ) {
|
||
data[ item.name ] = data[ item.name ] || [];
|
||
data[ item.name ].push( item.value );
|
||
// Append
|
||
} else {
|
||
data[ item.name ] = item.value;
|
||
}
|
||
});
|
||
|
||
// return
|
||
return data;
|
||
};
|
||
|
||
/**
|
||
* 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
|
||
// - use try/catch to avoid JS error if cookies are disabled on front-end form
|
||
try {
|
||
var preferences = JSON.parse(localStorage.getItem('acf')) || {};
|
||
} catch(e) {
|
||
var 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
|
||
};
|
||
}
|
||
|
||
// defaults
|
||
args = acf.parseArgs(args, {
|
||
target: false,
|
||
search: '',
|
||
replace: '',
|
||
rename: true,
|
||
before: function( $el ){},
|
||
after: function( $el, $el2 ){},
|
||
append: function( $el, $el2 ){
|
||
$el.after( $el2 );
|
||
}
|
||
});
|
||
|
||
// 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
|
||
if( args.rename ) {
|
||
acf.rename({
|
||
target: $el2,
|
||
search: args.search,
|
||
replace: args.replace,
|
||
replacer: ( typeof args.rename === 'function' ? args.rename : null )
|
||
});
|
||
}
|
||
|
||
// 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 );
|
||
|
||
/**
|
||
* Fires after an element has been duplicated and appended to the DOM.
|
||
*
|
||
* @date 30/10/19
|
||
* @since 5.8.7
|
||
*
|
||
* @param jQuery $el The original element.
|
||
* @param jQuery $el2 The duplicated element.
|
||
*/
|
||
acf.doAction('duplicate', $el, $el2 );
|
||
|
||
// append
|
||
acf.doAction('append', $el2);
|
||
|
||
// 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 param.
|
||
if( args instanceof jQuery ) {
|
||
args = {
|
||
target: args
|
||
};
|
||
}
|
||
|
||
// Apply default args.
|
||
args = acf.parseArgs(args, {
|
||
target: false,
|
||
destructive: false,
|
||
search: '',
|
||
replace: '',
|
||
replacer: null
|
||
});
|
||
|
||
// Extract args.
|
||
var $el = args.target;
|
||
|
||
// Provide backup for empty args.
|
||
if( !args.search ) {
|
||
args.search = $el.attr('data-id');
|
||
}
|
||
if( !args.replace ) {
|
||
args.replace = acf.uniqid('acf');
|
||
}
|
||
if( !args.replacer ) {
|
||
args.replacer = function( name, value, search, replace ){
|
||
return value.replace( search, replace );
|
||
};
|
||
}
|
||
|
||
// Callback function for jQuery replacing.
|
||
var withReplacer = function( name ){
|
||
return function( i, value ){
|
||
return args.replacer( name, value, args.search, args.replace );
|
||
}
|
||
};
|
||
|
||
// Destructive Replace.
|
||
if( args.destructive ) {
|
||
var html = acf.strReplace( args.search, args.replace, $el.outerHTML() );
|
||
$el.replaceWith( html );
|
||
|
||
// Standard Replace.
|
||
} else {
|
||
$el.attr('data-id', args.replace);
|
||
$el.find('[id*="' + args.search + '"]').attr('id', withReplacer('id'));
|
||
$el.find('[for*="' + args.search + '"]').attr('for', withReplacer('for'));
|
||
$el.find('[name*="' + args.search + '"]').attr('name', withReplacer('name'));
|
||
}
|
||
|
||
// 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');
|
||
|
||
// language
|
||
if( acf.has('language') ) {
|
||
data.lang = acf.get('language');
|
||
}
|
||
|
||
// 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/ajax/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
|
||
}
|
||
|
||
// update value
|
||
$input.val( value );
|
||
|
||
// prevent select elements displaying blank value if option doesn't exist
|
||
if( $input.is('select') && $input.val() === null ) {
|
||
$input.val( prevValue );
|
||
return false;
|
||
}
|
||
|
||
// 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 || !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 || !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 = $input[0].files.length ? acf.isget($input[0].files, 0) : false;
|
||
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' );
|
||
};
|
||
|
||
/**
|
||
* Returns the error message from an XHR object.
|
||
*
|
||
* @date 17/3/20
|
||
* @since 5.8.9
|
||
*
|
||
* @param object xhr The XHR object.
|
||
* @return (string)
|
||
*/
|
||
acf.getXhrError = function( xhr ){
|
||
if( xhr.responseJSON && xhr.responseJSON.message ) {
|
||
return xhr.responseJSON.message;
|
||
} else if( xhr.statusText ) {
|
||
return xhr.statusText;
|
||
}
|
||
return "";
|
||
};
|
||
|
||
/**
|
||
* 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.escAttr(text) + '">' + crawl( item.children ) + '</optgroup>';
|
||
|
||
// option
|
||
} else {
|
||
itemsHtml += '<option value="' + acf.escAttr(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 );
|
||
};
|
||
|
||
/**
|
||
* acf.isGutenberg
|
||
*
|
||
* Returns true if the Gutenberg editor is being used.
|
||
*
|
||
* @date 14/11/18
|
||
* @since 5.8.0
|
||
*
|
||
* @param vois
|
||
* @return bool
|
||
*/
|
||
acf.isGutenberg = function(){
|
||
return !!( window.wp && wp.data && wp.data.select && wp.data.select( 'core/editor' ) );
|
||
};
|
||
|
||
/**
|
||
* acf.objectToArray
|
||
*
|
||
* Returns an array of items from the given object.
|
||
*
|
||
* @date 20/11/18
|
||
* @since 5.8.0
|
||
*
|
||
* @param object obj The object of items.
|
||
* @return array
|
||
*/
|
||
acf.objectToArray = function( obj ){
|
||
return Object.keys( obj ).map(function( key ){
|
||
return obj[key];
|
||
});
|
||
};
|
||
|
||
/**
|
||
* acf.debounce
|
||
*
|
||
* Returns a debounced version of the passed function which will postpone its execution until after `wait` milliseconds have elapsed since the last time it was invoked.
|
||
*
|
||
* @date 28/8/19
|
||
* @since 5.8.1
|
||
*
|
||
* @param function callback The callback function.
|
||
* @return int wait The number of milliseconds to wait.
|
||
*/
|
||
acf.debounce = function( callback, wait ){
|
||
var timeout;
|
||
return function(){
|
||
var context = this;
|
||
var args = arguments;
|
||
var later = function(){
|
||
callback.apply( context, args );
|
||
};
|
||
clearTimeout( timeout );
|
||
timeout = setTimeout( later, wait );
|
||
};
|
||
};
|
||
|
||
/**
|
||
* acf.throttle
|
||
*
|
||
* Returns a throttled version of the passed function which will allow only one execution per `limit` time period.
|
||
*
|
||
* @date 28/8/19
|
||
* @since 5.8.1
|
||
*
|
||
* @param function callback The callback function.
|
||
* @return int wait The number of milliseconds to wait.
|
||
*/
|
||
acf.throttle = function( callback, limit ){
|
||
var busy = false;
|
||
return function(){
|
||
if( busy ) return;
|
||
busy = true;
|
||
setTimeout(function(){
|
||
busy = false;
|
||
}, limit);
|
||
callback.apply( this, arguments );
|
||
};
|
||
};
|
||
|
||
/**
|
||
* acf.isInView
|
||
*
|
||
* Returns true if the given element is in view.
|
||
*
|
||
* @date 29/8/19
|
||
* @since 5.8.1
|
||
*
|
||
* @param elem el The dom element to inspect.
|
||
* @return bool
|
||
*/
|
||
acf.isInView = function( el ){
|
||
if( el instanceof jQuery ) {
|
||
el = el[0];
|
||
}
|
||
var rect = el.getBoundingClientRect();
|
||
return (
|
||
rect.top !== rect.bottom &&
|
||
rect.top >= 0 &&
|
||
rect.left >= 0 &&
|
||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
||
);
|
||
};
|
||
|
||
/**
|
||
* acf.onceInView
|
||
*
|
||
* Watches for a dom element to become visible in the browser and then excecutes the passed callback.
|
||
*
|
||
* @date 28/8/19
|
||
* @since 5.8.1
|
||
*
|
||
* @param dom el The dom element to inspect.
|
||
* @param function callback The callback function.
|
||
*/
|
||
acf.onceInView = (function() {
|
||
|
||
// Define list.
|
||
var items = [];
|
||
var id = 0;
|
||
|
||
// Define check function.
|
||
var check = function() {
|
||
items.forEach(function( item ){
|
||
if( acf.isInView(item.el) ) {
|
||
item.callback.apply( this );
|
||
pop( item.id );
|
||
}
|
||
});
|
||
};
|
||
|
||
// And create a debounced version.
|
||
var debounced = acf.debounce( check, 300 );
|
||
|
||
// Define add function.
|
||
var push = function( el, callback ) {
|
||
|
||
// Add event listener.
|
||
if( !items.length ) {
|
||
$(window).on( 'scroll resize', debounced ).on( 'acfrefresh orientationchange', check );
|
||
}
|
||
|
||
// Append to list.
|
||
items.push({ id: id++, el: el, callback: callback });
|
||
}
|
||
|
||
// Define remove function.
|
||
var pop = function( id ) {
|
||
|
||
// Remove from list.
|
||
items = items.filter(function(item) {
|
||
return (item.id !== id);
|
||
});
|
||
|
||
// Clean up listener.
|
||
if( !items.length ) {
|
||
$(window).off( 'scroll resize', debounced ).off( 'acfrefresh orientationchange', check );
|
||
}
|
||
}
|
||
|
||
// Define returned function.
|
||
return function( el, callback ){
|
||
|
||
// Allow jQuery object.
|
||
if( el instanceof jQuery )
|
||
el = el[0];
|
||
|
||
// Execute callback if already in view or add to watch list.
|
||
if( acf.isInView(el) ) {
|
||
callback.apply( this );
|
||
} else {
|
||
push( el, callback );
|
||
}
|
||
}
|
||
})();
|
||
|
||
/**
|
||
* acf.once
|
||
*
|
||
* Creates a function that is restricted to invoking `func` once.
|
||
*
|
||
* @date 2/9/19
|
||
* @since 5.8.1
|
||
*
|
||
* @param function func The function to restrict.
|
||
* @return function
|
||
*/
|
||
acf.once = function( func ){
|
||
var i = 0;
|
||
return function(){
|
||
if( i++ > 0 ) {
|
||
return (func = undefined);
|
||
}
|
||
return func.apply(this, arguments);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Focuses attention to a specific element.
|
||
*
|
||
* @date 05/05/2020
|
||
* @since 5.9.0
|
||
*
|
||
* @param jQuery $el The jQuery element to focus.
|
||
* @return void
|
||
*/
|
||
acf.focusAttention = function( $el ){
|
||
var wait = 1000;
|
||
|
||
// Apply class to focus attention.
|
||
$el.addClass( 'acf-attention -focused' );
|
||
|
||
// Scroll to element if needed.
|
||
var scrollTime = 500;
|
||
if( !acf.isInView( $el ) ) {
|
||
$( 'body, html' ).animate({
|
||
scrollTop: $el.offset().top - ( $(window).height() / 2 )
|
||
}, scrollTime);
|
||
wait += scrollTime;
|
||
}
|
||
|
||
// Remove class after $wait amount of time.
|
||
var fadeTime = 250;
|
||
setTimeout(function(){
|
||
$el.removeClass( '-focused' );
|
||
setTimeout(function(){
|
||
$el.removeClass( 'acf-attention' );
|
||
}, fadeTime);
|
||
}, wait);
|
||
};
|
||
|
||
/**
|
||
* Description
|
||
*
|
||
* @date 05/05/2020
|
||
* @since 5.9.0
|
||
*
|
||
* @param type Var Description.
|
||
* @return type Description.
|
||
*/
|
||
acf.onFocus = function( $el, callback ){
|
||
|
||
// Only run once per element.
|
||
// if( $el.data('acf.onFocus') ) {
|
||
// return false;
|
||
// }
|
||
|
||
// Vars.
|
||
var ignoreBlur = false;
|
||
var focus = false;
|
||
|
||
// Functions.
|
||
var onFocus = function(){
|
||
ignoreBlur = true;
|
||
setTimeout(function(){
|
||
ignoreBlur = false;
|
||
}, 1);
|
||
setFocus( true );
|
||
};
|
||
var onBlur = function(){
|
||
if( !ignoreBlur ) {
|
||
setFocus( false );
|
||
}
|
||
};
|
||
var addEvents = function(){
|
||
$(document).on('click', onBlur);
|
||
//$el.on('acfBlur', onBlur);
|
||
$el.on('blur', 'input, select, textarea', onBlur);
|
||
};
|
||
var removeEvents = function(){
|
||
$(document).off('click', onBlur);
|
||
//$el.off('acfBlur', onBlur);
|
||
$el.off('blur', 'input, select, textarea', onBlur);
|
||
};
|
||
var setFocus = function( value ){
|
||
if( focus === value ) {
|
||
return;
|
||
}
|
||
if( value ) {
|
||
addEvents();
|
||
} else {
|
||
removeEvents();
|
||
}
|
||
focus = value;
|
||
callback( value );
|
||
};
|
||
|
||
// Add events and set data.
|
||
$el.on('click', onFocus);
|
||
//$el.on('acfFocus', onFocus);
|
||
$el.on('focus', 'input, select, textarea', onFocus);
|
||
//$el.data('acf.onFocus', true);
|
||
};
|
||
|
||
/*
|
||
* 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);
|
||
};
|
||
|
||
}
|
||
|
||
/**
|
||
* Returns true if value is a number or a numeric string.
|
||
*
|
||
* @date 30/11/20
|
||
* @since 5.9.4
|
||
* @link https://stackoverflow.com/questions/9716468/pure-javascript-a-function-like-jquerys-isnumeric/9716488#9716488
|
||
*
|
||
* @param mixed n The variable being evaluated.
|
||
* @return bool.
|
||
*/
|
||
acf.isNumeric = function( n ){
|
||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||
}
|
||
|
||
/**
|
||
* Triggers a "refresh" action used by various Components to redraw the DOM.
|
||
*
|
||
* @date 26/05/2020
|
||
* @since 5.9.0
|
||
*
|
||
* @param void
|
||
* @return void
|
||
*/
|
||
acf.refresh = acf.debounce(function(){
|
||
$( window ).trigger('acfrefresh');
|
||
acf.doAction('refresh');
|
||
}, 0);
|
||
|
||
// Set up actions from events
|
||
$(document).ready(function(){
|
||
acf.doAction('ready');
|
||
});
|
||
|
||
$(window).on('load', function(){
|
||
|
||
// Use timeout to ensure action runs after Gutenberg has modified DOM elements during "DOMContentLoaded".
|
||
setTimeout(function(){
|
||
acf.doAction('load');
|
||
});
|
||
});
|
||
|
||
$(window).on('beforeunload', 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, prevValue]);
|
||
this.trigger('changed', [name, value, prevValue]);
|
||
}
|
||
|
||
// 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){
|
||
|
||
// validate
|
||
if( !this.validateEvent(e) ) {
|
||
return;
|
||
}
|
||
|
||
// construct args
|
||
var args = acf.arrayArgs( arguments );
|
||
var extraArgs = args.slice(1);
|
||
var eventArgs = [ e, $(e.currentTarget) ].concat( extraArgs );
|
||
|
||
// callback
|
||
callback.apply(this, eventArgs);
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 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(){
|
||
|
||
// Extract 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');
|
||
|
||
// Update.
|
||
this.title( title );
|
||
this.content( content );
|
||
if( width ) {
|
||
this.$('.acf-popup-box').css('width', width);
|
||
}
|
||
if( height ) {
|
||
this.$('.acf-popup-box').css('min-height', height);
|
||
}
|
||
this.loading( loading );
|
||
|
||
// Trigger 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.models.Modal = acf.Model.extend({
|
||
data: {
|
||
title: '',
|
||
content: '',
|
||
toolbar: '',
|
||
},
|
||
events: {
|
||
'click .acf-modal-close': 'onClickClose',
|
||
},
|
||
setup: function( props ){
|
||
$.extend(this.data, props);
|
||
this.$el = $();
|
||
this.render();
|
||
},
|
||
initialize: function(){
|
||
this.open();
|
||
},
|
||
render: function(){
|
||
|
||
// Extract vars.
|
||
var title = this.get('title');
|
||
var content = this.get('content');
|
||
var toolbar = this.get('toolbar');
|
||
|
||
// Create element.
|
||
var $el = $([
|
||
'<div>',
|
||
'<div class="acf-modal">',
|
||
'<div class="acf-modal-title">',
|
||
'<h2>' + title + '</h2>',
|
||
'<button class="acf-modal-close" type="button"><span class="dashicons dashicons-no"></span></button>',
|
||
'</div>',
|
||
'<div class="acf-modal-content">' + content + '</div>',
|
||
'<div class="acf-modal-toolbar">' + toolbar + '</div>',
|
||
'</div>',
|
||
'<div class="acf-modal-backdrop acf-modal-close"></div>',
|
||
'</div>'
|
||
].join('') );
|
||
|
||
// Update DOM.
|
||
if( this.$el ) {
|
||
this.$el.replaceWith( $el );
|
||
}
|
||
this.$el = $el;
|
||
|
||
// Trigger action.
|
||
acf.doAction('append', $el);
|
||
},
|
||
update: function( props ){
|
||
this.data = acf.parseArgs(props, this.data);
|
||
this.render();
|
||
},
|
||
title: function( title ){
|
||
this.$('.acf-modal-title h2').html( title );
|
||
},
|
||
content: function( content ){
|
||
this.$('.acf-modal-content').html( content );
|
||
},
|
||
toolbar: function( toolbar ){
|
||
this.$('.acf-modal-toolbar').html( toolbar );
|
||
},
|
||
open: function(){
|
||
$('body').append( this.$el );
|
||
},
|
||
close: function(){
|
||
this.remove();
|
||
},
|
||
onClickClose: function( e, $el ){
|
||
e.preventDefault();
|
||
this.close();
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Returns a new modal.
|
||
*
|
||
* @date 21/4/20
|
||
* @since 5.9.0
|
||
*
|
||
* @param object props The modal props.
|
||
* @return object
|
||
*/
|
||
acf.newModal = function( props ){
|
||
return new acf.models.Modal( props );
|
||
};
|
||
|
||
})(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();
|
||
|
||
// refresh events
|
||
this.removeEvents();
|
||
this.addEvents();
|
||
},
|
||
|
||
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( acf.escHtml( html ) );
|
||
},
|
||
|
||
text: function( text ){
|
||
this.$('p').html( acf.escHtml( 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.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 position.
|
||
$tooltip.removeClass('right left bottom top').css({ top: 0, left: 0 });
|
||
|
||
// Declare tollerance to edge of screen.
|
||
var tolerance = 10;
|
||
|
||
// Find target position.
|
||
var targetWidth = $target.outerWidth();
|
||
var targetHeight = $target.outerHeight();
|
||
var targetTop = $target.offset().top;
|
||
var targetLeft = $target.offset().left;
|
||
|
||
// Find tooltip position.
|
||
var tooltipWidth = $tooltip.outerWidth();
|
||
var tooltipHeight = $tooltip.outerHeight();
|
||
var tooltipTop = $tooltip.offset().top; // Should be 0, but WP media grid causes this to be 32 (toolbar padding).
|
||
|
||
// Assume default top alignment.
|
||
var top = targetTop - tooltipHeight - tooltipTop;
|
||
var left = targetLeft + (targetWidth / 2) - (tooltipWidth / 2);
|
||
|
||
// Check if too far left.
|
||
if( left < tolerance ) {
|
||
$tooltip.addClass('right');
|
||
left = targetLeft + targetWidth;
|
||
top = targetTop + (targetHeight / 2) - (tooltipHeight / 2) - tooltipTop;
|
||
|
||
// Check if too far right.
|
||
} else if( (left + tooltipWidth + tolerance) > $(window).width() ) {
|
||
$tooltip.addClass('left');
|
||
left = targetLeft - tooltipWidth;
|
||
top = targetTop + (targetHeight / 2) - (tooltipHeight / 2) - tooltipTop;
|
||
|
||
// Check if too far up.
|
||
} else if( top - $(window).scrollTop() < tolerance ) {
|
||
$tooltip.addClass('bottom');
|
||
top = targetTop + targetHeight - tooltipTop;
|
||
|
||
// No colision with edges.
|
||
} 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 event from propagating completely to allow "targetConfirm" to be clicked.
|
||
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); |