2 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
4 * Use, modification, and distribution are subject to the terms specified in the
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))
14 var hook = this[hook_name];
16 if (avoid_duplicates && hook.indexOf(func) != -1)
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(...).
32 function run_hooks (hook, args) {
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) {
42 for (let i = 0, hlen = hook.length; i < hlen; ++i)
43 if (hook[i].apply(null, Array.prototype.slice.call(args)))
48 function run_hooks_until_failure (hook, args) {
51 for (let i = 0, hlen = hook.length; i < hlen; ++i)
52 if (!hook[i].apply(null, Array.prototype.slice.call(args)))
57 var hook_type_doc_strings = [
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];
75 h = this[hook_name] = [];
76 if (hook_type == null)
80 h.run = prototype.run;
82 case RUN_HOOK_UNTIL_SUCCESS:
83 h.run = prototype.run_until_success;
85 case RUN_HOOK_UNTIL_FAILURE:
86 h.run = prototype.run_until_failure;
89 h.hook_type = hook_type;
90 h.hook_name = hook_name;
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);
99 var hook_global_prototype = {
101 run_hooks(this, arguments);
103 run_until_success: function () {
104 return run_hooks_until_success(this, arguments);
106 run_until_failure: function () {
107 return run_hooks_until_failure(this, arguments);
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 = {
121 var hook_name = this.hook_name;
122 if (hook_name in x) run_hooks(x[hook_name], arguments);
123 run_hooks(this, arguments);
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);
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);
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);
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")
147 function local_hook_definer (prop_name, extra_doc_string) {
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);
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);
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);
168 return function (hook_name, hook_type, doc_string) {
169 initialize_hook(prototype, hook_name, hook_type, doc_string, extra_doc_string);
173 function remove_hook (hook_name, func) {
174 var hook = this[hook_name];
176 if (hook && (index = hook.indexOf(func)) != -1)
177 hook.splice(index, 1);