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._ensure_input_area_showing();
23 var e = m.input_element;
24 var c = e.controllers.getControllerForCommand(command);
25 if (c && c.isCommandEnabled(command))
27 var s = m.current_state;
28 if ((s instanceof text_entry_minibuffer_state))
29 s.handle_input_changed();
33 /* Ignore exceptions. */
37 I.minibuffer.current_state.mark_active = !I.minibuffer.current_state.mark_active;
40 function (I) I.minibuffer.current_state.mark_active
43 function minibuffer_insert_character(window, n, event)
45 var m = window.minibuffer;
46 var s = m.current_state;
47 if (!(s instanceof basic_minibuffer_state))
48 throw "Invalid minibuffer state";
49 m._ensure_input_area_showing();
50 var val = m._input_text;
51 var sel_start = m._selection_start;
52 var sel_end = m._selection_end;
53 var insert = String.fromCharCode(event.charCode);
54 var out = val.substr(0, sel_start);
55 for (var i = 0; i < n; ++i)
57 out += val.substr(sel_end);
59 var new_sel = sel_end + n;
60 m._set_selection(new_sel, new_sel);
62 if (s instanceof text_entry_minibuffer_state)
63 s.handle_input_changed();
65 interactive("minibuffer-insert-character", function (I) {
66 minibuffer_insert_character(I.window, I.p, I.event);
69 function minibuffer_state(keymap, prompt, input, selection_start, selection_end)
78 this.selection_start = selection_start;
80 this.selection_start = 0;
82 this.selection_end = selection_end;
84 this.selection_end = this.selection_start;
86 minibuffer_state.prototype.load = function () {}
87 minibuffer_state.prototype.unload = function () {}
88 minibuffer_state.prototype.destroy = function () {}
91 * The parameter `args' is an object specifying the arguments for
92 * basic_minibuffer_state. The following properties of args must/may
97 * initial_value: [optional] specifies the initial text
99 * select: [optional] specifies to select the initial text if set to non-null
101 define_keywords("$prompt", "$initial_value", "$select");
102 function basic_minibuffer_state()
105 var initial_value = arguments.$initial_value || "";
106 var sel_start, sel_end;
107 if (arguments.$select)
110 sel_end = initial_value.length;
112 sel_start = sel_end = initial_value.length;
114 minibuffer_state.call(this, minibuffer_base_keymap,
115 arguments.$prompt, initial_value,
118 basic_minibuffer_state.prototype.__proto__ = minibuffer_state.prototype; // inherit from minibuffer_state
120 define_user_variable("minibuffer_input_mode_show_message_timeout", 1000, "Time duration (in milliseconds) to flash minibuffer messages while in minibuffer input mode.");
122 function minibuffer (window)
124 this.element = window.document.getElementById("minibuffer");
125 this.output_element = window.document.getElementById("minibuffer-message");
126 this.input_prompt_element = window.document.getElementById("minibuffer-prompt");
127 this.input_element = window.document.getElementById("minibuffer-input");
129 this.input_element.inputField.addEventListener("blur", function() {
130 if (m._input_mode_enabled && !m._showing_message)
134 m.input_element.focus();
138 this.window = window;
139 this.last_message = "";
143 minibuffer.prototype = {
144 constructor : minibuffer.constructor,
145 get _selection_start () { return this.input_element.selectionStart; },
146 get _selection_end () { return this.input_element.selectionEnd; },
147 get _input_text () { return this.input_element.value; },
148 set _input_text (text) { this.input_element.value = text; },
149 get prompt () { return this.input_prompt_element.value; },
150 set prompt (s) { this.input_prompt_element.value = s; },
152 _set_selection : function (start, end) {
154 start = this._input_text.length;
156 end = this._input_text.length;
157 this.input_element.setSelectionRange(start,end);
160 /* Saved focus state */
161 saved_focused_frame : null,
162 saved_focused_element : null,
164 default_message : "",
166 current_message : null,
168 /* This method will display the specified string in the
169 * minibuffer, without recording it in any log/Messages buffer. */
170 show : function (str) {
171 this.current_message = str;
175 _show : function (str) {
176 if (this.last_message != str)
178 this.output_element.value = str;
179 this.last_message = str;
183 message : function (str) {
184 /* TODO: add the message to a *Messages* buffer, and/or
185 * possibly dump them to the console. */
189 if (str.length > 0 && this._input_mode_enabled)
190 this._ensure_message_area_showing();
192 clear : function () {
193 this.current_message = null;
194 this._show(this.default_message);
197 set_default_message : function (str) {
198 this.default_message = str;
199 if (this.current_message == null)
203 get current_state () {
204 if (this.states.length == 0)
206 return this.states[this.states.length - 1];
209 push_state : function (state) {
211 this.states.push(state);
212 this._restore_state();
213 state.load(this.window);
216 pop_state : function (restore_focus) {
217 if (restore_focus === undefined)
218 restore_focus = true;
219 this.current_state.destroy();
221 this._restore_state(restore_focus);
224 pop_all : function () {
225 while (this.states.length > 0) {
226 this.current_state.destroy();
231 remove_state : function (state, restore_focus) {
232 if (restore_focus === undefined)
233 restore_focus = true;
234 var i = this.states.indexOf(state);
236 this.states.splice(i, 1);
237 this._restore_state(restore_focus);
240 _input_mode_enabled : false,
242 /* If _input_mode_enabled is true, this is set to indicate that
243 * the message area is being temporarily shown instead of the
245 _showing_message : false,
247 _message_timer_ID : null,
249 /* This must only be called if _input_mode_enabled is true */
250 _ensure_input_area_showing : function () {
251 if (this._showing_message)
253 this.window.clearTimeout(this._message_timer_ID);
254 this._message_timer_ID = null;
255 this._showing_message = false;
256 this._switch_to_input_mode();
260 /* This must only be called if _input_mode_enabled is true */
261 _ensure_message_area_showing : function () {
262 if (this._showing_message)
263 this.window.clearTimeout(this._message_timer_ID);
265 this._showing_message = true;
266 this._switch_to_message_mode();
269 this._message_timer_ID = this.window.setTimeout(function(){
270 obj._ensure_input_area_showing();
271 }, minibuffer_input_mode_show_message_timeout);
274 _switch_to_input_mode : function () {
275 this.element.setAttribute("minibuffermode", "input");
276 this.input_element.focus();
279 _switch_to_message_mode : function () {
280 this.element.setAttribute("minibuffermode", "message");
283 _restore_state : function (restore_focus) {
284 var s = this.current_state;
286 if (!this._input_mode_enabled)
288 this.saved_focused_frame = this.window.document.commandDispatcher.focusedWindow;
289 this.saved_focused_element = this.window.document.commandDispatcher.focusedElement;
290 this._input_mode_enabled = true;
291 this._switch_to_input_mode();
293 this.window.keyboard.set_override_keymap(s.keymap);
294 this._input_text = s.input;
295 this.prompt = s.prompt;
296 this._set_selection(s.selection_start, s.selection_end);
298 if (this._input_mode_enabled)
300 this._input_mode_enabled = false;
301 if (!this._showing_message)
302 this._switch_to_message_mode();
304 this.window.clearTimeout(this._message_timer_ID);
305 this._message_timer_ID = null;
306 this._showing_message = false;
310 if (this.saved_focused_element)
311 set_focus_no_scroll(this.window, this.saved_focused_element);
312 else if (this.saved_focused_frame)
313 set_focus_no_scroll(this.window, this.saved_focused_frame);
315 this.saved_focused_element = null;
316 this.saved_focused_frame = null;
317 this.window.keyboard.set_override_keymap(null);
322 _save_state : function () {
323 var s = this.current_state;
326 s.input = this._input_text;
327 s.prompt = this.prompt;
328 s.selection_start = this._selection_start;
329 s.selection_end = this._selection_end;
330 s.unload(this.window);
334 insert_before : function (element) {
335 this.element.parentNode.insertBefore(element, this.element);
339 function minibuffer_initialize_window(window)
341 window.minibuffer = new minibuffer(window);
344 add_hook("window_initialize_early_hook", minibuffer_initialize_window);
346 function minibuffer_window_close_handler(window) {
347 window.minibuffer.pop_all();
349 add_hook("window_close_hook", minibuffer_window_close_handler);
351 /* Note: This is concise, but doesn't seem to be useful in practice,
352 * because nothing can be done with the state alone. */
353 minibuffer.prototype.check_state = function(type) {
354 var s = this.current_state;
355 if (!(s instanceof type))
356 throw new Error("Invalid minibuffer state.");