1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/firebug",
  5     "firebug/lib/events",
  6     "firebug/lib/wrapper",
  7     "firebug/lib/css",
  8     "firebug/lib/dom",
  9     "firebug/lib/string",
 10     "firebug/console/autoCompleter"
 11 ],
 12 function(Firebug, Events, Wrapper, Css, Dom, Str) {
 13 
 14 // ********************************************************************************************* //
 15 // Constants
 16 
 17 const Cc = Components.classes;
 18 const Ci = Components.interfaces;
 19 
 20 // ********************************************************************************************* //
 21 
 22 Firebug.CommandHistory = function()
 23 {
 24     const commandHistoryMax = 1000;
 25 
 26     var commandsPopup = Firebug.chrome.$("fbCommandHistory");
 27     var commands = this.commands = [];
 28     var commandPointer = 0;
 29     var commandInsertPointer = -1;
 30 
 31     this.getLastCommand = function()
 32     {
 33         var command = commands[commandInsertPointer];
 34         if (!command)
 35             return "";
 36 
 37         return command;
 38     };
 39 
 40     this.appendToHistory = function(command)
 41     {
 42         if (commands[commandInsertPointer] != command)
 43         {
 44             commandInsertPointer++;
 45             if (commandInsertPointer >= commandHistoryMax)
 46                 commandInsertPointer = 0;
 47 
 48             commands[commandInsertPointer] = command;
 49         }
 50 
 51         commandPointer = commandInsertPointer + 1;
 52 
 53         if (Firebug.chrome.$("fbCommandLineHistoryButton").hasAttribute("disabled"))
 54         {
 55             Firebug.chrome.$("fbCommandLineHistoryButton").removeAttribute("disabled");
 56             Firebug.chrome.$("fbCommandEditorHistoryButton").removeAttribute("disabled");
 57 
 58             this.attachListeners();
 59         }
 60     };
 61 
 62     this.attachListeners = function()
 63     {
 64         Events.addEventListener(commandsPopup, "mouseover", this.onMouseOver, true);
 65         Events.addEventListener(commandsPopup, "mouseup", this.onMouseUp, true);
 66         Events.addEventListener(commandsPopup, "popuphidden", this.onPopupHidden, true);
 67     };
 68 
 69     this.detachListeners = function()
 70     {
 71         Events.removeEventListener(commandsPopup, "mouseover", this.onMouseOver, true);
 72         Events.removeEventListener(commandsPopup, "mouseup", this.onMouseUp, true);
 73         Events.removeEventListener(commandsPopup, "popuphidden", this.onPopupHidden, true);
 74     };
 75 
 76     this.cycleCommands = function(context, dir)
 77     {
 78         var command;
 79         var commandLine = Firebug.CommandLine.getCommandLine(context);
 80 
 81         commandPointer += dir;
 82         if (commandPointer < 0)
 83             commandPointer = 0;
 84         else if (commandPointer > commands.length)
 85             commandPointer = commands.length;
 86 
 87         if (commandPointer < commands.length)
 88         {
 89             command = commands[commandPointer];
 90             if (commandsPopup.state == "open")
 91             {
 92                 var commandElement = commandsPopup.children[commandPointer];
 93                 this.selectCommand(commandElement);
 94 
 95                 Dom.scrollMenupopup(commandsPopup, commandElement);
 96             }
 97         }
 98         else
 99         {
100             command = "";
101             this.removeCommandSelection();
102         }
103 
104         commandLine.value = command;
105         Firebug.CommandLine.autoCompleter.hide();
106         Firebug.CommandLine.update(context);
107         setCursorToEOL(commandLine);
108     };
109 
110     this.isShown = function()
111     {
112         return commandsPopup.state == "open";
113     };
114 
115     this.show = function(element)
116     {
117         if (this.isShown())
118             return this.hide();
119 
120         Dom.eraseNode(commandsPopup);
121 
122         if(commands.length == 0)
123             return;
124 
125         var doc = commandsPopup.ownerDocument;
126 
127         for (var i = 0; i < commands.length; i++)
128         {
129             var hbox = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
130 
131             hbox.classList.add("commandHistoryItem");
132             var shortExpr = Str.cropString(Str.stripNewLines(commands[i]), 50);
133             hbox.innerHTML = Str.escapeForTextNode(shortExpr);
134             hbox.value = i;
135             commandsPopup.appendChild(hbox);
136 
137             if (i === commandPointer)
138                 this.selectCommand(hbox);
139         }
140 
141         commandsPopup.openPopup(element, "before_start", 0, 0, false, false);
142 
143         // make sure last element is visible
144         setTimeout(Dom.scrollMenupopup, 10, commandsPopup, hbox);
145         this.isOpen = true;
146 
147         return true;
148     };
149 
150     this.hide = function()
151     {
152         commandsPopup.hidePopup();
153         this.isOpen = false;
154         return true;
155     };
156 
157     this.toggle = function(element)
158     {
159         this.isShown() ? this.hide() : this.show(element);
160     };
161 
162     this.removeCommandSelection = function()
163     {
164         var selected = commandsPopup.ownerDocument.getElementsByClassName("selected")[0];
165         Css.removeClass(selected, "selected");
166     };
167 
168     this.selectCommand = function(element)
169     {
170         this.removeCommandSelection();
171 
172         Css.setClass(element, "selected");
173     };
174 
175     this.onMouseOver = function(event)
176     {
177         var hovered = event.target;
178 
179         if (hovered.localName == "vbox")
180             return;
181 
182         Firebug.CommandLine.commandHistory.selectCommand(hovered);
183     };
184 
185     this.onMouseUp = function(event)
186     {
187         var i = event.target.value;
188         if (i == undefined)
189             return;
190 
191         var commandLine = Firebug.CommandLine.getCommandLine(Firebug.currentContext);
192 
193         commandLine.value = commands[i];
194         commandPointer = event.target.value;
195 
196         Firebug.CommandLine.commandHistory.hide();
197     };
198 
199     this.onPopupHidden = function(event)
200     {
201         Firebug.chrome.setGlobalAttribute("fbCommandLineHistoryButton", "checked", "false");
202         Firebug.chrome.setGlobalAttribute("fbCommandEditorHistoryButton", "checked", "false");
203         this.isOpen = false;
204     };
205 };
206 
207 // ********************************************************************************************* //
208 // Helpers
209 
210 //xxxHonza: duplicated in console/autoCompleter.js
211 function setCursorToEOL(input)
212 {
213     // textbox version, https://developer.mozilla.org/en/XUL/Property/inputField
214     // input.inputField.setSelectionRange(len, len);
215     input.setSelectionRange(input.value.length, input.value.length);
216 }
217 
218 // ********************************************************************************************* //
219 // Registration
220 
221 return Firebug.CommandHistory;
222 
223 // ********************************************************************************************* //
224 });
225