Bug 1359597 - Set up new console with devtools-launchpad;r=Honza

MozReview-Commit-ID: FxuwGLYef5v

--HG--
extra : rebase_source : e526562574050eba6b77b464f559e2c95d6c8c3a
This commit is contained in:
Brian Grinstead 2017-04-26 08:10:04 -07:00
Родитель 42086632ef
Коммит 3a385c46db
14 изменённых файлов: 1240 добавлений и 35 удалений

Просмотреть файл

@ -10,6 +10,9 @@
*/
const DevTools = {
chromeWindowType: "navigator:browser",
getToolbox: function () {
return {};
}
};
exports.gDevTools = DevTools;

Просмотреть файл

@ -0,0 +1,596 @@
@import "chrome://devtools/skin/widgets.css";
@import "resource://devtools/client/themes/light-theme.css";
/* Webconsole specific theme variables */
.theme-light,
.theme-firebug {
--error-color: #FF0000;
--error-background-color: #FFEBEB;
--warning-background-color: #FFFFC8;
}
/* General output styles */
a {
-moz-user-focus: normal;
-moz-user-input: enabled;
cursor: pointer;
text-decoration: underline;
}
/* Workaround for Bug 575675 - FindChildWithRules aRelevantLinkVisited
* assertion when loading HTML page with links in XUL iframe */
*:visited { }
.webconsole-filterbar-wrapper {
flex-grow: 0;
}
.webconsole-filterbar-primary {
display: flex;
}
.devtools-toolbar.webconsole-filterbar-secondary {
height: initial;
}
.webconsole-filterbar-primary .devtools-plaininput {
flex: 1 1 100%;
}
.webconsole-output.hideTimestamps > .message > .timestamp {
display: none;
}
.message.startGroup .message-body > .objectBox-string,
.message.startGroupCollapsed .message-body > .objectBox-string {
color: var(--theme-body-color);
font-weight: bold;
}
.webconsole-output-wrapper .message > .icon {
margin: 3px 0 0 0;
padding: 0 0 0 6px;
}
.message.error > .icon::before {
background-position: -12px -36px;
}
.message.warn > .icon::before {
background-position: -24px -36px;
}
.message.info > .icon::before {
background-position: -36px -36px;
}
.message.network .method {
margin-inline-end: 5px;
}
.network .message-flex-body > .message-body {
display: flex;
}
.webconsole-output-wrapper .message .indent {
display: inline-block;
border-inline-end: solid 1px var(--theme-splitter-color);
}
.message.startGroup .indent,
.message.startGroupCollapsed .indent {
border-inline-end-color: transparent;
margin-inline-end: 5px;
}
.message.startGroup .icon,
.message.startGroupCollapsed .icon {
display: none;
}
/* console.table() */
.new-consoletable {
width: 100%;
border-collapse: collapse;
--consoletable-border: 1px solid var(--table-splitter-color);
}
.new-consoletable thead,
.new-consoletable tbody {
background-color: var(--theme-body-background);
}
.new-consoletable th {
background-color: var(--theme-selection-background);
color: var(--theme-selection-color);
margin: 0;
padding: 5px 0 0;
font-weight: inherit;
border-inline-end: var(--consoletable-border);
border-bottom: var(--consoletable-border);
}
.new-consoletable tr:nth-of-type(even) {
background-color: var(--table-zebra-background);
}
.new-consoletable td {
padding: 3px 4px;
min-width: 100px;
-moz-user-focus: normal;
color: var(--theme-body-color);
border-inline-end: var(--consoletable-border);
height: 1.25em;
line-height: 1.25em;
}
/* Layout */
.webconsole-output {
flex: 1;
direction: ltr;
overflow: auto;
-moz-user-select: text;
position: relative;
}
:root,
body,
#app-wrapper {
height: 100%;
margin: 0;
padding: 0;
}
body {
overflow: hidden;
}
#app-wrapper {
display: flex;
flex-direction: column;
}
:root, body {
margin: 0;
padding: 0;
height: 100%;
}
#app-wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
#left-wrapper {
flex: 1;
display: flex;
flex-direction: column;
}
#output-container {
flex: 1;
overflow: hidden;
}
.webconsole-output-wrapper {
display: flex;
flex-direction: column;
height: 100%;
}
.message {
display: flex;
padding: 0 7px;
width: 100%;
box-sizing: border-box;
}
.message > .prefix,
.message > .timestamp {
flex: none;
color: var(--theme-comment);
margin: 3px 6px 0 0;
}
.message > .indent {
flex: none;
}
.message > .icon {
flex: none;
margin: 3px 6px 0 0;
padding: 0 4px;
height: 1em;
align-self: flex-start;
}
.theme-firebug .message > .icon {
margin: 0;
margin-inline-end: 6px;
}
.theme-firebug .message[severity="error"],
.theme-light .message.error,
.theme-firebug .message.error {
color: var(--error-color);
background-color: var(--error-background-color);
}
.theme-firebug .message[severity="warn"],
.theme-light .message.warn,
.theme-firebug .message.warn {
background-color: var(--warning-background-color);
}
.message > .icon::before {
content: "";
background-image: url(chrome://devtools/skin/images/webconsole.svg);
background-position: 12px 12px;
background-repeat: no-repeat;
background-size: 72px 60px;
width: 12px;
height: 12px;
display: inline-block;
}
.theme-light .message > .icon::before {
background-image: url(chrome://devtools/skin/images/webconsole.svg#light-icons);
}
.message > .message-body-wrapper {
flex: auto;
min-width: 0px;
margin: 3px;
}
/* The red bubble that shows the number of times a message is repeated */
.message-repeats {
-moz-user-select: none;
flex: none;
margin: 2px 6px;
padding: 0 6px;
height: 1.25em;
color: white;
background-color: red;
border-radius: 40px;
font: message-box;
font-size: 0.9em;
font-weight: 600;
}
.message-repeats[value="1"] {
display: none;
}
.message-location {
max-width: 40%;
}
.stack-trace {
/* The markup contains extra whitespace to improve formatting of clipboard text.
Make sure this whitespace doesn't affect the HTML rendering */
white-space: normal;
}
.stack-trace .frame-link-source,
.message-location .frame-link-source {
/* Makes the file name truncated (and ellipsis shown) on the left side */
direction: rtl;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.stack-trace .frame-link-source-inner,
.message-location .frame-link-source-inner {
/* Enforce LTR direction for the file name - fixes bug 1290056 */
direction: ltr;
unicode-bidi: embed;
}
.stack-trace .frame-link-function-display-name {
max-width: 50%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.message-flex-body {
display: flex;
}
.message-body > * {
white-space: pre-wrap;
word-wrap: break-word;
}
.message-flex-body > .message-body {
display: block;
flex: auto;
}
#output-container.hideTimestamps > .message {
padding-inline-start: 0;
margin-inline-start: 7px;
width: calc(100% - 7px);
}
#output-container.hideTimestamps > .message > .timestamp {
display: none;
}
#output-container.hideTimestamps > .message > .indent {
background-color: var(--theme-body-background);
}
.message:hover {
background-color: var(--theme-selection-background-semitransparent) !important;
}
.theme-light .message.error {
background-color: rgba(255, 150, 150, 0.3);
}
.theme-dark .message.error {
background-color: rgba(235, 83, 104, 0.17);
}
.console-string {
color: var(--theme-highlight-lightorange);
}
.theme-selected .console-string,
.theme-selected .cm-number,
.theme-selected .cm-variable,
.theme-selected .kind-ArrayLike {
color: #f5f7fa !important; /* Selection Text Color */
}
.message.network.error > .icon::before {
background-position: -12px 0;
}
.message.network > .message-body {
display: flex;
flex-wrap: wrap;
}
.message.network .method {
flex: none;
}
.message.network:not(.navigation-marker) .url {
flex: 1 1 auto;
/* Make sure the URL is very small initially, let flex change width as needed. */
width: 100px;
min-width: 5em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.message.network .status {
flex: none;
margin-inline-start: 6px;
}
.message.network.mixed-content .url {
color: var(--theme-highlight-red);
}
.message .learn-more-link {
color: var(--theme-highlight-blue);
margin: 0 6px;
}
.message.network .xhr {
background-color: var(--theme-body-color-alt);
color: var(--theme-body-background);
border-radius: 3px;
font-weight: bold;
font-size: 10px;
padding: 2px;
line-height: 10px;
margin-inline-start: 3px;
margin-inline-end: 1ex;
}
.message.cssparser > .indent {
border-inline-end: solid #00b6f0 6px;
}
.message.cssparser.error > .icon::before {
background-position: -12px -12px;
}
.message.cssparser.warn > .icon::before {
background-position: -24px -12px;
}
.message.exception > .indent {
border-inline-end: solid #fb9500 6px;
}
.message.exception.error > .icon::before {
background-position: -12px -24px;
}
.message.exception.warn > .icon::before {
background-position: -24px -24px;
}
.message.console-api > .indent {
border-inline-end: solid #cbcbcb 6px;
}
.message.server > .indent {
border-inline-end: solid #90B090 6px;
}
/* Input and output styles */
.message.command > .indent,
.message.result > .indent {
border-inline-end: solid #808080 6px;
}
.message.command > .icon::before {
background-position: -48px -36px;
}
.message.result > .icon::before {
background-position: -60px -36px;
}
/* JSTerm Styles */
#jsterm-wrapper {
flex: 0;
}
.jsterm-input-container {
background-color: var(--theme-tab-toolbar-background);
border-top: 1px solid var(--theme-splitter-color);
}
.theme-light .jsterm-input-container {
/* For light theme use a white background for the input - it looks better
than off-white */
background-color: #fff;
border-top-color: #e0e0e0;
}
.theme-firebug .jsterm-input-container {
border-top: 1px solid #ccc;
}
.jsterm-input-node,
.jsterm-complete-node {
border: none;
padding: 0;
padding-inline-start: 20px;
margin: 0;
-moz-appearance: none; appearance: none;
background-color: transparent;
}
.jsterm-input-node[focused="true"] {
background-image: var(--theme-command-line-image-focus);
box-shadow: none;
}
.jsterm-complete-node {
color: var(--theme-comment);
}
.jsterm-input-node {
/* Always allow scrolling on input - it auto expands in js by setting height,
but don't want it to get bigger than the window. 24px = toolbar height. */
max-height: calc(90vh - 24px);
background-image: var(--theme-command-line-image);
background-repeat: no-repeat;
background-size: 16px 16px;
background-position: 4px 50%;
color: var(--theme-content-color1);
}
:-moz-any(.jsterm-input-node,
.jsterm-complete-node) > .textbox-input-box > .textbox-textarea {
overflow-x: hidden;
/* Set padding for console input on textbox to make sure it is inlcuded in
scrollHeight that is used when resizing JSTerminal's input. Note: textbox
default style has important already */
padding: 4px 0 !important;
}
#webconsole-notificationbox,
.jsterm-stack-node {
width: 100%;
}
.message.security > .indent {
border-inline-end: solid red 6px;
}
.message.security.error > .icon::before {
background-position: -12px -48px;
}
.message.security.warn > .icon::before {
background-position: -24px -48px;
}
.navigation-marker {
color: #aaa;
background: linear-gradient(#aaa, #aaa) no-repeat left 50%;
background-size: 100% 2px;
margin-top: 6px;
margin-bottom: 6px;
font-size: 0.9em;
}
.navigation-marker .url {
padding-inline-end: 9px;
text-decoration: none;
background: var(--theme-body-background);
}
.theme-light .navigation-marker .url {
background: #fff;
}
.stacktrace {
display: none;
padding: 5px 10px;
margin: 5px 0 0 0;
overflow-y: auto;
border: 1px solid var(--theme-splitter-color);
border-radius: 3px;
}
.theme-light .message.error .stacktrace {
background-color: rgba(255, 255, 255, 0.5);
}
.theme-dark .message.error .stacktrace {
background-color: rgba(0, 0, 0, 0.5);
}
.message.open .stacktrace {
display: block;
}
.message .theme-twisty {
display: inline-block;
vertical-align: middle;
margin: 3px 0 0 0;
flex-shrink: 0;
}
/*Do not mirror the twisty because container force to ltr */
.message .theme-twisty:dir(rtl),
.message .theme-twisty:-moz-locale-dir(rtl) {
transform: none;
}
.cm-s-mozilla a[class] {
font-style: italic;
text-decoration: none;
}
.cm-s-mozilla a[class]:hover,
.cm-s-mozilla a[class]:focus {
text-decoration: underline;
}
a.learn-more-link.webconsole-learn-more-link {
font-style: normal;
}
/* Open DOMNode in inspector button */
.open-inspector {
background: url(chrome://devtools/skin/images/vview-open-inspector.png) no-repeat 0 0;
padding-left: 16px;
margin-left: 5px;
cursor: pointer;
}
.elementNode:hover .open-inspector,
.open-inspector:hover {
filter: url(images/filters.svg#checked-icon-state);
}
.elementNode:hover .open-inspector:active,
.open-inspector:active {
filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
}

Просмотреть файл

@ -1,3 +1,7 @@
{
"presets": ["es2015"]
"env": {
"test": {
"presets": ["es2015"]
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env node */
"use strict";
const fs = require("fs");
const path = require("path");
function getConfig() {
if (process.env.TARGET === "firefox-panel") {
return require("../configs/firefox-panel.json");
}
const developmentConfig = require("../configs/development.json");
let localConfig = {};
if (fs.existsSync(path.resolve(__dirname, "../configs/local.json"))) {
localConfig = require("../configs/local.json");
}
return Object.assign({}, developmentConfig, localConfig);
}
module.exports = {
getConfig,
};

Просмотреть файл

@ -0,0 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env node */
"use strict";
const toolbox = require("devtools-launchpad/index");
const feature = require("devtools-config");
const { getConfig } = require("./configure");
const envConfig = getConfig();
feature.setConfig(envConfig);
let webpackConfig = require("../webpack.config");
toolbox.startDevServer(envConfig, webpackConfig, __dirname);

Просмотреть файл

@ -0,0 +1,35 @@
{
"title": "Console",
"environment": "development",
"baseWorkerURL": "http://localhost:8000/public/build/",
"host": "",
"theme": "light",
"dir": "ltr",
"features": {
},
"logging": {
"client": false,
"firefoxProxy": false,
"actions": false
},
"chrome": {
"debug": false,
"host": "localhost",
"port": 9222
},
"node": {
"debug": false,
"host": "localhost",
"port": 9229
},
"firefox": {
"webSocketConnection": false,
"proxyHost": "localhost:9000",
"webSocketHost": "localhost:6080",
"mcPath": "./firefox"
},
"development": {
"serverPort": 8000,
"examplesPort": 7999
}
}

Просмотреть файл

@ -0,0 +1,95 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env browser */
"use strict";
const React = require("react");
const ReactDOM = require("react-dom");
const { EventEmitter } = require("devtools-modules");
const { Services: { appinfo, pref } } = require("devtools-modules");
const { bootstrap } = require("devtools-launchpad");
EventEmitter.decorate(window);
require("../../themes/new-webconsole.css");
require("../../shared/components/reps/reps.css");
pref("devtools.debugger.remote-timeout", 10000);
pref("devtools.hud.loglimit", 1000);
pref("devtools.webconsole.filter.error", true);
pref("devtools.webconsole.filter.warn", true);
pref("devtools.webconsole.filter.info", true);
pref("devtools.webconsole.filter.log", true);
pref("devtools.webconsole.filter.debug", true);
pref("devtools.webconsole.filter.css", false);
pref("devtools.webconsole.filter.net", false);
pref("devtools.webconsole.filter.netxhr", false);
pref("devtools.webconsole.ui.filterbar", false);
pref("devtools.webconsole.inputHistoryCount", 50);
pref("devtools.webconsole.persistlog", false);
pref("devtools.webconsole.timestampMessages", false);
pref("devtools.webconsole.autoMultiline", true);
const NewConsoleOutputWrapper = require("../new-console-output/new-console-output-wrapper");
const NewWebConsoleFrame = require("../new-webconsole").NewWebConsoleFrame;
// Replicate the DOM that the root component lives within
const el = document.createElement("div");
el.style.flex = "1";
el.innerHTML = `
<div id="app-wrapper" class="theme-body">
<div id="output-container" role="document" aria-live="polite" />
</div>
`;
document.querySelector("#mount").appendChild(el);
document.documentElement.classList.add("theme-light");
// Copied from netmonitor/index.js:
window.addEventListener("DOMContentLoaded", () => {
for (let link of document.head.querySelectorAll("link")) {
link.href = link.href.replace(/(resource|chrome)\:\/\//, "/");
}
if (appinfo.OS === "Darwin") {
document.documentElement.setAttribute("platform", "mac");
} else if (appinfo.OS === "Linux") {
document.documentElement.setAttribute("platform", "linux");
} else {
document.documentElement.setAttribute("platform", "win");
}
});
let consoleFrame;
function onConnect(connection) {
// If we are on the main dashboard don't render the component
if (!connection || !connection.tabConnection || !connection.tabConnection.tabTarget) {
return;
}
// Stub out properties that are received from hudservice
const owner = {
iframeWindow: window,
chromeWindow: window,
hudId: "hud_0",
target: connection.tabConnection.tabTarget,
_browserConsole: false,
NewConsoleOutputWrapper,
};
consoleFrame = new NewWebConsoleFrame(owner);
consoleFrame.init().then(function () {
console.log("NewWebConsoleFrame initialized");
});
}
// This is just a hack until the local dev environment includes jsterm
window.evaluateJS = function (input) {
consoleFrame.webConsoleClient.evaluateJSAsync(`${input}`, function (r) {
consoleFrame.newConsoleOutput.dispatchMessageAdd(r);
}, {});
};
bootstrap(React, ReactDOM, el).then(onConnect);

Просмотреть файл

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function JSTerm(webConsoleFrame) {
this.hud = webConsoleFrame;
this.hudId = this.hud.hudId;
this.historyLoaded = new Promise(r => {
r();
});
this.openVariablesView = () => { };
this.init = () => { };
}
module.exports.JSTerm = JSTerm;

Просмотреть файл

@ -7,11 +7,11 @@
"use strict";
const actionModules = [
"enhancers",
"filters",
"messages",
"ui",
].map(filename => require(`./${filename}`));
require("./enhancers"),
require("./filters"),
require("./messages"),
require("./ui"),
];
const actions = Object.assign({}, ...actionModules);

Просмотреть файл

@ -6,7 +6,10 @@
const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
const Utils = {
L10n
L10n,
supportsString: function (s) {
return s;
}
};
module.exports = {

Просмотреть файл

@ -0,0 +1,269 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils");
const EventEmitter = require("devtools/shared/event-emitter");
const promise = require("promise");
const defer = require("devtools/shared/defer");
const Services = require("Services");
const { gDevTools } = require("devtools/client/framework/devtools");
const { JSTerm } = require("devtools/client/webconsole/jsterm");
const { WebConsoleConnectionProxy } = require("devtools/client/webconsole/webconsole-connection-proxy");
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
// XXX: This file is incomplete (see bug 1326937).
// It's used when loading the webconsole with devtools-launchpad, but will ultimately be
// the entry point for the new frontend
/**
* A WebConsoleFrame instance is an interactive console initialized *per target*
* that displays console log data as well as provides an interactive terminal to
* manipulate the target's document content.
*
* The WebConsoleFrame is responsible for the actual Web Console UI
* implementation.
*
* @constructor
* @param object webConsoleOwner
* The WebConsole owner object.
*/
function NewWebConsoleFrame(webConsoleOwner) {
this.owner = webConsoleOwner;
this.hudId = this.owner.hudId;
this.isBrowserConsole = this.owner._browserConsole;
this.NEW_CONSOLE_OUTPUT_ENABLED = true;
this.window = this.owner.iframeWindow;
this._onToolboxPrefChanged = this._onToolboxPrefChanged.bind(this);
EventEmitter.decorate(this);
}
NewWebConsoleFrame.prototype = {
/**
* Getter for the debugger WebConsoleClient.
* @type object
*/
get webConsoleClient() {
return this.proxy ? this.proxy.webConsoleClient : null;
},
/**
* Initialize the WebConsoleFrame instance.
* @return object
* A promise object that resolves once the frame is ready to use.
*/
init() {
this._initUI();
let connectionInited = this._initConnection();
// Don't reject if the history fails to load for some reason.
// This would be fine, the panel will just start with empty history.
let allReady = this.jsterm.historyLoaded.catch(() => {}).then(() => {
return connectionInited;
});
// This notification is only used in tests. Don't chain it onto
// the returned promise because the console panel needs to be attached
// to the toolbox before the web-console-created event is receieved.
let notifyObservers = () => {
let id = WebConsoleUtils.supportsString(this.hudId);
if (Services.obs) {
Services.obs.notifyObservers(id, "web-console-created");
}
};
allReady.then(notifyObservers, notifyObservers)
.then(this.newConsoleOutput.init);
return allReady;
},
destroy() {
if (this._destroyer) {
return this._destroyer.promise;
}
this._destroyer = defer();
Services.prefs.addObserver(PREF_MESSAGE_TIMESTAMP, this._onToolboxPrefChanged);
this.React = this.ReactDOM = this.FrameView = null;
let onDestroy = () => {
this._destroyer.resolve(null);
};
if (this.proxy) {
this.proxy.disconnect().then(onDestroy);
this.proxy = null;
} else {
onDestroy();
}
return this._destroyer.promise;
},
_onUpdateListeners() {
},
logWarningAboutReplacedAPI() {
},
/**
* Setter for saving of network request and response bodies.
*
* @param boolean value
* The new value you want to set.
*/
setSaveRequestAndResponseBodies: function (value) {
if (!this.webConsoleClient) {
// Don't continue if the webconsole disconnected.
return promise.resolve(null);
}
let deferred = defer();
let newValue = !!value;
let toSet = {
"NetworkMonitor.saveRequestAndResponseBodies": newValue,
};
// Make sure the web console client connection is established first.
this.webConsoleClient.setPreferences(toSet, response => {
if (!response.error) {
this._saveRequestAndResponseBodies = newValue;
deferred.resolve(response);
} else {
deferred.reject(response.error);
}
});
return deferred.promise;
},
/**
* Connect to the server using the remote debugging protocol.
*
* @private
* @return object
* A promise object that is resolved/reject based on the connection
* result.
*/
_initConnection: function () {
if (this._initDefer) {
return this._initDefer.promise;
}
this._initDefer = defer();
this.proxy = new WebConsoleConnectionProxy(this, this.owner.target);
this.proxy.connect().then(() => {
// on success
this._initDefer.resolve(this);
}, (reason) => {
// on failure
// TODO Print a message to console
this._initDefer.reject(reason);
});
return this._initDefer.promise;
},
_initUI: function () {
this.document = this.window.document;
this.rootElement = this.document.documentElement;
this.outputNode = this.document.getElementById("output-container");
this.completeNode = this.document.querySelector(".jsterm-complete-node");
this.inputNode = this.document.querySelector(".jsterm-input-node");
this.jsterm = new JSTerm(this);
this.jsterm.init();
let toolbox = gDevTools.getToolbox(this.owner.target);
// @TODO Remove this once JSTerm is handled with React/Redux.
this.window.jsterm = this.jsterm;
// @TODO Once the toolbox has been converted to React, see if passing
// in JSTerm is still necessary.
// Handle both launchpad and toolbox loading
let Wrapper = this.owner.NewConsoleOutputWrapper || this.window.NewConsoleOutput;
this.newConsoleOutput = new Wrapper(
this.outputNode, this.jsterm, toolbox, this.owner, this.document);
// Toggle the timestamp on preference change
Services.prefs.addObserver(PREF_MESSAGE_TIMESTAMP, this._onToolboxPrefChanged);
this._onToolboxPrefChanged();
},
/**
* Handler for page location changes.
*
* @param string uri
* New page location.
* @param string title
* New page title.
*/
onLocationChange: function (uri, title) {
this.contentLocation = uri;
if (this.owner.onLocationChange) {
this.owner.onLocationChange(uri, title);
}
},
/**
* Release an actor.
*
* @private
* @param string actor
* The actor ID you want to release.
*/
_releaseObject: function (actor) {
if (this.proxy) {
this.proxy.releaseActor(actor);
}
},
/**
* Called when the message timestamp pref changes.
*/
_onToolboxPrefChanged: function () {
let newValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
this.newConsoleOutput.dispatchTimestampsToggle(newValue);
},
/**
* Handler for the tabNavigated notification.
*
* @param string event
* Event name.
* @param object packet
* Notification packet received from the server.
*/
handleTabNavigated: function (event, packet) {
if (event == "will-navigate") {
if (this.persistLog) {
// Add a _type to hit convertCachedPacket.
packet._type = true;
this.newConsoleOutput.dispatchMessageAdd(packet);
} else {
this.jsterm.clearOutput();
}
}
if (packet.url) {
this.onLocationChange(packet.url, packet.title);
}
if (event == "navigate" && !packet.nativeConsoleAPI) {
this.logWarningAboutReplacedAPI();
}
},
};
exports.NewWebConsoleFrame = NewWebConsoleFrame;

Просмотреть файл

@ -1,21 +1,35 @@
{
"name": "webconsole",
"version": "0.0.1",
"devDependencies": {
"amd-loader": "0.0.5",
"babel-preset-es2015": "^6.6.0",
"babel-register": "^6.7.2",
"cross-env": "^3.1.3",
"enzyme": "^2.4.1",
"expect": "^1.16.0",
"jsdom": "^9.4.1",
"jsdom-global": "^2.0.0",
"mocha": "^2.5.3",
"require-hacker": "^2.1.4",
"sinon": "^1.17.5"
"engines": {
"node": ">=6.9.0"
},
"scripts": {
"postinstall": "cd ../ && npm install && cd webconsole",
"test": "cross-env NODE_PATH=../../../ mocha new-console-output/test/**/*.test.js --compilers js:babel-register -r jsdom-global/register -r ./new-console-output/test/require-helper.js"
"start": "node bin/dev-server",
"test": "cross-env NODE_ENV=test NODE_PATH=../../../ mocha new-console-output/test/**/*.test.js --compilers js:babel-register -r jsdom-global/register -r ./new-console-output/test/require-helper.js"
},
"dependencies": {
"amd-loader": "0.0.5",
"babel-preset-es2015": "^6.6.0",
"babel-register": "^6.24.0",
"cross-env": "^3.1.3",
"devtools-config": "0.0.12",
"devtools-launchpad": "0.0.67",
"devtools-modules": "0.0.24",
"enzyme": "^2.4.1",
"expect": "^1.16.0",
"file-loader": "^0.10.1",
"immutable": "^3.8.1",
"jsdom": "^9.4.1",
"jsdom-global": "^2.0.0",
"json-loader": "^0.5.4",
"mocha": "^2.5.3",
"raw-loader": "^0.5.1",
"react": "=15.3.2",
"react-dom": "=15.3.2",
"react-redux": "=5.0.3",
"redux": "^3.6.0",
"require-hacker": "^2.1.4",
"sinon": "^1.17.5"
}
}

Просмотреть файл

@ -6,14 +6,8 @@
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const {Utils: WebConsoleUtils} =
require("devtools/client/webconsole/utils");
const BrowserLoaderModule = {};
Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
const promise = require("promise");
const {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils");
const defer = require("devtools/shared/defer");
const Services = require("Services");
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
@ -127,18 +121,17 @@ WebConsoleConnectionProxy.prototype = {
return this._connectDefer.promise;
}
this._connectDefer = promise.defer();
this._connectDefer = defer();
let timeout = Services.prefs.getIntPref(PREF_CONNECTION_TIMEOUT);
this._connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._connectTimer.initWithCallback(this._connectionTimeout,
timeout, Ci.nsITimer.TYPE_ONE_SHOT);
this._connectTimer = setTimeout(this._connectionTimeout, timeout);
let connPromise = this._connectDefer.promise;
connPromise.then(() => {
this._connectTimer.cancel();
clearTimeout(this._connectTimer);
this._connectTimer = null;
}, () => {
clearTimeout(this._connectTimer);
this._connectTimer = null;
});
@ -475,7 +468,7 @@ WebConsoleConnectionProxy.prototype = {
return this._disconnecter.promise;
}
this._disconnecter = promise.defer();
this._disconnecter = defer();
if (!this.client) {
this._disconnecter.resolve(null);

Просмотреть файл

@ -0,0 +1,128 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env node */
/* eslint max-len: [0] */
"use strict";
const {toolboxConfig} = require("./node_modules/devtools-launchpad/index");
const { NormalModuleReplacementPlugin } = require("webpack");
const {getConfig} = require("./bin/configure");
const path = require("path");
const projectPath = path.join(__dirname, "local-dev");
let webpackConfig = {
entry: {
console: [path.join(projectPath, "index.js")],
},
module: {
loaders: [
{
test: /\.(png|svg)$/,
loader: "file-loader?name=[path][name].[ext]",
},
]
},
output: {
path: path.join(__dirname, "assets/build"),
filename: "[name].js",
publicPath: "/assets/build",
},
externals: [
{
"promise": "var Promise",
}
],
};
webpackConfig.resolve = {
alias: {
"Services": "devtools-modules/client/shared/shim/Services",
"devtools/client/webconsole/jsterm": path.join(projectPath, "jsterm-stub"),
"devtools/client/webconsole/utils": path.join(__dirname, "new-console-output/test/fixtures/WebConsoleUtils"),
"devtools/client/webconsole/new-console-output": path.join(__dirname, "new-console-output"),
"devtools/client/webconsole/webconsole-connection-proxy": path.join(__dirname, "webconsole-connection-proxy"),
"react": path.join(__dirname, "node_modules/react"),
"devtools/client/shared/vendor/immutable": "immutable",
"devtools/client/shared/vendor/react": "react",
"devtools/client/shared/vendor/react-dom": "react-dom",
"devtools/client/shared/vendor/react-redux": "react-redux",
"devtools/client/shared/vendor/redux": "redux",
"devtools/client/locales": path.join(__dirname, "../../client/locales/en-US"),
"toolkit/locales": path.join(__dirname, "../../../toolkit/locales/en-US"),
"devtools/shared/locales": path.join(__dirname, "../../shared/locales/en-US"),
"devtools/shared/plural-form": path.join(__dirname, "../../shared/plural-form"),
"devtools/shared/l10n": path.join(__dirname, "../../shared/l10n"),
"devtools/client/framework/devtools": path.join(__dirname, "../../client/shims/devtools"),
"devtools/client/framework/menu": "devtools-modules/client/framework/menu",
"devtools/client/framework/menu-item": path.join(__dirname, "../../client/framework/menu-item"),
"devtools/client/shared/components/reps/reps": path.join(__dirname, "../../client/shared/components/reps/reps"),
"devtools/client/shared/redux/middleware/thunk": path.join(__dirname, "../../client/shared/redux/middleware/thunk"),
"devtools/client/shared/components/stack-trace": path.join(__dirname, "../../client/shared/components/stack-trace"),
"devtools/client/shared/source-utils": path.join(__dirname, "../../client/shared/source-utils"),
"devtools/client/shared/components/frame": path.join(__dirname, "../../client/shared/components/frame"),
"devtools/shared/defer": path.join(__dirname, "../../shared/defer"),
"devtools/shared/event-emitter": "devtools-modules/shared/event-emitter",
"devtools/shared/client/main": path.join(__dirname, "new-console-output/test/fixtures/ObjectClient"),
"devtools/shared/platform/clipboard": path.join(__dirname, "../../shared/platform/content/clipboard"),
}
};
const mappings = [
[
/utils\/menu/, "devtools-launchpad/src/components/shared/menu"
],
[
/chrome:\/\/devtools\/skin/,
(result) => {
result.request = result.request
.replace("./chrome://devtools/skin", path.join(__dirname, "../themes"));
}
],
[
/chrome:\/\/devtools\/content/,
(result) => {
result.request = result.request
.replace("./chrome://devtools/content", path.join(__dirname, ".."));
}
],
[
/resource:\/\/devtools/,
(result) => {
result.request = result.request
.replace("./resource://devtools/client", path.join(__dirname, ".."));
}
],
];
webpackConfig.plugins = mappings.map(([regex, res]) =>
new NormalModuleReplacementPlugin(regex, res));
// Exclude to transpile all scripts in devtools/ but not for this folder
const basePath = path.join(__dirname, "../../").replace(/\\/g, "\\\\");
const baseName = path.basename(__dirname);
webpackConfig.babelExcludes = new RegExp(`^${basePath}(.(?!${baseName}))*$`);
let config = toolboxConfig(webpackConfig, getConfig());
// Remove loaders from devtools-launchpad's webpack.config.js
// * For svg-inline loader:
// Webconsole uses file loader to bundle image assets instead of svg-inline loader
// * For raw loader:
// devtools/shared/l10n has preloaded raw loader in require.context
config.module.loaders = config.module.loaders
.filter((loader) => !["svg-inline", "raw"].includes(loader.loader));
module.exports = config;