import assign from '../data/object-assign';
/**
* @description Holds the list of filters currently subscribed to events. Added to global scope so that it is available when accessed from outside of this module. i.e. gform.utils.addFilter().
* @type {Array} Associative array of current filters
*/
window.gform = window.gform || {};
window.gform.instances = window.gform.instances || {};
window.gform.instances.filters = window.gform.instances.filters || [];
const filters = window.gform.instances.filters;
/**
* @module filter
* @description Triggers a filter event, allowing event subscribers to modify the specified data object. Each subscribed callback will be executed in order in a blocking/synchronous way.
*
* @since 3.0.1
*
* @param {object} opts The options object.
* @param {object} opts.data Data object sent to callbacks to be filtered.
* @param {string} opts.event The event name.
*
* @requires assign
*
* @return {object} Returns the filtered data object.
*
* @example
* import { filter } from "@gravityforms/utils";
*
* async function Example() {
* let filteredData = 'hello';
*
* filteredData = await filter( { event: 'gform/example/event_name', data: filteredData } );
* };
*
* // elsewhere in the codebase
*
* addFilter( 'gform/example/event_name', ( data ) => {
* data = 'hello again!';
* return data;
* }, 11 );
*
*/
const filter = async function( opts = {} ) {
const options = assign(
{
data: {},
event: '',
}, opts );
if ( filters[ options.event ] !== undefined ) {
const callbacks = filters[ options.event ];
//sort by priority.
callbacks.sort( ( a, b ) => a.priority - b.priority );
// execute callbacks synchronously and in order.
for ( let i = 0; i < callbacks.length; i++ ) {
const callback = callbacks[ i ];
if ( callback.isAsync ) {
options.data = await callback.callable( options.data );
} else {
options.data = callback.callable( options.data );
}
}
}
return options.data;
};
/**
* @function addAsyncFilter
* @description Adds an async callback function to a filter event.
*
* @since 3.0.1
*
* @param {string} event The event name.
* @param {Function} callable The callback function to be executed. The callback function takes a 'data' parameter as argument that can be of any type (depends on the event being fired). Defaults to 10.
* @param {int} priority The filter priority. This determines the execution order. Lower priority filters execute first.
*
* @return {void}
*
* @example
* import { addAsyncFilter } from "@gravityforms/utils";
*
* function Example() {
*
* addAsyncFilter( 'gform/example/event_name', async function ( data ) {
* data = 'filtered data';
* return data;
* }, 10 );
*
* };
*
* // elsewhere in the codebase
* let filteredData = 'hello';
* filteredData = await filter( { event: 'gform/example/event_name', data: filteredData } );*
*
*/
const addAsyncFilter = function( event, callable, priority = 10 ) {
addFilter( event, callable, priority, true );
};
/**
* @function addFilter
* @description Adds a callback function to a filter event.
*
* @since 3.0.1
*
* @param {string} event The event name.
* @param {Function} callable The callback function to be executed. The callback function takes a 'data' parameter as argument that can be of any type (depends on the event being fired). Defaults to 10.
* @param {int} priority The filter priority. This determines the execution order. Lower priority filters execute first.
* @param {boolean} isAsync Wether or not the callable parameter is an async function. Defaults to false.
*
* @return {void}
*
* @example
* import { addFilter } from "@gravityforms/utils";
*
* function Example() {
*
* addFilter( 'gform/example/event_name', function ( data ) {
* data = 'filtered data';
* return data;
* } );
*
* };
*
* // elsewhere in the codebase
* let filteredData = 'hello';
* filteredData = await filter( { event: 'gform/example/event_name', data: filteredData } );*
*
*/
const addFilter = function( event, callable, priority = 10, isAsync = false ) {
if ( filters[ event ] === undefined ) {
filters[ event ] = [];
}
const tag = event + '_' + filters[ event ].length;
filters[ event ].push( { tag, callable, priority, isAsync } );
};
/**
* @function removeFilter
* @description Removes a callback function from the list of filters.
*
* @since 3.0.1
*
* @param {string} event The event name.
* @param {int} priority The filter priority. Removes filters of this priority. If ommitted, filters of any priority will be removed.
* @param {string} tag Removes functions of this tag. If ommitted, functions of any tag will be removed. Tag is formatted as 'event-name_function-index'.
*
* @return {void}
*
* @example
* import { removeFilter } from "@gravityforms/utils";
*
* function Example() {
*
* // removes all filters that are subscribed to 'gform/example/event_name' and that have priority 10.
* removeFilter( 'gform/example/event_name', 10);
* };
*
*/
const removeFilter = function( event, priority = null, tag = null ) {
if ( filters[ event ] === undefined ) {
return;
}
const callbacks = filters[ event ];
for ( let i = callbacks.length - 1; i >= 0; i-- ) {
if ( ( tag === null || tag === callbacks[ i ].tag ) && ( priority === null || parseInt( callbacks[ i ].priority ) === parseInt( priority ) ) ) {
callbacks.splice( i, 1 );
}
}
};
export { filter, addAsyncFilter, addFilter, removeFilter };