whitespace
[conkeror.git] / modules / hook.js
blob4928bdacc3aa3e9d7cd5647ff2d3a88d21f7afad
1 /**
2  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
3  * (C) Copyright 2010 John J. Foerch
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
9 in_module(null);
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))
18         this[hook_name] = [];
19     var hook = this[hook_name];
21     if (hook.indexOf(func) != -1)
22         return func;
24     if (prepend)
25         hook.unshift(func);
26     else
27         hook.push(func);
28     return func;
31 /**
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(...).
36  */
37 function run_hooks (hook, args) {
38     if (hook == null)
39         return;
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) {
45     if (hook == null)
46         return false;
47     var result;
48     for (let i = 0, hlen = hook.length; i < hlen; ++i)
49         if ((result = hook[i].apply(null, Array.prototype.slice.call(args))))
50             return result;
51     return false;
54 function run_hooks_until_failure (hook, args) {
55     if (hook == null)
56         return true;
57     for (let i = 0, hlen = hook.length; i < hlen; ++i)
58         if (!hook[i].apply(null, Array.prototype.slice.call(args)))
59             return false;
60     return true;
63 function run_coroutine_hooks (hook, args) {
64     if (hook == null)
65         yield co_return();
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) {
71     if (hook == null)
72         yield co_return(false);
73     var result;
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) {
81     if (hook == null)
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) {
97     var docstrings = {
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'."
106     };
107     var h = this[hook_name];
108     if (h == null)
109         h = this[hook_name] = [];
110     if (hook_type == null)
111         hook_type = RUN_HOOK;
112     h.run = run;
113     h.hook_type = hook_type;
114     h.hook_name = hook_name;
115     h.doc_string =
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);
120     return h;
123 function define_hook (hook_name, hook_type, doc_string) {
124     const prototype = {
125         RUN_HOOK: function () {
126             run_hooks(this, arguments);
127         },
128         RUN_HOOK_UNTIL_SUCCESS: function () {
129             return run_hooks_until_success(this, arguments);
130         },
131         RUN_HOOK_UNTIL_FAILURE: function () {
132             return run_hooks_until_failure(this, arguments);
133         }
134     };
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) {
140     const prototype = {
141         RUN_HOOK: function () {
142             yield run_coroutine_hooks(this, arguments);
143         },
144         RUN_HOOK_UNTIL_SUCCESS: function () {
145             var result = yield run_coroutine_hooks_until_success(this, arguments);
146             yield co_return(result);
147         },
148         RUN_HOOK_UNTIL_FAILURE: function () {
149             var result = yield run_coroutine_hooks_until_failure(this, arguments);
150             yield co_return(result);
151         }
152     };
153     initialize_hook(prototype[hook_type || RUN_HOOK],
154                     hook_name, hook_type, doc_string);
157 function simple_local_hook_definer (extra_doc_string) {
158     const prototype = {
159         RUN_HOOK: function (x) {
160             var hook_name = this.hook_name;
161             if (hook_name in x)
162                 run_hooks(x[hook_name], arguments);
163             run_hooks(this, arguments);
164         },
165         RUN_HOOK_UNTIL_SUCCESS: function (x) {
166             var hook_name = this.hook_name;
167             var result;
168             if ((hook_name in x) && (result = run_hooks_until_success(x[hook_name], arguments)))
169                 return result;
170             return run_hooks_until_success(conkeror[hook_name], arguments);
171         },
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))
175                 return false;
176             return run_hooks_until_failure(conkeror[hook_name], arguments);
177         }
178     };
179     return function (hook_name, hook_type, doc_string) {
180         initialize_hook(prototype[hook_type || RUN_HOOK],
181                         hook_name, hook_type, doc_string,
182                         extra_doc_string);
183     };
186 function simple_local_coroutine_hook_definer (extra_doc_string) {
187     const prototype = {
188         RUN_HOOK: function (x) {
189             var hook_name = this.hook_name;
190             if (hook_name in x)
191                 yield run_coroutine_hooks(x[hook_name], arguments);
192             yield run_coroutine_hooks(this, arguments);
193         },
194         RUN_HOOK_UNTIL_SUCCESS: function (x) {
195             var hook_name = this.hook_name;
196             var result;
197             if ((hook_name in x) &&
198                 (result = yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
199             {
200                 yield co_return(result);
201             }
202             result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
203             yield co_return(result);
204         },
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)))
209             {
210                 yield co_return(false);
211             }
212             var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
213             yield co_return(result);
214         }
215     };
216     return function (hook_name, hook_type, doc_string) {
217         initialize_hook(prototype[hook_type || RUN_HOOK],
218                         hook_name, hook_type, doc_string,
219                         extra_doc_string);
220     };
223 function local_hook_definer (prop_name, extra_doc_string) {
224     const prototype = {
225         RUN_HOOK: function (x) {
226             var hook_name = this.hook_name;
227             if (hook_name in x)
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);
232         },
233         RUN_HOOK_UNTIL_SUCCESS: function (x) {
234             var hook_name = this.hook_name;
235             var result;
236             if ((hook_name in x) && (result = run_hooks_until_success(x[hook_name], arguments)))
237                 return result;
238             if ((hook_name in x[prop_name]) && (result = run_hooks_until_success(x[prop_name][hook_name], arguments)))
239                 return result;
240             return run_hooks_until_success(conkeror[hook_name], arguments);
241         },
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))
245                 return false;
246             if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments))
247                 return false;
248             return run_hooks_until_failure(conkeror[hook_name], arguments);
249         }
250     };
251     return function (hook_name, hook_type, doc_string) {
252         initialize_hook(prototype[hook_type || RUN_HOOK],
253                         hook_name, hook_type, doc_string,
254                         extra_doc_string);
255     };
258 function local_coroutine_hook_definer (prop_name, extra_doc_string) {
259     const prototype = {
260         RUN_HOOK: function (x) {
261             var hook_name = this.hook_name;
262             if (hook_name in x)
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);
267         },
268         RUN_HOOK_UNTIL_SUCCESS: function (x) {
269             var hook_name = this.hook_name;
270             var result;
271             if ((hook_name in x) &&
272                 (result = yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
273             {
274                 yield co_return(result);
275             }
276             if ((hook_name in x[prop_name]) &&
277                 (result = yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
278             {
279                 yield co_return(result);
280             }
281             result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
282             yield co_return(result);
283         },
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)))
288             {
289                 yield co_return(false);
290             }
291             if ((hook_name in x[prop_name]) &&
292                 !(yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
293             {
294                 yield co_return(false);
295             }
296             var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
297             yield co_return(result);
298         }
299     };
300     return function (hook_name, hook_type, doc_string) {
301         initialize_hook(prototype[hook_type || RUN_HOOK],
302                         hook_name, hook_type, doc_string,
303                         extra_doc_string);
304     };
307 function remove_hook (hook_name, func) {
308     var hook = this[hook_name];
309     var index;
310     if (hook && (index = hook.indexOf(func)) != -1)
311         hook.splice(index, 1);
314 provide("hook");