2 /* This should only be used for minibuffer states where it makes
3 * sense. In particular, it should not be used if additional cleanup
5 function minibuffer_abort (window)
7 var m = window.minibuffer;
8 var s = m.current_state;
10 throw "Invalid minibuffer state";
13 interactive("minibuffer-abort", function (I) {minibuffer_abort(I.window);});
15 function minibuffer_do_command(window, command) {
17 var m = window.minibuffer;
18 if (m._input_mode_enabled)
20 m._ensure_input_area_showing();
21 var e = m.input_element;
22 var c = e.controllers.getControllerForCommand(command);
23 if (c && c.isCommandEnabled(command))
25 var s = m.current_state;
26 if ((s instanceof text_entry_minibuffer_state))
27 s.handle_input_changed();
35 for each (let c_temp in builtin_commands) {
37 interactive("minibuffer-" + c, function(I) {minibuffer_do_command(I.window, c);});
40 for each (let c_temp in builtin_commands_with_count)
43 if (typeof(c) == "string")
44 interactive("minibuffer-" + c, function (I) {
45 do_repeatedly_positive(minibuffer_do_command, I.p,
49 interactive("minibuffer-" + c[0], function (I) {
50 do_repeatedly(minibuffer_do_command, I.p, [I.window, c[0]], [I.window, c[1]]);
52 interactive("minibuffer-" + c[1], function (I) {
53 do_repeatedly(minibuffer_do_command, I.p, [I.window, c[1]], [I.window, c[0]]);
58 function minibuffer_insert_character(window, n, event)
60 var m = window.minibuffer;
61 var s = m.current_state;
62 if (!(s instanceof basic_minibuffer_state))
63 throw "Invalid minibuffer state";
64 m._ensure_input_area_showing();
65 var val = m._input_text;
66 var sel_start = m._selection_start;
67 var sel_end = m._selection_end;
68 var insert = String.fromCharCode(event.charCode);
69 var out = val.substr(0, sel_start);
70 for (var i = 0; i < n; ++i)
72 out += val.substr(sel_end);
74 var new_sel = sel_end + n;
75 m._set_selection(new_sel, new_sel);
77 if (s instanceof text_entry_minibuffer_state)
78 s.handle_input_changed();
80 interactive("minibuffer-insert-character", function (I) {
81 minibuffer_insert_character(I.window, I.p, I.event);
84 function minibuffer_state(keymap, prompt, input, selection_start, selection_end)
93 this.selection_start = selection_start;
95 this.selection_start = 0;
97 this.selection_end = selection_end;
99 this.selection_end = this.selection_start;
101 minibuffer_state.prototype.load = function () {}
102 minibuffer_state.prototype.unload = function () {}
103 minibuffer_state.prototype.destroy = function () {}
106 * The parameter `args' is an object specifying the arguments for
107 * basic_minibuffer_state. The following properties of args must/may
112 * initial_value: [optional] specifies the initial text
114 * select: [optional] specifies to select the initial text if set to non-null
116 define_keywords("$prompt", "$initial_value", "$select");
117 function basic_minibuffer_state()
120 var initial_value = arguments.$initial_value || "";
121 var sel_start, sel_end;
122 if (arguments.$select)
125 sel_end = initial_value.length;
127 sel_start = sel_end = initial_value.length;
129 minibuffer_state.call(this, minibuffer_base_keymap,
130 arguments.$prompt, initial_value,
133 basic_minibuffer_state.prototype.__proto__ = minibuffer_state.prototype; // inherit from minibuffer_state
135 /* USER PREFERENCE */
136 var minibuffer_input_mode_show_message_timeout = 1000;
138 function minibuffer (window)
140 this.element = window.document.getElementById("minibuffer");
141 this.output_element = window.document.getElementById("minibuffer-message");
142 this.input_prompt_element = window.document.getElementById("minibuffer-prompt");
143 this.input_element = window.document.getElementById("minibuffer-input");
145 this.input_element.inputField.addEventListener("blur", function() {
146 if (m._input_mode_enabled && !m._showing_message)
150 m.input_element.focus();
154 this.window = window;
155 this.last_message = "";
159 minibuffer.prototype = {
160 constructor : minibuffer.constructor,
161 get _selection_start () { return this.input_element.selectionStart; },
162 get _selection_end () { return this.input_element.selectionEnd; },
163 get _input_text () { return this.input_element.value; },
164 set _input_text (text) { this.input_element.value = text; },
165 get prompt () { return this.input_prompt_element.value; },
166 set prompt (s) { this.input_prompt_element.value = s; },
168 _set_selection : function (start, end) {
170 start = this._input_text.length;
172 end = this._input_text.length;
173 this.input_element.setSelectionRange(start,end);
176 /* Saved focus state */
177 saved_focused_frame : null,
178 saved_focused_element : null,
180 default_message : "",
182 current_message : null,
184 /* This method will display the specified string in the
185 * minibuffer, without recording it in any log/Messages buffer. */
186 show : function (str) {
187 this.current_message = str;
191 _show : function (str) {
192 if (this.last_message != str)
194 this.output_element.value = str;
195 this.last_message = str;
199 message : function (str) {
200 /* TODO: add the message to a *Messages* buffer, and/or
201 * possibly dump them to the console. */
205 if (str.length > 0 && this._input_mode_enabled)
206 this._ensure_message_area_showing();
208 clear : function () {
209 this.current_message = null;
210 this._show(this.default_message);
213 set_default_message : function (str) {
214 this.default_message = str;
215 if (this.current_message == null)
219 get current_state () {
220 if (this.states.length == 0)
222 return this.states[this.states.length - 1];
225 push_state : function (state) {
227 this.states.push(state);
228 this._restore_state();
229 state.load(this.window);
232 pop_state : function (restore_focus) {
233 if (restore_focus === undefined)
234 restore_focus = true;
235 this.current_state.destroy();
237 this._restore_state(restore_focus);
240 pop_all : function () {
241 while (this.states.length > 0) {
242 this.current_state.destroy();
247 remove_state : function (state, restore_focus) {
248 if (restore_focus === undefined)
249 restore_focus = true;
250 var i = this.states.indexOf(state);
252 this.states.splice(i, 1);
253 this._restore_state(restore_focus);
256 _input_mode_enabled : false,
258 /* If _input_mode_enabled is true, this is set to indicate that
259 * the message area is being temporarily shown instead of the
261 _showing_message : false,
263 _message_timer_ID : null,
265 /* This must only be called if _input_mode_enabled is true */
266 _ensure_input_area_showing : function () {
267 if (this._showing_message)
269 this.window.clearTimeout(this._message_timer_ID);
270 this._message_timer_ID = null;
271 this._showing_message = false;
272 this._switch_to_input_mode();
276 /* This must only be called if _input_mode_enabled is true */
277 _ensure_message_area_showing : function () {
278 if (this._showing_message)
279 this.window.clearTimeout(this._message_timer_ID);
281 this._showing_message = true;
282 this._switch_to_message_mode();
285 this._message_timer_ID = this.window.setTimeout(function(){
286 obj._ensure_input_area_showing();
287 }, minibuffer_input_mode_show_message_timeout);
290 _switch_to_input_mode : function () {
291 this.element.setAttribute("minibuffermode", "input");
292 this.input_element.focus();
295 _switch_to_message_mode : function () {
296 this.element.setAttribute("minibuffermode", "message");
299 _restore_state : function (restore_focus) {
300 var s = this.current_state;
302 if (!this._input_mode_enabled)
304 this.saved_focused_frame = this.window.document.commandDispatcher.focusedWindow;
305 this.saved_focused_element = this.window.document.commandDispatcher.focusedElement;
306 this._input_mode_enabled = true;
307 this._switch_to_input_mode();
309 this.window.keyboard.set_override_keymap(s.keymap);
310 this._input_text = s.input;
311 this.prompt = s.prompt;
312 this._set_selection(s.selection_start, s.selection_end);
314 if (this._input_mode_enabled)
316 this._input_mode_enabled = false;
317 if (!this._showing_message)
318 this._switch_to_message_mode();
320 this.window.clearTimeout(this._message_timer_ID);
321 this._message_timer_ID = null;
322 this._showing_message = false;
326 if (this.saved_focused_element)
327 set_focus_no_scroll(this.window, this.saved_focused_element);
328 else if (this.saved_focused_frame)
329 set_focus_no_scroll(this.window, this.saved_focused_frame);
331 this.saved_focused_element = null;
332 this.saved_focused_frame = null;
333 this.window.keyboard.set_override_keymap(null);
338 _save_state : function () {
339 var s = this.current_state;
342 s.input = this._input_text;
343 s.prompt = this.prompt;
344 s.selection_start = this._selection_start;
345 s.selection_end = this._selection_end;
346 s.unload(this.window);
350 insert_before : function (element) {
351 this.element.parentNode.insertBefore(element, this.element);
355 function minibuffer_initialize_window(window)
357 window.minibuffer = new minibuffer(window);
360 add_hook("window_initialize_early_hook", minibuffer_initialize_window);
362 function minibuffer_window_close_handler(window) {
363 window.minibuffer.pop_all();
365 add_hook("window_close_hook", minibuffer_window_close_handler);
367 /* Note: This is concise, but doesn't seem to be useful in practice,
368 * because nothing can be done with the state alone. */
369 minibuffer.prototype.check_state = function(type) {
370 var s = this.current_state;
371 if (!(s instanceof type))
372 throw new Error("Invalid minibuffer state.");