A hook function is registered with a hook via the plugin's ep.json
file. See
the Plugins section for details. A hook may have many registered functions from
different plugins.
Some hooks call their registered functions one at a time until one of them returns a value. Others always call all of their registered functions and combine the results (if applicable).
Note: The documentation in this section applies to every hook unless the hook-specific documentation says otherwise.
Hook functions are called with three arguments:
hookName
- The name of the hook being invoked.context
- An object with some relevant information about the context of the
call. See the hook-specific documentation for details.cb
- For asynchronous operations this callback can be called to signal
completion and optionally provide a return value. The callback takes a single
argument, the meaning of which depends on the hook (see the "Return values"
section for general information that applies to most hooks). This callback
always returns undefined
.The presence of a callback parameter suggests that every hook function can run asynchronously. While that is the eventual goal, there are some legacy hooks that expect their hook functions to provide a value synchronously. For such hooks, the hook functions must do one of the following:
undefined
is acceptable) and
return undefined
, in that order.undefined
(null
is acceptable) and
never call the callback. Note that async
functions always return a
Promise, so they must never be used for synchronous hooks.hookName
and context
) and return any non-Promise
value (undefined
is acceptable).For hooks that permit asynchronous behavior, the hook functions must do one or more of the following:
undefined
and call the callback, in either order.undefined
(null
is acceptable) and never call
the callback. Note that async
functions always return a Promise, so they
must never call the callback.hookName
and context
).Note that the acceptable behaviors for asynchronous hook functions is a superset of the acceptable behaviors for synchronous hook functions.
WARNING: The number of parameters is determined by examining Function.length, which does not count default parameters or "rest" parameters. To avoid problems, do not use default or rest parameters when defining hook functions.
A hook function can provide a value to Etherpad in one of the following ways:
undefined
unless
the hook function only has two parameters. (Hook functions with three
parameters that want to provide undefined
should instead use the callback.)Examples:
exports.exampleOne = (hookName, context, callback) => {
return 'valueOne';
};
exports.exampleTwo = (hookName, context, callback) => {
callback('valueTwo');
return;
};
// ONLY FOR HOOKS THAT PERMIT ASYNCHRONOUS BEHAVIOR
exports.exampleThree = (hookName, context, callback) => {
return new Promise('valueThree');
};
// ONLY FOR HOOKS THAT PERMIT ASYNCHRONOUS BEHAVIOR
exports.exampleFour = (hookName, context, callback) => {
callback(new Promise('valueFour'));
return;
};
// ONLY FOR HOOKS THAT PERMIT ASYNCHRONOUS BEHAVIOR
exports.exampleFive = async (hookName, context) => {
// Note that this function is async, so it actually returns a Promise that
// is resolved to 'valueFive'.
return 'valueFive';
};
Etherpad collects the values provided by the hook functions into an array,
filters out all undefined
values, then flattens the array one level.
Flattening one level makes it possible for a hook function to behave as if it
were multiple separate hook functions.
For example: Suppose a hook has eight registered functions that return the
following values: 1
, [2]
, ['3a', '3b']
[[4]]
, undefined
,
[undefined]
, []
, and null
. The value returned to the caller of the hook is
[1, 2, '3a', '3b', [4], undefined, null]
.