3 var interactive_methods = {
4 a: { func: function (spec) {
5 // -- Function name: symbol with a function definition.
10 active_document: { func: function (spec) {
11 // -- The document currently being browsed.
12 return this.window.content.document;
16 // b: existing buffer.
17 b: { async: function (spec, iargs, callback, callback_args, given_args) {
19 var existing_names = new Object();
20 this.buffers.for_each(function(b) {
21 var base_name = b.name;
24 while (existing_names["i_" + name])
27 name = base_name + "<" + index + ">";
29 existing_names["i_" + name] = true;
32 var prompt = (1 in spec && spec[1] ? spec[1].call (this, callback_args) : "Buffer: ");
33 var initval = (2 in spec && spec[2] ?
34 spec[2].call (this, callback_args) : this.buffers.current.name);
36 this.minibuffer.read({prompt: prompt, initial_value: initval, history: "buffer",
38 callback: function (s) {
39 callback_args.push (s);
40 do_interactive.call (frame, iargs, callback, callback_args, given_args);
43 doc: "Name of existing buffer, defaulting to the current one.\n"+
44 "Its optional arguments are:\n"+
45 "PROMPT A string prompt for the minibuffer read. The default is 'Buffer: '.\n"+
46 "INITVAL A function to get the initial value. The default is the current URL."
49 // XXX: does it make sense to have an interactive method for non-existent buffers?
50 B: { func: function (spec) {
51 // -- Name of buffer, possibly nonexistent.
56 c: { func: function (spec) {
62 C: { func: function (spec) {
63 // -- Command name: symbol with interactive function definition.
68 content_charset: { func: function (spec) {
69 // -- Charset of content area of focusedWindow
70 var focusedWindow = this.document.commandDispatcher.focusedWindow;
71 if (focusedWindow == this.window)
72 focusedWindow = this.content;
74 return this.document.commandDispatcher.focusedWindow.document.characterSet;
80 content_selection: { func: function (spec) {
81 // -- Selection of content area of focusedWindow
82 var focusedWindow = this.document.commandDispatcher.focusedWindow;
83 if (focusedWindow == this.window)
84 focusedWindow = this.content;
85 return focusedWindow.getSelection ();
89 current_buffer_window: { func: function (spec) {
94 current_command: { func: function (spec) {
95 // -- Name of the command being evaluated right now.
96 return conkeror.current_command;
100 current_frame: { func: function (spec) {
101 // -- Frame of the current command.
106 current_frameset_frame: { func: function (spec) {
107 var w = this.document.commandDispatcher.focusedWindow;
108 if (w.top != this.content)
114 current_frameset_frame_url: { func: function (spec) {
115 var w = this.document.commandDispatcher.focusedWindow;
116 if (w.top != this.content)
118 return w.location.href;
122 current_url: { func: function (spec) {
123 return this.getWebNavigation().currentURI.spec;
127 d: { func: function (spec) {
128 // -- Value of point as number. Does not do I/O.
133 D: { func: function (spec) {
134 // -- Directory name.
139 // e: Event that invoked this command.
140 e: { func: function (spec) { return this.keyboard_state.last_command_event; } },
142 f: { async: function (spec, iargs, callback, callback_args, given_args) {
143 // -- Exisiting file object. (nsILocalFile)
144 var prompt = (1 in spec && spec[1] ? spec[1].call (this, callback_args) : "File: ");
145 var initval = (2 in spec && spec[2] ? spec[2].call (this, callback_args) : default_directory.path);
146 var hist = (3 in spec ? spec[3] : null);
148 this.minibuffer.read({
150 initial_value: initval,
152 callback: function (s) {
153 var f = Components.classes["@mozilla.org/file/local;1"]
154 .createInstance(Components.interfaces.nsILocalFile);
156 callback_args.push (f);
157 do_interactive.call (frame, iargs, callback, callback_args, given_args);
162 F: { async: function (spec, iargs, callback, callback_args, given_args) {
163 // -- Possibly nonexistent file object. (nsILocalFile)
164 var prompt = (1 in spec && spec[1] ? spec[1].call (this, callback_args) : "File: ");
165 var initval = (2 in spec && spec[2] ? spec[2].call (this, callback_args) : default_directory.path);
166 var hist = (3 in spec ? spec[3] : null);
168 this.minibuffer.read({
170 initial_value: initval,
172 callback: function (s) {
173 var f = Components.classes["@mozilla.org/file/local;1"]
174 .createInstance(Components.interfaces.nsILocalFile);
176 callback_args.push (f);
177 do_interactive.call (frame, iargs, callback, callback_args, given_args);
182 focused_link_url: { func: function (spec) {
183 // -- Focused link element
184 ///JJF: check for errors or wrong element type.
185 return get_link_location (this.document.commandDispatcher.focusedElement);
190 // i: Ignored, i.e. always nil. Does not do I/O.
191 i: { func: function (spec) { return null; } },
193 // image: numbered image.
194 image: { async: function (spec, iargs, callback, callback_args, given_args) {
195 // -- Number read using minibuffer.
196 var prompt = (1 in spec ? spec[1].call (this, callback_args) : "Image Number: ");
197 var buf_state = this.getBrowser().numberedImages;
199 // turn on image numbers
200 gTurnOffLinksAfter = true;
201 this.toggleNumberedImages();
204 // Setup a context for the context-keymap system.
205 this.readFromMiniBuffer (prompt, null, null, null, null, null,
207 callback_args.push (s);
208 if (gTurnOffLinksAfter) {
209 toggleNumberedImages();
210 gTurnOffLinksAfter = false;
212 do_interactive.call (frame, iargs, callback, callback_args, given_args);
215 if (this.gTurnOffLinksAfter) {
216 this.toggleNumberedImages ();
217 this.gTurnOffLinksAfter = false;
224 image_url: { async: function (spec, iargs, callback, callback_args, given_args) {
226 var prompt = (1 in spec ? spec[1].call (this, callback_args) : "Image Number: ");
227 var buf_state = this.getBrowser().numberedImages;
229 // turn on image numbers
230 this.gTurnOffLinksAfter = true;
231 this.toggleNumberedImages();
234 // Setup a context for the context-keymap system.
235 this.readFromMiniBuffer (prompt, null, null, null, null, null,
237 function fail (number)
239 this.message ("'"+number+"' is not the number of any image here. ");
241 var nl = this.get_numberedlink (s);
242 if (! nl) { this.fail (s); return; }
243 var type = nl.nlnode.getAttribute("__conktype");
245 if (type == "image" && nl.node.getAttribute("src")) {
246 loc = nl.node.getAttribute("src");
247 loc = makeURLAbsolute (nl.node.baseURI, loc);
251 callback_args.push (loc);
253 if (this.gTurnOffLinksAfter) {
254 this.toggleNumberedImages();
255 this.gTurnOffLinksAfter = false;
257 do_interactive.call (frame, iargs, callback, callback_args, given_args);
260 if (this.gTurnOffLinksAfter) {
261 this.toggleNumberedImages ();
262 this.gTurnOffLinksAfter = false;
269 k: { func: function (spec) {
270 // -- Key sequence (downcase the last event if needed to get a definition).
275 K: { func: function (spec) {
276 // -- Key sequence to be redefined (do not downcase the last event).
281 // link: numbered link
282 link: { async: function (spec, iargs, callback, callback_args, given_args) {
283 var prompt = (1 in spec && spec[1] ? spec[1].call (this, callback_args) : "Link Number: ");
284 var initVal = (2 in spec && spec[2] ? spec[2].call (this, callback_args) : "");
285 /* FIXME: numbered link toggling is not yet working */
287 var buf_state = this.getBrowser().numberedLinks;
289 this.gTurnOffLinksAfter = true;
290 toggleNumberedLinks();
292 // Setup a context for the context-keymap system.
293 this.numberedlinks_minibuffer_active = true;
295 this.minibuffer.read ({prompt: prompt, initial_value: initVal,
296 callback: function (s) {
297 callback_args.push (s);
298 /* FIXME: numbered link toggling not yet working
299 if (this.gTurnOffLinksAfter) {
300 this.toggleNumberedLinks();
301 this.gTurnOffLinksAfter = false;
303 // unset keymap context
304 this.numberedlinks_minibuffer_active = false;
305 do_interactive.call (frame, iargs, callback, callback_args, given_args);
309 /* FIXME: numbered link toggling not yet working */
311 if (this.gTurnOffLinksAfter) {
312 this.toggleNumberedLinks ();
313 this.gTurnOffLinksAfter = false;
316 // unset keymap context
317 this.numberedlinks_minibuffer_active = false;
322 m: { func: function (spec) {
323 // -- Value of mark as number. Does not do I/O.
328 mathml_node: { async: function (spec, iargs, callback, callback_args, given_args) {
329 // -- DOM node of a MathML
330 //TO-DO: implement mathml_node interactive spec.
331 callback_args.push (null);
332 do_interactive.call (this, iargs, callback, callback_args, given_args);
336 minibuffer_exit: { func: function (spec) {
337 // -- minibuffer.exit
338 return this.minibuffer.exit;
342 // n: Number read using minibuffer.
343 n: { async: function (spec, iargs, callback, callback_args, given_args) {
344 var prompt = "Number: ";
350 callback: function (s) {
351 callback_args.push (s);
352 do_interactive.call (frame, iargs, callback, callback_args, given_args);
358 N: { func: function (spec) {
359 // -- Raw prefix arg, or if none, do like code `n'.
364 // p: Prefix arg converted to number. Does not do I/O.
365 p: { func: function (spec) {
366 return univ_arg_to_number(this.gPrefixArg);
370 // P: Prefix arg in raw form. Does not do I/O.
371 P: { func: function (spec) {
372 return this.gPrefixArg;
376 pref: { func: function (spec) {
378 var type = preferences.getPrefType (pref);
380 case preferences.PREF_BOOL:
381 return preferences.getBoolPref (pref);
382 case preferences.PREF_INT:
383 return preferences.getIntPref (pref);
384 case preferences.PREF_STRING:
385 return preferences.getCharPref (pref);
392 r: { func: function (spec) {
393 // -- Region: point and mark as 2 numeric args, smallest first. Does no I/O.
398 result: { func: function (spec) {
399 // -- result of given function
400 return (1 in spec ? spec[1]() : null);
404 s: { async: function (spec, iargs, callback, callback_args, given_args) {
406 var prompt = "String: ";
410 this.minibuffer.read({ prompt: prompt,
411 callback: function (s) {
412 callback_args.push (s);
413 do_interactive.call (frame, iargs, callback, callback_args, given_args);
418 S: { func: function (spec) {
424 //RETROJ: this may be improperly named. it can read either an url or a
425 // webjump from the minibuffer, but it will always return an url.
426 url_or_webjump: { async: function (spec, iargs, callback, callback_args, given_args) {
427 var prompt = (1 in spec && spec[1] ? spec[1].call (this, callback_args) : "URL: ");
428 var initval = (2 in spec && spec[2] ? spec[2].call (this, callback_args) : "");
429 var hist = (3 in spec ? spec[3] : null);
430 var completions = (4 in spec && spec[4] ? spec[4].call (this, callback_args) : []);
432 this.minibuffer.read({prompt: prompt, initial_value : initval, history: hist,
433 completions : completions,
434 allow_non_matches : true,
435 callback : function (match, s) {
436 if (s == "") // well-formedness check. (could be better!)
437 throw ("invalid url or webjump (\""+s+"\")");
438 callback_args.push (get_url_or_webjump (s));
439 do_interactive.call (frame, iargs, callback, callback_args, given_args);
444 v: { func: function (spec) {
445 // -- Variable name: symbol that is user-variable-p.
450 value: { func: function (spec) {
452 return (1 in spec ? spec[1] : null);
456 x: { func: function (spec) {
457 // -- Lisp expression read but not evaluated.
462 X: { func: function (spec) {
463 // -- Lisp expression read and evaluated.
468 z: { func: function (spec) {
474 Z: { func: function (spec) {
475 // -- Coding system, nil if no prefix arg.
481 function do_interactive (iargs, callback, callback_args, given_args)
483 if (! callback_args) callback_args = Array ();
486 while (iargs.length > 0)
488 // process as many synchronous args as possible
489 iarg = iargs.shift ();
490 if (given_args && 0 in given_args) {
491 var got = given_args.shift ();
493 callback_args.push (got);
497 if (typeof (iarg) == "string") {
504 if (! method in interactive_methods) {
505 // prefix should get reset on failed interactive call.
506 this.gPrefixArg = null;
507 this.minibuffer.message ("Failed: invalid interactive specifier: '"+iarg+"'");
511 if ('func' in interactive_methods[method])
513 // 'func' denotes that this method can be done synchronously.
515 callback_args.push (interactive_methods[method].func.call (this, iarg));
517 this.minibuffer.message ('do_interactive (' + method + '): ' + e);
519 // do_interactive (iargs, callback, callback_args);
521 // an asynchronous call needs to be made. break the loop and let
522 // the async handler below take over.
529 if (! 'async' in interactive_methods[method]) {
530 // fail. improperly defined interactive method.
531 // prefix should get reset on failed interactive call.
532 this.gPrefixArg = null;
533 this.minibuffer.message ("Failed: improperly defined interactive specifer: '"+iarg+"'");
536 // go on a little trip..
538 // asynchronous methods get called with their interactive spec and
539 // all the information they need to continue the interactive
540 // process when their data has been gathered.
543 interactive_methods[method].async.call (this, iarg, iargs, callback, callback_args, given_args);
545 this.minibuffer.message ('do_interactive (' + method + '): ' + e);
548 // always reset the prefix arg after collecting all
549 // interactive data, in case it appears multiple times in the
551 this.gPrefixArg = null;
553 callback.call (this, callback_args);
555 this.minibuffer.message ('do_interactive <CALLBACK>: ' + e);
556 dumpln ('do_interactive <CALLBACK>: ' + e);
562 function call_interactively(frame, cmd, given_args)
565 conkeror.current_command = cmd;
566 for (var i=0; i < conkeror.commands.length; i++) {
567 if (conkeror.commands[i][0] == cmd)
569 // Copy the interactive args spec, because do_interactive is
570 // destructive to its first argument.
571 var iargs = conkeror.commands[i][2].slice (0);
572 var given = given_args ? given_args.slice (0) : null;
573 do_interactive.call (frame,
576 conkeror.commands[i][1].apply (conkeror, args);
583 frame.minibuffer.message("No such command '" + cmd + "'");
585 frame.minibuffer.message ("call_interactively: " + e);
590 function interactive(name, fn, args)
592 for (var i=0; i < conkeror.commands.length; i++) {
593 if (conkeror.commands[i][0] == name) {
594 conkeror.commands[i] = [name,fn,args];
598 conkeror.commands.push([name,fn,args]);