tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

compatibility.js (8504B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const {
      8  COMPATIBILITY_APPEND_NODE_FAILURE,
      9  COMPATIBILITY_CLEAR_DESTROYED_NODES,
     10  COMPATIBILITY_INIT_USER_SETTINGS_SUCCESS,
     11  COMPATIBILITY_INIT_USER_SETTINGS_FAILURE,
     12  COMPATIBILITY_INTERNAL_APPEND_NODE,
     13  COMPATIBILITY_INTERNAL_NODE_UPDATE,
     14  COMPATIBILITY_INTERNAL_REMOVE_NODE,
     15  COMPATIBILITY_INTERNAL_UPDATE_SELECTED_NODE_ISSUES,
     16  COMPATIBILITY_REMOVE_NODE_FAILURE,
     17  COMPATIBILITY_UPDATE_NODE_FAILURE,
     18  COMPATIBILITY_UPDATE_NODES_FAILURE,
     19  COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS,
     20  COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE,
     21  COMPATIBILITY_UPDATE_SETTINGS_VISIBILITY,
     22  COMPATIBILITY_UPDATE_TARGET_BROWSERS_START,
     23  COMPATIBILITY_UPDATE_TARGET_BROWSERS_SUCCESS,
     24  COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE,
     25  COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE,
     26  COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START,
     27  COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_SUCCESS,
     28  COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE,
     29  COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE,
     30 } = require("resource://devtools/client/inspector/compatibility/actions/index.js");
     31 
     32 const INITIAL_STATE = {
     33  defaultTargetBrowsers: [],
     34  isSettingsVisible: false,
     35  isTopLevelTargetProcessing: false,
     36  selectedNode: null,
     37  selectedNodeIssues: [],
     38  topLevelTarget: null,
     39  topLevelTargetIssues: [],
     40  targetBrowsers: [],
     41 };
     42 
     43 const reducers = {
     44  [COMPATIBILITY_APPEND_NODE_FAILURE](state, { error }) {
     45    _showError(COMPATIBILITY_APPEND_NODE_FAILURE, error);
     46    return state;
     47  },
     48  [COMPATIBILITY_CLEAR_DESTROYED_NODES](state) {
     49    const topLevelTargetIssues = _clearDestroyedNodes(
     50      state.topLevelTargetIssues
     51    );
     52    return Object.assign({}, state, { topLevelTargetIssues });
     53  },
     54  [COMPATIBILITY_INIT_USER_SETTINGS_SUCCESS](
     55    state,
     56    { defaultTargetBrowsers, targetBrowsers }
     57  ) {
     58    return Object.assign({}, state, { defaultTargetBrowsers, targetBrowsers });
     59  },
     60  [COMPATIBILITY_INIT_USER_SETTINGS_FAILURE](state, { error }) {
     61    _showError(COMPATIBILITY_INIT_USER_SETTINGS_FAILURE, error);
     62    return state;
     63  },
     64  [COMPATIBILITY_INTERNAL_APPEND_NODE](state, { node, issues }) {
     65    const topLevelTargetIssues = _appendTopLevelTargetIssues(
     66      state.topLevelTargetIssues,
     67      node,
     68      issues
     69    );
     70    return Object.assign({}, state, { topLevelTargetIssues });
     71  },
     72  [COMPATIBILITY_INTERNAL_NODE_UPDATE](state, { node, issues }) {
     73    const topLevelTargetIssues = _updateTopLevelTargetIssues(
     74      state.topLevelTargetIssues,
     75      node,
     76      issues
     77    );
     78    return Object.assign({}, state, { topLevelTargetIssues });
     79  },
     80  [COMPATIBILITY_INTERNAL_REMOVE_NODE](state, { node }) {
     81    const topLevelTargetIssues = _removeNodeOrIssues(
     82      state.topLevelTargetIssues,
     83      node,
     84      []
     85    );
     86    return Object.assign({}, state, { topLevelTargetIssues });
     87  },
     88  [COMPATIBILITY_INTERNAL_UPDATE_SELECTED_NODE_ISSUES](state, { issues }) {
     89    return Object.assign({}, state, { selectedNodeIssues: issues });
     90  },
     91  [COMPATIBILITY_REMOVE_NODE_FAILURE](state, { error }) {
     92    _showError(COMPATIBILITY_UPDATE_NODES_FAILURE, error);
     93    return state;
     94  },
     95  [COMPATIBILITY_UPDATE_NODE_FAILURE](state, { error }) {
     96    _showError(COMPATIBILITY_UPDATE_NODES_FAILURE, error);
     97    return state;
     98  },
     99  [COMPATIBILITY_UPDATE_NODES_FAILURE](state, { error }) {
    100    _showError(COMPATIBILITY_UPDATE_NODES_FAILURE, error);
    101    return state;
    102  },
    103  [COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS](state, { node }) {
    104    return Object.assign({}, state, { selectedNode: node });
    105  },
    106  [COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE](state, { error }) {
    107    _showError(COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, error);
    108    return state;
    109  },
    110  [COMPATIBILITY_UPDATE_SETTINGS_VISIBILITY](state, { visibility }) {
    111    return Object.assign({}, state, { isSettingsVisible: visibility });
    112  },
    113  [COMPATIBILITY_UPDATE_TARGET_BROWSERS_START](state) {
    114    return Object.assign({}, state, {
    115      isTopLevelTargetProcessing: true,
    116      topLevelTargetIssues: [],
    117    });
    118  },
    119  [COMPATIBILITY_UPDATE_TARGET_BROWSERS_SUCCESS](state, { targetBrowsers }) {
    120    return Object.assign({}, state, { targetBrowsers });
    121  },
    122  [COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE](state, { error }) {
    123    _showError(COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE, error);
    124    return state;
    125  },
    126  [COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE](state) {
    127    return Object.assign({}, state, { isTopLevelTargetProcessing: false });
    128  },
    129  [COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START](state) {
    130    return Object.assign({}, state, {
    131      isTopLevelTargetProcessing: true,
    132      topLevelTargetIssues: [],
    133    });
    134  },
    135  [COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_SUCCESS](state, { target }) {
    136    return Object.assign({}, state, { topLevelTarget: target });
    137  },
    138  [COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE](state, { error }) {
    139    _showError(COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE, error);
    140    return state;
    141  },
    142  [COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE](state) {
    143    return Object.assign({}, state, { isTopLevelTargetProcessing: false });
    144  },
    145 };
    146 
    147 function _appendTopLevelTargetIssues(targetIssues, node, issues) {
    148  targetIssues = [...targetIssues];
    149  for (const issue of issues) {
    150    const index = _indexOfIssue(targetIssues, issue);
    151    if (index < 0) {
    152      issue.nodes = [node];
    153      targetIssues.push(issue);
    154      continue;
    155    }
    156 
    157    const targetIssue = targetIssues[index];
    158    const nodeIndex = targetIssue.nodes.findIndex(
    159      issueNode => issueNode.actorID === node.actorID
    160    );
    161 
    162    if (nodeIndex < 0) {
    163      targetIssue.nodes = [...targetIssue.nodes, node];
    164    }
    165  }
    166  return targetIssues;
    167 }
    168 
    169 function _clearDestroyedNodes(targetIssues) {
    170  return targetIssues.reduce((newIssues, targetIssue) => {
    171    const retainedNodes = targetIssue.nodes.filter(
    172      n => n.targetFront && !n.targetFront.isDestroyed()
    173    );
    174 
    175    // All the nodes for a given issue are destroyed
    176    if (retainedNodes.length === 0) {
    177      // Remove issue.
    178      return newIssues;
    179    }
    180 
    181    targetIssue.nodes = retainedNodes;
    182    return [...newIssues, targetIssue];
    183  }, []);
    184 }
    185 
    186 function _indexOfIssue(issues, issue) {
    187  return issues.findIndex(
    188    i => i.type === issue.type && i.property === issue.property
    189  );
    190 }
    191 
    192 function _indexOfNode(issue, node) {
    193  return issue.nodes.findIndex(n => n.actorID === node.actorID);
    194 }
    195 
    196 function _removeNodeOrIssues(targetIssues, node, issues) {
    197  return targetIssues.reduce((newIssues, targetIssue) => {
    198    if (issues.length && _indexOfIssue(issues, targetIssue) >= 0) {
    199      // The targetIssue is still in the node.
    200      return [...newIssues, targetIssue];
    201    }
    202 
    203    const indexOfNodeInTarget = _indexOfNode(targetIssue, node);
    204    if (indexOfNodeInTarget < 0) {
    205      // The targetIssue does not have the node to remove.
    206      return [...newIssues, targetIssue];
    207    }
    208 
    209    // This issue on the updated node is gone.
    210    if (targetIssue.nodes.length === 1) {
    211      // Remove issue.
    212      return newIssues;
    213    }
    214 
    215    // Remove node from the nodes.
    216    targetIssue.nodes = [
    217      ...targetIssue.nodes.slice(0, indexOfNodeInTarget),
    218      ...targetIssue.nodes.slice(indexOfNodeInTarget + 1),
    219    ];
    220    return [...newIssues, targetIssue];
    221  }, []);
    222 }
    223 
    224 function _updateTopLevelTargetIssues(targetIssues, node, issues) {
    225  // Remove issues or node.
    226  targetIssues = _removeNodeOrIssues(targetIssues, node, issues);
    227 
    228  // Append issues or node.
    229  const appendables = issues.filter(issue => {
    230    const indexOfIssue = _indexOfIssue(targetIssues, issue);
    231    return (
    232      indexOfIssue < 0 || _indexOfNode(targetIssues[indexOfIssue], node) < 0
    233    );
    234  });
    235  targetIssues = _appendTopLevelTargetIssues(targetIssues, node, appendables);
    236 
    237  // Update fields.
    238  for (const issue of issues) {
    239    const indexOfIssue = _indexOfIssue(targetIssues, issue);
    240 
    241    if (indexOfIssue < 0) {
    242      continue;
    243    }
    244 
    245    const targetIssue = targetIssues[indexOfIssue];
    246    targetIssues[indexOfIssue] = Object.assign(issue, {
    247      nodes: targetIssue.nodes,
    248    });
    249  }
    250 
    251  return targetIssues;
    252 }
    253 
    254 function _showError(action, error) {
    255  console.error(`[${action}] ${error.message}`);
    256  console.error(error.stack);
    257 }
    258 
    259 module.exports = function (state = INITIAL_STATE, action) {
    260  const reducer = reducers[action.type];
    261  return reducer ? reducer(state, action) : state;
    262 };