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 define_builtin_commands(
17 function (I, command) {
20 if (m._input_mode_enabled)
22 m._restore_normal_state();
23 var e = m.input_element;
24 var c = e.controllers.getControllerForCommand(command);
26 m.ignore_input_events = true;
27 if (c && c.isCommandEnabled(command))
30 m.ignore_input_events = false;
32 var s = m.current_state;
33 let x = s.ran_minibuffer_command;
39 /* Ignore exceptions. */
43 I.minibuffer.current_state.mark_active = !I.minibuffer.current_state.mark_active;
46 function (I) I.minibuffer.current_state.mark_active
49 function minibuffer_state(keymap, use_input_mode)
52 this.use_input_mode = use_input_mode;
54 minibuffer_state.prototype.load = function () {}
55 minibuffer_state.prototype.unload = function () {}
56 minibuffer_state.prototype.destroy = function () {}
58 function minibuffer_message_state(keymap, message, destroy_function)
60 minibuffer_state.call(this, keymap, false);
61 this._message = message;
63 this.destroy = destroy_function;
65 minibuffer_message_state.prototype = {
66 __proto__: minibuffer_state.prototype,
67 load : function (window) {
70 unload : function (window) {
73 get message () { return this._message; },
76 this.window.minibuffer._restore_normal_state();
77 this.window.minibuffer._show(this._message);
82 function minibuffer_input_state(keymap, prompt, input, selection_start, selection_end)
90 this.selection_start = selection_start;
92 this.selection_start = 0;
94 this.selection_end = selection_end;
96 this.selection_end = this.selection_start;
98 minibuffer_state.call(this, keymap, true);
100 minibuffer_input_state.prototype.__proto__ = minibuffer_state.prototype;
104 * The parameter `args' is an object specifying the arguments for
105 * basic_minibuffer_state. The following properties of args must/may
110 * initial_value: [optional] specifies the initial text
112 * select: [optional] specifies to select the initial text if set to non-null
114 define_keywords("$prompt", "$initial_value", "$select");
115 function basic_minibuffer_state()
118 var initial_value = arguments.$initial_value || "";
119 var sel_start, sel_end;
120 if (arguments.$select)
123 sel_end = initial_value.length;
125 sel_start = sel_end = initial_value.length;
127 minibuffer_input_state.call(this, minibuffer_base_keymap,
128 arguments.$prompt, initial_value,
131 basic_minibuffer_state.prototype.__proto__ = minibuffer_input_state.prototype; // inherit from minibuffer_state
133 define_variable("minibuffer_input_mode_show_message_timeout", 1000, "Time duration (in milliseconds) to flash minibuffer messages while in minibuffer input mode.");
135 function minibuffer (window)
137 this.element = window.document.getElementById("minibuffer");
138 this.output_element = window.document.getElementById("minibuffer-message");
139 this.input_prompt_element = window.document.getElementById("minibuffer-prompt");
140 this.input_element = window.document.getElementById("minibuffer-input");
142 this.input_element.inputField.addEventListener("blur", function() {
143 if (m.active && m._input_mode_enabled && !m._showing_message)
147 m.input_element.inputField.focus();
151 this.input_element.addEventListener("input", function(e) {
152 if (m.ignore_input_events || !m._input_mode_enabled)
154 var s = m.current_state;
161 // Ensure that the input area will have focus if a message is
162 // currently being flashed so that the default handler for key
163 // events will properly add text to the input area.
164 window.addEventListener("keydown", function (e) {
165 if (m._input_mode_enabled && m._showing_message)
166 m._restore_normal_state();
168 this.window = window;
169 this.last_message = "";
173 minibuffer.prototype = {
174 constructor : minibuffer.constructor,
175 get _selection_start () { return this.input_element.selectionStart; },
176 get _selection_end () { return this.input_element.selectionEnd; },
177 get _input_text () { return this.input_element.value; },
178 set _input_text (text) { this.input_element.value = text; },
179 get prompt () { return this.input_prompt_element.value; },
180 set prompt (s) { this.input_prompt_element.value = s; },
182 _set_selection : function (start, end) {
184 start = this._input_text.length;
186 end = this._input_text.length;
187 this.input_element.setSelectionRange(start,end);
190 /* Saved focus state */
191 saved_focused_frame : null,
192 saved_focused_element : null,
194 default_message : "",
196 current_message : null,
198 /* This method will display the specified string in the
199 * minibuffer, without recording it in any log/Messages buffer. */
200 show : function (str, force) {
201 if (!this.active || force) {
202 this.current_message = str;
207 _show : function (str, force) {
208 if (this.last_message != str)
210 this.output_element.value = str;
211 this.last_message = str;
215 message : function (str) {
216 /* TODO: add the message to a *Messages* buffer, and/or
217 * possibly dump them to the console. */
218 this.show(str, true /* force */);
220 if (str.length > 0 && this.active)
221 this._flash_temporary_message();
223 clear : function () {
224 this.current_message = null;
226 this._show(this.default_message);
229 set_default_message : function (str) {
230 this.default_message = str;
231 if (this.current_message == null)
235 get current_state () {
236 if (this.states.length == 0)
238 return this.states[this.states.length - 1];
241 push_state : function (state) {
243 this.states.push(state);
244 this._restore_state();
245 state.load(this.window);
248 pop_state : function () {
249 this.current_state.destroy();
251 this._restore_state();
254 pop_all : function () {
255 while (this.states.length > 0) {
256 this.current_state.destroy();
261 remove_state : function (state) {
262 var i = this.states.indexOf(state);
265 var was_current = (i == (this.states.length - 1));
267 this.states.splice(i, 1);
269 this._restore_state();
272 _input_mode_enabled : false,
276 /* If _input_mode_enabled is true, this is set to indicate that
277 * the message area is being temporarily shown instead of the
279 _showing_message : false,
281 _message_timer_ID : null,
283 /* This must only be called if _input_mode_enabled is true */
284 _restore_normal_state : function () {
285 if (this._showing_message)
287 this.window.clearTimeout(this._message_timer_ID);
288 this._message_timer_ID = null;
289 this._showing_message = false;
291 if (this._input_mode_enabled)
292 this._switch_to_input_mode();
294 this._show(this.current_state._message);
298 /* This must only be called if _input_mode_enabled is true */
299 _flash_temporary_message : function () {
300 if (this._showing_message)
301 this.window.clearTimeout(this._message_timer_ID);
303 this._showing_message = true;
304 if (this._input_mode_enabled)
305 this._switch_to_message_mode();
308 this._message_timer_ID = this.window.setTimeout(function(){
309 obj._restore_normal_state();
310 }, minibuffer_input_mode_show_message_timeout);
313 _switch_to_input_mode : function () {
314 this.element.setAttribute("minibuffermode", "input");
315 this.input_element.inputField.focus();
318 _switch_to_message_mode : function () {
319 this.element.setAttribute("minibuffermode", "message");
322 _restore_state : function () {
323 var s = this.current_state;
324 var want_input_mode = false;
327 this.saved_focused_frame = this.window.document.commandDispatcher.focusedWindow;
328 this.saved_focused_element = this.window.document.commandDispatcher.focusedElement;
330 if (s.use_input_mode) {
331 want_input_mode = true;
332 this._input_text = s.input;
333 this.prompt = s.prompt;
334 this._set_selection(s.selection_start, s.selection_end);
336 this._show(s._message);
338 this.window.keyboard.set_override_keymap(s.keymap);
343 this.window.keyboard.set_override_keymap(null);
344 if (this.saved_focused_element)
345 set_focus_no_scroll(this.window, this.saved_focused_element);
346 else if (this.saved_focused_frame)
347 set_focus_no_scroll(this.window, this.saved_focused_frame);
348 this.saved_focused_element = null;
349 this.saved_focused_frame = null;
350 this._show(this.current_message || this.default_message);
353 var in_input_mode = this._input_mode_enabled && !this._showing_message;
354 if (this._showing_message) {
355 this.window.clearTimeout(this._message_timer_ID);
356 this._message_timer_ID = null;
357 this._showing_message = false;
359 if (want_input_mode && !in_input_mode)
360 this._switch_to_input_mode();
361 else if (!want_input_mode && in_input_mode)
362 this._switch_to_message_mode();
363 this._input_mode_enabled = want_input_mode;
366 _save_state : function () {
367 var s = this.current_state;
370 if (s.use_input_mode) {
371 s.input = this._input_text;
372 s.prompt = this.prompt;
373 s.selection_start = this._selection_start;
374 s.selection_end = this._selection_end;
376 s.unload(this.window);
380 insert_before : function (element) {
381 this.element.parentNode.insertBefore(element, this.element);
385 function minibuffer_initialize_window(window)
387 window.minibuffer = new minibuffer(window);
390 add_hook("window_initialize_early_hook", minibuffer_initialize_window);
392 function minibuffer_window_close_handler(window) {
393 window.minibuffer.pop_all();
395 add_hook("window_close_hook", minibuffer_window_close_handler);
397 /* Note: This is concise, but doesn't seem to be useful in practice,
398 * because nothing can be done with the state alone. */
399 minibuffer.prototype.check_state = function(type) {
400 var s = this.current_state;
401 if (!(s instanceof type))
402 throw new Error("Invalid minibuffer state.");
406 minibuffer.prototype.show_wait_message = function (initial_message, destroy_function) {
407 var s = new minibuffer_message_state(minibuffer_message_keymap, initial_message, destroy_function);