2 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
4 * Use, modification, and distribution are subject to the terms specified in the
8 /* Adds the specified function to the specified hook. To add a local
9 * hook, invoke this function as: add_hook.call(context, hook_name, ...).
10 * Note: hook_name must be a string */
11 function add_hook(hook_name, func, prepend, avoid_duplicates)
15 var hook = this[hook_name];
17 if (avoid_duplicates && hook.indexOf(func) != -1)
28 * Call every function in the array `hook' with the remaining
29 * arguments of this function. Note: This should only be used by
30 * define_hook and friends to define hook.run(...) functions. Hooks
31 * should always be run by calling hook.run(...).
33 function run_hooks(hook, args)
37 for (let i = 0; i < hook.length; ++i)
38 hook[i].apply (null, Array.prototype.slice.call(args));
41 function run_hooks_until_success(hook, args)
45 for (let i = 0; i < hook.length; ++i)
46 if (hook[i].apply (null, Array.prototype.slice.call(args)))
51 function run_hooks_until_failure(hook, args)
55 for (let i = 0; i < hook.length; ++i)
56 if (!hook[i].apply (null, Array.prototype.slice.call(args)))
61 var hook_type_doc_strings = [
63 "Each hook function added is run in sequence.",
64 /* RUN_HOOK_UNTIL_SUCCESS */
65 "Only boolean-valued hook functions may be added. Each hook function added is run in sequence until a value that conerts to true is returned.",
66 /* RUN_HOOK_UNTIL_FAILURE */
67 "Only boolean-valued hook functions may be added. Each hook function added is run in sequence until a value that conerts to false is returned."];
70 /* This should only be used by define_hook functions */
71 function initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string)
73 var h = this[hook_name];
75 h = this[hook_name] = [];
76 if (hook_type == null)
80 h.run = prototype.run;
82 case RUN_HOOK_UNTIL_SUCCESS:
83 h.run = prototype.run_until_success;
85 case RUN_HOOK_UNTIL_FAILURE:
86 h.run = prototype.run_until_failure;
89 h.hook_type = hook_type;
90 h.hook_name = hook_name;
92 (doc_string? doc_string + "\n" : "") +
93 hook_type_doc_strings[hook_type] +
94 (extra_doc_string? "\n" + extra_doc_string : "");
95 h.source_code_reference = get_caller_source_code_reference(1);
99 var hook_global_prototype = {
101 run_hooks(this, arguments);
103 run_until_success: function() {
104 return run_hooks_until_success(this, arguments);
106 run_until_failure: function() {
107 return run_hooks_until_failure(this, arguments);
112 const RUN_HOOK_UNTIL_SUCCESS = 1;
113 const RUN_HOOK_UNTIL_FAILURE = 2;
115 function define_hook(hook_name, hook_type, doc_string)
117 initialize_hook(hook_global_prototype, hook_name, hook_type, doc_string);
120 var hook_simple_local_prototype = {
122 var hook_name = this.hook_name;
123 if (hook_name in x) run_hooks(x[hook_name], arguments);
124 run_hooks(this, arguments);
126 run_until_success: function (x) {
127 var hook_name = this.hook_name;
128 if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
129 return run_hooks_until_success(conkeror[hook_name], arguments);
131 run_until_failure: function (x) {
132 var hook_name = this.hook_name;
133 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
134 return run_hooks_until_failure(conkeror[hook_name], arguments);
138 function simple_local_hook_definer(extra_doc_string) {
139 return function (hook_name, hook_type, doc_string) {
140 initialize_hook(hook_simple_local_prototype, hook_name, hook_type, doc_string, extra_doc_string);
144 /* This function is called with a variable number of string arguments
145 * in addition to the first, that specify the additional hook arrays
146 * to use. As an example: local_hook_definer("buffer", "buffer", "buffer.window")
148 function local_hook_definer(prop_name, extra_doc_string) {
151 var hook_name = this.hook_name;
152 if (hook_name in x) run_hooks(x[hook_name], arguments);
153 if (hook_name in x[prop_name]) run_hooks(x[prop_name][hook_name], arguments);
154 run_hooks(this, arguments);
156 run_until_success: function (x) {
157 var hook_name = this.hook_name;
158 if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
159 if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments)) return true;
160 return run_hooks_until_success(conkeror[hook_name], arguments);
162 run_until_failure: function (x) {
163 var hook_name = this.hook_name;
164 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
165 if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments)) return false;
166 return run_hooks_until_failure(conkeror[hook_name], arguments);
169 return function (hook_name, hook_type, doc_string) {
170 initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string);
174 function remove_hook(hook_name, func)
176 var hook = this[hook_name];
178 if (hook && (index = hook.indexOf(func)) != -1)
179 hook.splice(index, 1);