зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound. a=merge
This commit is contained in:
Коммит
d85c7f6cc3
|
@ -304,6 +304,7 @@ var gSync = {
|
|||
this.remoteClients.map(client => client.id);
|
||||
|
||||
clients.forEach(clientId => this.sendTabToDevice(url, clientId, title));
|
||||
gPageActionButton.panel.hidePopup();
|
||||
}
|
||||
|
||||
function addTargetDevice(clientId, name, clientType) {
|
||||
|
|
|
@ -129,8 +129,6 @@ var whitelist = new Set([
|
|||
platforms: ["linux", "win"]},
|
||||
{file: "chrome://browser/skin/customizableui/panelarrow-customizeTip@2x.png",
|
||||
platforms: ["linux", "win"]},
|
||||
// Bug 1320058
|
||||
{file: "chrome://browser/skin/preferences/saveFile.png", platforms: ["win"]},
|
||||
// Bug 1316187
|
||||
{file: "chrome://global/content/customizeToolbar.xul"},
|
||||
// Bug 1343837
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
padding-inline-end: 4px;
|
||||
}
|
||||
|
||||
#sidebar-icon,
|
||||
#sidebar-switcher-arrow,
|
||||
#sidebar-close > .toolbarbutton-icon {
|
||||
-moz-context-properties: fill;
|
||||
|
@ -106,19 +105,31 @@
|
|||
}
|
||||
%endif
|
||||
|
||||
/* Use bookmarks star as default icon for the sidebar box (including when opening a web page) */
|
||||
|
||||
#sidebar-box[sidebarcommand="viewWebPanelsSidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/places/defaultFavicon.svg);
|
||||
}
|
||||
|
||||
#sidebar-switcher-bookmarks > .toolbarbutton-icon,
|
||||
#sidebar-box[sidebarcommand="viewWebPanelsSidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon,
|
||||
#sidebar-box[sidebarcommand="viewBookmarksSidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
|
||||
list-style-image: url(chrome://browser/skin/bookmark.svg);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
#sidebar-switcher-history > .toolbarbutton-icon,
|
||||
#sidebar-box[sidebarcommand="viewHistorySidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
|
||||
list-style-image: url(chrome://browser/skin/history.svg);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
#sidebar-switcher-tabs > .toolbarbutton-icon,
|
||||
#sidebar-box[sidebarcommand="viewTabsSidebar"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon {
|
||||
list-style-image: url(chrome://browser/skin/sync.svg);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ menuitem[appHandlerIcon="ask"] {
|
|||
|
||||
richlistitem[appHandlerIcon="save"],
|
||||
menuitem[appHandlerIcon="save"] {
|
||||
list-style-image: url("chrome://browser/skin/preferences/application.png");
|
||||
list-style-image: url("chrome://browser/skin/preferences/saveFile.png");
|
||||
}
|
||||
|
||||
richlistitem[appHandlerIcon="feed"],
|
||||
|
|
|
@ -28,8 +28,8 @@ add_task(function* removeLegacyExtension() {
|
|||
|
||||
// Click the remove button and wait for the DOM to change.
|
||||
const addonListMutation = waitForMutation(
|
||||
getTemporaryAddonList(document),
|
||||
{ childList: true });
|
||||
getTemporaryAddonList(document).parentNode,
|
||||
{ childList: true, subtree: true });
|
||||
getRemoveButton(document, addonID).click();
|
||||
yield addonListMutation;
|
||||
|
||||
|
@ -57,8 +57,8 @@ add_task(function* removeWebextension() {
|
|||
|
||||
// Click the remove button and wait for the DOM to change.
|
||||
const addonListMutation = waitForMutation(
|
||||
getTemporaryAddonList(document),
|
||||
{ childList: true });
|
||||
getTemporaryAddonList(document).parentNode,
|
||||
{ childList: true, subtree: true });
|
||||
getRemoveButton(document, addonID).click();
|
||||
yield addonListMutation;
|
||||
|
||||
|
|
|
@ -213,7 +213,8 @@ function* installAddon({document, path, name, isWebExtension}) {
|
|||
|
||||
function* uninstallAddon({document, id, name}) {
|
||||
let addonList = getAddonListWithAddon(document, id);
|
||||
let addonListMutation = waitForMutation(addonList, { childList: true });
|
||||
let addonListMutation = waitForMutation(addonList.parentNode,
|
||||
{ childList: true, subtree: true });
|
||||
|
||||
// Now uninstall this addon
|
||||
yield new Promise(done => {
|
||||
|
@ -233,13 +234,18 @@ function* uninstallAddon({document, id, name}) {
|
|||
});
|
||||
});
|
||||
|
||||
// Ensure that the UI removes the addon from the list
|
||||
yield addonListMutation;
|
||||
let names = [...addonList.querySelectorAll(".target-name")];
|
||||
names = names.map(element => element.textContent);
|
||||
ok(!names.includes(name),
|
||||
"After uninstall, the addon name disappears from the list of addons: "
|
||||
+ names);
|
||||
|
||||
// If parentNode is none, that means the entire addonList was removed from the
|
||||
// document. This happens when the addon we are removing is the last one.
|
||||
if (addonList.parentNode !== null) {
|
||||
// Ensure that the UI removes the addon from the list
|
||||
let names = [...addonList.querySelectorAll(".target-name")];
|
||||
names = names.map(element => element.textContent);
|
||||
ok(!names.includes(name),
|
||||
"After uninstall, the addon name disappears from the list of addons: "
|
||||
+ names);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -277,7 +277,9 @@ HighlightersOverlay.prototype = {
|
|||
|
||||
try {
|
||||
highlighter = yield utils.getHighlighterByType(type);
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
// Ignore any error
|
||||
}
|
||||
|
||||
if (!highlighter) {
|
||||
return null;
|
||||
|
|
|
@ -111,16 +111,20 @@ EventTooltip.prototype = {
|
|||
if (location) {
|
||||
sourceMapService.originalPositionFor(location.url, location.line)
|
||||
.then((originalLocation) => {
|
||||
if (originalLocation) {
|
||||
const { sourceUrl, line } = originalLocation;
|
||||
let newURI = sourceUrl + ":" + line;
|
||||
filename.textContent = newURI;
|
||||
filename.setAttribute("title", newURI);
|
||||
let eventEditor = this._eventEditors.get(content);
|
||||
eventEditor.uri = newURI;
|
||||
// Do nothing if the tooltip was destroyed while we were
|
||||
// waiting for a response.
|
||||
if (this._tooltip) {
|
||||
if (originalLocation) {
|
||||
const { sourceUrl, line } = originalLocation;
|
||||
let newURI = sourceUrl + ":" + line;
|
||||
filename.textContent = newURI;
|
||||
filename.setAttribute("title", newURI);
|
||||
let eventEditor = this._eventEditors.get(content);
|
||||
eventEditor.uri = newURI;
|
||||
}
|
||||
// This is emitted for testing.
|
||||
this._tooltip.emit("event-tooltip-source-map-ready");
|
||||
}
|
||||
// This is emitted for testing.
|
||||
this._tooltip.emit("event-tooltip-source-map-ready");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ const {
|
|||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
const {
|
||||
getAllMessages,
|
||||
getAllMessagesUiById,
|
||||
getAllMessagesTableDataById,
|
||||
getVisibleMessages,
|
||||
} = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const MessageContainer = createFactory(require("devtools/client/webconsole/new-console-output/components/message-container").MessageContainer);
|
||||
|
||||
|
@ -23,7 +23,6 @@ const ConsoleOutput = createClass({
|
|||
displayName: "ConsoleOutput",
|
||||
|
||||
propTypes: {
|
||||
messages: PropTypes.object.isRequired,
|
||||
messagesUi: PropTypes.object.isRequired,
|
||||
serviceContainer: PropTypes.shape({
|
||||
attachRefToHud: PropTypes.func.isRequired,
|
||||
|
@ -33,6 +32,7 @@ const ConsoleOutput = createClass({
|
|||
dispatch: PropTypes.func.isRequired,
|
||||
timestampsVisible: PropTypes.bool,
|
||||
messagesTableData: PropTypes.object.isRequired,
|
||||
visibleMessages: PropTypes.array.isRequired,
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -53,7 +53,7 @@ const ConsoleOutput = createClass({
|
|||
// Figure out if we are at the bottom. If so, then any new message should be scrolled
|
||||
// into view.
|
||||
const lastChild = outputNode.lastChild;
|
||||
const delta = nextProps.messages.size - this.props.messages.size;
|
||||
const delta = nextProps.visibleMessages.length - this.props.visibleMessages.length;
|
||||
this.shouldScrollBottom = delta > 0 && isScrolledToBottom(lastChild, outputNode);
|
||||
},
|
||||
|
||||
|
@ -72,14 +72,14 @@ const ConsoleOutput = createClass({
|
|||
render() {
|
||||
let {
|
||||
dispatch,
|
||||
messages,
|
||||
visibleMessages,
|
||||
messagesUi,
|
||||
messagesTableData,
|
||||
serviceContainer,
|
||||
timestampsVisible,
|
||||
} = this.props;
|
||||
|
||||
let messageNodes = messages.map((message) => {
|
||||
let messageNodes = visibleMessages.map((message) => {
|
||||
return (
|
||||
MessageContainer({
|
||||
dispatch,
|
||||
|
@ -120,7 +120,7 @@ function isScrolledToBottom(outputNode, scrollNode) {
|
|||
|
||||
function mapStateToProps(state, props) {
|
||||
return {
|
||||
messages: getAllMessages(state),
|
||||
visibleMessages: getVisibleMessages(state),
|
||||
messagesUi: getAllMessagesUiById(state),
|
||||
messagesTableData: getAllMessagesTableDataById(state),
|
||||
timestampsVisible: state.ui.timestampsVisible,
|
||||
|
|
|
@ -6,15 +6,22 @@
|
|||
"use strict";
|
||||
|
||||
const Immutable = require("devtools/client/shared/vendor/immutable");
|
||||
const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
|
||||
|
||||
const constants = require("devtools/client/webconsole/new-console-output/constants");
|
||||
const {isGroupType} = require("devtools/client/webconsole/new-console-output/utils/messages");
|
||||
const Services = require("Services");
|
||||
|
||||
const logLimit = Math.max(Services.prefs.getIntPref("devtools.hud.loglimit"), 1);
|
||||
const {
|
||||
MESSAGE_TYPE,
|
||||
MESSAGE_SOURCE
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
const { getGripPreviewItems } = require("devtools/client/shared/components/reps/reps");
|
||||
const { getSourceNames } = require("devtools/client/shared/source-utils");
|
||||
|
||||
const MessageState = Immutable.Record({
|
||||
// List of all the messages added to the console.
|
||||
messagesById: Immutable.List(),
|
||||
messagesById: Immutable.OrderedMap(),
|
||||
// Array of the visible messages.
|
||||
visibleMessages: [],
|
||||
// List of the message ids which are opened.
|
||||
messagesUiById: Immutable.List(),
|
||||
// Map of the form {messageId : tableData}, which represent the data passed
|
||||
|
@ -30,15 +37,18 @@ const MessageState = Immutable.Record({
|
|||
removedMessages: [],
|
||||
});
|
||||
|
||||
function messages(state = new MessageState(), action) {
|
||||
function messages(state = new MessageState(), action, filtersState, prefsState) {
|
||||
const {
|
||||
messagesById,
|
||||
messagesUiById,
|
||||
messagesTableDataById,
|
||||
groupsById,
|
||||
currentGroup,
|
||||
visibleMessages,
|
||||
} = state;
|
||||
|
||||
const {logLimit} = prefsState;
|
||||
|
||||
switch (action.type) {
|
||||
case constants.MESSAGE_ADD:
|
||||
let newMessage = action.message;
|
||||
|
@ -56,23 +66,27 @@ function messages(state = new MessageState(), action) {
|
|||
if (newMessage.allowRepeating && messagesById.size > 0) {
|
||||
let lastMessage = messagesById.last();
|
||||
if (lastMessage.repeatId === newMessage.repeatId) {
|
||||
return state.withMutations(function (record) {
|
||||
record.set("messagesById", messagesById.pop().push(
|
||||
newMessage.set("repeat", lastMessage.repeat + 1)
|
||||
));
|
||||
});
|
||||
return state.set(
|
||||
"messagesById",
|
||||
messagesById.set(
|
||||
lastMessage.id,
|
||||
lastMessage.set("repeat", lastMessage.repeat + 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let parentGroups = getParentGroups(currentGroup, groupsById);
|
||||
newMessage = newMessage.withMutations(function (message) {
|
||||
message.set("groupId", currentGroup);
|
||||
message.set("indent", parentGroups.length);
|
||||
});
|
||||
|
||||
return state.withMutations(function (record) {
|
||||
// Add the new message with a reference to the parent group.
|
||||
record.set("messagesById", messagesById.push(newMessage));
|
||||
let parentGroups = getParentGroups(currentGroup, groupsById);
|
||||
const addedMessage = newMessage.withMutations(function (message) {
|
||||
message.set("groupId", currentGroup);
|
||||
message.set("indent", parentGroups.length);
|
||||
});
|
||||
record.set(
|
||||
"messagesById",
|
||||
messagesById.set(newMessage.id, addedMessage)
|
||||
);
|
||||
|
||||
if (newMessage.type === "trace") {
|
||||
// We want the stacktrace to be open by default.
|
||||
|
@ -87,39 +101,109 @@ function messages(state = new MessageState(), action) {
|
|||
}
|
||||
}
|
||||
|
||||
if (shouldMessageBeVisible(addedMessage, record, filtersState)) {
|
||||
record.set("visibleMessages", [...visibleMessages, newMessage.id]);
|
||||
}
|
||||
|
||||
// Remove top level message if the total count of top level messages
|
||||
// exceeds the current limit.
|
||||
limitTopLevelMessageCount(state, record);
|
||||
if (record.messagesById.size > logLimit) {
|
||||
limitTopLevelMessageCount(state, record, logLimit);
|
||||
}
|
||||
});
|
||||
|
||||
case constants.MESSAGES_CLEAR:
|
||||
return state.withMutations(function (record) {
|
||||
return new MessageState({
|
||||
// Store all removed messages associated with some arguments.
|
||||
// This array is used by `releaseActorsEnhancer` to release
|
||||
// all related backend actors.
|
||||
record.set("removedMessages",
|
||||
record.messagesById.filter(msg => msg.parameters).toArray());
|
||||
|
||||
// Clear immutable state.
|
||||
record.set("messagesById", Immutable.List());
|
||||
record.set("messagesUiById", Immutable.List());
|
||||
record.set("groupsById", Immutable.Map());
|
||||
record.set("currentGroup", null);
|
||||
"removedMessages": [...state.messagesById].reduce((res, [id, msg]) => {
|
||||
if (msg.parameters) {
|
||||
res.push(msg);
|
||||
}
|
||||
return res;
|
||||
}, [])
|
||||
});
|
||||
|
||||
case constants.MESSAGE_OPEN:
|
||||
return state.set("messagesUiById", messagesUiById.push(action.id));
|
||||
return state.withMutations(function (record) {
|
||||
record.set("messagesUiById", messagesUiById.push(action.id));
|
||||
|
||||
// If the message is a group
|
||||
if (isGroupType(messagesById.get(action.id).type)) {
|
||||
// We want to make its children visible
|
||||
const messagesToShow = [...messagesById].reduce((res, [id, message]) => {
|
||||
if (
|
||||
!visibleMessages.includes(message.id)
|
||||
&& getParentGroups(message.groupId, groupsById).includes(action.id)
|
||||
&& shouldMessageBeVisible(
|
||||
message,
|
||||
record,
|
||||
filtersState,
|
||||
// We want to check if the message is in an open group
|
||||
// only if it is not a direct child of the group we're opening.
|
||||
message.groupId !== action.id
|
||||
)
|
||||
) {
|
||||
res.push(id);
|
||||
}
|
||||
return res;
|
||||
}, []);
|
||||
|
||||
// We can then insert the messages ids right after the one of the group.
|
||||
const insertIndex = visibleMessages.indexOf(action.id) + 1;
|
||||
record.set("visibleMessages", [
|
||||
...visibleMessages.slice(0, insertIndex),
|
||||
...messagesToShow,
|
||||
...visibleMessages.slice(insertIndex),
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
case constants.MESSAGE_CLOSE:
|
||||
let index = state.messagesUiById.indexOf(action.id);
|
||||
return state.deleteIn(["messagesUiById", index]);
|
||||
return state.withMutations(function (record) {
|
||||
let messageId = action.id;
|
||||
let index = record.messagesUiById.indexOf(messageId);
|
||||
record.deleteIn(["messagesUiById", index]);
|
||||
|
||||
// If the message is a group
|
||||
if (isGroupType(messagesById.get(messageId).type)) {
|
||||
// Hide all its children
|
||||
record.set(
|
||||
"visibleMessages",
|
||||
[...visibleMessages].filter(id => getParentGroups(
|
||||
messagesById.get(id).groupId,
|
||||
groupsById
|
||||
).includes(messageId) === false
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
case constants.MESSAGE_TABLE_RECEIVE:
|
||||
const {id, data} = action;
|
||||
return state.set("messagesTableDataById", messagesTableDataById.set(id, data));
|
||||
case constants.NETWORK_MESSAGE_UPDATE:
|
||||
let updateMessage = action.message;
|
||||
return state.set("messagesById", messagesById.map((message) =>
|
||||
(message.id === updateMessage.id) ? updateMessage : message
|
||||
return state.set("messagesById", messagesById.set(
|
||||
updateMessage.id,
|
||||
updateMessage
|
||||
));
|
||||
|
||||
case constants.REMOVED_MESSAGES_CLEAR:
|
||||
return state.set("removedMessages", []);
|
||||
|
||||
case constants.FILTER_TOGGLE:
|
||||
case constants.FILTER_TEXT_SET:
|
||||
return state.set(
|
||||
"visibleMessages",
|
||||
[...messagesById].reduce((res, [messageId, message]) => {
|
||||
if (shouldMessageBeVisible(message, state, filtersState)) {
|
||||
res.push(messageId);
|
||||
}
|
||||
return res;
|
||||
}, [])
|
||||
);
|
||||
}
|
||||
|
||||
return state;
|
||||
|
@ -156,36 +240,88 @@ function getParentGroups(currentGroup, groupsById) {
|
|||
|
||||
/**
|
||||
* Remove all top level messages that exceeds message limit.
|
||||
* Also release all backend actors associated with these
|
||||
* messages.
|
||||
* Also populate an array of all backend actors associated with these
|
||||
* messages so they can be released.
|
||||
*/
|
||||
function limitTopLevelMessageCount(state, record) {
|
||||
let tempRecord = {
|
||||
messagesById: record.messagesById,
|
||||
messagesUiById: record.messagesUiById,
|
||||
messagesTableDataById: record.messagesTableDataById,
|
||||
groupsById: record.groupsById,
|
||||
};
|
||||
function limitTopLevelMessageCount(state, record, logLimit) {
|
||||
let topLevelCount = record.groupsById.size === 0
|
||||
? record.messagesById.size
|
||||
: getToplevelMessageCount(record);
|
||||
|
||||
let removedMessages = state.removedMessages;
|
||||
|
||||
// Remove top level messages logged over the limit.
|
||||
let topLevelCount = getToplevelMessageCount(tempRecord);
|
||||
while (topLevelCount > logLimit) {
|
||||
removedMessages.push(...removeFirstMessage(tempRecord));
|
||||
topLevelCount--;
|
||||
if (topLevelCount <= logLimit) {
|
||||
return record;
|
||||
}
|
||||
|
||||
// Filter out messages with no arguments. Only actual arguments
|
||||
// can be associated with backend actors.
|
||||
removedMessages = state.removedMessages.filter(msg => msg.parameters);
|
||||
const removedMessagesId = [];
|
||||
const removedMessages = [];
|
||||
let visibleMessages = [...record.visibleMessages];
|
||||
|
||||
// Update original record object
|
||||
record.set("messagesById", tempRecord.messagesById);
|
||||
record.set("messagesUiById", tempRecord.messagesUiById);
|
||||
record.set("messagesTableDataById", tempRecord.messagesTableDataById);
|
||||
record.set("groupsById", tempRecord.groupsById);
|
||||
record.set("removedMessages", removedMessages);
|
||||
let cleaningGroup = false;
|
||||
record.messagesById.forEach((message, id) => {
|
||||
// If we were cleaning a group and the current message does not have
|
||||
// a groupId, we're done cleaning.
|
||||
if (cleaningGroup === true && !message.groupId) {
|
||||
cleaningGroup = false;
|
||||
}
|
||||
|
||||
// If we're not cleaning a group and the message count is below the logLimit,
|
||||
// we exit the forEach iteration.
|
||||
if (cleaningGroup === false && topLevelCount <= logLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're not currently cleaning a group, and the current message is identified
|
||||
// as a group, set the cleaning flag to true.
|
||||
if (cleaningGroup === false && record.groupsById.has(id)) {
|
||||
cleaningGroup = true;
|
||||
}
|
||||
|
||||
if (!message.groupId) {
|
||||
topLevelCount--;
|
||||
}
|
||||
|
||||
removedMessagesId.push(id);
|
||||
|
||||
// Filter out messages with no arguments. Only actual arguments
|
||||
// can be associated with backend actors.
|
||||
if (message && message.parameters) {
|
||||
removedMessages.push(message);
|
||||
}
|
||||
|
||||
const index = visibleMessages.indexOf(id);
|
||||
if (index > -1) {
|
||||
visibleMessages.splice(index, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (removedMessages.length > 0) {
|
||||
record.set("removedMessages", record.removedMessages.concat(removedMessages));
|
||||
}
|
||||
|
||||
if (record.visibleMessages.length > visibleMessages.length) {
|
||||
record.set("visibleMessages", visibleMessages);
|
||||
}
|
||||
|
||||
const isInRemovedId = id => removedMessagesId.includes(id);
|
||||
const mapHasRemovedIdKey = map => map.findKey((value, id) => isInRemovedId(id));
|
||||
const cleanUpCollection = map => removedMessagesId.forEach(id => map.remove(id));
|
||||
|
||||
record.set("messagesById", record.messagesById.withMutations(cleanUpCollection));
|
||||
|
||||
if (record.messagesUiById.find(isInRemovedId)) {
|
||||
record.set("messagesUiById", record.messagesUiById.withMutations(cleanUpCollection));
|
||||
}
|
||||
if (mapHasRemovedIdKey(record.messagesTableDataById)) {
|
||||
record.set("messagesTableDataById",
|
||||
record.messagesTableDataById.withMutations(cleanUpCollection));
|
||||
}
|
||||
if (mapHasRemovedIdKey(record.groupsById)) {
|
||||
record.set("groupsById", record.groupsById.withMutations(cleanUpCollection));
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -193,48 +329,209 @@ function limitTopLevelMessageCount(state, record) {
|
|||
* within a group).
|
||||
*/
|
||||
function getToplevelMessageCount(record) {
|
||||
return [...record.messagesById].filter(message => !message.groupId).length;
|
||||
return record.messagesById.count(message => !message.groupId);
|
||||
}
|
||||
|
||||
function shouldMessageBeVisible(message, messagesState, filtersState, checkGroup = true) {
|
||||
return (
|
||||
(
|
||||
checkGroup === false
|
||||
|| isInOpenedGroup(message, messagesState.groupsById, messagesState.messagesUiById)
|
||||
)
|
||||
&& (
|
||||
isUnfilterable(message)
|
||||
|| (
|
||||
matchLevelFilters(message, filtersState)
|
||||
&& matchCssFilters(message, filtersState)
|
||||
&& matchNetworkFilters(message, filtersState)
|
||||
&& matchSearchFilters(message, filtersState)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function isUnfilterable(message) {
|
||||
return [
|
||||
MESSAGE_TYPE.COMMAND,
|
||||
MESSAGE_TYPE.RESULT,
|
||||
MESSAGE_TYPE.START_GROUP,
|
||||
MESSAGE_TYPE.START_GROUP_COLLAPSED,
|
||||
].includes(message.type);
|
||||
}
|
||||
|
||||
function isInOpenedGroup(message, groupsById, messagesUI) {
|
||||
return !message.groupId
|
||||
|| (
|
||||
!isGroupClosed(message.groupId, messagesUI)
|
||||
&& !hasClosedParentGroup(groupsById.get(message.groupId), messagesUI)
|
||||
);
|
||||
}
|
||||
|
||||
function hasClosedParentGroup(group, messagesUI) {
|
||||
return group.some(groupId => isGroupClosed(groupId, messagesUI));
|
||||
}
|
||||
|
||||
function isGroupClosed(groupId, messagesUI) {
|
||||
return messagesUI.includes(groupId) === false;
|
||||
}
|
||||
|
||||
function matchLevelFilters(message, filters) {
|
||||
return filters.get(message.level) === true;
|
||||
}
|
||||
|
||||
function matchNetworkFilters(message, filters) {
|
||||
return (
|
||||
message.source !== MESSAGE_SOURCE.NETWORK
|
||||
|| (filters.get("net") === true && message.isXHR === false)
|
||||
|| (filters.get("netxhr") === true && message.isXHR === true)
|
||||
);
|
||||
}
|
||||
|
||||
function matchCssFilters(message, filters) {
|
||||
return (
|
||||
message.source != MESSAGE_SOURCE.CSS
|
||||
|| filters.get("css") === true
|
||||
);
|
||||
}
|
||||
|
||||
function matchSearchFilters(message, filters) {
|
||||
let text = filters.text || "";
|
||||
return (
|
||||
text === ""
|
||||
// Look for a match in parameters.
|
||||
|| isTextInParameters(text, message.parameters)
|
||||
// Look for a match in location.
|
||||
|| isTextInFrame(text, message.frame)
|
||||
// Look for a match in net events.
|
||||
|| isTextInNetEvent(text, message.request)
|
||||
// Look for a match in stack-trace.
|
||||
|| isTextInStackTrace(text, message.stacktrace)
|
||||
// Look for a match in messageText.
|
||||
|| isTextInMessageText(text, message.messageText)
|
||||
// Look for a match in notes.
|
||||
|| isTextInNotes(text, message.notes)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove first (the oldest) message from the store. The methods removes
|
||||
* also all its references and children from the store.
|
||||
* Returns true if given text is included in provided stack frame.
|
||||
*/
|
||||
function isTextInFrame(text, frame) {
|
||||
if (!frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
functionName,
|
||||
line,
|
||||
column,
|
||||
source
|
||||
} = frame;
|
||||
const { short } = getSourceNames(source);
|
||||
|
||||
return `${functionName ? functionName + " " : ""}${short}:${line}:${column}`
|
||||
.toLocaleLowerCase()
|
||||
.includes(text.toLocaleLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in provided parameters.
|
||||
*/
|
||||
function isTextInParameters(text, parameters) {
|
||||
if (!parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
text = text.toLocaleLowerCase();
|
||||
return getAllProps(parameters).some(prop =>
|
||||
(prop + "").toLocaleLowerCase().includes(text)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in provided net event grip.
|
||||
*/
|
||||
function isTextInNetEvent(text, request) {
|
||||
if (!request) {
|
||||
return false;
|
||||
}
|
||||
|
||||
text = text.toLocaleLowerCase();
|
||||
|
||||
let method = request.method.toLocaleLowerCase();
|
||||
let url = request.url.toLocaleLowerCase();
|
||||
return method.includes(text) || url.includes(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in provided stack trace.
|
||||
*/
|
||||
function isTextInStackTrace(text, stacktrace) {
|
||||
if (!Array.isArray(stacktrace)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// isTextInFrame expect the properties of the frame object to be in the same
|
||||
// order they are rendered in the Frame component.
|
||||
return stacktrace.some(frame => isTextInFrame(text, {
|
||||
functionName: frame.functionName || l10n.getStr("stacktrace.anonymousFunction"),
|
||||
source: frame.filename,
|
||||
lineNumber: frame.lineNumber,
|
||||
columnNumber: frame.columnNumber
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in `messageText` field.
|
||||
*/
|
||||
function isTextInMessageText(text, messageText) {
|
||||
if (!messageText) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return messageText.toLocaleLowerCase().includes(text.toLocaleLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in notes.
|
||||
*/
|
||||
function isTextInNotes(text, notes) {
|
||||
if (!Array.isArray(notes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return notes.some(note =>
|
||||
// Look for a match in location.
|
||||
isTextInFrame(text, note.frame) ||
|
||||
// Look for a match in messageBody.
|
||||
(
|
||||
note.messageBody &&
|
||||
note.messageBody.toLocaleLowerCase().includes(text.toLocaleLowerCase())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flat array of all the grips and their properties.
|
||||
*
|
||||
* @return {Array} Flat array of removed messages.
|
||||
* @param {Array} Grips
|
||||
* @return {Array} Flat array of the grips and their properties.
|
||||
*/
|
||||
function removeFirstMessage(record) {
|
||||
let firstMessage = record.messagesById.first();
|
||||
record.messagesById = record.messagesById.shift();
|
||||
function getAllProps(grips) {
|
||||
let result = grips.reduce((res, grip) => {
|
||||
let previewItems = getGripPreviewItems(grip);
|
||||
let allProps = previewItems.length > 0 ? getAllProps(previewItems) : [];
|
||||
return [...res, grip, grip.class, ...allProps];
|
||||
}, []);
|
||||
|
||||
// Remove from list of opened groups.
|
||||
let uiIndex = record.messagesUiById.indexOf(firstMessage);
|
||||
if (uiIndex >= 0) {
|
||||
record.messagesUiById = record.messagesUiById.delete(uiIndex);
|
||||
}
|
||||
// We are interested only in primitive props (to search for)
|
||||
// not in objects and undefined previews.
|
||||
result = result.filter(grip =>
|
||||
typeof grip != "object" &&
|
||||
typeof grip != "undefined"
|
||||
);
|
||||
|
||||
// Remove from list of tables.
|
||||
if (record.messagesTableDataById.has(firstMessage.id)) {
|
||||
record.messagesTableDataById = record.messagesTableDataById.delete(firstMessage.id);
|
||||
}
|
||||
|
||||
// Remove from list of parent groups.
|
||||
if (record.groupsById.has(firstMessage.id)) {
|
||||
record.groupsById = record.groupsById.delete(firstMessage.id);
|
||||
}
|
||||
|
||||
let removedMessages = [firstMessage];
|
||||
|
||||
// Remove all children. This loop assumes that children of removed
|
||||
// group immediately follows the group. We use recursion since
|
||||
// there might be inner groups.
|
||||
let message = record.messagesById.first();
|
||||
while (message.groupId == firstMessage.id) {
|
||||
removedMessages.push(...removeFirstMessage(record));
|
||||
message = record.messagesById.first();
|
||||
}
|
||||
|
||||
// Return array with all removed messages.
|
||||
return removedMessages;
|
||||
return [...new Set(result)];
|
||||
}
|
||||
|
||||
exports.messages = messages;
|
||||
|
|
|
@ -5,42 +5,14 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
|
||||
const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
|
||||
const { getGripPreviewItems } = require("devtools/client/shared/components/reps/reps");
|
||||
const { getSourceNames } = require("devtools/client/shared/source-utils");
|
||||
const {
|
||||
MESSAGE_TYPE,
|
||||
MESSAGE_SOURCE
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
|
||||
function getAllMessages(state) {
|
||||
let messages = getAllMessagesById(state);
|
||||
let filters = getAllFilters(state);
|
||||
|
||||
let groups = getAllGroupsById(state);
|
||||
let messagesUI = getAllMessagesUiById(state);
|
||||
|
||||
return messages.filter(message => {
|
||||
return (
|
||||
isInOpenedGroup(message, groups, messagesUI)
|
||||
&& (
|
||||
isUnfilterable(message)
|
||||
|| (
|
||||
matchLevelFilters(message, filters)
|
||||
&& matchCssFilters(message, filters)
|
||||
&& matchNetworkFilters(message, filters)
|
||||
&& matchSearchFilters(message, filters)
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function getAllMessagesById(state) {
|
||||
return state.messages.messagesById;
|
||||
}
|
||||
|
||||
function getMessage(state, id) {
|
||||
return getAllMessagesById(state).get(id);
|
||||
}
|
||||
|
||||
function getAllMessagesUiById(state) {
|
||||
return state.messages.messagesUiById;
|
||||
}
|
||||
|
@ -57,184 +29,16 @@ function getCurrentGroup(state) {
|
|||
return state.messages.currentGroup;
|
||||
}
|
||||
|
||||
function isUnfilterable(message) {
|
||||
return [
|
||||
MESSAGE_TYPE.COMMAND,
|
||||
MESSAGE_TYPE.RESULT,
|
||||
MESSAGE_TYPE.START_GROUP,
|
||||
MESSAGE_TYPE.START_GROUP_COLLAPSED,
|
||||
].includes(message.type);
|
||||
function getVisibleMessages(state) {
|
||||
return state.messages.visibleMessages.map(id => getMessage(state, id));
|
||||
}
|
||||
|
||||
function isInOpenedGroup(message, groups, messagesUI) {
|
||||
return !message.groupId
|
||||
|| (
|
||||
!isGroupClosed(message.groupId, messagesUI)
|
||||
&& !hasClosedParentGroup(groups.get(message.groupId), messagesUI)
|
||||
);
|
||||
}
|
||||
|
||||
function hasClosedParentGroup(group, messagesUI) {
|
||||
return group.some(groupId => isGroupClosed(groupId, messagesUI));
|
||||
}
|
||||
|
||||
function isGroupClosed(groupId, messagesUI) {
|
||||
return messagesUI.includes(groupId) === false;
|
||||
}
|
||||
|
||||
function matchLevelFilters(message, filters) {
|
||||
return filters.get(message.level) === true;
|
||||
}
|
||||
|
||||
function matchNetworkFilters(message, filters) {
|
||||
return (
|
||||
message.source !== MESSAGE_SOURCE.NETWORK
|
||||
|| (filters.get("net") === true && message.isXHR === false)
|
||||
|| (filters.get("netxhr") === true && message.isXHR === true)
|
||||
);
|
||||
}
|
||||
|
||||
function matchCssFilters(message, filters) {
|
||||
return (
|
||||
message.source != MESSAGE_SOURCE.CSS
|
||||
|| filters.get("css") === true
|
||||
);
|
||||
}
|
||||
|
||||
function matchSearchFilters(message, filters) {
|
||||
let text = filters.text || "";
|
||||
return (
|
||||
text === ""
|
||||
// Look for a match in parameters.
|
||||
|| isTextInParameters(text, message.parameters)
|
||||
// Look for a match in location.
|
||||
|| isTextInFrame(text, message.frame)
|
||||
// Look for a match in net events.
|
||||
|| isTextInNetEvent(text, message.request)
|
||||
// Look for a match in stack-trace.
|
||||
|| isTextInStackTrace(text, message.stacktrace)
|
||||
// Look for a match in messageText.
|
||||
|| isTextInMessageText(text, message.messageText)
|
||||
// Look for a match in notes.
|
||||
|| isTextInNotes(text, message.notes)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in provided stack frame.
|
||||
*/
|
||||
function isTextInFrame(text, frame) {
|
||||
if (!frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { short } = getSourceNames(frame.source);
|
||||
return `${short}:${frame.line}:${frame.column}`
|
||||
.toLocaleLowerCase()
|
||||
.includes(text.toLocaleLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in provided parameters.
|
||||
*/
|
||||
function isTextInParameters(text, parameters) {
|
||||
if (!parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
text = text.toLocaleLowerCase();
|
||||
return getAllProps(parameters).find(prop =>
|
||||
(prop + "").toLocaleLowerCase().includes(text)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in provided net event grip.
|
||||
*/
|
||||
function isTextInNetEvent(text, request) {
|
||||
if (!request) {
|
||||
return false;
|
||||
}
|
||||
|
||||
text = text.toLocaleLowerCase();
|
||||
|
||||
let method = request.method.toLocaleLowerCase();
|
||||
let url = request.url.toLocaleLowerCase();
|
||||
return method.includes(text) || url.includes(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in provided stack trace.
|
||||
*/
|
||||
function isTextInStackTrace(text, stacktrace) {
|
||||
if (!Array.isArray(stacktrace)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// isTextInFrame expect the properties of the frame object to be in the same
|
||||
// order they are rendered in the Frame component.
|
||||
return stacktrace.some(frame => isTextInFrame(text, {
|
||||
functionName: frame.functionName || l10n.getStr("stacktrace.anonymousFunction"),
|
||||
filename: frame.filename,
|
||||
lineNumber: frame.lineNumber,
|
||||
columnNumber: frame.columnNumber
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in `messageText` field.
|
||||
*/
|
||||
function isTextInMessageText(text, messageText) {
|
||||
if (!messageText) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return messageText.toLocaleLowerCase().includes(text.toLocaleLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in notes.
|
||||
*/
|
||||
function isTextInNotes(text, notes) {
|
||||
if (!Array.isArray(notes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return notes.some(note =>
|
||||
// Look for a match in location.
|
||||
isTextInFrame(text, note.frame) ||
|
||||
// Look for a match in messageBody.
|
||||
(note.messageBody &&
|
||||
note.messageBody.toLocaleLowerCase()
|
||||
.includes(text.toLocaleLowerCase()))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flat array of all the grips and their properties.
|
||||
*
|
||||
* @param {Array} Grips
|
||||
* @return {Array} Flat array of the grips and their properties.
|
||||
*/
|
||||
function getAllProps(grips) {
|
||||
let result = grips.reduce((res, grip) => {
|
||||
let previewItems = getGripPreviewItems(grip);
|
||||
let allProps = previewItems.length > 0 ? getAllProps(previewItems) : [];
|
||||
return [...res, grip, grip.class, ...allProps];
|
||||
}, []);
|
||||
|
||||
// We are interested only in primitive props (to search for)
|
||||
// not in objects and undefined previews.
|
||||
result = result.filter(grip =>
|
||||
typeof grip != "object" &&
|
||||
typeof grip != "undefined"
|
||||
);
|
||||
|
||||
return [...new Set(result)];
|
||||
}
|
||||
|
||||
exports.getAllMessages = getAllMessages;
|
||||
exports.getAllMessagesUiById = getAllMessagesUiById;
|
||||
exports.getAllMessagesTableDataById = getAllMessagesTableDataById;
|
||||
exports.getAllGroupsById = getAllGroupsById;
|
||||
exports.getCurrentGroup = getCurrentGroup;
|
||||
module.exports = {
|
||||
getMessage,
|
||||
getAllMessagesById,
|
||||
getAllMessagesUiById,
|
||||
getAllMessagesTableDataById,
|
||||
getAllGroupsById,
|
||||
getCurrentGroup,
|
||||
getVisibleMessages,
|
||||
};
|
||||
|
|
|
@ -8,7 +8,6 @@ const {PrefState} = require("devtools/client/webconsole/new-console-output/reduc
|
|||
const {UiState} = require("devtools/client/webconsole/new-console-output/reducers/ui");
|
||||
const {
|
||||
applyMiddleware,
|
||||
combineReducers,
|
||||
compose,
|
||||
createStore
|
||||
} = require("devtools/client/shared/vendor/redux");
|
||||
|
@ -23,11 +22,12 @@ const {
|
|||
const { reducers } = require("./reducers/index");
|
||||
const Services = require("Services");
|
||||
|
||||
function configureStore(hud) {
|
||||
function configureStore(hud, options = {}) {
|
||||
const logLimit = options.logLimit
|
||||
|| Math.max(Services.prefs.getIntPref("devtools.hud.loglimit"), 1);
|
||||
|
||||
const initialState = {
|
||||
prefs: new PrefState({
|
||||
logLimit: Math.max(Services.prefs.getIntPref("devtools.hud.loglimit"), 1),
|
||||
}),
|
||||
prefs: new PrefState({ logLimit }),
|
||||
filters: new FilterState({
|
||||
error: Services.prefs.getBoolPref(PREFS.FILTER.ERROR),
|
||||
warn: Services.prefs.getBoolPref(PREFS.FILTER.WARN),
|
||||
|
@ -44,12 +44,34 @@ function configureStore(hud) {
|
|||
};
|
||||
|
||||
return createStore(
|
||||
combineReducers(reducers),
|
||||
createRootReducer(),
|
||||
initialState,
|
||||
compose(applyMiddleware(thunk), enableActorReleaser(hud), enableBatching())
|
||||
);
|
||||
}
|
||||
|
||||
function createRootReducer() {
|
||||
return function rootReducer(state, action) {
|
||||
// We want to compute the new state for all properties except "messages".
|
||||
const newState = [...Object.entries(reducers)].reduce((res, [key, reducer]) => {
|
||||
if (key !== "messages") {
|
||||
res[key] = reducer(state[key], action);
|
||||
}
|
||||
return res;
|
||||
}, {});
|
||||
|
||||
return Object.assign(newState, {
|
||||
// specifically pass the updated filters and prefs state as additional arguments.
|
||||
messages: reducers.messages(
|
||||
state.messages,
|
||||
action,
|
||||
newState.filters,
|
||||
newState.prefs,
|
||||
),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A enhancer for the store to handle batched actions.
|
||||
*/
|
||||
|
|
|
@ -31,8 +31,8 @@ function setupActions() {
|
|||
/**
|
||||
* Prepare the store for use in testing.
|
||||
*/
|
||||
function setupStore(input, hud) {
|
||||
const store = configureStore(hud);
|
||||
function setupStore(input, hud, options) {
|
||||
const store = configureStore(hud, options);
|
||||
|
||||
// Add the messages from the input commands to the store.
|
||||
input.forEach((cmd) => {
|
||||
|
|
|
@ -16,19 +16,19 @@ add_task(function* () {
|
|||
let hud = toolbox.getCurrentPanel().hud;
|
||||
|
||||
const store = hud.ui.newConsoleOutput.getStore();
|
||||
// Adding loggin each time the store is modified in order to check
|
||||
// Adding logging each time the store is modified in order to check
|
||||
// the store state in case of failure.
|
||||
store.subscribe(() => {
|
||||
const messages = store.getState().messages.messagesById.toJS()
|
||||
.map(message => {
|
||||
return {
|
||||
const messages = store.getState().messages.messagesById
|
||||
.reduce(function (res, message) {
|
||||
res.push({
|
||||
id: message.id,
|
||||
type: message.type,
|
||||
parameters: message.parameters,
|
||||
messageText: message.messageText
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
return res;
|
||||
}, []);
|
||||
info("messages : " + JSON.stringify(messages));
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ const expect = require("expect");
|
|||
const actions = require("devtools/client/webconsole/new-console-output/actions/index");
|
||||
const { messageAdd } = require("devtools/client/webconsole/new-console-output/actions/index");
|
||||
const { ConsoleCommand } = require("devtools/client/webconsole/new-console-output/types");
|
||||
const { getAllMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const { getVisibleMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
|
||||
const { setupStore } = require("devtools/client/webconsole/new-console-output/test/helpers");
|
||||
const { MESSAGE_LEVEL } = require("devtools/client/webconsole/new-console-output/constants");
|
||||
|
@ -25,22 +25,22 @@ describe("Filtering", () => {
|
|||
beforeEach(() => {
|
||||
store = prepareBaseStore();
|
||||
store.dispatch(actions.filtersClear());
|
||||
numMessages = getAllMessages(store.getState()).size;
|
||||
numMessages = getVisibleMessages(store.getState()).length;
|
||||
});
|
||||
|
||||
describe("Level filter", () => {
|
||||
it("filters log messages", () => {
|
||||
store.dispatch(actions.filterToggle(MESSAGE_LEVEL.LOG));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages - 3);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages - 3);
|
||||
});
|
||||
|
||||
it("filters debug messages", () => {
|
||||
store.dispatch(actions.filterToggle(MESSAGE_LEVEL.DEBUG));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages - 1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages - 1);
|
||||
});
|
||||
|
||||
// @TODO add info stub
|
||||
|
@ -49,15 +49,15 @@ describe("Filtering", () => {
|
|||
it("filters warning messages", () => {
|
||||
store.dispatch(actions.filterToggle(MESSAGE_LEVEL.WARN));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages - 1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages - 1);
|
||||
});
|
||||
|
||||
it("filters error messages", () => {
|
||||
store.dispatch(actions.filterToggle(MESSAGE_LEVEL.ERROR));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages - 1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages - 1);
|
||||
});
|
||||
|
||||
it("filters css messages", () => {
|
||||
|
@ -66,52 +66,51 @@ describe("Filtering", () => {
|
|||
);
|
||||
store.dispatch(messageAdd(message));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages);
|
||||
|
||||
store.dispatch(actions.filterToggle("css"));
|
||||
messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages + 1);
|
||||
messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages + 1);
|
||||
});
|
||||
|
||||
it("filters xhr messages", () => {
|
||||
let message = stubPreparedMessages.get("XHR GET request");
|
||||
store.dispatch(messageAdd(message));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages);
|
||||
|
||||
store.dispatch(actions.filterToggle("netxhr"));
|
||||
messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages + 1);
|
||||
messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages + 1);
|
||||
});
|
||||
|
||||
it("filters network messages", () => {
|
||||
let message = stubPreparedMessages.get("GET request");
|
||||
store.dispatch(messageAdd(message));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages);
|
||||
|
||||
store.dispatch(actions.filterToggle("net"));
|
||||
messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages + 1);
|
||||
messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages + 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Text filter", () => {
|
||||
it("matches on value grips", () => {
|
||||
store.dispatch(actions.filterTextSet("danger"));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size - numUnfilterableMessages).toEqual(1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
});
|
||||
|
||||
it("matches unicode values", () => {
|
||||
store.dispatch(actions.filterTextSet("鼬"));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size - numUnfilterableMessages).toEqual(1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
});
|
||||
|
||||
it("matches locations", () => {
|
||||
|
@ -124,8 +123,8 @@ describe("Filtering", () => {
|
|||
|
||||
store.dispatch(actions.filterTextSet("search-location-test.js"));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size - numUnfilterableMessages).toEqual(1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
});
|
||||
|
||||
it("matches stacktrace functionName", () => {
|
||||
|
@ -134,8 +133,8 @@ describe("Filtering", () => {
|
|||
|
||||
store.dispatch(actions.filterTextSet("testStacktraceFiltering"));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size - numUnfilterableMessages).toEqual(1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
});
|
||||
|
||||
it("matches stacktrace location", () => {
|
||||
|
@ -151,16 +150,16 @@ describe("Filtering", () => {
|
|||
|
||||
store.dispatch(actions.filterTextSet("search-location-test.js:85:13"));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size - numUnfilterableMessages).toEqual(1);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
});
|
||||
|
||||
it("restores all messages once text is cleared", () => {
|
||||
store.dispatch(actions.filterTextSet("danger"));
|
||||
store.dispatch(actions.filterTextSet(""));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages);
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length).toEqual(numMessages);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -189,7 +188,7 @@ describe("Clear filters", () => {
|
|||
"net": false,
|
||||
"netxhr": true,
|
||||
"warn": true,
|
||||
"text": "foobar"
|
||||
"text": "foobar",
|
||||
});
|
||||
|
||||
store.dispatch(actions.filtersClear());
|
||||
|
@ -204,7 +203,7 @@ describe("Clear filters", () => {
|
|||
"net": false,
|
||||
"netxhr": false,
|
||||
"warn": true,
|
||||
"text": ""
|
||||
"text": "",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
"use strict";
|
||||
|
||||
const {
|
||||
getAllMessages,
|
||||
getAllMessagesUiById,
|
||||
getAllGroupsById,
|
||||
getAllMessagesById,
|
||||
getAllMessagesTableDataById,
|
||||
getAllMessagesUiById,
|
||||
getCurrentGroup,
|
||||
getVisibleMessages,
|
||||
} = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const {
|
||||
setupActions,
|
||||
|
@ -35,18 +37,16 @@ describe("Message reducer:", () => {
|
|||
const message = stubPreparedMessages.get("console.log('foobar', 'test')");
|
||||
dispatch(actions.messageAdd(packet));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
|
||||
expect(messages.first()).toEqual(message);
|
||||
});
|
||||
|
||||
it("increments repeat on a repeating message", () => {
|
||||
const { dispatch, getState } = setupStore([
|
||||
"console.log('foobar', 'test')",
|
||||
"console.log('foobar', 'test')"
|
||||
]);
|
||||
const key1 = "console.log('foobar', 'test')";
|
||||
const { dispatch, getState } = setupStore([key1, key1]);
|
||||
|
||||
const packet = clonePacket(stubPackets.get("console.log('foobar', 'test')"));
|
||||
const packet = clonePacket(stubPackets.get(key1));
|
||||
|
||||
// Repeat ID must be the same even if the timestamp is different.
|
||||
packet.message.timeStamp = 1;
|
||||
|
@ -54,26 +54,23 @@ describe("Message reducer:", () => {
|
|||
packet.message.timeStamp = 2;
|
||||
dispatch(actions.messageAdd(packet));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
|
||||
expect(messages.size).toBe(1);
|
||||
expect(messages.first().repeat).toBe(4);
|
||||
});
|
||||
|
||||
it("does not clobber a unique message", () => {
|
||||
const { dispatch, getState } = setupStore([
|
||||
"console.log('foobar', 'test')",
|
||||
"console.log('foobar', 'test')"
|
||||
]);
|
||||
const key1 = "console.log('foobar', 'test')";
|
||||
const { dispatch, getState } = setupStore([key1, key1]);
|
||||
|
||||
const packet = stubPackets.get("console.log('foobar', 'test')");
|
||||
const packet = stubPackets.get(key1);
|
||||
dispatch(actions.messageAdd(packet));
|
||||
|
||||
const packet2 = stubPackets.get("console.log(undefined)");
|
||||
dispatch(actions.messageAdd(packet2));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
|
||||
const messages = getAllMessagesById(getState());
|
||||
expect(messages.size).toBe(2);
|
||||
expect(messages.first().repeat).toBe(3);
|
||||
expect(messages.last().repeat).toBe(1);
|
||||
|
@ -84,7 +81,7 @@ describe("Message reducer:", () => {
|
|||
|
||||
dispatch(actions.messageAdd(stubPackets.get("console.clear()")));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
|
||||
expect(messages.size).toBe(1);
|
||||
expect(messages.first().parameters[0]).toBe("Console was cleared.");
|
||||
|
@ -93,13 +90,20 @@ describe("Message reducer:", () => {
|
|||
it("clears the messages list in response to MESSAGES_CLEAR action", () => {
|
||||
const { dispatch, getState } = setupStore([
|
||||
"console.log('foobar', 'test')",
|
||||
"console.log(undefined)"
|
||||
"console.log(undefined)",
|
||||
"console.table(['red', 'green', 'blue']);",
|
||||
"console.group('bar')",
|
||||
]);
|
||||
|
||||
dispatch(actions.messagesClear());
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
expect(messages.size).toBe(0);
|
||||
const state = getState();
|
||||
expect(getAllMessagesById(state).size).toBe(0);
|
||||
expect(getVisibleMessages(state).length).toBe(0);
|
||||
expect(getAllMessagesUiById(state).size).toBe(0);
|
||||
expect(getAllGroupsById(state).size).toBe(0);
|
||||
expect(getAllMessagesTableDataById(state).size).toBe(0);
|
||||
expect(getCurrentGroup(state)).toBe(null);
|
||||
});
|
||||
|
||||
it("properly limits number of messages", () => {
|
||||
|
@ -113,13 +117,13 @@ describe("Message reducer:", () => {
|
|||
dispatch(actions.messageAdd(packet));
|
||||
}
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
expect(messages.count()).toBe(logLimit);
|
||||
expect(messages.first().parameters[0]).toBe(`message num 3`);
|
||||
expect(messages.last().parameters[0]).toBe(`message num ${logLimit + 2}`);
|
||||
});
|
||||
|
||||
it("properly limits number of groups", () => {
|
||||
it("properly limits number of messages when there are nested groups", () => {
|
||||
const { dispatch, getState } = setupStore([]);
|
||||
|
||||
const logLimit = 1000;
|
||||
|
@ -128,23 +132,74 @@ describe("Message reducer:", () => {
|
|||
const packetGroup = clonePacket(stubPackets.get("console.group('bar')"));
|
||||
const packetGroupEnd = clonePacket(stubPackets.get("console.groupEnd()"));
|
||||
|
||||
packetGroup.message.arguments = [`group-1`];
|
||||
dispatch(actions.messageAdd(packetGroup));
|
||||
packetGroup.message.arguments = [`group-1-1`];
|
||||
dispatch(actions.messageAdd(packetGroup));
|
||||
packetGroup.message.arguments = [`group-1-1-1`];
|
||||
dispatch(actions.messageAdd(packetGroup));
|
||||
packet.message.arguments = [`message-in-group-1`];
|
||||
dispatch(actions.messageAdd(packet));
|
||||
packet.message.arguments = [`message-in-group-2`];
|
||||
dispatch(actions.messageAdd(packet));
|
||||
// Closing group-1-1-1
|
||||
dispatch(actions.messageAdd(packetGroupEnd));
|
||||
// Closing group-1-1
|
||||
dispatch(actions.messageAdd(packetGroupEnd));
|
||||
// Closing group-1
|
||||
dispatch(actions.messageAdd(packetGroupEnd));
|
||||
|
||||
for (let i = 0; i < logLimit; i++) {
|
||||
packet.message.arguments = [`message-${i}`];
|
||||
dispatch(actions.messageAdd(packet));
|
||||
}
|
||||
|
||||
const visibleMessages = getVisibleMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
|
||||
expect(messages.count()).toBe(logLimit);
|
||||
expect(visibleMessages.length).toBe(logLimit);
|
||||
expect(visibleMessages[0].parameters[0]).toBe(`message-0`);
|
||||
expect(visibleMessages[logLimit - 1].parameters[0]).toBe(`message-${logLimit - 1}`);
|
||||
|
||||
// The groups were cleaned up.
|
||||
const groups = getAllGroupsById(getState());
|
||||
expect(groups.count()).toBe(0);
|
||||
});
|
||||
|
||||
it("properly limits number of groups", () => {
|
||||
const logLimit = 100;
|
||||
const { dispatch, getState } = setupStore([], null, {logLimit});
|
||||
|
||||
const packet = clonePacket(stubPackets.get("console.log(undefined)"));
|
||||
const packetGroup = clonePacket(stubPackets.get("console.group('bar')"));
|
||||
const packetGroupEnd = clonePacket(stubPackets.get("console.groupEnd()"));
|
||||
|
||||
for (let i = 0; i < logLimit + 2; i++) {
|
||||
packet.message.arguments = [`message num ${i}`];
|
||||
dispatch(actions.messageAdd(packetGroup));
|
||||
packet.message.arguments = [`message-${i}-a`];
|
||||
dispatch(actions.messageAdd(packet));
|
||||
packet.message.arguments = [`message-${i}-b`];
|
||||
dispatch(actions.messageAdd(packet));
|
||||
dispatch(actions.messageAdd(packetGroupEnd));
|
||||
}
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
expect(messages.count()).toBe(logLimit * 2);
|
||||
expect(messages.get(1).parameters[0]).toBe(`message num 2`);
|
||||
expect(messages.last().parameters[0]).toBe(`message num ${logLimit + 1}`);
|
||||
const visibleMessages = getVisibleMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
// We should have three times the logLimit since each group has one message inside.
|
||||
expect(messages.count()).toBe(logLimit * 3);
|
||||
|
||||
// We should have logLimit number of groups
|
||||
const groups = getAllGroupsById(getState());
|
||||
expect(groups.count()).toBe(logLimit);
|
||||
|
||||
expect(visibleMessages[1].parameters[0]).toBe(`message-2-a`);
|
||||
expect(messages.last().parameters[0]).toBe(`message-${logLimit + 1}-b`);
|
||||
});
|
||||
|
||||
it("properly limits number of collapsed groups", () => {
|
||||
const { dispatch, getState } = setupStore([]);
|
||||
|
||||
const logLimit = 1000;
|
||||
const logLimit = 100;
|
||||
const { dispatch, getState } = setupStore([], null, {logLimit});
|
||||
|
||||
const packet = clonePacket(stubPackets.get("console.log(undefined)"));
|
||||
const packetGroupCollapsed = clonePacket(
|
||||
|
@ -152,16 +207,30 @@ describe("Message reducer:", () => {
|
|||
const packetGroupEnd = clonePacket(stubPackets.get("console.groupEnd()"));
|
||||
|
||||
for (let i = 0; i < logLimit + 2; i++) {
|
||||
packetGroupCollapsed.message.arguments = [`message num ${i}`];
|
||||
packetGroupCollapsed.message.arguments = [`group-${i}`];
|
||||
dispatch(actions.messageAdd(packetGroupCollapsed));
|
||||
packet.message.arguments = [`message-${i}-a`];
|
||||
dispatch(actions.messageAdd(packet));
|
||||
packet.message.arguments = [`message-${i}-b`];
|
||||
dispatch(actions.messageAdd(packet));
|
||||
dispatch(actions.messageAdd(packetGroupEnd));
|
||||
}
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
expect(messages.count()).toBe(logLimit);
|
||||
expect(messages.first().parameters[0]).toBe(`message num 2`);
|
||||
expect(messages.last().parameters[0]).toBe(`message num ${logLimit + 1}`);
|
||||
const messages = getAllMessagesById(getState());
|
||||
// We should have three times the logLimit since each group has two message inside.
|
||||
expect(messages.size).toBe(logLimit * 3);
|
||||
|
||||
// We should have logLimit number of groups
|
||||
const groups = getAllGroupsById(getState());
|
||||
expect(groups.count()).toBe(logLimit);
|
||||
|
||||
expect(messages.first().parameters[0]).toBe(`group-2`);
|
||||
expect(messages.last().parameters[0]).toBe(`message-${logLimit + 1}-b`);
|
||||
|
||||
const visibleMessages = getVisibleMessages(getState());
|
||||
expect(visibleMessages.length).toBe(logLimit);
|
||||
const lastVisibleMessage = visibleMessages[visibleMessages.length - 1];
|
||||
expect(lastVisibleMessage.parameters[0]).toBe(`group-${logLimit + 1}`);
|
||||
});
|
||||
|
||||
it("does not add null messages to the store", () => {
|
||||
|
@ -170,7 +239,7 @@ describe("Message reducer:", () => {
|
|||
const message = stubPackets.get("console.time('bar')");
|
||||
dispatch(actions.messageAdd(message));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
expect(messages.size).toBe(0);
|
||||
});
|
||||
|
||||
|
@ -180,7 +249,7 @@ describe("Message reducer:", () => {
|
|||
const packet = stubPackets.get("console.table('bar')");
|
||||
dispatch(actions.messageAdd(packet));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
const tableMessage = messages.last();
|
||||
expect(tableMessage.level).toEqual(MESSAGE_TYPE.LOG);
|
||||
});
|
||||
|
@ -191,7 +260,7 @@ describe("Message reducer:", () => {
|
|||
const message = stubPackets.get("console.group('bar')");
|
||||
dispatch(actions.messageAdd(message));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
expect(messages.size).toBe(1);
|
||||
});
|
||||
|
||||
|
@ -204,7 +273,7 @@ describe("Message reducer:", () => {
|
|||
const packet = stubPackets.get("console.log('foobar', 'test')");
|
||||
dispatch(actions.messageAdd(packet));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
expect(messages.size).toBe(2);
|
||||
expect(messages.last().groupId).toBe(messages.first().id);
|
||||
});
|
||||
|
@ -215,7 +284,7 @@ describe("Message reducer:", () => {
|
|||
const message = stubPackets.get("console.groupEnd('bar')");
|
||||
dispatch(actions.messageAdd(message));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
expect(messages.size).toBe(0);
|
||||
});
|
||||
|
||||
|
@ -228,8 +297,8 @@ describe("Message reducer:", () => {
|
|||
dispatch(actions.messageAdd(
|
||||
stubPackets.get("console.log('foobar', 'test')")));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
expect(messages.size).toBe(1);
|
||||
const messages = getVisibleMessages(getState());
|
||||
expect(messages.length).toBe(1);
|
||||
});
|
||||
|
||||
it("adds console.dirxml call as console.log", () => {
|
||||
|
@ -238,7 +307,7 @@ describe("Message reducer:", () => {
|
|||
const packet = stubPackets.get("console.dirxml(window)");
|
||||
dispatch(actions.messageAdd(packet));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
const dirxmlMessage = messages.last();
|
||||
expect(dirxmlMessage.level).toEqual(MESSAGE_TYPE.LOG);
|
||||
});
|
||||
|
@ -251,7 +320,7 @@ describe("Message reducer:", () => {
|
|||
const message = stubPackets.get("console.trace()");
|
||||
dispatch(actions.messageAdd(message));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
const messagesUi = getAllMessagesUiById(getState());
|
||||
expect(messagesUi.size).toBe(1);
|
||||
expect(messagesUi.first()).toBe(messages.first().id);
|
||||
|
@ -278,7 +347,7 @@ describe("Message reducer:", () => {
|
|||
const message = stubPackets.get("console.group('bar')");
|
||||
dispatch(actions.messageAdd(message));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
const messagesUi = getAllMessagesUiById(getState());
|
||||
expect(messagesUi.size).toBe(1);
|
||||
expect(messagesUi.first()).toBe(messages.first().id);
|
||||
|
@ -302,7 +371,7 @@ describe("Message reducer:", () => {
|
|||
const packet = stubPackets.get("console.group('bar')");
|
||||
dispatch(actions.messageAdd(packet));
|
||||
|
||||
const messages = getAllMessages(getState());
|
||||
const messages = getAllMessagesById(getState());
|
||||
const currentGroup = getCurrentGroup(getState());
|
||||
expect(currentGroup).toBe(messages.first().id);
|
||||
});
|
||||
|
@ -313,19 +382,19 @@ describe("Message reducer:", () => {
|
|||
"console.groupCollapsed('foo')"
|
||||
]);
|
||||
|
||||
let messages = getAllMessages(getState());
|
||||
let messages = getAllMessagesById(getState());
|
||||
let currentGroup = getCurrentGroup(getState());
|
||||
expect(currentGroup).toBe(messages.last().id);
|
||||
|
||||
const endFooPacket = stubPackets.get("console.groupEnd('foo')");
|
||||
dispatch(actions.messageAdd(endFooPacket));
|
||||
messages = getAllMessages(getState());
|
||||
messages = getAllMessagesById(getState());
|
||||
currentGroup = getCurrentGroup(getState());
|
||||
expect(currentGroup).toBe(messages.first().id);
|
||||
|
||||
const endBarPacket = stubPackets.get("console.groupEnd('bar')");
|
||||
dispatch(actions.messageAdd(endBarPacket));
|
||||
messages = getAllMessages(getState());
|
||||
messages = getAllMessagesById(getState());
|
||||
currentGroup = getCurrentGroup(getState());
|
||||
expect(currentGroup).toBe(null);
|
||||
});
|
||||
|
@ -349,7 +418,7 @@ describe("Message reducer:", () => {
|
|||
const barPacket = stubPackets.get("console.group('bar')");
|
||||
dispatch(actions.messageAdd(barPacket));
|
||||
|
||||
let messages = getAllMessages(getState());
|
||||
let messages = getAllMessagesById(getState());
|
||||
let groupsById = getAllGroupsById(getState());
|
||||
expect(groupsById.size).toBe(1);
|
||||
expect(groupsById.has(messages.first().id)).toBe(true);
|
||||
|
@ -357,7 +426,7 @@ describe("Message reducer:", () => {
|
|||
|
||||
const fooPacket = stubPackets.get("console.groupCollapsed('foo')");
|
||||
dispatch(actions.messageAdd(fooPacket));
|
||||
messages = getAllMessages(getState());
|
||||
messages = getAllMessagesById(getState());
|
||||
groupsById = getAllGroupsById(getState());
|
||||
expect(groupsById.size).toBe(2);
|
||||
expect(groupsById.has(messages.last().id)).toBe(true);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
const expect = require("expect");
|
||||
|
||||
const actions = require("devtools/client/webconsole/new-console-output/actions/index");
|
||||
const { getAllMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const { getVisibleMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const { setupStore } = require("devtools/client/webconsole/new-console-output/test/helpers");
|
||||
|
||||
describe("Searching in grips", () => {
|
||||
|
@ -20,42 +20,42 @@ describe("Searching in grips", () => {
|
|||
describe("Search in table & array & object props", () => {
|
||||
it("matches on value grips", () => {
|
||||
store.dispatch(actions.filterTextSet("red"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(3);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Search in object value", () => {
|
||||
it("matches on value grips", () => {
|
||||
store.dispatch(actions.filterTextSet("redValue"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(1);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Search in regex", () => {
|
||||
it("matches on value grips", () => {
|
||||
store.dispatch(actions.filterTextSet("a.b.c"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(1);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Search in map values", () => {
|
||||
it("matches on value grips", () => {
|
||||
store.dispatch(actions.filterTextSet("value1"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(1);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Search in map keys", () => {
|
||||
it("matches on value grips", () => {
|
||||
store.dispatch(actions.filterTextSet("key1"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(1);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Search in text", () => {
|
||||
it("matches on value grips", () => {
|
||||
store.dispatch(actions.filterTextSet("myobj"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(1);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -63,19 +63,19 @@ describe("Searching in grips", () => {
|
|||
it("matches on network messages", () => {
|
||||
store.dispatch(actions.filterToggle("net"));
|
||||
store.dispatch(actions.filterTextSet("get"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(1);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Search in frame", () => {
|
||||
it("matches on file name", () => {
|
||||
store.dispatch(actions.filterTextSet("test-console-api.html:1:27"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(7);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(7);
|
||||
});
|
||||
|
||||
it("do not match on full url", () => {
|
||||
store.dispatch(actions.filterTextSet("http://example.com/browser/devtools"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(0);
|
||||
expect(getVisibleMessages(store.getState()).length).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const promise = require("promise");
|
||||
const {AddonManager} = require("resource://gre/modules/AddonManager.jsm");
|
||||
const Services = require("Services");
|
||||
const {getJSON} = require("devtools/client/shared/getjson");
|
||||
|
@ -51,24 +50,24 @@ AddonManager.addAddonListener(addonsListener);
|
|||
var GetAvailableAddons_promise = null;
|
||||
var GetAvailableAddons = exports.GetAvailableAddons = function () {
|
||||
if (!GetAvailableAddons_promise) {
|
||||
let deferred = promise.defer();
|
||||
GetAvailableAddons_promise = deferred.promise;
|
||||
let addons = {
|
||||
simulators: [],
|
||||
adb: null
|
||||
};
|
||||
getJSON(ADDONS_URL).then(json => {
|
||||
for (let stability in json) {
|
||||
for (let version of json[stability]) {
|
||||
addons.simulators.push(new SimulatorAddon(stability, version));
|
||||
GetAvailableAddons_promise = new Promise((resolve, reject) => {
|
||||
let addons = {
|
||||
simulators: [],
|
||||
adb: null
|
||||
};
|
||||
getJSON(ADDONS_URL).then(json => {
|
||||
for (let stability in json) {
|
||||
for (let version of json[stability]) {
|
||||
addons.simulators.push(new SimulatorAddon(stability, version));
|
||||
}
|
||||
}
|
||||
}
|
||||
addons.adb = new ADBAddon();
|
||||
addons.adapters = new AdaptersAddon();
|
||||
deferred.resolve(addons);
|
||||
}, e => {
|
||||
GetAvailableAddons_promise = null;
|
||||
deferred.reject(e);
|
||||
addons.adb = new ADBAddon();
|
||||
addons.adapters = new AdaptersAddon();
|
||||
resolve(addons);
|
||||
}, e => {
|
||||
GetAvailableAddons_promise = null;
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
return GetAvailableAddons_promise;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
const {Cu} = require("chrome");
|
||||
|
||||
const promise = require("promise");
|
||||
const {TargetFactory} = require("devtools/client/framework/target");
|
||||
const Services = require("Services");
|
||||
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
|
@ -277,7 +276,7 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
reloadTab: function () {
|
||||
if (this.selectedProject && this.selectedProject.type != "tab") {
|
||||
return promise.reject("tried to reload non-tab project");
|
||||
return Promise.reject("tried to reload non-tab project");
|
||||
}
|
||||
return this.getTarget().then(target => {
|
||||
target.activeTab.reload();
|
||||
|
@ -313,7 +312,7 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
let app = this._getProjectFront(this.selectedProject);
|
||||
if (!app) {
|
||||
return promise.reject("Can't find app front for selected project");
|
||||
return Promise.reject("Can't find app front for selected project");
|
||||
}
|
||||
|
||||
return Task.spawn(function* () {
|
||||
|
@ -325,9 +324,9 @@ var AppManager = exports.AppManager = {
|
|||
try {
|
||||
return yield app.getTarget();
|
||||
} catch (e) {}
|
||||
let deferred = promise.defer();
|
||||
setTimeout(deferred.resolve, 500);
|
||||
yield deferred.promise;
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, 500);
|
||||
});
|
||||
}
|
||||
|
||||
AppManager.reportError("error_cantConnectToApp", app.manifest.manifestURL);
|
||||
|
@ -460,36 +459,36 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
if (this.connected && this.selectedRuntime === runtime) {
|
||||
// Already connected
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let deferred = promise.defer();
|
||||
let deferred = new Promise((resolve, reject) => {
|
||||
this.disconnectRuntime().then(() => {
|
||||
this.selectedRuntime = runtime;
|
||||
|
||||
this.disconnectRuntime().then(() => {
|
||||
this.selectedRuntime = runtime;
|
||||
|
||||
let onConnectedOrDisconnected = () => {
|
||||
this.connection.off(Connection.Events.CONNECTED, onConnectedOrDisconnected);
|
||||
this.connection.off(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
|
||||
if (this.connected) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject();
|
||||
let onConnectedOrDisconnected = () => {
|
||||
this.connection.off(Connection.Events.CONNECTED, onConnectedOrDisconnected);
|
||||
this.connection.off(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
|
||||
if (this.connected) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
this.connection.on(Connection.Events.CONNECTED, onConnectedOrDisconnected);
|
||||
this.connection.on(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
|
||||
try {
|
||||
// Reset the connection's state to defaults
|
||||
this.connection.resetOptions();
|
||||
// Only watch for errors here. Final resolution occurs above, once
|
||||
// we've reached the CONNECTED state.
|
||||
this.selectedRuntime.connect(this.connection)
|
||||
.then(null, e => reject(e));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
this.connection.on(Connection.Events.CONNECTED, onConnectedOrDisconnected);
|
||||
this.connection.on(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
|
||||
try {
|
||||
// Reset the connection's state to defaults
|
||||
this.connection.resetOptions();
|
||||
// Only watch for errors here. Final resolution occurs above, once
|
||||
// we've reached the CONNECTED state.
|
||||
this.selectedRuntime.connect(this.connection)
|
||||
.then(null, e => deferred.reject(e));
|
||||
} catch (e) {
|
||||
deferred.reject(e);
|
||||
}
|
||||
}, deferred.reject);
|
||||
}, reject);
|
||||
});
|
||||
|
||||
// Record connection result in telemetry
|
||||
let logResult = result => {
|
||||
|
@ -499,10 +498,10 @@ var AppManager = exports.AppManager = {
|
|||
"_CONNECTION_RESULT", result);
|
||||
}
|
||||
};
|
||||
deferred.promise.then(() => logResult(true), () => logResult(false));
|
||||
deferred.then(() => logResult(true), () => logResult(false));
|
||||
|
||||
// If successful, record connection time in telemetry
|
||||
deferred.promise.then(() => {
|
||||
deferred.then(() => {
|
||||
const timerId = "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS";
|
||||
this._telemetry.startTimer(timerId);
|
||||
this.connection.once(Connection.Events.STATUS_CHANGED, () => {
|
||||
|
@ -514,7 +513,7 @@ var AppManager = exports.AppManager = {
|
|||
// Bug 1121100 may find a better way to silence these.
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
return deferred;
|
||||
},
|
||||
|
||||
_recordRuntimeInfo: Task.async(function* () {
|
||||
|
@ -570,17 +569,18 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
disconnectRuntime: function () {
|
||||
if (!this.connected) {
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
}
|
||||
let deferred = promise.defer();
|
||||
this.connection.once(Connection.Events.DISCONNECTED, () => deferred.resolve());
|
||||
this.connection.disconnect();
|
||||
return deferred.promise;
|
||||
|
||||
return new Promise(resolve => {
|
||||
this.connection.once(Connection.Events.DISCONNECTED, () => resolve());
|
||||
this.connection.disconnect();
|
||||
});
|
||||
},
|
||||
|
||||
launchRuntimeApp: function () {
|
||||
if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
|
||||
return promise.reject("attempting to launch a non-runtime app");
|
||||
return Promise.reject("attempting to launch a non-runtime app");
|
||||
}
|
||||
let app = this._getProjectFront(this.selectedProject);
|
||||
return app.launch();
|
||||
|
@ -588,7 +588,7 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
launchOrReloadRuntimeApp: function () {
|
||||
if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
|
||||
return promise.reject("attempting to launch / reload a non-runtime app");
|
||||
return Promise.reject("attempting to launch / reload a non-runtime app");
|
||||
}
|
||||
let app = this._getProjectFront(this.selectedProject);
|
||||
if (!app.running) {
|
||||
|
@ -607,17 +607,17 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
if (!project || (project.type != "packaged" && project.type != "hosted")) {
|
||||
console.error("Can't install project. Unknown type of project.");
|
||||
return promise.reject("Can't install");
|
||||
return Promise.reject("Can't install");
|
||||
}
|
||||
|
||||
if (!this._listTabsResponse) {
|
||||
this.reportError("error_cantInstallNotFullyConnected");
|
||||
return promise.reject("Can't install");
|
||||
return Promise.reject("Can't install");
|
||||
}
|
||||
|
||||
if (!this._appsFront) {
|
||||
console.error("Runtime doesn't have a webappsActor");
|
||||
return promise.reject("Can't install");
|
||||
return Promise.reject("Can't install");
|
||||
}
|
||||
|
||||
return Task.spawn(function* () {
|
||||
|
@ -635,7 +635,7 @@ var AppManager = exports.AppManager = {
|
|||
let installPromise;
|
||||
|
||||
if (project.type != "packaged" && project.type != "hosted") {
|
||||
return promise.reject("Don't know how to install project");
|
||||
return Promise.reject("Don't know how to install project");
|
||||
}
|
||||
|
||||
let response;
|
||||
|
@ -674,15 +674,16 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
let {app} = response;
|
||||
if (!app.running) {
|
||||
let deferred = promise.defer();
|
||||
self.on("app-manager-update", function onUpdate(event, what) {
|
||||
if (what == "project-started") {
|
||||
self.off("app-manager-update", onUpdate);
|
||||
deferred.resolve();
|
||||
}
|
||||
let deferred = new Promise(resolve => {
|
||||
self.on("app-manager-update", function onUpdate(event, what) {
|
||||
if (what == "project-started") {
|
||||
self.off("app-manager-update", onUpdate);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
yield app.launch();
|
||||
yield deferred.promise;
|
||||
yield deferred;
|
||||
} else {
|
||||
yield app.reload();
|
||||
}
|
||||
|
@ -698,7 +699,7 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
validateAndUpdateProject: function (project) {
|
||||
if (!project) {
|
||||
return promise.reject();
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return Task.spawn(function* () {
|
||||
|
@ -823,7 +824,7 @@ var AppManager = exports.AppManager = {
|
|||
|
||||
writeManifest: function (project) {
|
||||
if (project.type != "packaged") {
|
||||
return promise.reject("Not a packaged app");
|
||||
return Promise.reject("Not a packaged app");
|
||||
}
|
||||
|
||||
if (!project.manifest) {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
const promise = require("promise");
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
|
@ -21,145 +20,135 @@ const IDB = {
|
|||
databaseName: "AppProjects",
|
||||
|
||||
open: function () {
|
||||
let deferred = promise.defer();
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = indexedDB.open(IDB.databaseName, 5);
|
||||
request.onerror = function (event) {
|
||||
reject("Unable to open AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
request.onupgradeneeded = function (event) {
|
||||
let db = event.target.result;
|
||||
db.createObjectStore("projects", { keyPath: "location" });
|
||||
};
|
||||
|
||||
let request = indexedDB.open(IDB.databaseName, 5);
|
||||
request.onerror = function (event) {
|
||||
deferred.reject("Unable to open AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
request.onupgradeneeded = function (event) {
|
||||
let db = event.target.result;
|
||||
db.createObjectStore("projects", { keyPath: "location" });
|
||||
};
|
||||
request.onsuccess = function () {
|
||||
let db = IDB._db = request.result;
|
||||
let objectStore = db.transaction("projects").objectStore("projects");
|
||||
let projects = [];
|
||||
let toRemove = [];
|
||||
objectStore.openCursor().onsuccess = function (event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor.value.location) {
|
||||
|
||||
request.onsuccess = function () {
|
||||
let db = IDB._db = request.result;
|
||||
let objectStore = db.transaction("projects").objectStore("projects");
|
||||
let projects = [];
|
||||
let toRemove = [];
|
||||
objectStore.openCursor().onsuccess = function (event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor.value.location) {
|
||||
|
||||
// We need to make sure this object has a `.location` property.
|
||||
// The UI depends on this property.
|
||||
// This should not be needed as we make sure to register valid
|
||||
// projects, but in the past (before bug 924568), we might have
|
||||
// registered invalid objects.
|
||||
// We need to make sure this object has a `.location` property.
|
||||
// The UI depends on this property.
|
||||
// This should not be needed as we make sure to register valid
|
||||
// projects, but in the past (before bug 924568), we might have
|
||||
// registered invalid objects.
|
||||
|
||||
|
||||
// We also want to make sure the location is valid.
|
||||
// If the location doesn't exist, we remove the project.
|
||||
// We also want to make sure the location is valid.
|
||||
// If the location doesn't exist, we remove the project.
|
||||
|
||||
try {
|
||||
let file = FileUtils.File(cursor.value.location);
|
||||
if (file.exists()) {
|
||||
projects.push(cursor.value);
|
||||
} else {
|
||||
toRemove.push(cursor.value.location);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH) {
|
||||
// A URL
|
||||
projects.push(cursor.value);
|
||||
try {
|
||||
let file = FileUtils.File(cursor.value.location);
|
||||
if (file.exists()) {
|
||||
projects.push(cursor.value);
|
||||
} else {
|
||||
toRemove.push(cursor.value.location);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH) {
|
||||
// A URL
|
||||
projects.push(cursor.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.continue();
|
||||
} else {
|
||||
let removePromises = [];
|
||||
for (let location of toRemove) {
|
||||
removePromises.push(IDB.remove(location));
|
||||
}
|
||||
Promise.all(removePromises).then(() => {
|
||||
resolve(projects);
|
||||
});
|
||||
}
|
||||
cursor.continue();
|
||||
} else {
|
||||
let removePromises = [];
|
||||
for (let location of toRemove) {
|
||||
removePromises.push(IDB.remove(location));
|
||||
}
|
||||
promise.all(removePromises).then(() => {
|
||||
deferred.resolve(projects);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
},
|
||||
|
||||
add: function (project) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
if (!project.location) {
|
||||
// We need to make sure this object has a `.location` property.
|
||||
deferred.reject("Missing location property on project object.");
|
||||
} else {
|
||||
let transaction = IDB._db.transaction(["projects"], "readwrite");
|
||||
let objectStore = transaction.objectStore("projects");
|
||||
let request = objectStore.add(project);
|
||||
request.onerror = function (event) {
|
||||
deferred.reject("Unable to add project to the AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
request.onsuccess = function () {
|
||||
deferred.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!project.location) {
|
||||
// We need to make sure this object has a `.location` property.
|
||||
reject("Missing location property on project object.");
|
||||
} else {
|
||||
let transaction = IDB._db.transaction(["projects"], "readwrite");
|
||||
let objectStore = transaction.objectStore("projects");
|
||||
let request = objectStore.add(project);
|
||||
request.onerror = function (event) {
|
||||
reject("Unable to add project to the AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
request.onsuccess = function () {
|
||||
resolve();
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
update: function (project) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
var transaction = IDB._db.transaction(["projects"], "readwrite");
|
||||
var objectStore = transaction.objectStore("projects");
|
||||
var request = objectStore.put(project);
|
||||
request.onerror = function (event) {
|
||||
deferred.reject("Unable to update project to the AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
request.onsuccess = function () {
|
||||
deferred.resolve();
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
return new Promise((resolve, reject) => {
|
||||
var transaction = IDB._db.transaction(["projects"], "readwrite");
|
||||
var objectStore = transaction.objectStore("projects");
|
||||
var request = objectStore.put(project);
|
||||
request.onerror = function (event) {
|
||||
reject("Unable to update project to the AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
request.onsuccess = function () {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
remove: function (location) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let request = IDB._db.transaction(["projects"], "readwrite")
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = IDB._db.transaction(["projects"], "readwrite")
|
||||
.objectStore("projects")
|
||||
.delete(location);
|
||||
request.onsuccess = function (event) {
|
||||
deferred.resolve();
|
||||
};
|
||||
request.onerror = function () {
|
||||
deferred.reject("Unable to delete project to the AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
request.onsuccess = function (event) {
|
||||
resolve();
|
||||
};
|
||||
request.onerror = function () {
|
||||
reject("Unable to delete project to the AppProjects indexedDB: " +
|
||||
this.error.name + " - " + this.error.message);
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var loadDeferred = promise.defer();
|
||||
|
||||
loadDeferred.resolve(IDB.open().then(function (projects) {
|
||||
var loadDeferred = IDB.open().then(function (projects) {
|
||||
AppProjects.projects = projects;
|
||||
AppProjects.emit("ready", projects);
|
||||
}));
|
||||
});
|
||||
|
||||
const AppProjects = {
|
||||
load: function () {
|
||||
return loadDeferred.promise;
|
||||
return loadDeferred;
|
||||
},
|
||||
|
||||
addPackaged: function (folder) {
|
||||
let file = FileUtils.File(folder.path);
|
||||
if (!file.exists()) {
|
||||
return promise.reject("path doesn't exist");
|
||||
return Promise.reject("path doesn't exist");
|
||||
}
|
||||
let existingProject = this.get(folder.path);
|
||||
if (existingProject) {
|
||||
return promise.reject("Already added");
|
||||
return Promise.reject("Already added");
|
||||
}
|
||||
let project = {
|
||||
type: "packaged",
|
||||
|
@ -182,7 +171,7 @@ const AppProjects = {
|
|||
addHosted: function (manifestURL) {
|
||||
let existingProject = this.get(manifestURL);
|
||||
if (existingProject) {
|
||||
return promise.reject("Already added");
|
||||
return Promise.reject("Already added");
|
||||
}
|
||||
let project = {
|
||||
type: "hosted",
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
"use strict";
|
||||
|
||||
var {Ci, Cu, CC} = require("chrome");
|
||||
const promise = require("promise");
|
||||
|
||||
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
const Services = require("Services");
|
||||
|
@ -64,46 +63,44 @@ AppValidator.prototype._getPackagedManifestURL = function () {
|
|||
};
|
||||
|
||||
AppValidator.checkManifest = function (manifestURL) {
|
||||
let deferred = promise.defer();
|
||||
let error;
|
||||
return new Promise((resolve, reject) => {
|
||||
let error;
|
||||
|
||||
let req = new XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
let req = new XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
|
||||
try {
|
||||
req.open("GET", manifestURL, true);
|
||||
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.invalidManifestURL", [manifestURL], 1);
|
||||
deferred.reject(error);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
req.onload = function () {
|
||||
let manifest = null;
|
||||
try {
|
||||
manifest = JSON.parse(req.responseText);
|
||||
req.open("GET", manifestURL, true);
|
||||
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2);
|
||||
deferred.reject(error);
|
||||
error = strings.formatStringFromName("validator.invalidManifestURL", [manifestURL], 1);
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
deferred.resolve({manifest, manifestURL});
|
||||
};
|
||||
req.onload = function () {
|
||||
let manifest = null;
|
||||
try {
|
||||
manifest = JSON.parse(req.responseText);
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2);
|
||||
reject(error);
|
||||
}
|
||||
|
||||
req.onerror = function () {
|
||||
error = strings.formatStringFromName("validator.noAccessManifestURL", [req.statusText, manifestURL], 2);
|
||||
deferred.reject(error);
|
||||
};
|
||||
resolve({manifest, manifestURL});
|
||||
};
|
||||
|
||||
try {
|
||||
req.send(null);
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.noAccessManifestURL", [e, manifestURL], 2);
|
||||
deferred.reject(error);
|
||||
}
|
||||
req.onerror = function () {
|
||||
error = strings.formatStringFromName("validator.noAccessManifestURL", [req.statusText, manifestURL], 2);
|
||||
reject(error);
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
try {
|
||||
req.send(null);
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.noAccessManifestURL", [e, manifestURL], 2);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.findManifestAtOrigin = function (manifestURL) {
|
||||
|
@ -112,16 +109,14 @@ AppValidator.findManifestAtOrigin = function (manifestURL) {
|
|||
};
|
||||
|
||||
AppValidator.findManifestPath = function (manifestURL) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
if (manifestURL.endsWith("manifest.webapp")) {
|
||||
deferred.reject();
|
||||
} else {
|
||||
let fixedManifest = manifestURL + "/manifest.webapp";
|
||||
deferred.resolve(AppValidator.checkManifest(fixedManifest));
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return new Promise((resolve, reject) => {
|
||||
if (manifestURL.endsWith("manifest.webapp")) {
|
||||
reject();
|
||||
} else {
|
||||
let fixedManifest = manifestURL + "/manifest.webapp";
|
||||
resolve(AppValidator.checkManifest(fixedManifest));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.checkAlternateManifest = function (manifestURL) {
|
||||
|
@ -138,24 +133,23 @@ AppValidator.checkAlternateManifest = function (manifestURL) {
|
|||
};
|
||||
|
||||
AppValidator.prototype._fetchManifest = function (manifestURL) {
|
||||
let deferred = promise.defer();
|
||||
this.manifestURL = manifestURL;
|
||||
return new Promise(resolve => {
|
||||
this.manifestURL = manifestURL;
|
||||
|
||||
AppValidator.checkManifest(manifestURL)
|
||||
.then(({manifest, manifestURL}) => {
|
||||
deferred.resolve(manifest);
|
||||
}, error => {
|
||||
AppValidator.checkAlternateManifest(manifestURL)
|
||||
.then(({manifest, manifestURL}) => {
|
||||
this.manifestURL = manifestURL;
|
||||
deferred.resolve(manifest);
|
||||
}, () => {
|
||||
this.error(error);
|
||||
deferred.resolve(null);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
AppValidator.checkManifest(manifestURL)
|
||||
.then(({manifest, manifestURL}) => {
|
||||
resolve(manifest);
|
||||
}, error => {
|
||||
AppValidator.checkAlternateManifest(manifestURL)
|
||||
.then(({manifest, manifestURL}) => {
|
||||
this.manifestURL = manifestURL;
|
||||
resolve(manifest);
|
||||
}, () => {
|
||||
this.error(error);
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.prototype._getManifest = function () {
|
||||
|
@ -163,18 +157,18 @@ AppValidator.prototype._getManifest = function () {
|
|||
if (this.type == "packaged") {
|
||||
manifestURL = this._getPackagedManifestURL();
|
||||
if (!manifestURL)
|
||||
return promise.resolve(null);
|
||||
return Promise.resolve(null);
|
||||
} else if (this.type == "hosted") {
|
||||
manifestURL = this.location;
|
||||
try {
|
||||
Services.io.newURI(manifestURL);
|
||||
} catch (e) {
|
||||
this.error(strings.formatStringFromName("validator.invalidHostedManifestURL", [manifestURL, e.message], 2));
|
||||
return promise.resolve(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
} else {
|
||||
this.error(strings.formatStringFromName("validator.invalidProjectType", [this.type], 1));
|
||||
return promise.resolve(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return this._fetchManifest(manifestURL);
|
||||
};
|
||||
|
@ -201,57 +195,53 @@ AppValidator.prototype._getOriginURL = function () {
|
|||
};
|
||||
|
||||
AppValidator.prototype.validateLaunchPath = function (manifest) {
|
||||
let deferred = promise.defer();
|
||||
// The launch_path field has to start with a `/`
|
||||
if (manifest.launch_path && manifest.launch_path[0] !== "/") {
|
||||
this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1));
|
||||
deferred.resolve();
|
||||
return deferred.promise;
|
||||
}
|
||||
let origin = this._getOriginURL();
|
||||
let path;
|
||||
if (this.type == "packaged") {
|
||||
path = "." + (manifest.launch_path || "/index.html");
|
||||
} else if (this.type == "hosted") {
|
||||
path = manifest.launch_path || "/";
|
||||
}
|
||||
let indexURL;
|
||||
try {
|
||||
indexURL = Services.io.newURI(path, null, Services.io.newURI(origin)).spec;
|
||||
} catch (e) {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [origin + path], 1));
|
||||
deferred.resolve();
|
||||
return deferred.promise;
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
// The launch_path field has to start with a `/`
|
||||
if (manifest.launch_path && manifest.launch_path[0] !== "/") {
|
||||
this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1));
|
||||
resolve();
|
||||
}
|
||||
let origin = this._getOriginURL();
|
||||
let path;
|
||||
if (this.type == "packaged") {
|
||||
path = "." + (manifest.launch_path || "/index.html");
|
||||
} else if (this.type == "hosted") {
|
||||
path = manifest.launch_path || "/";
|
||||
}
|
||||
let indexURL;
|
||||
try {
|
||||
indexURL = Services.io.newURI(path, null, Services.io.newURI(origin)).spec;
|
||||
} catch (e) {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [origin + path], 1));
|
||||
return resolve();
|
||||
}
|
||||
|
||||
let req = new XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
try {
|
||||
req.open("HEAD", indexURL, true);
|
||||
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
||||
} catch (e) {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
||||
deferred.resolve();
|
||||
return deferred.promise;
|
||||
}
|
||||
req.onload = () => {
|
||||
if (req.status >= 400)
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2));
|
||||
deferred.resolve();
|
||||
};
|
||||
req.onerror = () => {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
||||
deferred.resolve();
|
||||
};
|
||||
let req = new XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
try {
|
||||
req.open("HEAD", indexURL, true);
|
||||
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
||||
} catch (e) {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
||||
return resolve();
|
||||
}
|
||||
req.onload = () => {
|
||||
if (req.status >= 400)
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2));
|
||||
resolve();
|
||||
};
|
||||
req.onerror = () => {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
||||
resolve();
|
||||
};
|
||||
|
||||
try {
|
||||
req.send(null);
|
||||
} catch (e) {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
try {
|
||||
req.send(null);
|
||||
} catch (e) {
|
||||
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.prototype.validateType = function (manifest) {
|
||||
|
@ -279,7 +269,7 @@ AppValidator.prototype.validate = function () {
|
|||
|
||||
// Skip validations for add-ons
|
||||
if (manifest.role === "addon" || manifest.manifest_version) {
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.validateManifest(manifest);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
const {Cu, Cc, Ci} = require("chrome");
|
||||
|
||||
const promise = require("promise");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const Subprocess = require("sdk/system/child_process/subprocess");
|
||||
|
@ -149,31 +148,30 @@ const ProjectBuilding = exports.ProjectBuilding = {
|
|||
// Subprocess changes CWD, we have to save and restore it.
|
||||
let originalCwd = yield OS.File.getCurrentDirectory();
|
||||
try {
|
||||
let defer = promise.defer();
|
||||
Subprocess.call({
|
||||
command: shell,
|
||||
arguments: args,
|
||||
environment: env,
|
||||
workdir: cwd,
|
||||
yield new Promise((resolve, reject) => {
|
||||
Subprocess.call({
|
||||
command: shell,
|
||||
arguments: args,
|
||||
environment: env,
|
||||
workdir: cwd,
|
||||
|
||||
stdout: data =>
|
||||
logger(data),
|
||||
stderr: data =>
|
||||
logger(data),
|
||||
stdout: data =>
|
||||
logger(data),
|
||||
stderr: data =>
|
||||
logger(data),
|
||||
|
||||
done: result => {
|
||||
logger("Terminated with error code: " + result.exitCode);
|
||||
if (result.exitCode == 0) {
|
||||
defer.resolve();
|
||||
} else {
|
||||
defer.reject("pre-package command failed with error code " + result.exitCode);
|
||||
done: result => {
|
||||
logger("Terminated with error code: " + result.exitCode);
|
||||
if (result.exitCode == 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject("pre-package command failed with error code " + result.exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
defer.promise.then(() => {
|
||||
});
|
||||
}).then(() => {
|
||||
OS.File.setCurrentDirectory(originalCwd);
|
||||
});
|
||||
yield defer.promise;
|
||||
} catch (e) {
|
||||
throw new Error("Unable to run pre-package command '" + command + "' " +
|
||||
args.join(" ") + ":\n" + (e.message || e));
|
||||
|
|
|
@ -7,7 +7,6 @@ const {Cu} = require("chrome");
|
|||
const Services = require("Services");
|
||||
const {AppProjects} = require("devtools/client/webide/modules/app-projects");
|
||||
const {AppManager} = require("devtools/client/webide/modules/app-manager");
|
||||
const promise = require("promise");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const utils = require("devtools/client/webide/modules/utils");
|
||||
|
@ -200,7 +199,7 @@ ProjectList.prototype = {
|
|||
}, true);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
updateApps: function () {
|
||||
|
@ -263,7 +262,7 @@ ProjectList.prototype = {
|
|||
}, true);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
updateCommands: function () {
|
||||
|
@ -299,69 +298,67 @@ ProjectList.prototype = {
|
|||
* what is updated to only those sections.
|
||||
*/
|
||||
update: function (options) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
if (options && options.type === "apps") {
|
||||
return this.updateApps();
|
||||
} else if (options && options.type === "tabs") {
|
||||
return this.updateTabs();
|
||||
}
|
||||
|
||||
let doc = this._doc;
|
||||
let projectsNode = doc.querySelector("#project-panel-projects");
|
||||
return new Promise((resolve, reject) => {
|
||||
let doc = this._doc;
|
||||
let projectsNode = doc.querySelector("#project-panel-projects");
|
||||
|
||||
while (projectsNode.hasChildNodes()) {
|
||||
projectsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
AppProjects.load().then(() => {
|
||||
let projects = AppProjects.projects;
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i];
|
||||
let panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
projectsNode.appendChild(panelItemNode);
|
||||
if (!project.validationStatus) {
|
||||
// The result of the validation process (storing names, icons, …) is not stored in
|
||||
// the IndexedDB database when App Manager v1 is used.
|
||||
// We need to run the validation again and update the name and icon of the app.
|
||||
AppManager.validateAndUpdateProject(project).then(() => {
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name,
|
||||
icon: project.icon
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name || AppManager.DEFAULT_PROJECT_NAME,
|
||||
icon: project.icon || AppManager.DEFAULT_PROJECT_ICON
|
||||
});
|
||||
}
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
AppManager.selectedProject = project;
|
||||
}, true);
|
||||
while (projectsNode.hasChildNodes()) {
|
||||
projectsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
}, deferred.reject);
|
||||
AppProjects.load().then(() => {
|
||||
let projects = AppProjects.projects;
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i];
|
||||
let panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
projectsNode.appendChild(panelItemNode);
|
||||
if (!project.validationStatus) {
|
||||
// The result of the validation process (storing names, icons, …) is not stored in
|
||||
// the IndexedDB database when App Manager v1 is used.
|
||||
// We need to run the validation again and update the name and icon of the app.
|
||||
AppManager.validateAndUpdateProject(project).then(() => {
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name,
|
||||
icon: project.icon
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name || AppManager.DEFAULT_PROJECT_NAME,
|
||||
icon: project.icon || AppManager.DEFAULT_PROJECT_ICON
|
||||
});
|
||||
}
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
AppManager.selectedProject = project;
|
||||
}, true);
|
||||
}
|
||||
|
||||
// List remote apps and the main process, if they exist
|
||||
this.updateApps();
|
||||
resolve();
|
||||
}, reject);
|
||||
|
||||
// Build the tab list right now, so it's fast...
|
||||
this.updateTabs();
|
||||
// List remote apps and the main process, if they exist
|
||||
this.updateApps();
|
||||
|
||||
// But re-list them and rebuild, in case any tabs navigated since the last
|
||||
// time they were listed.
|
||||
if (AppManager.connected) {
|
||||
AppManager.listTabs().then(() => {
|
||||
this.updateTabs();
|
||||
}).catch(console.error);
|
||||
}
|
||||
// Build the tab list right now, so it's fast...
|
||||
this.updateTabs();
|
||||
|
||||
return deferred.promise;
|
||||
// But re-list them and rebuild, in case any tabs navigated since the last
|
||||
// time they were listed.
|
||||
if (AppManager.connected) {
|
||||
AppManager.listTabs().then(() => {
|
||||
this.updateTabs();
|
||||
}).catch(console.error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
|
|
|
@ -9,7 +9,6 @@ const { Cc, Ci, Cu } = require("chrome");
|
|||
|
||||
const Environment = require("sdk/system/environment").env;
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const promise = require("promise");
|
||||
const Subprocess = require("sdk/system/child_process/subprocess");
|
||||
const Services = require("Services");
|
||||
|
||||
|
@ -104,21 +103,21 @@ SimulatorProcess.prototype = {
|
|||
|
||||
// Request a B2G instance kill.
|
||||
kill() {
|
||||
let deferred = promise.defer();
|
||||
if (this.process) {
|
||||
this.once("exit", (e, exitCode) => {
|
||||
this.shuttingDown = false;
|
||||
deferred.resolve(exitCode);
|
||||
});
|
||||
if (!this.shuttingDown) {
|
||||
this.shuttingDown = true;
|
||||
this.emit("kill", null);
|
||||
this.process.kill();
|
||||
return new Promise(resolve => {
|
||||
if (this.process) {
|
||||
this.once("exit", (e, exitCode) => {
|
||||
this.shuttingDown = false;
|
||||
resolve(exitCode);
|
||||
});
|
||||
if (!this.shuttingDown) {
|
||||
this.shuttingDown = true;
|
||||
this.emit("kill", null);
|
||||
this.process.kill();
|
||||
}
|
||||
} else {
|
||||
return resolve(undefined);
|
||||
}
|
||||
return deferred.promise;
|
||||
} else {
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Maybe log output messages.
|
||||
|
|
|
@ -12,7 +12,6 @@ loader.lazyRequireGetter(this, "OldAddonSimulatorProcess", "devtools/client/webi
|
|||
loader.lazyRequireGetter(this, "CustomSimulatorProcess", "devtools/client/webide/modules/simulator-process", true);
|
||||
const asyncStorage = require("devtools/shared/async-storage");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const promise = require("promise");
|
||||
const Services = require("Services");
|
||||
|
||||
const SimulatorRegExp = new RegExp(Services.prefs.getCharPref("devtools.webide.simulatorAddonRegExp"));
|
||||
|
@ -46,18 +45,19 @@ var Simulators = {
|
|||
|
||||
// If the simulator had a reference to an addon, fix it.
|
||||
if (options.addonID) {
|
||||
let deferred = promise.defer();
|
||||
AddonManager.getAddonByID(options.addonID, addon => {
|
||||
simulator.addon = addon;
|
||||
delete simulator.options.addonID;
|
||||
deferred.resolve();
|
||||
let deferred = new Promise(resolve => {
|
||||
AddonManager.getAddonByID(options.addonID, addon => {
|
||||
simulator.addon = addon;
|
||||
delete simulator.options.addonID;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
jobs.push(deferred.promise);
|
||||
jobs.push(deferred);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
yield promise.all(jobs);
|
||||
yield Promise.all(jobs);
|
||||
yield Simulators._addUnusedAddons();
|
||||
Simulators.emitUpdated();
|
||||
return Simulators._simulators;
|
||||
|
@ -79,7 +79,7 @@ var Simulators = {
|
|||
jobs.push(Simulators.addIfUnusedAddon(addon, true));
|
||||
});
|
||||
|
||||
yield promise.all(jobs);
|
||||
yield Promise.all(jobs);
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -117,19 +117,19 @@ var Simulators = {
|
|||
* @return Promised addon list.
|
||||
*/
|
||||
findSimulatorAddons() {
|
||||
let deferred = promise.defer();
|
||||
AddonManager.getAllAddons(all => {
|
||||
let addons = [];
|
||||
for (let addon of all) {
|
||||
if (Simulators.isSimulatorAddon(addon)) {
|
||||
addons.push(addon);
|
||||
return new Promise(resolve => {
|
||||
AddonManager.getAllAddons(all => {
|
||||
let addons = [];
|
||||
for (let addon of all) {
|
||||
if (Simulators.isSimulatorAddon(addon)) {
|
||||
addons.push(addon);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort simulator addons by name.
|
||||
addons.sort(LocaleCompare);
|
||||
deferred.resolve(addons);
|
||||
// Sort simulator addons by name.
|
||||
addons.sort(LocaleCompare);
|
||||
resolve(addons);
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -139,7 +139,7 @@ var Simulators = {
|
|||
let simulators = this._simulators;
|
||||
let matching = simulators.filter(s => s.addon && s.addon.id == addon.id);
|
||||
if (matching.length > 0) {
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
}
|
||||
let options = {};
|
||||
options.name = addon.name.replace(" Simulator", "");
|
||||
|
@ -176,7 +176,7 @@ var Simulators = {
|
|||
if (!silently) {
|
||||
this.emitUpdated();
|
||||
}
|
||||
return promise.resolve(simulator);
|
||||
return Promise.resolve(simulator);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -332,13 +332,13 @@ Simulator.prototype = {
|
|||
}
|
||||
this.process.run();
|
||||
|
||||
return promise.resolve(this.options.port);
|
||||
return Promise.resolve(this.options.port);
|
||||
},
|
||||
|
||||
kill() {
|
||||
let process = this.process;
|
||||
if (!process) {
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
}
|
||||
this.process = null;
|
||||
return process.kill();
|
||||
|
|
|
@ -7,7 +7,6 @@ const { Cu } = require("chrome");
|
|||
const { TargetFactory } = require("devtools/client/framework/target");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { Connection } = require("devtools/shared/client/connection-manager");
|
||||
const promise = require("promise");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
const _knownTabStores = new WeakMap();
|
||||
|
@ -95,25 +94,26 @@ TabStore.prototype = {
|
|||
|
||||
listTabs: function () {
|
||||
if (!this._connection || !this._connection.client) {
|
||||
return promise.reject(new Error("Can't listTabs, not connected."));
|
||||
return Promise.reject(new Error("Can't listTabs, not connected."));
|
||||
}
|
||||
let deferred = promise.defer();
|
||||
this._connection.client.listTabs(response => {
|
||||
if (response.error) {
|
||||
this._connection.disconnect();
|
||||
deferred.reject(response.error);
|
||||
return;
|
||||
}
|
||||
let tabsChanged = JSON.stringify(this.tabs) !== JSON.stringify(response.tabs);
|
||||
this.response = response;
|
||||
this.tabs = response.tabs;
|
||||
this._checkSelectedTab();
|
||||
if (tabsChanged) {
|
||||
this.emit("tab-list");
|
||||
}
|
||||
deferred.resolve(response);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this._connection.client.listTabs(response => {
|
||||
if (response.error) {
|
||||
this._connection.disconnect();
|
||||
reject(response.error);
|
||||
return;
|
||||
}
|
||||
let tabsChanged = JSON.stringify(this.tabs) !== JSON.stringify(response.tabs);
|
||||
this.response = response;
|
||||
this.tabs = response.tabs;
|
||||
this._checkSelectedTab();
|
||||
if (tabsChanged) {
|
||||
this.emit("tab-list");
|
||||
}
|
||||
resolve(response);
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
// TODO: Tab "selection" should really take place by creating a TabProject
|
||||
|
|
|
@ -64,12 +64,12 @@ function test() {
|
|||
}
|
||||
|
||||
function connectToLocal(win, docRuntime) {
|
||||
let deferred = promise.defer();
|
||||
win.AppManager.connection.once(
|
||||
return new Promise(resolve => {
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
() => deferred.resolve());
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
return deferred.promise;
|
||||
resolve);
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
});
|
||||
}
|
||||
|
||||
function selectTabProject(win, docProject) {
|
||||
|
|
|
@ -8,7 +8,6 @@ var {utils: Cu, classes: Cc, interfaces: Ci} = Components;
|
|||
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const promise = require("promise");
|
||||
const Services = require("Services");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { AppProjects } = require("devtools/client/webide/modules/app-projects");
|
||||
|
@ -71,18 +70,14 @@ var openWebIDE = Task.async(function* (autoInstallAddons) {
|
|||
function closeWebIDE(win) {
|
||||
info("Closing WebIDE");
|
||||
|
||||
let deferred = promise.defer();
|
||||
return new Promise(resolve => {
|
||||
win.addEventListener("unload", function () {
|
||||
info("WebIDE closed");
|
||||
SimpleTest.executeSoon(resolve);
|
||||
}, {once: true});
|
||||
|
||||
win.addEventListener("unload", function () {
|
||||
info("WebIDE closed");
|
||||
SimpleTest.executeSoon(() => {
|
||||
deferred.resolve();
|
||||
});
|
||||
}, {once: true});
|
||||
|
||||
win.close();
|
||||
|
||||
return deferred.promise;
|
||||
win.close();
|
||||
});
|
||||
}
|
||||
|
||||
function removeAllProjects() {
|
||||
|
@ -98,93 +93,87 @@ function removeAllProjects() {
|
|||
}
|
||||
|
||||
function nextTick() {
|
||||
let deferred = promise.defer();
|
||||
SimpleTest.executeSoon(() => {
|
||||
deferred.resolve();
|
||||
return new Promise(resolve => {
|
||||
SimpleTest.executeSoon(resolve);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForUpdate(win, update) {
|
||||
info("Wait: " + update);
|
||||
let deferred = promise.defer();
|
||||
win.AppManager.on("app-manager-update", function onUpdate(e, what) {
|
||||
info("Got: " + what);
|
||||
if (what !== update) {
|
||||
return;
|
||||
}
|
||||
win.AppManager.off("app-manager-update", onUpdate);
|
||||
deferred.resolve(win.UI._updatePromise);
|
||||
return new Promise(resolve => {
|
||||
win.AppManager.on("app-manager-update", function onUpdate(e, what) {
|
||||
info("Got: " + what);
|
||||
if (what !== update) {
|
||||
return;
|
||||
}
|
||||
win.AppManager.off("app-manager-update", onUpdate);
|
||||
resolve(win.UI._updatePromise);
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForTime(time) {
|
||||
let deferred = promise.defer();
|
||||
setTimeout(() => {
|
||||
deferred.resolve();
|
||||
}, time);
|
||||
return deferred.promise;
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
}
|
||||
|
||||
function documentIsLoaded(doc) {
|
||||
let deferred = promise.defer();
|
||||
if (doc.readyState == "complete") {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
doc.addEventListener("readystatechange", function onChange() {
|
||||
if (doc.readyState == "complete") {
|
||||
doc.removeEventListener("readystatechange", onChange);
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
return deferred.promise;
|
||||
return new Promise(resolve => {
|
||||
if (doc.readyState == "complete") {
|
||||
resolve();
|
||||
} else {
|
||||
doc.addEventListener("readystatechange", function onChange() {
|
||||
if (doc.readyState == "complete") {
|
||||
doc.removeEventListener("readystatechange", onChange);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function lazyIframeIsLoaded(iframe) {
|
||||
let deferred = promise.defer();
|
||||
iframe.addEventListener("load", function () {
|
||||
deferred.resolve(nextTick());
|
||||
}, {capture: true, once: true});
|
||||
return deferred.promise;
|
||||
return new Promise(resolve => {
|
||||
iframe.addEventListener("load", function () {
|
||||
resolve(nextTick());
|
||||
}, {capture: true, once: true});
|
||||
});
|
||||
}
|
||||
|
||||
function addTab(aUrl, aWindow) {
|
||||
info("Adding tab: " + aUrl);
|
||||
|
||||
let deferred = promise.defer();
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
return new Promise(resolve => {
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
|
||||
targetWindow.focus();
|
||||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
targetWindow.focus();
|
||||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
deferred.resolve(tab);
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
resolve(tab);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function removeTab(aTab, aWindow) {
|
||||
info("Removing tab.");
|
||||
|
||||
let deferred = promise.defer();
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
let tabContainer = targetBrowser.tabContainer;
|
||||
return new Promise(resolve => {
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
let tabContainer = targetBrowser.tabContainer;
|
||||
|
||||
tabContainer.addEventListener("TabClose", function (aEvent) {
|
||||
info("Tab removed and finished closing.");
|
||||
deferred.resolve();
|
||||
}, {once: true});
|
||||
tabContainer.addEventListener("TabClose", function (aEvent) {
|
||||
info("Tab removed and finished closing.");
|
||||
resolve();
|
||||
}, {once: true});
|
||||
|
||||
targetBrowser.removeTab(aTab);
|
||||
return deferred.promise;
|
||||
targetBrowser.removeTab(aTab);
|
||||
});
|
||||
}
|
||||
|
||||
function getRuntimeDocument(win) {
|
||||
|
|
|
@ -22,30 +22,26 @@
|
|||
const {Devices} = Cu.import("resource://devtools/shared/apps/Devices.jsm");
|
||||
const {Simulators} = require("devtools/client/webide/modules/simulators");
|
||||
|
||||
let adbAddonsInstalled = promise.defer();
|
||||
Devices.on("addon-status-updated", function onUpdate1() {
|
||||
Devices.off("addon-status-updated", onUpdate1);
|
||||
adbAddonsInstalled.resolve();
|
||||
});
|
||||
let adbAddonsInstalled;
|
||||
|
||||
function getVersion(name) {
|
||||
return name.match(/(\d+\.\d+)/)[0];
|
||||
}
|
||||
|
||||
function onSimulatorInstalled(name) {
|
||||
let deferred = promise.defer();
|
||||
Simulators.on("updated", function onUpdate() {
|
||||
Simulators.findSimulatorAddons().then(addons => {
|
||||
for (let addon of addons) {
|
||||
if (name == addon.name.replace(" Simulator", "")) {
|
||||
Simulators.off("updated", onUpdate);
|
||||
nextTick().then(deferred.resolve);
|
||||
return;
|
||||
return new Promise(resolve => {
|
||||
Simulators.on("updated", function onUpdate() {
|
||||
Simulators.findSimulatorAddons().then(addons => {
|
||||
for (let addon of addons) {
|
||||
if (name == addon.name.replace(" Simulator", "")) {
|
||||
Simulators.off("updated", onUpdate);
|
||||
nextTick().then(resolve);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function installSimulatorFromUI(doc, name) {
|
||||
|
@ -55,39 +51,39 @@
|
|||
}
|
||||
|
||||
function uninstallSimulatorFromUI(doc, name) {
|
||||
let deferred = promise.defer();
|
||||
Simulators.on("updated", function onUpdate() {
|
||||
nextTick().then(() => {
|
||||
let li = doc.querySelector('[status="uninstalled"][addon="simulator-' + getVersion(name) + '"]');
|
||||
if (li) {
|
||||
Simulators.off("updated", onUpdate);
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject("Can't find item");
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
Simulators.on("updated", function onUpdate() {
|
||||
nextTick().then(() => {
|
||||
let li = doc.querySelector('[status="uninstalled"][addon="simulator-' + getVersion(name) + '"]');
|
||||
if (li) {
|
||||
Simulators.off("updated", onUpdate);
|
||||
resolve();
|
||||
} else {
|
||||
reject("Can't find item");
|
||||
}
|
||||
});
|
||||
});
|
||||
let li = doc.querySelector('[status="installed"][addon="simulator-' + getVersion(name) + '"]');
|
||||
li.querySelector(".uninstall-button").click();
|
||||
});
|
||||
let li = doc.querySelector('[status="installed"][addon="simulator-' + getVersion(name) + '"]');
|
||||
li.querySelector(".uninstall-button").click();
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function uninstallADBFromUI(doc) {
|
||||
let deferred = promise.defer();
|
||||
Devices.on("addon-status-updated", function onUpdate() {
|
||||
nextTick().then(() => {
|
||||
let li = doc.querySelector('[status="uninstalled"][addon="adb"]');
|
||||
if (li) {
|
||||
Devices.off("addon-status-updated", onUpdate);
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject("Can't find item");
|
||||
}
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
Devices.on("addon-status-updated", function onUpdate() {
|
||||
nextTick().then(() => {
|
||||
let li = doc.querySelector('[status="uninstalled"][addon="adb"]');
|
||||
if (li) {
|
||||
Devices.off("addon-status-updated", onUpdate);
|
||||
resolve();
|
||||
} else {
|
||||
reject("Can't find item");
|
||||
}
|
||||
})
|
||||
});
|
||||
let li = doc.querySelector('[status="installed"][addon="adb"]');
|
||||
li.querySelector(".uninstall-button").click();
|
||||
});
|
||||
let li = doc.querySelector('[status="installed"][addon="adb"]');
|
||||
li.querySelector(".uninstall-button").click();
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
Task.spawn(function*() {
|
||||
|
@ -97,7 +93,12 @@
|
|||
let win = yield openWebIDE(true);
|
||||
let docRuntime = getRuntimeDocument(win);
|
||||
|
||||
yield adbAddonsInstalled.promise;
|
||||
adbAddonsInstalled = new Promise(resolve => {
|
||||
Devices.on("addon-status-updated", function onUpdate1() {
|
||||
Devices.off("addon-status-updated", onUpdate1);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
ok(Devices.helperAddonInstalled, "Helper has been auto-installed");
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
is(connection, win.AppManager.connection, "connection is valid");
|
||||
connection.host = null; // force connectPipe
|
||||
connection.connect();
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
get id() {
|
||||
|
|
|
@ -35,12 +35,13 @@
|
|||
let nbox = win.document.querySelector("#notificationbox");
|
||||
let notification = nbox.getNotificationWithValue("webide:errornotification");
|
||||
ok(!notification, "No notification yet");
|
||||
let deferred = promise.defer();
|
||||
nextTick().then(() => {
|
||||
deferred.reject("BOOM!");
|
||||
let deferred = new Promise((resolve, reject) => {
|
||||
nextTick().then(() => {
|
||||
reject("BOOM!");
|
||||
});
|
||||
});
|
||||
try {
|
||||
yield win.UI.busyUntil(deferred.promise, "xx");
|
||||
yield win.UI.busyUntil(deferred, "xx");
|
||||
} catch(e) {/* This *will* fail */}
|
||||
notification = nbox.getNotificationWithValue("webide:errornotification");
|
||||
ok(notification, "Error has been reported");
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
|
||||
<script type="application/javascript">
|
||||
function connectToLocal(win, docRuntime) {
|
||||
let deferred = promise.defer();
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
() => deferred.resolve());
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
return deferred.promise;
|
||||
return new Promise(resolve => {
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
resolve);
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
|
@ -33,7 +33,7 @@
|
|||
let docRuntime = getRuntimeDocument(win);
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
yield connectToLocal(win, docRuntime);
|
||||
connectToLocal(win, docRuntime);
|
||||
|
||||
// Select main process
|
||||
yield waitForUpdate(win, "runtime-targets");
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
is(connection, win.AppManager.connection, "connection is valid");
|
||||
connection.host = null; // force connectPipe
|
||||
connection.connect();
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
get name() {
|
||||
|
@ -72,8 +72,7 @@
|
|||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
let deferred = promise.defer();
|
||||
return deferred.promise;
|
||||
return new Promise(() => {});
|
||||
},
|
||||
|
||||
get name() {
|
||||
|
@ -83,8 +82,7 @@
|
|||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
let deferred = promise.defer();
|
||||
return deferred.promise;
|
||||
return new Promise(() => {});
|
||||
},
|
||||
|
||||
prolongedConnection: true,
|
||||
|
@ -164,36 +162,35 @@
|
|||
|
||||
Services.prefs.setIntPref("devtools.webide.busyTimeout", 100);
|
||||
|
||||
// Wait for error message since connection never completes
|
||||
let errorDeferred = promise.defer();
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
errorDeferred.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Click the infinite runtime
|
||||
items[1].click();
|
||||
ok(win.document.querySelector("window").className, "busy", "UI is busy");
|
||||
yield errorDeferred.promise;
|
||||
|
||||
// Check for unexpected error message since this is prolonged
|
||||
let noErrorDeferred = promise.defer();
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
noErrorDeferred.reject();
|
||||
}
|
||||
};
|
||||
// Wait for error message since connection never completes
|
||||
let errorDeferred = new Promise(resolve => {
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Click the prolonged runtime
|
||||
items[2].click();
|
||||
ok(win.document.querySelector("window").className, "busy", "UI is busy");
|
||||
|
||||
setTimeout(() => {
|
||||
noErrorDeferred.resolve();
|
||||
}, 1000);
|
||||
// Check for unexpected error message since this is prolonged
|
||||
let noErrorDeferred = new Promise((resolve, reject) => {
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
yield noErrorDeferred.promise;
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
|
|
@ -29,31 +29,31 @@
|
|||
|
||||
function addonStatus(addon, status) {
|
||||
if (addon.status == status) {
|
||||
return promise.resolve();
|
||||
return Promise.resolve();
|
||||
}
|
||||
let deferred = promise.defer();
|
||||
addon.on("update", function onUpdate() {
|
||||
if (addon.status == status) {
|
||||
addon.off("update", onUpdate);
|
||||
nextTick().then(() => deferred.resolve());
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
addon.on("update", function onUpdate() {
|
||||
if (addon.status == status) {
|
||||
addon.off("update", onUpdate);
|
||||
nextTick().then(() => resolve());
|
||||
}
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForUpdate(length) {
|
||||
info(`Wait for update with length ${length}`);
|
||||
let deferred = promise.defer();
|
||||
let handler = (_, data) => {
|
||||
if (data.length != length) {
|
||||
return;
|
||||
}
|
||||
info(`Got update with length ${length}`);
|
||||
Simulators.off("updated", handler);
|
||||
deferred.resolve();
|
||||
};
|
||||
Simulators.on("updated", handler);
|
||||
return deferred.promise;
|
||||
return new Promise(resolve => {
|
||||
let handler = (_, data) => {
|
||||
if (data.length != length) {
|
||||
return;
|
||||
}
|
||||
info(`Got update with length ${length}`);
|
||||
Simulators.off("updated", handler);
|
||||
resolve();
|
||||
};
|
||||
Simulators.on("updated", handler);
|
||||
});
|
||||
}
|
||||
|
||||
Task.spawn(function* () {
|
||||
|
@ -70,9 +70,9 @@
|
|||
|
||||
// Hack SimulatorProcesses to spy on simulation parameters.
|
||||
|
||||
let runPromise;
|
||||
function fakeRun() {
|
||||
runPromise.resolve({
|
||||
let resolver;
|
||||
function fakeRun() {
|
||||
resolver({
|
||||
path: this.b2gBinary.path,
|
||||
args: this.args
|
||||
});
|
||||
|
@ -85,9 +85,10 @@
|
|||
CustomSimulatorProcess.prototype.run = fakeRun;
|
||||
|
||||
function runSimulator(i) {
|
||||
runPromise = promise.defer();
|
||||
findAll(".runtime-panel-item-simulator")[i].click();
|
||||
return runPromise.promise;
|
||||
return new Promise(resolve => {
|
||||
resolver = resolve;
|
||||
findAll(".runtime-panel-item-simulator")[i].click();
|
||||
});
|
||||
}
|
||||
|
||||
// Install fake "Firefox OS 1.0" simulator addon.
|
||||
|
|
|
@ -42,10 +42,11 @@
|
|||
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
let deferred = promise.defer();
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
() => deferred.resolve());
|
||||
let deferred = new Promise(resolve => {
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
resolve);
|
||||
});
|
||||
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
|
||||
|
|
|
@ -4449,12 +4449,13 @@ nsContentUtils::GetSubdocumentWithOuterWindowId(nsIDocument *aDocument,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = nsGlobalWindow::GetOuterWindowWithId(aOuterWindowId)->AsOuter();
|
||||
RefPtr<nsGlobalWindow> window = nsGlobalWindow::GetOuterWindowWithId(aOuterWindowId);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> foundDoc = window->GetDoc();
|
||||
nsCOMPtr<nsPIDOMWindowOuter> outerWindow = window->AsOuter();
|
||||
nsCOMPtr<nsIDocument> foundDoc = outerWindow->GetDoc();
|
||||
if (nsContentUtils::ContentIsCrossDocDescendantOf(foundDoc, aDocument)) {
|
||||
// Note that ContentIsCrossDocDescendantOf will return true if
|
||||
// foundDoc == aDocument.
|
||||
|
|
|
@ -7631,6 +7631,7 @@ protected:
|
|||
virtual nsresult
|
||||
DispatchToWorkThread() = 0;
|
||||
|
||||
// Should only be called by Run().
|
||||
virtual void
|
||||
SendResults() = 0;
|
||||
|
||||
|
@ -21579,6 +21580,11 @@ FactoryOp::NoteDatabaseBlocked(Database* aDatabase)
|
|||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FactoryOp, DatabaseOperationBase)
|
||||
|
||||
// Run() assumes that the caller holds a strong reference to the object that
|
||||
// can't be cleared while Run() is being executed.
|
||||
// So if you call Run() directly (as opposed to dispatching to an event queue)
|
||||
// you need to make sure there's such a reference.
|
||||
// See bug 1356824 for more details.
|
||||
NS_IMETHODIMP
|
||||
FactoryOp::Run()
|
||||
{
|
||||
|
@ -21663,8 +21669,11 @@ FactoryOp::DirectoryLockAcquired(DirectoryLock* aLock)
|
|||
mResultCode = rv;
|
||||
}
|
||||
|
||||
// The caller holds a strong reference to us, no need for a self reference
|
||||
// before calling Run().
|
||||
|
||||
mState = State::SendingResults;
|
||||
SendResults();
|
||||
MOZ_ALWAYS_SUCCEEDS(Run());
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -21682,8 +21691,11 @@ FactoryOp::DirectoryLockFailed()
|
|||
mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
// The caller holds a strong reference to us, no need for a self reference
|
||||
// before calling Run().
|
||||
|
||||
mState = State::SendingResults;
|
||||
SendResults();
|
||||
MOZ_ALWAYS_SUCCEEDS(Run());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -22475,12 +22487,18 @@ OpenDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
|
|||
rv = NS_OK;
|
||||
}
|
||||
|
||||
// We are being called with an assuption that mWaitingFactoryOp holds a strong
|
||||
// reference to us.
|
||||
RefPtr<OpenDatabaseOp> kungFuDeathGrip;
|
||||
|
||||
if (mMaybeBlockedDatabases.RemoveElement(aDatabase) &&
|
||||
mMaybeBlockedDatabases.IsEmpty()) {
|
||||
if (actorDestroyed) {
|
||||
DatabaseActorInfo* info;
|
||||
MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId, &info));
|
||||
MOZ_ASSERT(info->mWaitingFactoryOp == this);
|
||||
kungFuDeathGrip =
|
||||
static_cast<OpenDatabaseOp*>(info->mWaitingFactoryOp.get());
|
||||
info->mWaitingFactoryOp = nullptr;
|
||||
} else {
|
||||
WaitForTransactions();
|
||||
|
@ -22492,6 +22510,9 @@ OpenDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
|
|||
mResultCode = rv;
|
||||
}
|
||||
|
||||
// A strong reference is held in kungFuDeathGrip, so it's safe to call Run()
|
||||
// directly.
|
||||
|
||||
mState = State::SendingResults;
|
||||
MOZ_ALWAYS_SUCCEEDS(Run());
|
||||
}
|
||||
|
@ -22611,17 +22632,15 @@ OpenDatabaseOp::SendResults()
|
|||
|
||||
mMaybeBlockedDatabases.Clear();
|
||||
|
||||
// Only needed if we're being called from within NoteDatabaseDone() since this
|
||||
// OpenDatabaseOp is only held alive by the gLiveDatabaseHashtable.
|
||||
RefPtr<OpenDatabaseOp> kungFuDeathGrip;
|
||||
|
||||
DatabaseActorInfo* info;
|
||||
if (gLiveDatabaseHashtable &&
|
||||
gLiveDatabaseHashtable->Get(mDatabaseId, &info) &&
|
||||
info->mWaitingFactoryOp) {
|
||||
MOZ_ASSERT(info->mWaitingFactoryOp == this);
|
||||
kungFuDeathGrip =
|
||||
static_cast<OpenDatabaseOp*>(info->mWaitingFactoryOp.get());
|
||||
// SendResults() should only be called by Run() and Run() should only be
|
||||
// called if there's a strong reference to the object that can't be cleared
|
||||
// here, so it's safe to clear mWaitingFactoryOp without adding additional
|
||||
// strong reference.
|
||||
info->mWaitingFactoryOp = nullptr;
|
||||
}
|
||||
|
||||
|
@ -23295,12 +23314,18 @@ DeleteDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
|
|||
rv = NS_OK;
|
||||
}
|
||||
|
||||
// We are being called with an assuption that mWaitingFactoryOp holds a strong
|
||||
// reference to us.
|
||||
RefPtr<OpenDatabaseOp> kungFuDeathGrip;
|
||||
|
||||
if (mMaybeBlockedDatabases.RemoveElement(aDatabase) &&
|
||||
mMaybeBlockedDatabases.IsEmpty()) {
|
||||
if (actorDestroyed) {
|
||||
DatabaseActorInfo* info;
|
||||
MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId, &info));
|
||||
MOZ_ASSERT(info->mWaitingFactoryOp == this);
|
||||
kungFuDeathGrip =
|
||||
static_cast<OpenDatabaseOp*>(info->mWaitingFactoryOp.get());
|
||||
info->mWaitingFactoryOp = nullptr;
|
||||
} else {
|
||||
WaitForTransactions();
|
||||
|
@ -23312,6 +23337,9 @@ DeleteDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
|
|||
mResultCode = rv;
|
||||
}
|
||||
|
||||
// A strong reference is held in kungFuDeathGrip, so it's safe to call Run()
|
||||
// directly.
|
||||
|
||||
mState = State::SendingResults;
|
||||
MOZ_ALWAYS_SUCCEEDS(Run());
|
||||
}
|
||||
|
@ -23637,6 +23665,8 @@ VersionChangeOp::RunOnOwningThread()
|
|||
}
|
||||
}
|
||||
|
||||
// We hold a strong ref to the deleteOp, so it's safe to call Run() directly.
|
||||
|
||||
deleteOp->mState = State::SendingResults;
|
||||
MOZ_ALWAYS_SUCCEEDS(deleteOp->Run());
|
||||
|
||||
|
@ -23851,6 +23881,11 @@ TransactionDatabaseOperationBase::NoteContinueReceived()
|
|||
|
||||
mInternalState = InternalState::SendingResults;
|
||||
|
||||
// This TransactionDatabaseOperationBase can only be held alive by the IPDL.
|
||||
// Run() can end up with clearing that last reference. So we need to add
|
||||
// a self reference here.
|
||||
RefPtr<TransactionDatabaseOperationBase> kungFuDeathGrip = this;
|
||||
|
||||
Unused << this->Run();
|
||||
}
|
||||
|
||||
|
@ -23896,11 +23931,6 @@ TransactionDatabaseOperationBase::SendPreprocessInfoOrResults(
|
|||
mInternalState == InternalState::SendingResults);
|
||||
MOZ_ASSERT(mTransaction);
|
||||
|
||||
// Only needed if we're being called from within NoteContinueReceived() since
|
||||
// this TransactionDatabaseOperationBase is only held alive by the IPDL.
|
||||
// SendSuccessResult/SendFailureResult releases that last reference.
|
||||
RefPtr<TransactionDatabaseOperationBase> kungFuDeathGrip;
|
||||
|
||||
if (NS_WARN_IF(IsActorDestroyed())) {
|
||||
// Don't send any notifications if the actor was destroyed already.
|
||||
if (NS_SUCCEEDED(mResultCode)) {
|
||||
|
@ -23908,10 +23938,6 @@ TransactionDatabaseOperationBase::SendPreprocessInfoOrResults(
|
|||
mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
} else {
|
||||
if (!aSendPreprocessInfo) {
|
||||
kungFuDeathGrip = this;
|
||||
}
|
||||
|
||||
if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) {
|
||||
// Aborted transactions always see their requests fail with ABORT_ERR,
|
||||
// even if the request succeeded or failed with another error.
|
||||
|
|
|
@ -219,6 +219,19 @@ AOMDecoder::IsAV1(const nsACString& aMimeType)
|
|||
|| aMimeType.EqualsLiteral("video/av1");
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
AOMDecoder::IsSupportedCodec(const nsAString& aCodecType)
|
||||
{
|
||||
// While AV1 is under development, we describe support
|
||||
// for a specific aom commit hash so sites can check
|
||||
// compatibility.
|
||||
auto version = NS_ConvertASCIItoUTF16("av1.experimental.");
|
||||
version.AppendLiteral("4d668d7feb1f8abd809d1bca0418570a7f142a36");
|
||||
return aCodecType.EqualsLiteral("av1") ||
|
||||
aCodecType.Equals(version);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
AOMDecoder::IsKeyframe(Span<const uint8_t> aBuffer) {
|
||||
|
|
|
@ -33,6 +33,9 @@ public:
|
|||
// by our demuxers to identify AV1 streams.
|
||||
static bool IsAV1(const nsACString& aMimeType);
|
||||
|
||||
// Return true if aCodecType is a supported codec description.
|
||||
static bool IsSupportedCodec(const nsAString& aCodecType);
|
||||
|
||||
// Return true if a sample is a keyframe.
|
||||
static bool IsKeyframe(Span<const uint8_t> aBuffer);
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#ifdef MOZ_AV1
|
||||
#include "AOMDecoder.h"
|
||||
#endif
|
||||
#include "MediaContainerType.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "WebMDemuxer.h"
|
||||
|
@ -51,6 +54,11 @@ WebMDecoder::IsSupportedType(const MediaContainerType& aContainerType)
|
|||
codec.EqualsLiteral("vp9") || codec.EqualsLiteral("vp9.0"))) {
|
||||
continue;
|
||||
}
|
||||
#ifdef MOZ_AV1
|
||||
if (isVideo && AOMDecoder::IsSupportedCodec(codec)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
// Some unsupported codec.
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ const TOPICS = [
|
|||
"weave:service:sync:start",
|
||||
"weave:service:sync:finish",
|
||||
"weave:service:sync:error",
|
||||
"fxaccounts:onverified",
|
||||
"fxaccounts:onlogin", // Defined in FxAccountsCommon, pulling it is expensive.
|
||||
"fxaccounts:onlogout",
|
||||
"fxaccounts:profilechange",
|
||||
|
|
|
@ -169,8 +169,9 @@ add_task(async function test_observer_refreshState() {
|
|||
let refreshState = sinon.spy(UIStateInternal, "refreshState");
|
||||
|
||||
let shouldRefresh = ["weave:service:login:change", "weave:service:login:error",
|
||||
"weave:service:ready", "fxaccounts:onlogin",
|
||||
"fxaccounts:onlogout", "fxaccounts:profilechange"];
|
||||
"weave:service:ready", "fxaccounts:onverified",
|
||||
"fxaccounts:onlogin", "fxaccounts:onlogout",
|
||||
"fxaccounts:profilechange"];
|
||||
|
||||
for (let topic of shouldRefresh) {
|
||||
let uiUpdateObserved = observeUIUpdate();
|
||||
|
|
|
@ -776,6 +776,17 @@ def parseKeyValue(strings, separator='=', context='key, value: '):
|
|||
return [string.split(separator, 1) for string in strings]
|
||||
|
||||
|
||||
def create_zip(path):
|
||||
"""
|
||||
Takes a `path` on disk and creates a zipfile with its contents. Returns a
|
||||
path to the location of the temporary zip file.
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
# `shutil.make_archive` writes to "{f.name}.zip", so we're really just
|
||||
# using `NamedTemporaryFile` as a way to get a random path.
|
||||
return shutil.make_archive(f.name, "zip", path)
|
||||
|
||||
|
||||
class MochitestDesktop(object):
|
||||
"""
|
||||
Mochitest class for desktop firefox.
|
||||
|
@ -2106,12 +2117,14 @@ toolbar#nav-bar {
|
|||
self.marionette = Marionette(**marionette_args)
|
||||
self.marionette.start_session(timeout=port_timeout)
|
||||
|
||||
# install specialpowers and mochikit as temporary addons
|
||||
# install specialpowers and mochikit addons
|
||||
addons = Addons(self.marionette)
|
||||
|
||||
if mozinfo.info.get('toolkit') != 'gonk':
|
||||
addons.install(os.path.join(here, 'extensions', 'specialpowers'), temp=True)
|
||||
addons.install(self.mochijar, temp=True)
|
||||
addons.install(create_zip(
|
||||
os.path.join(here, 'extensions', 'specialpowers')
|
||||
))
|
||||
addons.install(create_zip(self.mochijar))
|
||||
|
||||
self.execute_start_script()
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ function test() {
|
|||
requestLongerTimeout(2);
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["extensions.checkUpdateSecurity", false],
|
||||
]});
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
@ -43,8 +45,6 @@ add_test(function() {
|
|||
|
||||
// Finally, cleanup things
|
||||
add_test(function() {
|
||||
Services.prefs.setBoolPref("xpinstall.signatures.required", true);
|
||||
|
||||
AddonManager.getAddonByID("update1@tests.mozilla.org", function(aAddon) {
|
||||
aAddon.uninstall();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче