browser/metro/base/content/console.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 let ConsolePanelView = {
michael@0 7 _list: null,
michael@0 8 _inited: false,
michael@0 9 _evalTextbox: null,
michael@0 10 _evalFrame: null,
michael@0 11 _evalCode: "",
michael@0 12 _bundle: null,
michael@0 13 _showChromeErrors: -1,
michael@0 14 _enabledPref: "devtools.errorconsole.enabled",
michael@0 15
michael@0 16 get enabled() {
michael@0 17 return Services.prefs.getBoolPref(this._enabledPref);
michael@0 18 },
michael@0 19
michael@0 20 get follow() {
michael@0 21 return document.getElementById("console-follow-checkbox").checked;
michael@0 22 },
michael@0 23
michael@0 24 init: function cv_init() {
michael@0 25 if (this._list)
michael@0 26 return;
michael@0 27
michael@0 28 this._list = document.getElementById("console-box");
michael@0 29 this._evalTextbox = document.getElementById("console-eval-textbox");
michael@0 30 this._bundle = Strings.browser;
michael@0 31
michael@0 32 this._count = 0;
michael@0 33 this.limit = 250;
michael@0 34 this.fieldMaxLength = 140;
michael@0 35
michael@0 36 try {
michael@0 37 // update users using the legacy pref
michael@0 38 if (Services.prefs.getBoolPref("browser.console.showInPanel")) {
michael@0 39 Services.prefs.setBoolPref(this._enabledPref, true);
michael@0 40 Services.prefs.clearUserPref("browser.console.showInPanel");
michael@0 41 }
michael@0 42 } catch(ex) {
michael@0 43 // likely don't have an old pref
michael@0 44 }
michael@0 45 Services.prefs.addObserver(this._enabledPref, this, false);
michael@0 46 },
michael@0 47
michael@0 48 show: function show() {
michael@0 49 if (this._inited)
michael@0 50 return;
michael@0 51 this._inited = true;
michael@0 52
michael@0 53 this.init(); // In case the panel is selected before init has been called.
michael@0 54
michael@0 55 Services.console.registerListener(this);
michael@0 56
michael@0 57 this.appendInitialItems();
michael@0 58
michael@0 59 // Delay creation of the iframe for startup performance
michael@0 60 this._evalFrame = document.createElement("iframe");
michael@0 61 this._evalFrame.id = "console-evaluator";
michael@0 62 this._evalFrame.collapsed = true;
michael@0 63 document.getElementById("console-container").appendChild(this._evalFrame);
michael@0 64
michael@0 65 this._evalFrame.addEventListener("load", this.loadOrDisplayResult.bind(this), true);
michael@0 66 },
michael@0 67
michael@0 68 uninit: function cv_uninit() {
michael@0 69 if (this._inited)
michael@0 70 Services.console.unregisterListener(this);
michael@0 71
michael@0 72 Services.prefs.removeObserver(this._enabledPref, this, false);
michael@0 73 },
michael@0 74
michael@0 75 observe: function(aSubject, aTopic, aData) {
michael@0 76 if (aTopic == "nsPref:changed") {
michael@0 77 // We may choose to create a new menu in v2
michael@0 78 }
michael@0 79 else
michael@0 80 this.appendItem(aSubject);
michael@0 81 },
michael@0 82
michael@0 83 showChromeErrors: function() {
michael@0 84 if (this._showChromeErrors != -1)
michael@0 85 return this._showChromeErrors;
michael@0 86
michael@0 87 try {
michael@0 88 let pref = Services.prefs;
michael@0 89 return this._showChromeErrors = pref.getBoolPref("javascript.options.showInConsole");
michael@0 90 }
michael@0 91 catch(ex) {
michael@0 92 return this._showChromeErrors = false;
michael@0 93 }
michael@0 94 },
michael@0 95
michael@0 96 appendItem: function cv_appendItem(aObject) {
michael@0 97 let index = -1;
michael@0 98 try {
michael@0 99 // Try to QI it to a script error to get more info
michael@0 100 let scriptError = aObject.QueryInterface(Ci.nsIScriptError);
michael@0 101
michael@0 102 // filter chrome urls
michael@0 103 if (!this.showChromeErrors && scriptError.sourceName.substr(0, 9) == "chrome://")
michael@0 104 return;
michael@0 105 index = this.appendError(scriptError);
michael@0 106 }
michael@0 107 catch (ex) {
michael@0 108 try {
michael@0 109 // Try to QI it to a console message
michael@0 110 let msg = aObject.QueryInterface(Ci.nsIConsoleMessage);
michael@0 111
michael@0 112 if (msg.message)
michael@0 113 index = this.appendMessage(msg.message);
michael@0 114 else // observed a null/"clear" message
michael@0 115 this.clearConsole();
michael@0 116 }
michael@0 117 catch (ex2) {
michael@0 118 // Give up and append the object itself as a string
michael@0 119 index = this.appendMessage(aObject);
michael@0 120 }
michael@0 121 }
michael@0 122 if (this.follow) {
michael@0 123 this._list.ensureIndexIsVisible(index);
michael@0 124 }
michael@0 125 },
michael@0 126
michael@0 127 truncateIfNecessary: function (aString) {
michael@0 128 if (!aString || aString.length <= this.fieldMaxLength) {
michael@0 129 return aString;
michael@0 130 }
michael@0 131 let truncatedString = aString.substring(0, this.fieldMaxLength);
michael@0 132 let Ci = Components.interfaces;
michael@0 133 let ellipsis = Services.prefs.getComplexValue("intl.ellipsis",
michael@0 134 Ci.nsIPrefLocalizedString).data;
michael@0 135 truncatedString = truncatedString + ellipsis;
michael@0 136 return truncatedString;
michael@0 137 },
michael@0 138
michael@0 139 appendError: function cv_appendError(aObject) {
michael@0 140 let row = this.createConsoleRow();
michael@0 141 let nsIScriptError = Ci.nsIScriptError;
michael@0 142
michael@0 143 // Is this error actually just a non-fatal warning?
michael@0 144 let warning = aObject.flags & nsIScriptError.warningFlag != 0;
michael@0 145
michael@0 146 let typetext = warning ? "typeWarning" : "typeError";
michael@0 147 row.setAttribute("typetext", this._bundle.GetStringFromName(typetext));
michael@0 148 row.setAttribute("type", warning ? "warning" : "error");
michael@0 149 row.setAttribute("msg", aObject.errorMessage);
michael@0 150 row.setAttribute("category", aObject.category);
michael@0 151 if (aObject.lineNumber || aObject.sourceName) {
michael@0 152 row.setAttribute("href", aObject.sourceName);
michael@0 153 row.setAttribute("line", aObject.lineNumber);
michael@0 154 }
michael@0 155 else {
michael@0 156 row.setAttribute("hideSource", "true");
michael@0 157 }
michael@0 158 // hide code by default, otherwise initial item display will
michael@0 159 // hang the browser.
michael@0 160 row.setAttribute("hideCode", "true");
michael@0 161 row.setAttribute("hideCaret", "true");
michael@0 162
michael@0 163 if (aObject.sourceLine) {
michael@0 164 row.setAttribute("code", this.truncateIfNecessary(aObject.sourceLine.replace(/\s/g, " ")));
michael@0 165 if (aObject.columnNumber) {
michael@0 166 row.setAttribute("col", aObject.columnNumber);
michael@0 167 }
michael@0 168 }
michael@0 169
michael@0 170 let mode = document.getElementById("console-filter").value;
michael@0 171 if (mode != "all" && mode != row.getAttribute("type")) {
michael@0 172 row.collapsed = true;
michael@0 173 }
michael@0 174
michael@0 175 row.setAttribute("onclick", "ConsolePanelView.onRowClick(this)");
michael@0 176 this.appendConsoleRow(row);
michael@0 177 return this._list.getIndexOfItem(row);
michael@0 178 },
michael@0 179
michael@0 180 appendMessage: function cv_appendMessage (aMessage) {
michael@0 181 let row = this.createConsoleRow();
michael@0 182 row.setAttribute("type", "message");
michael@0 183 row.setAttribute("msg", aMessage);
michael@0 184
michael@0 185 let mode = document.getElementById("console-filter").value;
michael@0 186 if (mode != "all" && mode != "message")
michael@0 187 row.collapsed = true;
michael@0 188
michael@0 189 this.appendConsoleRow(row);
michael@0 190 return this._list.getIndexOfItem(row);
michael@0 191 },
michael@0 192
michael@0 193 createConsoleRow: function cv_createConsoleRow() {
michael@0 194 let row = document.createElement("richlistitem");
michael@0 195 row.setAttribute("class", "console-row");
michael@0 196 return row;
michael@0 197 },
michael@0 198
michael@0 199 appendConsoleRow: function cv_appendConsoleRow(aRow) {
michael@0 200 this._list.appendChild(aRow);
michael@0 201 if (++this._count > this.limit) {
michael@0 202 this.deleteFirst();
michael@0 203 }
michael@0 204 },
michael@0 205
michael@0 206 deleteFirst: function cv_deleteFirst() {
michael@0 207 let node = this._list.firstChild;
michael@0 208 this._list.removeChild(node);
michael@0 209 --this._count;
michael@0 210 },
michael@0 211
michael@0 212 appendInitialItems: function cv_appendInitialItems() {
michael@0 213 this._list.collapsed = true;
michael@0 214 let messages = Services.console.getMessageArray();
michael@0 215
michael@0 216 // In case getMessageArray returns 0-length array as null
michael@0 217 if (!messages)
michael@0 218 messages = [];
michael@0 219
michael@0 220 let limit = messages.length - this.limit;
michael@0 221 if (limit < 0)
michael@0 222 limit = 0;
michael@0 223
michael@0 224 // Checks if console ever been cleared
michael@0 225 for (var i = messages.length - 1; i >= limit; --i) {
michael@0 226 if (!messages[i].message) {
michael@0 227 break;
michael@0 228 }
michael@0 229 }
michael@0 230
michael@0 231 // Populate with messages after latest "clear"
michael@0 232 while (++i < messages.length) {
michael@0 233 this.appendItem(messages[i]);
michael@0 234 }
michael@0 235 this._list.collapsed = false;
michael@0 236 },
michael@0 237
michael@0 238 clearConsole: function cv_clearConsole() {
michael@0 239 if (this._count == 0) // already clear
michael@0 240 return;
michael@0 241 this._count = 0;
michael@0 242
michael@0 243 let newRows = this._list.cloneNode(false);
michael@0 244 this._list.parentNode.replaceChild(newRows, this._list);
michael@0 245 this._list = newRows;
michael@0 246 this.selectedItem = null;
michael@0 247 },
michael@0 248
michael@0 249 copyAll: function () {
michael@0 250 let mode = document.getElementById("console-filter").value;
michael@0 251 let rows = this._list.childNodes;
michael@0 252 let copyText = "";
michael@0 253 for (let i=0; i < rows.length; i++) {
michael@0 254 let row = rows[i];
michael@0 255 if (mode == "all" || row.getAttribute ("type") == mode) {
michael@0 256 let text = "* " + row.getAttribute("msg");
michael@0 257 if (row.hasAttribute("href")) {
michael@0 258 text += "\r\n " + row.getAttribute("href") + " line:" + row.getAttribute("line");
michael@0 259 }
michael@0 260 if (row.hasAttribute("code")) {
michael@0 261 text += "\r\n " + row.getAttribute("code") + " col:" + row.getAttribute("col");
michael@0 262 }
michael@0 263 copyText += text + "\r\n";
michael@0 264 }
michael@0 265 }
michael@0 266 let clip = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
michael@0 267 clip.copyString(copyText, document);
michael@0 268 },
michael@0 269
michael@0 270 changeMode: function cv_changeMode() {
michael@0 271 let mode = document.getElementById("console-filter").value;
michael@0 272 if (this._list.getAttribute("mode") != mode) {
michael@0 273 let rows = this._list.childNodes;
michael@0 274 for (let i=0; i < rows.length; i++) {
michael@0 275 let row = rows[i];
michael@0 276 if (mode == "all" || row.getAttribute ("type") == mode)
michael@0 277 row.collapsed = false;
michael@0 278 else
michael@0 279 row.collapsed = true;
michael@0 280 }
michael@0 281 this._list.mode = mode;
michael@0 282 this._list.scrollToIndex(0);
michael@0 283 }
michael@0 284 },
michael@0 285
michael@0 286 onContextMenu: function cv_onContextMenu(aEvent) {
michael@0 287 let row = aEvent.target;
michael@0 288 let text = ["msg", "href", "line", "code", "col"].map(function(attr) row.getAttribute(attr))
michael@0 289 .filter(function(x) x).join("\r\n");
michael@0 290
michael@0 291 ContextMenuUI.showContextMenu({
michael@0 292 target: row,
michael@0 293 json: {
michael@0 294 types: ["copy"],
michael@0 295 string: text,
michael@0 296 xPos: aEvent.clientX,
michael@0 297 yPos: aEvent.clientY
michael@0 298 }
michael@0 299 });
michael@0 300 },
michael@0 301
michael@0 302 onRowClick: function (aRow) {
michael@0 303 if (aRow.hasAttribute("code")) {
michael@0 304 aRow.setAttribute("hideCode", "false");
michael@0 305 }
michael@0 306 if (aRow.hasAttribute("col")) {
michael@0 307 aRow.setAttribute("hideCaret", "false");
michael@0 308 }
michael@0 309 },
michael@0 310
michael@0 311 onEvalKeyPress: function cv_onEvalKeyPress(aEvent) {
michael@0 312 if (aEvent.keyCode == 13)
michael@0 313 this.evaluateTypein();
michael@0 314 },
michael@0 315
michael@0 316 onConsoleBoxKeyPress: function cv_onConsoleBoxKeyPress(aEvent) {
michael@0 317 if ((aEvent.charCode == 99 || aEvent.charCode == 67) && aEvent.ctrlKey && this._list && this._list.selectedItem) {
michael@0 318 let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
michael@0 319 clipboard.copyString(this._list.selectedItem.getAttribute("msg"), document);
michael@0 320 }
michael@0 321 },
michael@0 322
michael@0 323 evaluateTypein: function cv_evaluateTypein() {
michael@0 324 this._evalCode = this._evalTextbox.value;
michael@0 325 this.loadOrDisplayResult();
michael@0 326 },
michael@0 327
michael@0 328 loadOrDisplayResult: function cv_loadOrDisplayResult() {
michael@0 329 if (this._evalCode) {
michael@0 330 this._evalFrame.contentWindow.location = "javascript: " + this._evalCode.replace(/%/g, "%25");
michael@0 331 this._evalCode = "";
michael@0 332 return;
michael@0 333 }
michael@0 334
michael@0 335 let resultRange = this._evalFrame.contentDocument.createRange();
michael@0 336 resultRange.selectNode(this._evalFrame.contentDocument.documentElement);
michael@0 337 let result = resultRange.toString();
michael@0 338 if (result)
michael@0 339 Services.console.logStringMessage(result);
michael@0 340 // or could use appendMessage which doesn't persist
michael@0 341 },
michael@0 342
michael@0 343 repeatChar: function cv_repeatChar(aChar, aCol) {
michael@0 344 if (--aCol <= 0)
michael@0 345 return "";
michael@0 346
michael@0 347 for (let i = 2; i < aCol; i += i)
michael@0 348 aChar += aChar;
michael@0 349
michael@0 350 return aChar + aChar.slice(0, aCol - aChar.length);
michael@0 351 }
michael@0 352 };

mercurial