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, avoid_duplicates) {
15 if (!(hook_name in this))
17 var hook = this[hook_name];
19 if (avoid_duplicates && 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) {
45 for (let i = 0, hlen = hook.length; i < hlen; ++i)
46 if (hook[i].apply(null, Array.prototype.slice.call(args)))
51 function run_hooks_until_failure (hook, args) {
54 for (let i = 0, hlen = hook.length; i < hlen; ++i)
55 if (!hook[i].apply(null, Array.prototype.slice.call(args)))
60 function run_coroutine_hooks (hook, args) {
63 for (let i = 0, hlen = hook.length; i < hlen; ++i)
64 yield hook[i].apply(null, Array.prototype.slice.call(args));
67 function run_coroutine_hooks_until_success (hook, args) {
69 yield co_return(false);
70 for (let i = 0, hlen = hook.length; i < hlen; ++i)
71 if ((yield hook[i].apply(null, Array.prototype.slice.call(args))))
72 yield co_return(true);
73 yield co_return(false);
76 function run_coroutine_hooks_until_failure (hook, args) {
78 yield co_return(true);
79 for (let i = 0, hlen = hook.length; i < hlen; ++i)
80 if (!(yield hook[i].apply(null, Array.prototype.slice.call(args))))
81 yield co_return(false);
82 yield co_return(true);
86 const RUN_HOOK = 'RUN_HOOK';
87 const RUN_HOOK_UNTIL_SUCCESS = 'RUN_HOOK_UNTIL_SUCCESS';
88 const RUN_HOOK_UNTIL_FAILURE = 'RUN_HOOK_UNTIL_FAILURE';
91 /* This should only be used by define_hook functions */
92 function initialize_hook (run, hook_name, hook_type, doc_string, extra_doc_string) {
94 RUN_HOOK: "Each hook function is run in sequence.",
95 RUN_HOOK_UNTIL_SUCCESS:
96 "Each hook function is run in sequence until one returns a "+
97 "logically true value.",
98 RUN_HOOK_UNTIL_FAILURE:
99 "Each hook function is run in sequence until one returns a "+
100 "logically false value. If no function returns such a "+
101 "value, then the result of the hook will be `true'."
103 var h = this[hook_name];
105 h = this[hook_name] = [];
106 if (hook_type == null)
107 hook_type = RUN_HOOK;
109 h.hook_type = hook_type;
110 h.hook_name = hook_name;
112 (doc_string? doc_string + "\n" : "") +
113 docstrings[hook_type] +
114 (extra_doc_string? "\n" + extra_doc_string : "");
115 h.source_code_reference = get_caller_source_code_reference(1);
119 function define_hook (hook_name, hook_type, doc_string) {
121 RUN_HOOK: function () {
122 run_hooks(this, arguments);
124 RUN_HOOK_UNTIL_SUCCESS: function () {
125 return run_hooks_until_success(this, arguments);
127 RUN_HOOK_UNTIL_FAILURE: function () {
128 return run_hooks_until_failure(this, arguments);
131 initialize_hook(prototype[hook_type || RUN_HOOK],
132 hook_name, hook_type, doc_string);
135 function define_coroutine_hook (hook_name, hook_type, doc_string) {
137 RUN_HOOK: function () {
138 yield run_coroutine_hooks(this, arguments);
140 RUN_HOOK_UNTIL_SUCCESS: function () {
141 var result = yield run_coroutine_hooks_until_success(this, arguments);
142 yield co_return(result);
144 RUN_HOOK_UNTIL_FAILURE: function () {
145 var result = yield run_coroutine_hooks_until_failure(this, arguments);
146 yield co_return(result);
149 initialize_hook(prototype[hook_type || RUN_HOOK],
150 hook_name, hook_type, doc_string);
153 function simple_local_hook_definer (extra_doc_string) {
155 RUN_HOOK: function (x) {
156 var hook_name = this.hook_name;
158 run_hooks(x[hook_name], arguments);
159 run_hooks(this, arguments);
161 RUN_HOOK_UNTIL_SUCCESS: function (x) {
162 var hook_name = this.hook_name;
163 if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments))
165 return run_hooks_until_success(conkeror[hook_name], arguments);
167 RUN_HOOK_UNTIL_FAILURE: function (x) {
168 var hook_name = this.hook_name;
169 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
171 return run_hooks_until_failure(conkeror[hook_name], arguments);
174 return function (hook_name, hook_type, doc_string) {
175 initialize_hook(prototype[hook_type || RUN_HOOK],
176 hook_name, hook_type, doc_string,
181 function simple_local_coroutine_hook_definer (extra_doc_string) {
183 RUN_HOOK: function (x) {
184 var hook_name = this.hook_name;
186 yield run_coroutine_hooks(x[hook_name], arguments);
187 yield run_coroutine_hooks(this, arguments);
189 RUN_HOOK_UNTIL_SUCCESS: function (x) {
190 var hook_name = this.hook_name;
191 if ((hook_name in x) &&
192 (yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
194 yield co_return(true);
196 var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
197 yield co_return(result);
199 RUN_HOOK_UNTIL_FAILURE: function (x) {
200 var hook_name = this.hook_name;
201 if ((hook_name in x) &&
202 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
204 yield co_return(false);
206 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
207 yield co_return(result);
210 return function (hook_name, hook_type, doc_string) {
211 initialize_hook(prototype[hook_type || RUN_HOOK],
212 hook_name, hook_type, doc_string,
217 function local_hook_definer (prop_name, extra_doc_string) {
219 RUN_HOOK: function (x) {
220 var hook_name = this.hook_name;
222 run_hooks(x[hook_name], arguments);
223 if (hook_name in x[prop_name])
224 run_hooks(x[prop_name][hook_name], arguments);
225 run_hooks(this, arguments);
227 RUN_HOOK_UNTIL_SUCCESS: function (x) {
228 var hook_name = this.hook_name;
229 if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments))
231 if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments))
233 return run_hooks_until_success(conkeror[hook_name], arguments);
235 RUN_HOOK_UNTIL_FAILURE: function (x) {
236 var hook_name = this.hook_name;
237 if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
239 if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments))
241 return run_hooks_until_failure(conkeror[hook_name], arguments);
244 return function (hook_name, hook_type, doc_string) {
245 initialize_hook(prototype[hook_type || RUN_HOOK],
246 hook_name, hook_type, doc_string,
251 function local_coroutine_hook_definer (prop_name, extra_doc_string) {
253 RUN_HOOK: function (x) {
254 var hook_name = this.hook_name;
256 yield run_coroutine_hooks(x[hook_name], arguments);
257 if (hook_name in x[prop_name])
258 yield run_coroutine_hooks(x[prop_name][hook_name], arguments);
259 yield run_coroutine_hooks(this, arguments);
261 RUN_HOOK_UNTIL_SUCCESS: function (x) {
262 var hook_name = this.hook_name;
263 if ((hook_name in x) &&
264 (yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
266 yield co_return(true);
268 if ((hook_name in x[prop_name]) &&
269 (yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
271 yield co_return(true);
273 var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
274 yield co_return(result);
276 RUN_HOOK_UNTIL_FAILURE: function (x) {
277 var hook_name = this.hook_name;
278 if ((hook_name in x) &&
279 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
281 yield co_return(false);
283 if ((hook_name in x[prop_name]) &&
284 !(yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
286 yield co_return(false);
288 var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
289 yield co_return(result);
292 return function (hook_name, hook_type, doc_string) {
293 initialize_hook(prototype[hook_type || RUN_HOOK],
294 hook_name, hook_type, doc_string,
299 function remove_hook (hook_name, func) {
300 var hook = this[hook_name];
302 if (hook && (index = hook.indexOf(func)) != -1)
303 hook.splice(index, 1);