issue139: C-h suffix for key combos
[conkeror/arlinius.git] / modules / hook.js
blob0488aed7ffafe0c75a47c9fbfba0e23a5be127b1
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) {
12     if (!(hook_name in this))
13         this[hook_name] = [];
14     var hook = this[hook_name];
16     if (avoid_duplicates && hook.indexOf(func) != -1)
17         return func;
19     if (prepend)
20         hook.unshift(func);
21     else
22         hook.push(func);
23     return func;
26 /**
27  * Call every function in the array `hook' with the remaining
28  * arguments of this function.  Note: This should only be used by
29  * define_hook and friends to define hook.run(...) functions.  Hooks
30  * should always be run by calling hook.run(...).
31  */
32 function run_hooks (hook, args) {
33     if (hook == null)
34         return;
35     for (let i = 0, hlen = hook.length; i < hlen; ++i)
36         hook[i].apply(null, Array.prototype.slice.call(args));
39 function run_hooks_until_success (hook, args) {
40     if (hook == null)
41         return false;
42     for (let i = 0, hlen = hook.length; i < hlen; ++i)
43         if (hook[i].apply(null, Array.prototype.slice.call(args)))
44             return true;
45     return false;
48 function run_hooks_until_failure (hook, args) {
49     if (hook == null)
50         return true;
51     for (let i = 0, hlen = hook.length; i < hlen; ++i)
52         if (!hook[i].apply(null, Array.prototype.slice.call(args)))
53             return false;
54     return true;
57 var hook_type_doc_strings = [
58     /* RUN_HOOK */
59     "Each hook function is run in sequence.",
61     /* RUN_HOOK_UNTIL_SUCCESS */
62     "Each hook function is run in sequence until one returns a "+
63         "logically true value.",
65     /* RUN_HOOK_UNTIL_FAILURE */
66     "Each hook function is run in sequence until one returns a "+
67         "logically false value.  If no function returns such a "+
68         "value, then the result of the hook will be `true'."];
71 /* This should only be used by define_hook functions */
72 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) {
116     initialize_hook(hook_global_prototype, hook_name, hook_type, doc_string);
119 var hook_simple_local_prototype = {
120     run: function (x) {
121         var hook_name = this.hook_name;
122         if (hook_name in x) run_hooks(x[hook_name], arguments);
123         run_hooks(this, arguments);
124     },
125     run_until_success: function (x) {
126         var hook_name = this.hook_name;
127         if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
128             return run_hooks_until_success(conkeror[hook_name], arguments);
129     },
130     run_until_failure: function (x) {
131         var hook_name = this.hook_name;
132         if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
133         return run_hooks_until_failure(conkeror[hook_name], arguments);
134     }
137 function simple_local_hook_definer (extra_doc_string) {
138     return function (hook_name, hook_type, doc_string) {
139         initialize_hook(hook_simple_local_prototype, hook_name, hook_type, doc_string, extra_doc_string);
140     };
143 /* This function is called with a variable number of string arguments
144  * in addition to the first, that specify the additional hook arrays
145  * to use.  As an example: local_hook_definer("buffer", "buffer", "buffer.window")
146  */
147 function local_hook_definer (prop_name, extra_doc_string) {
148     var prototype = {
149         run: function (x) {
150             var hook_name = this.hook_name;
151             if (hook_name in x) run_hooks(x[hook_name], arguments);
152             if (hook_name in x[prop_name]) run_hooks(x[prop_name][hook_name], arguments);
153             run_hooks(this, arguments);
154         },
155         run_until_success: function (x) {
156             var hook_name = this.hook_name;
157             if ((hook_name in x) && run_hooks_until_success(x[hook_name], arguments)) return true;
158             if ((hook_name in x[prop_name]) && run_hooks_until_success(x[prop_name][hook_name], arguments)) return true;
159             return run_hooks_until_success(conkeror[hook_name], arguments);
160         },
161         run_until_failure: function (x) {
162             var hook_name = this.hook_name;
163             if ((hook_name in x) && !run_hooks_until_success(x[hook_name], arguments)) return false;
164             if ((hook_name in x[prop_name]) && !run_hooks_until_success(x[prop_name][hook_name], arguments)) return false;
165             return run_hooks_until_failure(conkeror[hook_name], arguments);
166         }
167     };
168     return function (hook_name, hook_type, doc_string) {
169         initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string);
170     };
173 function remove_hook (hook_name, func) {
174     var hook = this[hook_name];
175     var index;
176     if (hook && (index = hook.indexOf(func)) != -1)
177         hook.splice(index, 1);