2 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
3 * (C) Copyright 2010 John J. Foerch
5 * Use, modification, and distribution are subject to the terms specified in the
11 require("coroutine.js");
13 /* Adds the specified function to the specified hook. To add a local
14 * hook, invoke this function as: add_hook.call(context, hook_name, ...).
15 * Note: hook_name must be a string */
16 function add_hook (hook_name, func, prepend) {
17 if (!(hook_name in this))
19 var hook = this[hook_name];
21 if (hook.indexOf(func) != -1)
32 * Call every function in the array `hook' with the remaining
33 * arguments of this function. Note: This should only be used by
34 * define_hook and friends to define hook.run(...) functions. Hooks
35 * should always be run by calling hook.run(...).
37 function run_hooks (hook, args) {
40 for (let i = 0, hlen = hook.length; i < hlen; ++i)
41 hook[i].apply(null, Array.prototype.slice.call(args));
44 function run_hooks_until_success (hook, args) {
47 for (let i = 0, hlen = hook.length; i < hlen; ++i)
48 if (hook[i].apply(null, Array.prototype.slice.call(args)))
53 function run_hooks_until_failure (hook, args) {
56 for (let i = 0, hlen = hook.length; i < hlen; ++i)
57 if (!hook[i].apply(null, Array.prototype.slice.call(args)))
62 function run_coroutine_hooks (hook, args) {
65 for (let i = 0, hlen = hook.length; i < hlen; ++i)
66 yield hook[i].apply(null, Array.prototype.slice.call(args));
69 function run_coroutine_hooks_until_success (hook, args) {
71 yield co_return(false);
72 for (let i = 0, hlen = hook.length; i < hlen; ++i)
73 if ((yield hook[i].apply(null, Array.prototype.slice.call(args))))
74 yield co_return(true);
75 yield co_return(false);
78 function run_coroutine_hooks_until_failure (hook, args) {
80 yield co_return(true);
81 for (let i = 0, hlen = hook.length; i < hlen; ++i)
82 if (!(yield hook[i].apply(null, Array.prototype.slice.call(args))))
83 yield co_return(false);
84 yield co_return(true);
88 const RUN_HOOK = 'RUN_HOOK';
89 const RUN_HOOK_UNTIL_SUCCESS = 'RUN_HOOK_UNTIL_SUCCESS';
90 const RUN_HOOK_UNTIL_FAILURE = 'RUN_HOOK_UNTIL_FAILURE';
93 /* This should only be used by define_hook functions */
94 function initialize_hook (run, hook_name, hook_type, doc_string, extra_doc_string) {
96 RUN_HOOK: "Each hook function is run in sequence.",
97 RUN_HOOK_UNTIL_SUCCESS:
98 "Each hook function is run in sequence until one returns a "+
99 "logically true value.",
100 RUN_HOOK_UNTIL_FAILURE:
101 "Each hook function is run in sequence until one returns a "+
102 "logically false value. If no function returns such a "+
103 "value, then the result of the hook will be `true'."
105 var h = this[hook_name];
107 h = this[hook_name] = [];
108 if (hook_type == null)
109 hook_type = RUN_HOOK;
111 h.hook_type = hook_type;
112 h.hook_name = hook_name;
114 (doc_string? doc_string + "\n" : "") +
115 docstrings[hook_type] +
116 (extra_doc_string? "\n" + extra_doc_string : "");
117 h.source_code_reference = get_caller_source_code_reference(1);
121 function define_hook (hook_name, hook_type, doc_string) {
123 RUN_HOOK: function () {
124 run_hooks(this, arguments);
126 RUN_HOOK_UNTIL_SUCCESS: function () {
127 return run_hooks_until_success(this, arguments);
129 RUN_HOOK_UNTIL_FAILURE: function () {
130 return run_hooks_until_failure(this, arguments);
133 initialize_hook(prototype[hook_type || RUN_HOOK],
134 hook_name, hook_type, doc_string);
137 function define_coroutine_hook (hook_name, hook_type, doc_string) {
139 RUN_HOOK: function () {
140 yield run_coroutine_hooks(this, arguments);
142 RUN_HOOK_UNTIL_SUCCESS: function () {
143 var result = yield run_coroutine_hooks_until_success(this, arguments);
144 yield co_return(result);
146 RUN_HOOK_UNTIL_FAILURE: function () {
147 var result = yield run_coroutine_hooks_until_failure(this, arguments);
148 yield co_return(result);
151 initialize_hook(prototype[hook_type || RUN_HOOK],
152 hook_name, hook_type, doc_string);
155 function simple_local_hook_definer (extra_doc_string) {
157 RUN_HOOK: function (x) {
158 var hook_name = this.hook_name;
160 run_hooks(x[hook_name], arguments);
161 run_hooks(this, arguments);
163 RUN_HOOK_UNTIL_SUCCESS: function (x) {
164 var hook_name = this.hook_name;
165 if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments))
167 return run_hooks_until_success(conkeror[hook_name], arguments);
169 RUN_HOOK_UNTIL_FAILURE: function (x) {
170 var hook_name = this.hook_name;
171 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
173 return run_hooks_until_failure(conkeror[hook_name], arguments);
176 return function (hook_name, hook_type, doc_string) {
177 initialize_hook(prototype[hook_type || RUN_HOOK],
178 hook_name, hook_type, doc_string,
183 function simple_local_coroutine_hook_definer (extra_doc_string) {
185 RUN_HOOK: function (x) {
186 var hook_name = this.hook_name;
188 yield run_coroutine_hooks(x[hook_name], arguments);
189 yield run_coroutine_hooks(this, arguments);
191 RUN_HOOK_UNTIL_SUCCESS: function (x) {
192 var hook_name = this.hook_name;
193 if ((hook_name in x) &&
194 (yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
196 yield co_return(true);
198 var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
199 yield co_return(result);
201 RUN_HOOK_UNTIL_FAILURE: function (x) {
202 var hook_name = this.hook_name;
203 if ((hook_name in x) &&
204 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
206 yield co_return(false);
208 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
209 yield co_return(result);
212 return function (hook_name, hook_type, doc_string) {
213 initialize_hook(prototype[hook_type || RUN_HOOK],
214 hook_name, hook_type, doc_string,
219 function local_hook_definer (prop_name, extra_doc_string) {
221 RUN_HOOK: function (x) {
222 var hook_name = this.hook_name;
224 run_hooks(x[hook_name], arguments);
225 if (hook_name in x[prop_name])
226 run_hooks(x[prop_name][hook_name], arguments);
227 run_hooks(this, arguments);
229 RUN_HOOK_UNTIL_SUCCESS: function (x) {
230 var hook_name = this.hook_name;
231 if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments))
233 if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments))
235 return run_hooks_until_success(conkeror[hook_name], arguments);
237 RUN_HOOK_UNTIL_FAILURE: function (x) {
238 var hook_name = this.hook_name;
239 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
241 if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments))
243 return run_hooks_until_failure(conkeror[hook_name], arguments);
246 return function (hook_name, hook_type, doc_string) {
247 initialize_hook(prototype[hook_type || RUN_HOOK],
248 hook_name, hook_type, doc_string,
253 function local_coroutine_hook_definer (prop_name, extra_doc_string) {
255 RUN_HOOK: function (x) {
256 var hook_name = this.hook_name;
258 yield run_coroutine_hooks(x[hook_name], arguments);
259 if (hook_name in x[prop_name])
260 yield run_coroutine_hooks(x[prop_name][hook_name], arguments);
261 yield run_coroutine_hooks(this, arguments);
263 RUN_HOOK_UNTIL_SUCCESS: function (x) {
264 var hook_name = this.hook_name;
265 if ((hook_name in x) &&
266 (yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
268 yield co_return(true);
270 if ((hook_name in x[prop_name]) &&
271 (yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
273 yield co_return(true);
275 var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
276 yield co_return(result);
278 RUN_HOOK_UNTIL_FAILURE: function (x) {
279 var hook_name = this.hook_name;
280 if ((hook_name in x) &&
281 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
283 yield co_return(false);
285 if ((hook_name in x[prop_name]) &&
286 !(yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
288 yield co_return(false);
290 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
291 yield co_return(result);
294 return function (hook_name, hook_type, doc_string) {
295 initialize_hook(prototype[hook_type || RUN_HOOK],
296 hook_name, hook_type, doc_string,
301 function remove_hook (hook_name, func) {
302 var hook = this[hook_name];
304 if (hook && (index = hook.indexOf(func)) != -1)
305 hook.splice(index, 1);