Files
wordpress-preseed/wp-content/plugins/advanced-custom-fields/assets/build/js/_acf-model.js
2019-09-11 19:08:46 +02:00

908 lines
16 KiB
JavaScript

(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);