diff options
Diffstat (limited to 'devtools/client/inspector/compatibility/reducers/compatibility.js')
-rw-r--r-- | devtools/client/inspector/compatibility/reducers/compatibility.js | 262 |
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; +}; |