browser-next-form-field: skip non-visible elements
[conkeror.git] / modules / hook.js
blob1c0c6cb635e00733a55406e2866e19f76e83b30c
1 /**
2  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
3  *
4  * Use, modification, and distribution are subject to the terms specified in the
5  * COPYING file.
6 **/
8 /* Adds the specified function to the specified hook.  To add a local
9  * hook, invoke this function as:  add_hook.call(context, hook_name, ...).
10  * Note: hook_name must be a string */
11 function add_hook(hook_name, func, prepend, avoid_duplicates)
13     if (!this[hook_name])
14         this[hook_name] = [];
15     var hook = this[hook_name];
17     if (avoid_duplicates && hook.indexOf(func) != -1)
18         return func;
20     if (prepend)
21         hook.unshift(func);
22     else
23         hook.push(func);
24     return func;
27 /**
28  * Call every function in the array `hook' with the remaining
29  * arguments of this function.  Note: This should only be used by
30  * define_hook and friends to define hook.run(...) functions.  Hooks
31  * should always be run by calling hook.run(...).
32  */
33 function run_hooks(hook, args)
35     if (hook == null)
36         return;
37     for (let i = 0; i < hook.length; ++i)
38         hook[i].apply (null, Array.prototype.slice.call(args));
41 function run_hooks_until_success(hook, args)
43     if (hook == null)
44         return false;
45     for (let i = 0; i < hook.length; ++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)
53     if (hook == null)
54         return true;
55     for (let i = 0; i < hook.length; ++i)
56         if (!hook[i].apply (null, Array.prototype.slice.call(args)))
57             return false;
58     return true;
61 var hook_type_doc_strings = [
62     /* RUN_HOOK */
63     "Each hook function added is run in sequence.",
64     /* RUN_HOOK_UNTIL_SUCCESS */
65     "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.",
66     /* RUN_HOOK_UNTIL_FAILURE */
67     "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."];
70 /* This should only be used by define_hook functions */
71 function initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string)
73     var h = this[hook_name];
74     if (h == null)
75         h = this[hook_name] = [];
76     if (hook_type == null)
77         hook_type = RUN_HOOK;
78     switch (hook_type) {
79     case RUN_HOOK:
80         h.run = prototype.run;
81         break;
82     case RUN_HOOK_UNTIL_SUCCESS:
83         h.run = prototype.run_until_success;
84         break;
85     case RUN_HOOK_UNTIL_FAILURE:
86         h.run = prototype.run_until_failure;
87         break;
88     }
89     h.hook_type = hook_type;
90     h.hook_name = hook_name;
91     h.doc_string =
92         (doc_string? doc_string + "\n" : "") +
93         hook_type_doc_strings[hook_type] +
94         (extra_doc_string? "\n" + extra_doc_string : "");
95     h.source_code_reference = get_caller_source_code_reference(1);
96     return h;
99 var hook_global_prototype = {
100     run: function() {
101         run_hooks(this, arguments);
102     },
103     run_until_success: function() {
104         return run_hooks_until_success(this, arguments);
105     },
106     run_until_failure: function() {
107         return run_hooks_until_failure(this, arguments);
108     }
111 const RUN_HOOK = 0;
112 const RUN_HOOK_UNTIL_SUCCESS = 1;
113 const RUN_HOOK_UNTIL_FAILURE = 2;
115 function define_hook(hook_name, hook_type, doc_string)
117     initialize_hook(hook_global_prototype, hook_name, hook_type, doc_string);
120 var hook_simple_local_prototype = {
121     run: function(x) {
122         var hook_name = this.hook_name;
123         if (hook_name in x) run_hooks(x[hook_name], arguments);
124         run_hooks(this, arguments);
125     },
126     run_until_success: function (x) {
127         var hook_name = this.hook_name;
128         if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
129             return run_hooks_until_success(conkeror[hook_name], arguments);
130     },
131     run_until_failure: function (x) {
132         var hook_name = this.hook_name;
133         if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
134         return run_hooks_until_failure(conkeror[hook_name], arguments);
135     }
138 function simple_local_hook_definer(extra_doc_string) {
139     return function (hook_name, hook_type, doc_string) {
140         initialize_hook(hook_simple_local_prototype, hook_name, hook_type, doc_string, extra_doc_string);
141     };
144 /* This function is called with a variable number of string arguments
145  * in addition to the first, that specify the additional hook arrays
146  * to use.  As an example: local_hook_definer("buffer", "buffer", "buffer.window")
147  */
148 function local_hook_definer(prop_name, extra_doc_string) {
149     var prototype = {
150         run: function(x) {
151             var hook_name = this.hook_name;
152             if (hook_name in x) run_hooks(x[hook_name], arguments);
153             if (hook_name in x[prop_name]) run_hooks(x[prop_name][hook_name], arguments);
154             run_hooks(this, arguments);
155         },
156         run_until_success: function (x) {
157             var hook_name = this.hook_name;
158             if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
159             if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments)) return true;
160             return run_hooks_until_success(conkeror[hook_name], arguments);
161         },
162         run_until_failure: function (x) {
163             var hook_name = this.hook_name;
164             if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
165             if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments)) return false;
166             return run_hooks_until_failure(conkeror[hook_name], arguments);
167         }
168     };
169     return function (hook_name, hook_type, doc_string) {
170         initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string);
171     };
174 function remove_hook(hook_name, func)
176     var hook = this[hook_name];
177     var index;
178     if (hook && (index = hook.indexOf(func)) != -1)
179         hook.splice(index, 1);