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
9 require("coroutine.js");
11 /* Adds the specified function to the specified hook. To add a local
12 * hook, invoke this function as: add_hook.call(context, hook_name, ...).
13 * Note: hook_name must be a string */
14 function add_hook (hook_name, func, prepend) {
15 if (!(hook_name in this))
17 var hook = this[hook_name];
19 if (hook.indexOf(func) != -1)
30 * Call every function in the array `hook' with the remaining
31 * arguments of this function. Note: This should only be used by
32 * define_hook and friends to define hook.run(...) functions. Hooks
33 * should always be run by calling hook.run(...).
35 function run_hooks (hook, args) {
38 for (let i = 0, hlen = hook.length; i < hlen; ++i)
39 hook[i].apply(null, Array.prototype.slice.call(args));
42 function run_hooks_until_success (hook, args) {
46 for (let i = 0, hlen = hook.length; i < hlen; ++i)
47 if ((result = hook[i].apply(null, Array.prototype.slice.call(args))))
52 function run_hooks_until_failure (hook, args) {
55 for (let i = 0, hlen = hook.length; i < hlen; ++i)
56 if (!hook[i].apply(null, Array.prototype.slice.call(args)))
61 function run_coroutine_hooks (hook, args) {
64 for (let i = 0, hlen = hook.length; i < hlen; ++i)
65 yield hook[i].apply(null, Array.prototype.slice.call(args));
68 function run_coroutine_hooks_until_success (hook, args) {
70 yield co_return(false);
72 for (let i = 0, hlen = hook.length; i < hlen; ++i)
73 if ((result = yield hook[i].apply(null, Array.prototype.slice.call(args))))
74 yield co_return(result);
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. That value is returned.",
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;
166 if ((hook_name in x) && (result = run_hooks_until_success(x[hook_name], arguments)))
168 return run_hooks_until_success(conkeror[hook_name], arguments);
170 RUN_HOOK_UNTIL_FAILURE: function (x) {
171 var hook_name = this.hook_name;
172 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
174 return run_hooks_until_failure(conkeror[hook_name], arguments);
177 return function (hook_name, hook_type, doc_string) {
178 initialize_hook(prototype[hook_type || RUN_HOOK],
179 hook_name, hook_type, doc_string,
184 function simple_local_coroutine_hook_definer (extra_doc_string) {
186 RUN_HOOK: function (x) {
187 var hook_name = this.hook_name;
189 yield run_coroutine_hooks(x[hook_name], arguments);
190 yield run_coroutine_hooks(this, arguments);
192 RUN_HOOK_UNTIL_SUCCESS: function (x) {
193 var hook_name = this.hook_name;
195 if ((hook_name in x) &&
196 (result = yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
198 yield co_return(result);
200 result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
201 yield co_return(result);
203 RUN_HOOK_UNTIL_FAILURE: function (x) {
204 var hook_name = this.hook_name;
205 if ((hook_name in x) &&
206 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
208 yield co_return(false);
210 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
211 yield co_return(result);
214 return function (hook_name, hook_type, doc_string) {
215 initialize_hook(prototype[hook_type || RUN_HOOK],
216 hook_name, hook_type, doc_string,
221 function local_hook_definer (prop_name, extra_doc_string) {
223 RUN_HOOK: function (x) {
224 var hook_name = this.hook_name;
226 run_hooks(x[hook_name], arguments);
227 if (hook_name in x[prop_name])
228 run_hooks(x[prop_name][hook_name], arguments);
229 run_hooks(this, arguments);
231 RUN_HOOK_UNTIL_SUCCESS: function (x) {
232 var hook_name = this.hook_name;
234 if ((hook_name in x) && (result = run_hooks_until_success(x[hook_name], arguments)))
236 if ((hook_name in x[prop_name]) && (result = run_hooks_until_success(x[prop_name][hook_name], arguments)))
238 return run_hooks_until_success(conkeror[hook_name], arguments);
240 RUN_HOOK_UNTIL_FAILURE: function (x) {
241 var hook_name = this.hook_name;
242 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
244 if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments))
246 return run_hooks_until_failure(conkeror[hook_name], arguments);
249 return function (hook_name, hook_type, doc_string) {
250 initialize_hook(prototype[hook_type || RUN_HOOK],
251 hook_name, hook_type, doc_string,
256 function local_coroutine_hook_definer (prop_name, extra_doc_string) {
258 RUN_HOOK: function (x) {
259 var hook_name = this.hook_name;
261 yield run_coroutine_hooks(x[hook_name], arguments);
262 if (hook_name in x[prop_name])
263 yield run_coroutine_hooks(x[prop_name][hook_name], arguments);
264 yield run_coroutine_hooks(this, arguments);
266 RUN_HOOK_UNTIL_SUCCESS: function (x) {
267 var hook_name = this.hook_name;
269 if ((hook_name in x) &&
270 (result = yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
272 yield co_return(result);
274 if ((hook_name in x[prop_name]) &&
275 (result = yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
277 yield co_return(result);
279 result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
280 yield co_return(result);
282 RUN_HOOK_UNTIL_FAILURE: function (x) {
283 var hook_name = this.hook_name;
284 if ((hook_name in x) &&
285 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
287 yield co_return(false);
289 if ((hook_name in x[prop_name]) &&
290 !(yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
292 yield co_return(false);
294 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
295 yield co_return(result);
298 return function (hook_name, hook_type, doc_string) {
299 initialize_hook(prototype[hook_type || RUN_HOOK],
300 hook_name, hook_type, doc_string,
305 function remove_hook (hook_name, func) {
306 var hook = this[hook_name];
308 if (hook && (index = hook.indexOf(func)) != -1)
309 hook.splice(index, 1);