Files
carpseeds.pl/wp-content/plugins/elementor-3.2.5-bck4/assets/dev/js/utils/hooks.js
2024-07-15 11:28:08 +02:00

260 lines
7.0 KiB
JavaScript

'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() {
var slice = Array.prototype.slice,
MethodsAvailable;
/**
* 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: {},
};
/**
* 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 ) {
var handlers, handler, i;
if ( ! STORAGE[ type ][ hook ] ) {
return;
}
if ( ! callback ) {
STORAGE[ type ][ hook ] = [];
} else {
handlers = STORAGE[ type ][ hook ];
if ( ! context ) {
for ( i = handlers.length; i--; ) {
if ( handlers[ i ].callback === callback ) {
handlers.splice( i, 1 );
}
}
} else {
for ( i = handlers.length; i--; ) {
handler = handlers[ i ];
if ( handler.callback === callback && handler.context === context ) {
handlers.splice( i, 1 );
}
}
}
}
}
/**
* 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;
}
/**
* 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 ) {
// TEMP FIX BUG
var hasSameCallback = false;
jQuery.each( hooks, function() {
if ( this.callback === callback ) {
hasSameCallback = true;
return false;
}
} );
if ( hasSameCallback ) {
return;
}
// END TEMP FIX BUG
hooks.push( hookObject );
hooks = _hookInsertSort( hooks );
} else {
hooks = [ hookObject ];
}
STORAGE[ type ][ hook ] = 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 ],
i,
len;
if ( ! handlers ) {
return ( 'filters' === type ) ? args[ 0 ] : false;
}
len = handlers.length;
if ( 'filters' === type ) {
for ( i = 0; i < len; i++ ) {
args[ 0 ] = handlers[ i ].callback.apply( handlers[ i ].context, args );
}
} else {
for ( i = 0; i < len; i++ ) {
handlers[ i ].callback.apply( handlers[ i ].context, args );
}
}
return ( 'filters' === type ) ? args[ 0 ] : true;
}
/**
* 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 ( 'string' === typeof action && 'function' === typeof callback ) {
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 = slice.call( arguments );
var action = args.shift();
if ( 'string' === typeof action ) {
_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 ( 'string' === typeof action ) {
_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 ( 'string' === typeof filter && 'function' === typeof callback ) {
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 = slice.call( arguments );
var filter = args.shift();
if ( 'string' === typeof filter ) {
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 ( 'string' === typeof filter ) {
_removeHook( 'filters', filter, callback );
}
return MethodsAvailable;
}
/**
* Maintain a reference to the object scope so our public methods never get confusing.
*/
MethodsAvailable = {
removeFilter: removeFilter,
applyFilters: applyFilters,
addFilter: addFilter,
removeAction: removeAction,
doAction: doAction,
addAction: addAction,
};
// return all of the publicly available methods
return MethodsAvailable;
};
module.exports = EventManager;