1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/metro/base/content/console.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,352 @@ 1.4 +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +let ConsolePanelView = { 1.10 + _list: null, 1.11 + _inited: false, 1.12 + _evalTextbox: null, 1.13 + _evalFrame: null, 1.14 + _evalCode: "", 1.15 + _bundle: null, 1.16 + _showChromeErrors: -1, 1.17 + _enabledPref: "devtools.errorconsole.enabled", 1.18 + 1.19 + get enabled() { 1.20 + return Services.prefs.getBoolPref(this._enabledPref); 1.21 + }, 1.22 + 1.23 + get follow() { 1.24 + return document.getElementById("console-follow-checkbox").checked; 1.25 + }, 1.26 + 1.27 + init: function cv_init() { 1.28 + if (this._list) 1.29 + return; 1.30 + 1.31 + this._list = document.getElementById("console-box"); 1.32 + this._evalTextbox = document.getElementById("console-eval-textbox"); 1.33 + this._bundle = Strings.browser; 1.34 + 1.35 + this._count = 0; 1.36 + this.limit = 250; 1.37 + this.fieldMaxLength = 140; 1.38 + 1.39 + try { 1.40 + // update users using the legacy pref 1.41 + if (Services.prefs.getBoolPref("browser.console.showInPanel")) { 1.42 + Services.prefs.setBoolPref(this._enabledPref, true); 1.43 + Services.prefs.clearUserPref("browser.console.showInPanel"); 1.44 + } 1.45 + } catch(ex) { 1.46 + // likely don't have an old pref 1.47 + } 1.48 + Services.prefs.addObserver(this._enabledPref, this, false); 1.49 + }, 1.50 + 1.51 + show: function show() { 1.52 + if (this._inited) 1.53 + return; 1.54 + this._inited = true; 1.55 + 1.56 + this.init(); // In case the panel is selected before init has been called. 1.57 + 1.58 + Services.console.registerListener(this); 1.59 + 1.60 + this.appendInitialItems(); 1.61 + 1.62 + // Delay creation of the iframe for startup performance 1.63 + this._evalFrame = document.createElement("iframe"); 1.64 + this._evalFrame.id = "console-evaluator"; 1.65 + this._evalFrame.collapsed = true; 1.66 + document.getElementById("console-container").appendChild(this._evalFrame); 1.67 + 1.68 + this._evalFrame.addEventListener("load", this.loadOrDisplayResult.bind(this), true); 1.69 + }, 1.70 + 1.71 + uninit: function cv_uninit() { 1.72 + if (this._inited) 1.73 + Services.console.unregisterListener(this); 1.74 + 1.75 + Services.prefs.removeObserver(this._enabledPref, this, false); 1.76 + }, 1.77 + 1.78 + observe: function(aSubject, aTopic, aData) { 1.79 + if (aTopic == "nsPref:changed") { 1.80 + // We may choose to create a new menu in v2 1.81 + } 1.82 + else 1.83 + this.appendItem(aSubject); 1.84 + }, 1.85 + 1.86 + showChromeErrors: function() { 1.87 + if (this._showChromeErrors != -1) 1.88 + return this._showChromeErrors; 1.89 + 1.90 + try { 1.91 + let pref = Services.prefs; 1.92 + return this._showChromeErrors = pref.getBoolPref("javascript.options.showInConsole"); 1.93 + } 1.94 + catch(ex) { 1.95 + return this._showChromeErrors = false; 1.96 + } 1.97 + }, 1.98 + 1.99 + appendItem: function cv_appendItem(aObject) { 1.100 + let index = -1; 1.101 + try { 1.102 + // Try to QI it to a script error to get more info 1.103 + let scriptError = aObject.QueryInterface(Ci.nsIScriptError); 1.104 + 1.105 + // filter chrome urls 1.106 + if (!this.showChromeErrors && scriptError.sourceName.substr(0, 9) == "chrome://") 1.107 + return; 1.108 + index = this.appendError(scriptError); 1.109 + } 1.110 + catch (ex) { 1.111 + try { 1.112 + // Try to QI it to a console message 1.113 + let msg = aObject.QueryInterface(Ci.nsIConsoleMessage); 1.114 + 1.115 + if (msg.message) 1.116 + index = this.appendMessage(msg.message); 1.117 + else // observed a null/"clear" message 1.118 + this.clearConsole(); 1.119 + } 1.120 + catch (ex2) { 1.121 + // Give up and append the object itself as a string 1.122 + index = this.appendMessage(aObject); 1.123 + } 1.124 + } 1.125 + if (this.follow) { 1.126 + this._list.ensureIndexIsVisible(index); 1.127 + } 1.128 + }, 1.129 + 1.130 + truncateIfNecessary: function (aString) { 1.131 + if (!aString || aString.length <= this.fieldMaxLength) { 1.132 + return aString; 1.133 + } 1.134 + let truncatedString = aString.substring(0, this.fieldMaxLength); 1.135 + let Ci = Components.interfaces; 1.136 + let ellipsis = Services.prefs.getComplexValue("intl.ellipsis", 1.137 + Ci.nsIPrefLocalizedString).data; 1.138 + truncatedString = truncatedString + ellipsis; 1.139 + return truncatedString; 1.140 + }, 1.141 + 1.142 + appendError: function cv_appendError(aObject) { 1.143 + let row = this.createConsoleRow(); 1.144 + let nsIScriptError = Ci.nsIScriptError; 1.145 + 1.146 + // Is this error actually just a non-fatal warning? 1.147 + let warning = aObject.flags & nsIScriptError.warningFlag != 0; 1.148 + 1.149 + let typetext = warning ? "typeWarning" : "typeError"; 1.150 + row.setAttribute("typetext", this._bundle.GetStringFromName(typetext)); 1.151 + row.setAttribute("type", warning ? "warning" : "error"); 1.152 + row.setAttribute("msg", aObject.errorMessage); 1.153 + row.setAttribute("category", aObject.category); 1.154 + if (aObject.lineNumber || aObject.sourceName) { 1.155 + row.setAttribute("href", aObject.sourceName); 1.156 + row.setAttribute("line", aObject.lineNumber); 1.157 + } 1.158 + else { 1.159 + row.setAttribute("hideSource", "true"); 1.160 + } 1.161 + // hide code by default, otherwise initial item display will 1.162 + // hang the browser. 1.163 + row.setAttribute("hideCode", "true"); 1.164 + row.setAttribute("hideCaret", "true"); 1.165 + 1.166 + if (aObject.sourceLine) { 1.167 + row.setAttribute("code", this.truncateIfNecessary(aObject.sourceLine.replace(/\s/g, " "))); 1.168 + if (aObject.columnNumber) { 1.169 + row.setAttribute("col", aObject.columnNumber); 1.170 + } 1.171 + } 1.172 + 1.173 + let mode = document.getElementById("console-filter").value; 1.174 + if (mode != "all" && mode != row.getAttribute("type")) { 1.175 + row.collapsed = true; 1.176 + } 1.177 + 1.178 + row.setAttribute("onclick", "ConsolePanelView.onRowClick(this)"); 1.179 + this.appendConsoleRow(row); 1.180 + return this._list.getIndexOfItem(row); 1.181 + }, 1.182 + 1.183 + appendMessage: function cv_appendMessage (aMessage) { 1.184 + let row = this.createConsoleRow(); 1.185 + row.setAttribute("type", "message"); 1.186 + row.setAttribute("msg", aMessage); 1.187 + 1.188 + let mode = document.getElementById("console-filter").value; 1.189 + if (mode != "all" && mode != "message") 1.190 + row.collapsed = true; 1.191 + 1.192 + this.appendConsoleRow(row); 1.193 + return this._list.getIndexOfItem(row); 1.194 + }, 1.195 + 1.196 + createConsoleRow: function cv_createConsoleRow() { 1.197 + let row = document.createElement("richlistitem"); 1.198 + row.setAttribute("class", "console-row"); 1.199 + return row; 1.200 + }, 1.201 + 1.202 + appendConsoleRow: function cv_appendConsoleRow(aRow) { 1.203 + this._list.appendChild(aRow); 1.204 + if (++this._count > this.limit) { 1.205 + this.deleteFirst(); 1.206 + } 1.207 + }, 1.208 + 1.209 + deleteFirst: function cv_deleteFirst() { 1.210 + let node = this._list.firstChild; 1.211 + this._list.removeChild(node); 1.212 + --this._count; 1.213 + }, 1.214 + 1.215 + appendInitialItems: function cv_appendInitialItems() { 1.216 + this._list.collapsed = true; 1.217 + let messages = Services.console.getMessageArray(); 1.218 + 1.219 + // In case getMessageArray returns 0-length array as null 1.220 + if (!messages) 1.221 + messages = []; 1.222 + 1.223 + let limit = messages.length - this.limit; 1.224 + if (limit < 0) 1.225 + limit = 0; 1.226 + 1.227 + // Checks if console ever been cleared 1.228 + for (var i = messages.length - 1; i >= limit; --i) { 1.229 + if (!messages[i].message) { 1.230 + break; 1.231 + } 1.232 + } 1.233 + 1.234 + // Populate with messages after latest "clear" 1.235 + while (++i < messages.length) { 1.236 + this.appendItem(messages[i]); 1.237 + } 1.238 + this._list.collapsed = false; 1.239 + }, 1.240 + 1.241 + clearConsole: function cv_clearConsole() { 1.242 + if (this._count == 0) // already clear 1.243 + return; 1.244 + this._count = 0; 1.245 + 1.246 + let newRows = this._list.cloneNode(false); 1.247 + this._list.parentNode.replaceChild(newRows, this._list); 1.248 + this._list = newRows; 1.249 + this.selectedItem = null; 1.250 + }, 1.251 + 1.252 + copyAll: function () { 1.253 + let mode = document.getElementById("console-filter").value; 1.254 + let rows = this._list.childNodes; 1.255 + let copyText = ""; 1.256 + for (let i=0; i < rows.length; i++) { 1.257 + let row = rows[i]; 1.258 + if (mode == "all" || row.getAttribute ("type") == mode) { 1.259 + let text = "* " + row.getAttribute("msg"); 1.260 + if (row.hasAttribute("href")) { 1.261 + text += "\r\n " + row.getAttribute("href") + " line:" + row.getAttribute("line"); 1.262 + } 1.263 + if (row.hasAttribute("code")) { 1.264 + text += "\r\n " + row.getAttribute("code") + " col:" + row.getAttribute("col"); 1.265 + } 1.266 + copyText += text + "\r\n"; 1.267 + } 1.268 + } 1.269 + let clip = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); 1.270 + clip.copyString(copyText, document); 1.271 + }, 1.272 + 1.273 + changeMode: function cv_changeMode() { 1.274 + let mode = document.getElementById("console-filter").value; 1.275 + if (this._list.getAttribute("mode") != mode) { 1.276 + let rows = this._list.childNodes; 1.277 + for (let i=0; i < rows.length; i++) { 1.278 + let row = rows[i]; 1.279 + if (mode == "all" || row.getAttribute ("type") == mode) 1.280 + row.collapsed = false; 1.281 + else 1.282 + row.collapsed = true; 1.283 + } 1.284 + this._list.mode = mode; 1.285 + this._list.scrollToIndex(0); 1.286 + } 1.287 + }, 1.288 + 1.289 + onContextMenu: function cv_onContextMenu(aEvent) { 1.290 + let row = aEvent.target; 1.291 + let text = ["msg", "href", "line", "code", "col"].map(function(attr) row.getAttribute(attr)) 1.292 + .filter(function(x) x).join("\r\n"); 1.293 + 1.294 + ContextMenuUI.showContextMenu({ 1.295 + target: row, 1.296 + json: { 1.297 + types: ["copy"], 1.298 + string: text, 1.299 + xPos: aEvent.clientX, 1.300 + yPos: aEvent.clientY 1.301 + } 1.302 + }); 1.303 + }, 1.304 + 1.305 + onRowClick: function (aRow) { 1.306 + if (aRow.hasAttribute("code")) { 1.307 + aRow.setAttribute("hideCode", "false"); 1.308 + } 1.309 + if (aRow.hasAttribute("col")) { 1.310 + aRow.setAttribute("hideCaret", "false"); 1.311 + } 1.312 + }, 1.313 + 1.314 + onEvalKeyPress: function cv_onEvalKeyPress(aEvent) { 1.315 + if (aEvent.keyCode == 13) 1.316 + this.evaluateTypein(); 1.317 + }, 1.318 + 1.319 + onConsoleBoxKeyPress: function cv_onConsoleBoxKeyPress(aEvent) { 1.320 + if ((aEvent.charCode == 99 || aEvent.charCode == 67) && aEvent.ctrlKey && this._list && this._list.selectedItem) { 1.321 + let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); 1.322 + clipboard.copyString(this._list.selectedItem.getAttribute("msg"), document); 1.323 + } 1.324 + }, 1.325 + 1.326 + evaluateTypein: function cv_evaluateTypein() { 1.327 + this._evalCode = this._evalTextbox.value; 1.328 + this.loadOrDisplayResult(); 1.329 + }, 1.330 + 1.331 + loadOrDisplayResult: function cv_loadOrDisplayResult() { 1.332 + if (this._evalCode) { 1.333 + this._evalFrame.contentWindow.location = "javascript: " + this._evalCode.replace(/%/g, "%25"); 1.334 + this._evalCode = ""; 1.335 + return; 1.336 + } 1.337 + 1.338 + let resultRange = this._evalFrame.contentDocument.createRange(); 1.339 + resultRange.selectNode(this._evalFrame.contentDocument.documentElement); 1.340 + let result = resultRange.toString(); 1.341 + if (result) 1.342 + Services.console.logStringMessage(result); 1.343 + // or could use appendMessage which doesn't persist 1.344 + }, 1.345 + 1.346 + repeatChar: function cv_repeatChar(aChar, aCol) { 1.347 + if (--aCol <= 0) 1.348 + return ""; 1.349 + 1.350 + for (let i = 2; i < aCol; i += i) 1.351 + aChar += aChar; 1.352 + 1.353 + return aChar + aChar.slice(0, aCol - aChar.length); 1.354 + } 1.355 +};