summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/compatibility/reducers/compatibility.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/inspector/compatibility/reducers/compatibility.js262
1 files changed, 262 insertions, 0 deletions
diff --git a/devtools/client/inspector/compatibility/reducers/compatibility.js b/devtools/client/inspector/compatibility/reducers/compatibility.js
new file mode 100644
index 0000000000..9f11e06216
--- /dev/null
+++ b/devtools/client/inspector/compatibility/reducers/compatibility.js
@@ -0,0 +1,262 @@
+/* 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: [],
+ isSettingsVisibile: 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, { isSettingsVisibile: 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, { target }) {
+ 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;
+};