42 lines
2.4 KiB
JavaScript
42 lines
2.4 KiB
JavaScript
|
let EXPORTED_SYMBOLS = ['hookFunction'];
|
||
|
|
||
|
/**
|
||
|
* Add hooks to a function to execute before and after it. The function to modify is functionContext[functionName]. Call only once per function - modification is not supported.
|
||
|
*
|
||
|
* Other addons wishing to access the original function may do so using the .originalFunction member of the replacement function. This member can also be set if required, to insert a new function replacement into the chain rather than appending.
|
||
|
*
|
||
|
* @param functionContext The object on which the function is a property
|
||
|
* @param functionName The name of the property containing the function (on functionContext)
|
||
|
* @param onBeforeFunction A function to be called before the hooked function is executed. It will be passed the same parameters as the hooked function. It's return value will be passed on to onAfterFunction
|
||
|
* @param onAfterFunction A function to be called after the hooked function is executed. The parameters passed to it are: onBeforeFunction return value, arguments object from original hooked function, return value from original hooked function. It's return value will be returned in place of that of the original function.
|
||
|
* @returns A function which can be called to safely un-hook the hook
|
||
|
*/
|
||
|
function hookFunction(functionContext, functionName, onBeforeFunction, onAfterFunction) {
|
||
|
let originalFunction = functionContext[functionName];
|
||
|
|
||
|
if (!originalFunction) {
|
||
|
throw new Error("Could not find function " + functionName);
|
||
|
}
|
||
|
|
||
|
let replacementFunction = function() {
|
||
|
let onBeforeResult = null;
|
||
|
if (onBeforeFunction) {
|
||
|
onBeforeResult = onBeforeFunction.apply(this, arguments);
|
||
|
}
|
||
|
let originalResult = replacementFunction.originalFunction.apply(this, arguments);
|
||
|
if (onAfterFunction) {
|
||
|
return onAfterFunction.call(this, onBeforeResult, arguments, originalResult);
|
||
|
} else {
|
||
|
return originalResult;
|
||
|
}
|
||
|
}
|
||
|
replacementFunction.originalFunction = originalFunction;
|
||
|
functionContext[functionName] = replacementFunction;
|
||
|
|
||
|
return function () {
|
||
|
// Not safe to simply assign originalFunction back again, as something else might have chained onto this function, which would then break the chain
|
||
|
// Unassigning these variables prevent any effects of the hook, though the function itself remains in place.
|
||
|
onBeforeFunction = null;
|
||
|
onAfterFunction = null;
|
||
|
};
|
||
|
}
|