--- a/devtools/client/locales/en-US/webconsole.properties
+++ b/devtools/client/locales/en-US/webconsole.properties
@@ -253,16 +253,17 @@ table.key=Key
table.value=Values
# LOCALIZATION NOTE (severity.error, severity.warn, severity.info, severity.log):
# tooltip for icons next to console output
severity.error=Error
severity.warn=Warning
severity.info=Info
severity.log=Log
+severity.debug=Debug
# LOCALIZATION NOTE (webconsole.find.key)
# Key shortcut used to focus the search box on upper right of the console
webconsole.find.key=CmdOrCtrl+F
# LOCALIZATION NOTE (webconsole.close.key)
# Key shortcut used to close the Browser console (doesn't work in regular web console)
webconsole.close.key=CmdOrCtrl+W
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -8,16 +8,21 @@
// React & Redux
const {
createClass,
createFactory,
PropTypes
} = require("devtools/client/shared/vendor/react");
+const {
+ MESSAGE_SOURCE,
+ MESSAGE_TYPE
+} = require("devtools/client/webconsole/new-console-output/constants");
+
const componentMap = new Map([
["ConsoleApiCall", require("./message-types/console-api-call").ConsoleApiCall],
["ConsoleCommand", require("./message-types/console-command").ConsoleCommand],
["DefaultRenderer", require("./message-types/default-renderer").DefaultRenderer],
["EvaluationResult", require("./message-types/evaluation-result").EvaluationResult],
["PageError", require("./message-types/page-error").PageError]
]);
@@ -31,32 +36,34 @@ const MessageContainer = createClass({
render() {
const { message } = this.props;
let MessageComponent = createFactory(getMessageComponent(message));
return MessageComponent({ message });
}
});
function getMessageComponent(message) {
- // @TODO Once packets have been converted to Chrome RDP structure, remove.
- if (message.messageType) {
- let {messageType} = message;
- if (!componentMap.has(messageType)) {
- return componentMap.get("DefaultRenderer");
- }
- return componentMap.get(messageType);
- }
-
switch (message.source) {
- case "javascript":
+ case MESSAGE_SOURCE.CONSOLE_API:
+ return componentMap.get("ConsoleApiCall");
+ case MESSAGE_SOURCE.JAVASCRIPT:
switch (message.type) {
- case "command":
+ case MESSAGE_TYPE.COMMAND:
return componentMap.get("ConsoleCommand");
+ case MESSAGE_TYPE.RESULT:
+ return componentMap.get("EvaluationResult");
+ // @TODO this is probably not the right behavior, but works for now.
+ // Chrome doesn't distinguish between page errors and log messages. We
+ // may want to remove the PageError component and just handle errors
+ // with ConsoleApiCall.
+ case MESSAGE_TYPE.LOG:
+ return componentMap.get("PageError");
+ default:
+ componentMap.get("DefaultRenderer");
}
- break;
}
return componentMap.get("DefaultRenderer");
}
module.exports.MessageContainer = MessageContainer;
// Exported so we can test it with unit tests.
--- a/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
@@ -20,20 +20,19 @@ ConsoleApiCall.displayName = "ConsoleApi
ConsoleApiCall.propTypes = {
message: PropTypes.object.isRequired,
};
function ConsoleApiCall(props) {
const { message } = props;
- const counter = message.data.counter;
- const messageBody = counter ?
- `${counter.label}: ${counter.count}` :
- message.data.arguments.map((arg) => GripMessageBody({grip: arg}));
+ const messageBody = message.parameters ?
+ message.parameters.map((grip) => GripMessageBody({grip})) :
+ message.messageText;
const icon = MessageIcon({severity: message.severity});
const repeat = MessageRepeat({repeat: message.repeat});
// @TODO Use of "is" is a temporary hack to get the category and severity
// attributes to be applied. There are targeted in webconsole's CSS rules,
// so if we remove this hack, we have to modify the CSS rules accordingly.
return dom.div({
--- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
@@ -35,15 +35,15 @@ function EvaluationResult(props) {
severity: message.severity
},
// @TODO add timestamp
// @TODO add indent if needed with console.group
icon,
dom.span(
{className: "message-body-wrapper message-body devtools-monospace"},
dom.span({},
- GripMessageBody({grip: message.data})
+ GripMessageBody({grip: message.parameters})
)
)
);
}
module.exports.EvaluationResult = EvaluationResult;
--- a/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
@@ -34,16 +34,16 @@ function PageError(props) {
is: "fdt-message",
category: message.category,
severity: message.severity
},
icon,
dom.span(
{className: "message-body-wrapper message-body devtools-monospace"},
dom.span({},
- message.data.errorMessage
+ message.messageText
)
),
repeat
);
}
module.exports.PageError = PageError;
--- a/devtools/client/webconsole/new-console-output/constants.js
+++ b/devtools/client/webconsole/new-console-output/constants.js
@@ -6,51 +6,31 @@
"use strict";
const actionTypes = {
MESSAGE_ADD: "MESSAGE_ADD",
MESSAGES_CLEAR: "MESSAGES_CLEAR",
};
const categories = {
- CATEGORY_NETWORK: 0,
- CATEGORY_CSS: 1,
- CATEGORY_JS: 2,
- CATEGORY_WEBDEV: 3,
- CATEGORY_INPUT: 4,
- CATEGORY_OUTPUT: 5,
- CATEGORY_SECURITY: 6,
- CATEGORY_SERVER: 7
+ CATEGORY_NETWORK: "network",
+ CATEGORY_CSS: "cssparser",
+ CATEGORY_JS: "exception",
+ CATEGORY_WEBDEV: "console",
+ CATEGORY_INPUT: "input",
+ CATEGORY_OUTPUT: "output",
+ CATEGORY_SECURITY: "security",
+ CATEGORY_SERVER: "server"
};
const severities = {
- SEVERITY_ERROR: 0,
- SEVERITY_WARNING: 1,
- SEVERITY_INFO: 2,
- SEVERITY_LOG: 3
-};
-
-// The fragment of a CSS class name that identifies categories/severities.
-const fragments = {
- CATEGORY_CLASS_FRAGMENTS: [
- "network",
- "cssparser",
- "exception",
- "console",
- "input",
- "output",
- "security",
- "server",
- ],
- SEVERITY_CLASS_FRAGMENTS: [
- "error",
- "warn",
- "info",
- "log",
- ]
+ SEVERITY_ERROR: "error",
+ SEVERITY_WARNING: "warn",
+ SEVERITY_INFO: "info",
+ SEVERITY_LOG: "log"
};
// A mapping from the console API log event levels to the Web Console
// severities.
const levels = {
LEVELS: {
error: severities.SEVERITY_ERROR,
exception: severities.SEVERITY_ERROR,
@@ -68,11 +48,50 @@ const levels = {
groupCollapsed: severities.SEVERITY_LOG,
groupEnd: severities.SEVERITY_LOG,
time: severities.SEVERITY_LOG,
timeEnd: severities.SEVERITY_LOG,
count: severities.SEVERITY_LOG
}
};
+const chromeRDPEnums = {
+ MESSAGE_SOURCE: {
+ XML: "xml",
+ JAVASCRIPT: "javascript",
+ NETWORK: "network",
+ CONSOLE_API: "console-api",
+ STORAGE: "storage",
+ APPCACHE: "appcache",
+ RENDERING: "rendering",
+ SECURITY: "security",
+ OTHER: "other",
+ DEPRECATION: "deprecation"
+ },
+ MESSAGE_TYPE: {
+ LOG: "log",
+ DIR: "dir",
+ TABLE: "table",
+ TRACE: "trace",
+ CLEAR: "clear",
+ START_GROUP: "startGroup",
+ START_GROUP_COLLAPSED: "startGroupCollapsed",
+ END_GROUP: "endGroup",
+ ASSERT: "assert",
+ PROFILE: "profile",
+ PROFILE_END: "profileEnd",
+ // Undocumented in Chrome RDP, but is used for evaluation results.
+ RESULT: "result",
+ // Undocumented in Chrome RDP, but is used for input.
+ COMMAND: "command"
+ },
+ MESSAGE_LEVEL: {
+ LOG: "log",
+ ERROR: "error",
+ WARN: "warn",
+ DEBUG: "debug",
+ INFO: "info"
+ }
+};
+
// Combine into a single constants object
-module.exports = Object.assign({}, actionTypes, categories, severities,
- fragments, levels);
+module.exports = Object.assign({}, actionTypes, categories, severities, levels,
+ chromeRDPEnums);
--- a/devtools/client/webconsole/new-console-output/reducers/messages.js
+++ b/devtools/client/webconsole/new-console-output/reducers/messages.js
@@ -8,18 +8,17 @@
const Immutable = require("devtools/client/shared/vendor/immutable");
const constants = require("devtools/client/webconsole/new-console-output/constants");
function messages(state = Immutable.List(), action) {
switch (action.type) {
case constants.MESSAGE_ADD:
let newMessage = action.message;
- // @TODO clean this up once we've switched to Chrome RDP packet structure.
- if (newMessage.data && newMessage.data.level === "clear") {
+ if (newMessage.type === "clear") {
return Immutable.List([newMessage]);
}
if (newMessage.allowRepeating && state.size > 0) {
let lastMessage = state.last();
if (lastMessage.repeatId === newMessage.repeatId) {
return state.pop().push(
newMessage.set("repeat", lastMessage.repeat + 1)
--- a/devtools/client/webconsole/new-console-output/test/components/test_message-icon.html
+++ b/devtools/client/webconsole/new-console-output/test/components/test_message-icon.html
@@ -9,22 +9,21 @@
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for MessageIcon component</p>
<script type="text/javascript;version=1.8">
window.onload = Task.async(function* () {
const {
- SEVERITY_CLASS_FRAGMENTS,
SEVERITY_ERROR,
} = require("devtools/client/webconsole/new-console-output/constants");
const { MessageIcon } = require("devtools/client/webconsole/new-console-output/components/message-icon");
- let severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_ERROR];
+ let severity = SEVERITY_ERROR;
const iconRendered = renderComponent(MessageIcon, { severity });
ok(iconRendered.classList.contains("icon"), "MessageIcon has expected class");
is(iconRendered.getAttribute("title"), "Error",
"MessageIcon shows correct title attribute");
SimpleTest.finish();
});
</script>
--- a/devtools/client/webconsole/new-console-output/test/store/test_messages.js
+++ b/devtools/client/webconsole/new-console-output/test/store/test_messages.js
@@ -53,43 +53,41 @@ add_task(function* () {
"Non-repeated messages aren't clobbered");
});
/**
* Test getRepeatId().
*/
add_task(function* () {
const message1 = prepareMessage(packet);
- const message2 = prepareMessage(packet);
+ let message2 = prepareMessage(packet);
equal(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns same repeat id for objects with the same values");
- message2.data.arguments = ["new args"];
+ message2 = message2.set("parameters", ["new args"]);
notEqual(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for different values");
});
/**
* Test adding a console.clear message to the store.
*/
add_task(function*() {
const { getState, dispatch } = storeFactory();
dispatch(actions.messageAdd(packet));
- const expectedMessage = prepareMessage(packet);
-
let messages = getAllMessages(getState());
- deepEqual(messages.toArray(), [expectedMessage],
+ equal(messages.size, 1,
"MESSAGE_ADD action adds a message");
dispatch(actions.messageAdd(clearPacket));
messages = getAllMessages(getState());
- deepEqual(messages.toArray(), [prepareMessage(clearPacket)],
+ deepEqual(messages.first(), prepareMessage(clearPacket),
"console.clear clears existing messages and add a new one");
});
/**
* Test message limit on the store.
*/
add_task(function* () {
const { getState, dispatch } = storeFactory();
@@ -99,31 +97,31 @@ add_task(function* () {
let newPacket = Object.assign({}, packet);
for (let i = 1; i <= messageNumber; i++) {
newPacket.message.arguments = [i];
dispatch(actions.messageAdd(newPacket));
}
let messages = getAllMessages(getState());
equal(messages.count(), logLimit, "Messages are pruned up to the log limit");
- deepEqual(messages.last().data.arguments, [messageNumber],
+ deepEqual(messages.last().parameters, [messageNumber],
"The last message is the expected one");
});
/**
* Test message limit on the store with user set prefs.
*/
add_task(function* () {
const userSetLimit = 10;
Services.prefs.setIntPref("devtools.hud.loglimit", userSetLimit);
const { getState, dispatch } = storeFactory();
let newPacket = Object.assign({}, packet);
for (let i = 1; i <= userSetLimit + 1; i++) {
- newPacket.message.arguments = [i];
+ newPacket.message.parameters = [i];
dispatch(actions.messageAdd(newPacket));
}
let messages = getAllMessages(getState());
equal(messages.count(), userSetLimit,
"Messages are pruned up to the user set log limit");
});
--- a/devtools/client/webconsole/new-console-output/test/utils/test_getRepeatId.html
+++ b/devtools/client/webconsole/new-console-output/test/utils/test_getRepeatId.html
@@ -22,87 +22,67 @@ window.onload = Task.async(function* ()
yield testDifferentValues();
yield testDifferentSeverities();
yield testFalsyValues();
yield testConsoleVsJSTerm();
SimpleTest.finish();
function testDuplicateValues() {
- const packet1 = yield getPacket("console.log('same')", "consoleAPICall");
- const packet2 = yield getPacket("console.log('same')", "consoleAPICall");
+ const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
+ const {message: message2} = yield getPacket("console.log('same')", "consoleAPICall");
- const message1 = prepareMessage(packet1);
- const message2 = prepareMessage(packet2);
-
- is(getRepeatId(message1.data), getRepeatId(message2.data),
+ is(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns same repeat id for objects with the same values");
}
function testDifferentValues() {
- const packet1 = yield getPacket("console.log('same')", "consoleAPICall");
- const packet2 = yield getPacket("console.log('diff')", "consoleAPICall");
+ const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
+ const {message: message2} = yield getPacket("console.log('diff')", "consoleAPICall");
- const message1 = prepareMessage(packet1);
- const message2 = prepareMessage(packet2);
-
- isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+ isnot(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for different values");
}
function testDifferentSeverities() {
- const packet1 = yield getPacket("console.log('test')", "consoleAPICall");
- const packet2 = yield getPacket("console.warn('test')", "consoleAPICall");
+ const {message: message1} = yield getPacket("console.log('test')", "consoleAPICall");
+ const {message: message2} = yield getPacket("console.warn('test')", "consoleAPICall");
- const message1 = prepareMessage(packet1);
- const message2 = prepareMessage(packet2);
-
- isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+ isnot(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for different severities");
}
function testFalsyValues() {
- const packetNaN = yield getPacket("console.log(NaN)", "consoleAPICall");
- const packetUnd = yield getPacket("console.log(undefined)", "consoleAPICall");
- const packetNul = yield getPacket("console.log(null)", "consoleAPICall");
-
- const messageNaN = prepareMessage(packetNaN);
- const messageUnd = prepareMessage(packetUnd);
- const messageNul = prepareMessage(packetNul);
+ const {message: messageNaN} = yield getPacket("console.log(NaN)", "consoleAPICall");
+ const {message: messageUnd} = yield getPacket("console.log(undefined)", "consoleAPICall");
+ const {message: messageNul} = yield getPacket("console.log(null)", "consoleAPICall");
const repeatIds = new Set([
- getRepeatId(messageNaN.data),
- getRepeatId(messageUnd.data),
- getRepeatId(messageNul.data)]
+ getRepeatId(messageNaN),
+ getRepeatId(messageUnd),
+ getRepeatId(messageNul)]
);
is(repeatIds.size, 3,
"getRepeatId() handles falsy values distinctly");
- const packetNaN2 = yield getPacket("console.log(NaN)", "consoleAPICall");
- const packetUnd2 = yield getPacket("console.log(undefined)", "consoleAPICall");
- const packetNul2 = yield getPacket("console.log(null)", "consoleAPICall");
+ const {message: messageNaN2} = yield getPacket("console.log(NaN)", "consoleAPICall");
+ const {message: messageUnd2} = yield getPacket("console.log(undefined)", "consoleAPICall");
+ const {message: messageNul2} = yield getPacket("console.log(null)", "consoleAPICall");
- const messageNaN2 = prepareMessage(packetNaN2);
- const messageUnd2 = prepareMessage(packetUnd2);
- const messageNul2 = prepareMessage(packetNul2);
-
- is(getRepeatId(messageNaN.data), getRepeatId(messageNaN2.data),
+ is(getRepeatId(messageNaN), getRepeatId(messageNaN2),
"getRepeatId() handles NaN values");
- is(getRepeatId(messageUnd.data), getRepeatId(messageUnd2.data),
+ is(getRepeatId(messageUnd), getRepeatId(messageUnd2),
"getRepeatId() handles undefined values");
- is(getRepeatId(messageNul.data), getRepeatId(messageNul2.data),
+ is(getRepeatId(messageNul), getRepeatId(messageNul2),
"getRepeatId() handles null values");
}
function testConsoleVsJSTerm() {
- const packet1 = yield getPacket("console.log(undefined)", "consoleAPICall");
- const packet2 = yield getPacket("undefined");
+ const {message: message1} = yield getPacket("console.log(undefined)", "consoleAPICall");
+ const {result: message2} = yield getPacket("undefined");
- const message1 = prepareMessage(packet1);
- const message2 = prepareMessage(packet2);
-
- isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+ isnot(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for console vs JSTerm");
}
});
</script>
</body>
</html>
--- a/devtools/client/webconsole/new-console-output/types.js
+++ b/devtools/client/webconsole/new-console-output/types.js
@@ -13,15 +13,18 @@ exports.ConsoleCommand = Immutable.Recor
source: null,
type: null,
category: null,
severity: null,
});
exports.ConsoleMessage = Immutable.Record({
allowRepeating: true,
+ source: null,
+ type: null,
+ level: null,
+ messageText: null,
+ parameters: null,
+ repeat: 1,
+ repeatId: null,
category: "output",
severity: "log",
- data: null,
- messageType: null,
- repeat: 1,
- repeatId: null,
});
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -2,87 +2,115 @@
/* 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 {
- CATEGORY_CLASS_FRAGMENTS,
+ MESSAGE_SOURCE,
+ MESSAGE_TYPE,
+ MESSAGE_LEVEL,
+ // Legacy
CATEGORY_JS,
- CATEGORY_WEBDEV,
CATEGORY_OUTPUT,
+ CATEGORY_WEBDEV,
LEVELS,
- SEVERITY_CLASS_FRAGMENTS,
- SEVERITY_ERROR,
- SEVERITY_WARNING,
SEVERITY_LOG,
} = require("../constants");
const WebConsoleUtils = require("devtools/shared/webconsole/utils").Utils;
const STRINGS_URI = "chrome://devtools/locale/webconsole.properties";
const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
const { ConsoleMessage } = require("../types");
function prepareMessage(packet) {
+ // This packet is already in the expected packet structure. Simply return.
if (packet.source) {
return packet;
}
+ return transformPacket(packet);
+}
+
+/**
+ * Transforms a packet from Firefox RDP structure to Chrome RDP structure.
+ */
+function transformPacket(packet) {
if (packet._type) {
packet = convertCachedPacket(packet);
}
switch (packet.type) {
case "consoleAPICall": {
- let data = Object.assign({}, packet.message);
- if (data.level === "clear") {
- data.arguments = [l10n.getStr("consoleCleared")];
- }
+ let { message } = packet;
+
+ let parameters = message.arguments;
+ let type = message.level;
+ let level = LEVELS[type] || MESSAGE_TYPE.LOG;
+ let messageText = null;
- return new ConsoleMessage({
- category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_WEBDEV],
- data,
- messageType: "ConsoleApiCall",
- repeatId: getRepeatId(data),
- severity: SEVERITY_CLASS_FRAGMENTS[LEVELS[data.level]] || "log",
- });
- }
- case "pageError": {
- let data = Object.assign({}, packet.pageError);
- let severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_ERROR];
- if (data.warning || data.strict) {
- severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_WARNING];
- } else if (data.info) {
- severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_LOG];
+ // Special per-type conversion.
+ switch (type) {
+ case "clear":
+ // We show a message to users when calls console.clear() is called.
+ parameters = [l10n.getStr("consoleCleared")];
+ break;
+ case "count":
+ // Chrome RDP doesn't have a special type for count.
+ type = MESSAGE_TYPE.LOG;
+ level = MESSAGE_LEVEL.DEBUG;
+ messageText = `${message.counter.label}: ${message.counter.count}`;
+ parameters = null;
+ break;
}
return new ConsoleMessage({
- category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_JS],
- data,
- messageType: "PageError",
- repeatId: getRepeatId(data),
- severity,
+ source: MESSAGE_SOURCE.CONSOLE_API,
+ type,
+ level,
+ parameters,
+ messageText,
+ repeatId: getRepeatId(message),
+ category: CATEGORY_WEBDEV,
+ severity: level,
});
}
- case "evaluationResult":
- default: {
- let data;
- if (typeof packet.result === "object") {
- data = Object.assign({}, packet.result);
- } else {
- data = packet.result;
+
+ case "pageError": {
+ let { pageError } = packet;
+ let level = MESSAGE_LEVEL.ERROR;
+ if (pageError.warning || pageError.strict) {
+ level = MESSAGE_LEVEL.WARN;
+ } else if (pageError.info) {
+ level = MESSAGE_LEVEL.INFO;
}
return new ConsoleMessage({
- category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_OUTPUT],
- data,
- messageType: "EvaluationResult",
- repeatId: getRepeatId(data),
- severity: SEVERITY_CLASS_FRAGMENTS[SEVERITY_LOG],
+ source: MESSAGE_SOURCE.JAVASCRIPT,
+ type: MESSAGE_TYPE.LOG,
+ messageText: pageError.errorMessage,
+ repeatId: getRepeatId(pageError),
+ category: CATEGORY_JS,
+ severity: level,
+ });
+ }
+
+ case "evaluationResult":
+ default: {
+ let { result } = packet;
+
+ return new ConsoleMessage({
+ source: MESSAGE_SOURCE.JAVASCRIPT,
+ type: MESSAGE_TYPE.RESULT,
+ level: MESSAGE_LEVEL.LOG,
+ parameters: result,
+ repeatId: getRepeatId(result),
+ category: CATEGORY_OUTPUT,
+ severity: SEVERITY_LOG,
});
}
}
}
// Helpers
function getRepeatId(message) {
let clonedMessage = JSON.parse(JSON.stringify(message));