.deb nightly builds: Make contact e-mail address configurable
[conkeror.git] / modules / hook.js
blobe3669f3201f3872534f3c95ae5b924d1b9c3ca96
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 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))
16         this[hook_name] = [];
17     var hook = this[hook_name];
19     if (avoid_duplicates && hook.indexOf(func) != -1)
20         return func;
22     if (prepend)
23         hook.unshift(func);
24     else
25         hook.push(func);
26     return func;
29 /**
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(...).
34  */
35 function run_hooks (hook, args) {
36     if (hook == null)
37         return;
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) {
43     if (hook == null)
44         return false;
45     for (let i = 0, hlen = hook.length; i < hlen; ++i)
46         if (hook[i].apply(null, Array.prototype.slice.call(args)))
47             return true;
48     return false;
51 function run_hooks_until_failure (hook, args) {
52     if (hook == null)
53         return true;
54     for (let i = 0, hlen = hook.length; i < hlen; ++i)
55         if (!hook[i].apply(null, Array.prototype.slice.call(args)))
56             return false;
57     return true;
60 function run_coroutine_hooks (hook, args) {
61     if (hook == null)
62         yield co_return();
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) {
68     if (hook == null)
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) {
77     if (hook == null)
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) {
93     var docstrings = {
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'."
102     };
103     var h = this[hook_name];
104     if (h == null)
105         h = this[hook_name] = [];
106     if (hook_type == null)
107         hook_type = RUN_HOOK;
108     h.run = run;
109     h.hook_type = hook_type;
110     h.hook_name = hook_name;
111     h.doc_string =
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);
116     return h;
119 function define_hook (hook_name, hook_type, doc_string) {
120     const prototype = {
121         RUN_HOOK: function () {
122             run_hooks(this, arguments);
123         },
124         RUN_HOOK_UNTIL_SUCCESS: function () {
125             return run_hooks_until_success(this, arguments);
126         },
127         RUN_HOOK_UNTIL_FAILURE: function () {
128             return run_hooks_until_failure(this, arguments);
129         }
130     };
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) {
136     const prototype = {
137         RUN_HOOK: function () {
138             yield run_coroutine_hooks(this, arguments);
139         },
140         RUN_HOOK_UNTIL_SUCCESS: function () {
141             var result = yield run_coroutine_hooks_until_success(this, arguments);
142             yield co_return(result);
143         },
144         RUN_HOOK_UNTIL_FAILURE: function () {
145             var result = yield run_coroutine_hooks_until_failure(this, arguments);
146             yield co_return(result);
147         }
148     };
149     initialize_hook(prototype[hook_type || RUN_HOOK],
150                     hook_name, hook_type, doc_string);
153 function simple_local_hook_definer (extra_doc_string) {
154     const prototype = {
155         RUN_HOOK: function (x) {
156             var hook_name = this.hook_name;
157             if (hook_name in x)
158                 run_hooks(x[hook_name], arguments);
159             run_hooks(this, arguments);
160         },
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))
164                 return true;
165             return run_hooks_until_success(conkeror[hook_name], arguments);
166         },
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))
170                 return false;
171             return run_hooks_until_failure(conkeror[hook_name], arguments);
172         }
173     };
174     return function (hook_name, hook_type, doc_string) {
175         initialize_hook(prototype[hook_type || RUN_HOOK],
176                         hook_name, hook_type, doc_string,
177                         extra_doc_string);
178     };
181 function simple_local_coroutine_hook_definer (extra_doc_string) {
182     const prototype = {
183         RUN_HOOK: function (x) {
184             var hook_name = this.hook_name;
185             if (hook_name in x)
186                 yield run_coroutine_hooks(x[hook_name], arguments);
187             yield run_coroutine_hooks(this, arguments);
188         },
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)))
193             {
194                 yield co_return(true);
195             }
196             var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
197             yield co_return(result);
198         },
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)))
203             {
204                 yield co_return(false);
205             }
206             var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
207             yield co_return(result);
208         }
209     };
210     return function (hook_name, hook_type, doc_string) {
211         initialize_hook(prototype[hook_type || RUN_HOOK],
212                         hook_name, hook_type, doc_string,
213                         extra_doc_string);
214     };
217 function local_hook_definer (prop_name, extra_doc_string) {
218     const prototype = {
219         RUN_HOOK: function (x) {
220             var hook_name = this.hook_name;
221             if (hook_name in x)
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);
226         },
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))
230                 return true;
231             if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments))
232                 return true;
233             return run_hooks_until_success(conkeror[hook_name], arguments);
234         },
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))
238                 return false;
239             if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments))
240                 return false;
241             return run_hooks_until_failure(conkeror[hook_name], arguments);
242         }
243     };
244     return function (hook_name, hook_type, doc_string) {
245         initialize_hook(prototype[hook_type || RUN_HOOK],
246                         hook_name, hook_type, doc_string,
247                         extra_doc_string);
248     };
251 function local_coroutine_hook_definer (prop_name, extra_doc_string) {
252     const prototype = {
253         RUN_HOOK: function (x) {
254             var hook_name = this.hook_name;
255             if (hook_name in x)
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);
260         },
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)))
265             {
266                 yield co_return(true);
267             }
268             if ((hook_name in x[prop_name]) &&
269                 (yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
270             {
271                 yield co_return(true);
272             }
273             var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
274             yield co_return(result);
275         },
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)))
280             {
281                 yield co_return(false);
282             }
283             if ((hook_name in x[prop_name]) &&
284                 !(yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
285             {
286                 yield co_return(false);
287             }
288             var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
289             yield co_return(result);
290         }
291     };
292     return function (hook_name, hook_type, doc_string) {
293         initialize_hook(prototype[hook_type || RUN_HOOK],
294                         hook_name, hook_type, doc_string,
295                         extra_doc_string);
296     };
299 function remove_hook (hook_name, func) {
300     var hook = this[hook_name];
301     var index;
302     if (hook && (index = hook.indexOf(func)) != -1)
303         hook.splice(index, 1);