Add webjump integration with OpenSearch search engines
[conkeror.git] / modules / hook.js
blobe6a7c460e7f0fceb05d038d2c4484a720d995864
2 /* Adds the specified function to the specified hook.  To add a local
3  * hook, invoke this function as:  add_hook.call(context, hook_name, ...).  
4  * Note: hook_name must be a string */
5 function add_hook(hook_name, func, prepend, avoid_duplicates)
7     if (!this[hook_name])
8         this[hook_name] = [];
9     var hook = this[hook_name];
11     if (avoid_duplicates && hook.indexOf(func) != -1)
12         return func;
14     if (prepend)
15         hook.unshift(func);
16     else
17         hook.push(func);
18     return func;
21 /**
22  * Call every function in the array `hook' with the remaining
23  * arguments of this function.  Note: This should only be used by
24  * define_hook and friends to define hook.run(...) functions.  Hooks
25  * should always be run by calling hook.run(...).
26  */
27 function run_hooks(hook, args)
29     if (hook == null)
30         return;
31     for (let i = 0; i < hook.length; ++i)
32         hook[i].apply (null, Array.prototype.slice.call(args));
35 function run_hooks_until_success(hook, args)
37     if (hook == null)
38         return false;
39     for (let i = 0; i < hook.length; ++i)
40         if (hook[i].apply (null, Array.prototype.slice.call(args)))
41             return true;
42     return false;
45 function run_hooks_until_failure(hook, args)
47     if (hook == null)
48         return true;
49     for (let i = 0; i < hook.length; ++i)
50         if (!hook[i].apply (null, Array.prototype.slice.call(args)))
51             return false;
52     return true;
55 var hook_type_doc_strings = [
56     /* RUN_HOOK */
57     "Each hook function added is run in sequence.",
58     /* RUN_HOOK_UNTIL_SUCCESS */
59     "Only boolean-valued hook functions may be added.  Each hook function added is run in sequence until a value that conerts to true is returned.",
60     /* RUN_HOOK_UNTIL_FAILURE */
61     "Only boolean-valued hook functions may be added.  Each hook function added is run in sequence until a value that conerts to false is returned."];
64 /* This should only be used by define_hook functions */
65 function initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string)
67     var h = this[hook_name];
68     if (h == null)
69         h = this[hook_name] = [];
70     if (hook_type == null)
71         hook_type = RUN_HOOK;
72     switch (hook_type) {
73     case RUN_HOOK:
74         h.run = prototype.run;
75         break;
76     case RUN_HOOK_UNTIL_SUCCESS:
77         h.run = prototype.run_until_success;
78         break;
79     case RUN_HOOK_UNTIL_FAILURE:
80         h.run = prototype.run_until_failure;
81         break;
82     }
83     h.hook_type = hook_type;
84     h.hook_name = hook_name;
85     h.doc_string =
86         (doc_string? doc_string + "\n" : "") +
87         hook_type_doc_strings[hook_type] +
88         (extra_doc_string? "\n" + extra_doc_string : "");
89     h.source_code_reference = get_caller_source_code_reference(1);
90     return h;
93 var hook_global_prototype = {
94     run: function() {
95         run_hooks(this, arguments);
96     },
97     run_until_success: function() {
98         return run_hooks_until_success(this, arguments);
99     },
100     run_until_failure: function() {
101         return run_hooks_until_failure(this, arguments);
102     }
105 const RUN_HOOK = 0;
106 const RUN_HOOK_UNTIL_SUCCESS = 1;
107 const RUN_HOOK_UNTIL_FAILURE = 2;
109 function define_hook(hook_name, hook_type, doc_string)
111     initialize_hook(hook_global_prototype, hook_name, hook_type, doc_string);
114 var hook_simple_local_prototype = {
115     run: function(x) {
116         var hook_name = this.hook_name;
117         if (hook_name in x) run_hooks(x[hook_name], arguments);
118         run_hooks(this, arguments);
119     },
120     run_until_success: function (x) {
121         var hook_name = this.hook_name;
122         if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
123             return run_hooks_until_success(conkeror[hook_name], arguments);
124     },
125     run_until_failure: function (x) {
126         var hook_name = this.hook_name;
127         if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
128         return run_hooks_until_failure(conkeror[hook_name], arguments);
129     }
132 function simple_local_hook_definer(extra_doc_string) {
133     return function (hook_name, hook_type, doc_string) {
134         initialize_hook(hook_simple_local_prototype, hook_name, hook_type, doc_string, extra_doc_string);
135     }
138 /* This function is called with a variable number of string arguments
139  * in addition to the first, that specify the additional hook arrays
140  * to use.  As an example: local_hook_definer("buffer", "buffer", "buffer.window")
141  */
142 function local_hook_definer(prop_name, extra_doc_string) {
143     var prototype = {
144         run: function(x) {
145             var hook_name = this.hook_name;
146             if (hook_name in x) run_hooks(x[hook_name], arguments);
147             if (hook_name in x[prop_name]) run_hooks(x[prop_name][hook_name], arguments);
148             run_hooks(this, arguments);
149         },
150         run_until_success: function (x) {
151             var hook_name = this.hook_name;
152             if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
153             if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments)) return true;
154             return run_hooks_until_success(conkeror[hook_name], arguments);
155         },
156         run_until_failure: function (x) {
157             var hook_name = this.hook_name;
158             if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
159             if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments)) return false;
160             return run_hooks_until_failure(conkeror[hook_name], arguments);
161         }
162     };
163     return function (hook_name, hook_type, doc_string) {
164         initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string);
165     }
168 function remove_hook(hook_name, func)
170     var hook = this[hook_name];
171     var index;
172     if (hook && (index = hook.indexOf(func)) != -1)
173         hook.splice(index, 1);