gmail-mode: let gmail handle the return key
[conkeror.git] / modules / hook.js
blob10271dc8332134d099401ab38fe520fcaa2abaad
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     for (let i = 0, hlen = hook.length; i < hlen; ++i)
48         if (hook[i].apply(null, Array.prototype.slice.call(args)))
49             return true;
50     return false;
53 function run_hooks_until_failure (hook, args) {
54     if (hook == null)
55         return true;
56     for (let i = 0, hlen = hook.length; i < hlen; ++i)
57         if (!hook[i].apply(null, Array.prototype.slice.call(args)))
58             return false;
59     return true;
62 function run_coroutine_hooks (hook, args) {
63     if (hook == null)
64         yield co_return();
65     for (let i = 0, hlen = hook.length; i < hlen; ++i)
66         yield hook[i].apply(null, Array.prototype.slice.call(args));
69 function run_coroutine_hooks_until_success (hook, args) {
70     if (hook == null)
71         yield co_return(false);
72     for (let i = 0, hlen = hook.length; i < hlen; ++i)
73         if ((yield hook[i].apply(null, Array.prototype.slice.call(args))))
74             yield co_return(true);
75     yield co_return(false);
78 function run_coroutine_hooks_until_failure (hook, args) {
79     if (hook == null)
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) {
95     var docstrings = {
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.",
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'."
104     };
105     var h = this[hook_name];
106     if (h == null)
107         h = this[hook_name] = [];
108     if (hook_type == null)
109         hook_type = RUN_HOOK;
110     h.run = run;
111     h.hook_type = hook_type;
112     h.hook_name = hook_name;
113     h.doc_string =
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);
118     return h;
121 function define_hook (hook_name, hook_type, doc_string) {
122     const prototype = {
123         RUN_HOOK: function () {
124             run_hooks(this, arguments);
125         },
126         RUN_HOOK_UNTIL_SUCCESS: function () {
127             return run_hooks_until_success(this, arguments);
128         },
129         RUN_HOOK_UNTIL_FAILURE: function () {
130             return run_hooks_until_failure(this, arguments);
131         }
132     };
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) {
138     const prototype = {
139         RUN_HOOK: function () {
140             yield run_coroutine_hooks(this, arguments);
141         },
142         RUN_HOOK_UNTIL_SUCCESS: function () {
143             var result = yield run_coroutine_hooks_until_success(this, arguments);
144             yield co_return(result);
145         },
146         RUN_HOOK_UNTIL_FAILURE: function () {
147             var result = yield run_coroutine_hooks_until_failure(this, arguments);
148             yield co_return(result);
149         }
150     };
151     initialize_hook(prototype[hook_type || RUN_HOOK],
152                     hook_name, hook_type, doc_string);
155 function simple_local_hook_definer (extra_doc_string) {
156     const prototype = {
157         RUN_HOOK: function (x) {
158             var hook_name = this.hook_name;
159             if (hook_name in x)
160                 run_hooks(x[hook_name], arguments);
161             run_hooks(this, arguments);
162         },
163         RUN_HOOK_UNTIL_SUCCESS: function (x) {
164             var hook_name = this.hook_name;
165             if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments))
166                 return true;
167             return run_hooks_until_success(conkeror[hook_name], arguments);
168         },
169         RUN_HOOK_UNTIL_FAILURE: function (x) {
170             var hook_name = this.hook_name;
171             if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
172                 return false;
173             return run_hooks_until_failure(conkeror[hook_name], arguments);
174         }
175     };
176     return function (hook_name, hook_type, doc_string) {
177         initialize_hook(prototype[hook_type || RUN_HOOK],
178                         hook_name, hook_type, doc_string,
179                         extra_doc_string);
180     };
183 function simple_local_coroutine_hook_definer (extra_doc_string) {
184     const prototype = {
185         RUN_HOOK: function (x) {
186             var hook_name = this.hook_name;
187             if (hook_name in x)
188                 yield run_coroutine_hooks(x[hook_name], arguments);
189             yield run_coroutine_hooks(this, arguments);
190         },
191         RUN_HOOK_UNTIL_SUCCESS: function (x) {
192             var hook_name = this.hook_name;
193             if ((hook_name in x) &&
194                 (yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
195             {
196                 yield co_return(true);
197             }
198             var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
199             yield co_return(result);
200         },
201         RUN_HOOK_UNTIL_FAILURE: function (x) {
202             var hook_name = this.hook_name;
203             if ((hook_name in x) &&
204                 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
205             {
206                 yield co_return(false);
207             }
208             var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
209             yield co_return(result);
210         }
211     };
212     return function (hook_name, hook_type, doc_string) {
213         initialize_hook(prototype[hook_type || RUN_HOOK],
214                         hook_name, hook_type, doc_string,
215                         extra_doc_string);
216     };
219 function local_hook_definer (prop_name, extra_doc_string) {
220     const prototype = {
221         RUN_HOOK: function (x) {
222             var hook_name = this.hook_name;
223             if (hook_name in x)
224                 run_hooks(x[hook_name], arguments);
225             if (hook_name in x[prop_name])
226                 run_hooks(x[prop_name][hook_name], arguments);
227             run_hooks(this, arguments);
228         },
229         RUN_HOOK_UNTIL_SUCCESS: function (x) {
230             var hook_name = this.hook_name;
231             if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments))
232                 return true;
233             if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments))
234                 return true;
235             return run_hooks_until_success(conkeror[hook_name], arguments);
236         },
237         RUN_HOOK_UNTIL_FAILURE: function (x) {
238             var hook_name = this.hook_name;
239             if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments))
240                 return false;
241             if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments))
242                 return false;
243             return run_hooks_until_failure(conkeror[hook_name], arguments);
244         }
245     };
246     return function (hook_name, hook_type, doc_string) {
247         initialize_hook(prototype[hook_type || RUN_HOOK],
248                         hook_name, hook_type, doc_string,
249                         extra_doc_string);
250     };
253 function local_coroutine_hook_definer (prop_name, extra_doc_string) {
254     const prototype = {
255         RUN_HOOK: function (x) {
256             var hook_name = this.hook_name;
257             if (hook_name in x)
258                 yield run_coroutine_hooks(x[hook_name], arguments);
259             if (hook_name in x[prop_name])
260                 yield run_coroutine_hooks(x[prop_name][hook_name], arguments);
261             yield run_coroutine_hooks(this, arguments);
262         },
263         RUN_HOOK_UNTIL_SUCCESS: function (x) {
264             var hook_name = this.hook_name;
265             if ((hook_name in x) &&
266                 (yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
267             {
268                 yield co_return(true);
269             }
270             if ((hook_name in x[prop_name]) &&
271                 (yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
272             {
273                 yield co_return(true);
274             }
275             var result = yield run_coroutine_hooks_until_success(conkeror[hook_name], arguments);
276             yield co_return(result);
277         },
278         RUN_HOOK_UNTIL_FAILURE: function (x) {
279             var hook_name = this.hook_name;
280             if ((hook_name in x) &&
281                 !(yield run_coroutine_hooks_until_success(x[hook_name], arguments)))
282             {
283                 yield co_return(false);
284             }
285             if ((hook_name in x[prop_name]) &&
286                 !(yield run_coroutine_hooks_until_success(x[prop_name][hook_name], arguments)))
287             {
288                 yield co_return(false);
289             }
290             var result = yield run_coroutine_hooks_until_failure(conkeror[hook_name], arguments);
291             yield co_return(result);
292         }
293     };
294     return function (hook_name, hook_type, doc_string) {
295         initialize_hook(prototype[hook_type || RUN_HOOK],
296                         hook_name, hook_type, doc_string,
297                         extra_doc_string);
298     };
301 function remove_hook (hook_name, func) {
302     var hook = this[hook_name];
303     var index;
304     if (hook && (index = hook.indexOf(func)) != -1)
305         hook.splice(index, 1);
308 provide("hook");