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) {
48 for (let i = 0, hlen = hook.length; i < hlen; ++i)
49 if ((result = hook[i].apply(null, Array.prototype.slice.call(args))))
54 function run_hooks_until_failure (hook, args) {
57 for (let i = 0, hlen = hook.length; i < hlen; ++i)
58 if (!hook[i].apply(null, Array.prototype.slice.call(args)))
63 function run_coroutine_hooks (hook, args) {
66 for (let i = 0, hlen = hook.length; i < hlen; ++i)
67 yield hook[i].apply(null, Array.prototype.slice.call(args));
70 function run_coroutine_hooks_until_success (hook, args) {
72 yield co_return(false);
74 for (let i = 0, hlen = hook.length; i < hlen; ++i)
75 if ((result = yield hook[i].apply(null, Array.prototype.slice.call(args))))
76 yield co_return(result);
77 yield co_return(false);
80 function run_coroutine_hooks_until_failure (hook, args) {
82 yield co_return(true);
83 for (let i = 0, hlen = hook.length; i < hlen; ++i)
84 if (!(yield hook[i].apply(null, Array.prototype.slice.call(args))))
85 yield co_return(false);
86 yield co_return(true);
90 const RUN_HOOK = 'RUN_HOOK';
91 const RUN_HOOK_UNTIL_SUCCESS = 'RUN_HOOK_UNTIL_SUCCESS';
92 const RUN_HOOK_UNTIL_FAILURE = 'RUN_HOOK_UNTIL_FAILURE';
95 /* This should only be used by define_hook functions */
96 function initialize_hook (run, hook_name, hook_type, doc_string, extra_doc_string) {
98 RUN_HOOK: "Each hook function is run in sequence.",
99 RUN_HOOK_UNTIL_SUCCESS:
100 "Each hook function is run in sequence until one returns a "+
101 "logically true value. That value is returned.",
102 RUN_HOOK_UNTIL_FAILURE:
103 "Each hook function is run in sequence until one returns a "+
104 "logically false value. If no function returns such a "+
105 "value, then the result of the hook will be `true'."
107 var h = this[hook_name];
109 h = this[hook_name] = [];
110 if (hook_type == null)
111 hook_type = RUN_HOOK;
113 h.hook_type = hook_type;
114 h.hook_name = hook_name;
116 (doc_string? doc_string + "\n" : "") +
117 docstrings[hook_type] +
118 (extra_doc_string? "\n" + extra_doc_string : "");
119 h.source_code_reference = get_caller_source_code_reference(1);
123 function define_hook (hook_name, hook_type, doc_string) {
125 RUN_HOOK: function () {
126 run_hooks(this, arguments);
128 RUN_HOOK_UNTIL_SUCCESS: function () {
129 return run_hooks_until_success(this, arguments);
131 RUN_HOOK_UNTIL_FAILURE: function () {
132 return run_hooks_until_failure(this, arguments);
135 initialize_hook(prototype[hook_type || RUN_HOOK],
136 hook_name, hook_type, doc_string);
139 function define_coroutine_hook (hook_name, hook_type, doc_string) {
141 RUN_HOOK: function () {
142 yield run_coroutine_hooks(this, arguments);
144 RUN_HOOK_UNTIL_SUCCESS: function () {
145 var result = yield run_coroutine_hooks_until_success(this, arguments);
146 yield co_return(result);
148 RUN_HOOK_UNTIL_FAILURE: function () {
149 var result = yield run_coroutine_hooks_until_failure(this, arguments);
150 yield co_return(result);
153 initialize_hook(prototype[hook_type || RUN_HOOK],
154 hook_name, hook_type, doc_string);
157 function simple_local_hook_definer (extra_doc_string) {
159 RUN_HOOK: function (x) {
160 var hook_name = this.hook_name;
162 run_hooks(x[hook_name], arguments);
163 run_hooks(this, arguments);
165 RUN_HOOK_UNTIL_SUCCESS: function (x) {
166 var hook_name = this.hook_name;
168 if ((hook_name in x) && (result = run_hooks_until_success(x[hook_name], arguments)))
170 return run_hooks_until_success(conkeror[hook_name], arguments);
172 RUN_HOOK_UNTIL_FAILURE: function (x) {
173 var hook_name = this.hook_name;
174 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
176 return run_hooks_until_failure(conkeror[hook_name], arguments);
179 return function (hook_name, hook_type, doc_string) {
180 initialize_hook(prototype[hook_type || RUN_HOOK],
181 hook_name, hook_type, doc_string,
186 function simple_local_coroutine_hook_definer (extra_doc_string) {
188 RUN_HOOK: function (x) {
189 var hook_name = this.hook_name;
191 yield run_coroutine_hooks(x[hook_name], arguments);
192 yield run_coroutine_hooks(this, arguments);
194 RUN_HOOK_UNTIL_SUCCESS: function (x) {
195 var hook_name = this.hook_name;
197 if ((hook_name in x) &&
198 (result = yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
200 yield co_return(result);
202 result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
203 yield co_return(result);
205 RUN_HOOK_UNTIL_FAILURE: function (x) {
206 var hook_name = this.hook_name;
207 if ((hook_name in x) &&
208 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
210 yield co_return(false);
212 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
213 yield co_return(result);
216 return function (hook_name, hook_type, doc_string) {
217 initialize_hook(prototype[hook_type || RUN_HOOK],
218 hook_name, hook_type, doc_string,
223 function local_hook_definer (prop_name, extra_doc_string) {
225 RUN_HOOK: function (x) {
226 var hook_name = this.hook_name;
228 run_hooks(x[hook_name], arguments);
229 if (hook_name in x[prop_name])
230 run_hooks(x[prop_name][hook_name], arguments);
231 run_hooks(this, arguments);
233 RUN_HOOK_UNTIL_SUCCESS: function (x) {
234 var hook_name = this.hook_name;
236 if ((hook_name in x) && (result = run_hooks_until_success(x[hook_name], arguments)))
238 if ((hook_name in x[prop_name]) && (result = run_hooks_until_success(x[prop_name][hook_name], arguments)))
240 return run_hooks_until_success(conkeror[hook_name], arguments);
242 RUN_HOOK_UNTIL_FAILURE: function (x) {
243 var hook_name = this.hook_name;
244 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
246 if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments))
248 return run_hooks_until_failure(conkeror[hook_name], arguments);
251 return function (hook_name, hook_type, doc_string) {
252 initialize_hook(prototype[hook_type || RUN_HOOK],
253 hook_name, hook_type, doc_string,
258 function local_coroutine_hook_definer (prop_name, extra_doc_string) {
260 RUN_HOOK: function (x) {
261 var hook_name = this.hook_name;
263 yield run_coroutine_hooks(x[hook_name], arguments);
264 if (hook_name in x[prop_name])
265 yield run_coroutine_hooks(x[prop_name][hook_name], arguments);
266 yield run_coroutine_hooks(this, arguments);
268 RUN_HOOK_UNTIL_SUCCESS: function (x) {
269 var hook_name = this.hook_name;
271 if ((hook_name in x) &&
272 (result = yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
274 yield co_return(result);
276 if ((hook_name in x[prop_name]) &&
277 (result = yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
279 yield co_return(result);
281 result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
282 yield co_return(result);
284 RUN_HOOK_UNTIL_FAILURE: function (x) {
285 var hook_name = this.hook_name;
286 if ((hook_name in x) &&
287 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
289 yield co_return(false);
291 if ((hook_name in x[prop_name]) &&
292 !(yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
294 yield co_return(false);
296 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
297 yield co_return(result);
300 return function (hook_name, hook_type, doc_string) {
301 initialize_hook(prototype[hook_type || RUN_HOOK],
302 hook_name, hook_type, doc_string,
307 function remove_hook (hook_name, func) {
308 var hook = this[hook_name];
310 if (hook && (index = hook.indexOf(func)) != -1)
311 hook.splice(index, 1);