262 lines
8.3 KiB
JavaScript
262 lines
8.3 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
const {
|
|
COMPATIBILITY_APPEND_NODE_FAILURE,
|
|
COMPATIBILITY_CLEAR_DESTROYED_NODES,
|
|
COMPATIBILITY_INIT_USER_SETTINGS_SUCCESS,
|
|
COMPATIBILITY_INIT_USER_SETTINGS_FAILURE,
|
|
COMPATIBILITY_INTERNAL_APPEND_NODE,
|
|
COMPATIBILITY_INTERNAL_NODE_UPDATE,
|
|
COMPATIBILITY_INTERNAL_REMOVE_NODE,
|
|
COMPATIBILITY_INTERNAL_UPDATE_SELECTED_NODE_ISSUES,
|
|
COMPATIBILITY_REMOVE_NODE_FAILURE,
|
|
COMPATIBILITY_UPDATE_NODE_FAILURE,
|
|
COMPATIBILITY_UPDATE_NODES_FAILURE,
|
|
COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS,
|
|
COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE,
|
|
COMPATIBILITY_UPDATE_SETTINGS_VISIBILITY,
|
|
COMPATIBILITY_UPDATE_TARGET_BROWSERS_START,
|
|
COMPATIBILITY_UPDATE_TARGET_BROWSERS_SUCCESS,
|
|
COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE,
|
|
COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE,
|
|
COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START,
|
|
COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_SUCCESS,
|
|
COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE,
|
|
COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE,
|
|
} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
|
|
|
|
const INITIAL_STATE = {
|
|
defaultTargetBrowsers: [],
|
|
isSettingsVisible: false,
|
|
isTopLevelTargetProcessing: false,
|
|
selectedNode: null,
|
|
selectedNodeIssues: [],
|
|
topLevelTarget: null,
|
|
topLevelTargetIssues: [],
|
|
targetBrowsers: [],
|
|
};
|
|
|
|
const reducers = {
|
|
[COMPATIBILITY_APPEND_NODE_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_APPEND_NODE_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_CLEAR_DESTROYED_NODES](state) {
|
|
const topLevelTargetIssues = _clearDestroyedNodes(
|
|
state.topLevelTargetIssues
|
|
);
|
|
return Object.assign({}, state, { topLevelTargetIssues });
|
|
},
|
|
[COMPATIBILITY_INIT_USER_SETTINGS_SUCCESS](
|
|
state,
|
|
{ defaultTargetBrowsers, targetBrowsers }
|
|
) {
|
|
return Object.assign({}, state, { defaultTargetBrowsers, targetBrowsers });
|
|
},
|
|
[COMPATIBILITY_INIT_USER_SETTINGS_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_INIT_USER_SETTINGS_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_INTERNAL_APPEND_NODE](state, { node, issues }) {
|
|
const topLevelTargetIssues = _appendTopLevelTargetIssues(
|
|
state.topLevelTargetIssues,
|
|
node,
|
|
issues
|
|
);
|
|
return Object.assign({}, state, { topLevelTargetIssues });
|
|
},
|
|
[COMPATIBILITY_INTERNAL_NODE_UPDATE](state, { node, issues }) {
|
|
const topLevelTargetIssues = _updateTopLevelTargetIssues(
|
|
state.topLevelTargetIssues,
|
|
node,
|
|
issues
|
|
);
|
|
return Object.assign({}, state, { topLevelTargetIssues });
|
|
},
|
|
[COMPATIBILITY_INTERNAL_REMOVE_NODE](state, { node }) {
|
|
const topLevelTargetIssues = _removeNodeOrIssues(
|
|
state.topLevelTargetIssues,
|
|
node,
|
|
[]
|
|
);
|
|
return Object.assign({}, state, { topLevelTargetIssues });
|
|
},
|
|
[COMPATIBILITY_INTERNAL_UPDATE_SELECTED_NODE_ISSUES](state, { issues }) {
|
|
return Object.assign({}, state, { selectedNodeIssues: issues });
|
|
},
|
|
[COMPATIBILITY_REMOVE_NODE_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_UPDATE_NODES_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_UPDATE_NODE_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_UPDATE_NODES_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_UPDATE_NODES_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_UPDATE_NODES_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS](state, { node }) {
|
|
return Object.assign({}, state, { selectedNode: node });
|
|
},
|
|
[COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_UPDATE_SETTINGS_VISIBILITY](state, { visibility }) {
|
|
return Object.assign({}, state, { isSettingsVisible: visibility });
|
|
},
|
|
[COMPATIBILITY_UPDATE_TARGET_BROWSERS_START](state) {
|
|
return Object.assign({}, state, {
|
|
isTopLevelTargetProcessing: true,
|
|
topLevelTargetIssues: [],
|
|
});
|
|
},
|
|
[COMPATIBILITY_UPDATE_TARGET_BROWSERS_SUCCESS](state, { targetBrowsers }) {
|
|
return Object.assign({}, state, { targetBrowsers });
|
|
},
|
|
[COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE](state) {
|
|
return Object.assign({}, state, { isTopLevelTargetProcessing: false });
|
|
},
|
|
[COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START](state) {
|
|
return Object.assign({}, state, {
|
|
isTopLevelTargetProcessing: true,
|
|
topLevelTargetIssues: [],
|
|
});
|
|
},
|
|
[COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_SUCCESS](state, { target }) {
|
|
return Object.assign({}, state, { topLevelTarget: target });
|
|
},
|
|
[COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE](state, { error }) {
|
|
_showError(COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE, error);
|
|
return state;
|
|
},
|
|
[COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE](state) {
|
|
return Object.assign({}, state, { isTopLevelTargetProcessing: false });
|
|
},
|
|
};
|
|
|
|
function _appendTopLevelTargetIssues(targetIssues, node, issues) {
|
|
targetIssues = [...targetIssues];
|
|
for (const issue of issues) {
|
|
const index = _indexOfIssue(targetIssues, issue);
|
|
if (index < 0) {
|
|
issue.nodes = [node];
|
|
targetIssues.push(issue);
|
|
continue;
|
|
}
|
|
|
|
const targetIssue = targetIssues[index];
|
|
const nodeIndex = targetIssue.nodes.findIndex(
|
|
issueNode => issueNode.actorID === node.actorID
|
|
);
|
|
|
|
if (nodeIndex < 0) {
|
|
targetIssue.nodes = [...targetIssue.nodes, node];
|
|
}
|
|
}
|
|
return targetIssues;
|
|
}
|
|
|
|
function _clearDestroyedNodes(targetIssues) {
|
|
return targetIssues.reduce((newIssues, targetIssue) => {
|
|
const retainedNodes = targetIssue.nodes.filter(
|
|
n => n.targetFront && !n.targetFront.isDestroyed()
|
|
);
|
|
|
|
// All the nodes for a given issue are destroyed
|
|
if (retainedNodes.length === 0) {
|
|
// Remove issue.
|
|
return newIssues;
|
|
}
|
|
|
|
targetIssue.nodes = retainedNodes;
|
|
return [...newIssues, targetIssue];
|
|
}, []);
|
|
}
|
|
|
|
function _indexOfIssue(issues, issue) {
|
|
return issues.findIndex(
|
|
i => i.type === issue.type && i.property === issue.property
|
|
);
|
|
}
|
|
|
|
function _indexOfNode(issue, node) {
|
|
return issue.nodes.findIndex(n => n.actorID === node.actorID);
|
|
}
|
|
|
|
function _removeNodeOrIssues(targetIssues, node, issues) {
|
|
return targetIssues.reduce((newIssues, targetIssue) => {
|
|
if (issues.length && _indexOfIssue(issues, targetIssue) >= 0) {
|
|
// The targetIssue is still in the node.
|
|
return [...newIssues, targetIssue];
|
|
}
|
|
|
|
const indexOfNodeInTarget = _indexOfNode(targetIssue, node);
|
|
if (indexOfNodeInTarget < 0) {
|
|
// The targetIssue does not have the node to remove.
|
|
return [...newIssues, targetIssue];
|
|
}
|
|
|
|
// This issue on the updated node is gone.
|
|
if (targetIssue.nodes.length === 1) {
|
|
// Remove issue.
|
|
return newIssues;
|
|
}
|
|
|
|
// Remove node from the nodes.
|
|
targetIssue.nodes = [
|
|
...targetIssue.nodes.slice(0, indexOfNodeInTarget),
|
|
...targetIssue.nodes.slice(indexOfNodeInTarget + 1),
|
|
];
|
|
return [...newIssues, targetIssue];
|
|
}, []);
|
|
}
|
|
|
|
function _updateTopLevelTargetIssues(targetIssues, node, issues) {
|
|
// Remove issues or node.
|
|
targetIssues = _removeNodeOrIssues(targetIssues, node, issues);
|
|
|
|
// Append issues or node.
|
|
const appendables = issues.filter(issue => {
|
|
const indexOfIssue = _indexOfIssue(targetIssues, issue);
|
|
return (
|
|
indexOfIssue < 0 || _indexOfNode(targetIssues[indexOfIssue], node) < 0
|
|
);
|
|
});
|
|
targetIssues = _appendTopLevelTargetIssues(targetIssues, node, appendables);
|
|
|
|
// Update fields.
|
|
for (const issue of issues) {
|
|
const indexOfIssue = _indexOfIssue(targetIssues, issue);
|
|
|
|
if (indexOfIssue < 0) {
|
|
continue;
|
|
}
|
|
|
|
const targetIssue = targetIssues[indexOfIssue];
|
|
targetIssues[indexOfIssue] = Object.assign(issue, {
|
|
nodes: targetIssue.nodes,
|
|
});
|
|
}
|
|
|
|
return targetIssues;
|
|
}
|
|
|
|
function _showError(action, error) {
|
|
console.error(`[${action}] ${error.message}`);
|
|
console.error(error.stack);
|
|
}
|
|
|
|
module.exports = function (state = INITIAL_STATE, action) {
|
|
const reducer = reducers[action.type];
|
|
return reducer ? reducer(state, action) : state;
|
|
};
|