tor-browser

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

sources-tree.js (4356B)


      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 import { createSelector } from "devtools/client/shared/vendor/reselect";
      6 
      7 /**
      8 * Main selector to build the SourceTree,
      9 * but this is also the source of data for the QuickOpen dialog.
     10 *
     11 * If no project directory root is set, this will return the thread items.
     12 * Otherwise this will return the items where we set the directory root.
     13 */
     14 export const getSourcesTreeSources = createSelector(
     15  getProjectDirectoryRoot,
     16  state => state.sourcesTree.threadItems,
     17  (projectDirectoryRoot, threadItems) => {
     18    // Only accept thread which have their thread attribute set.
     19    // This may come late, if we receive ADD_SOURCES before INSERT_THREAD.
     20    // Also filter out threads which have no sources, in case we had
     21    // INSERT_THREAD with no ADD_SOURCES.
     22    threadItems = threadItems.filter(
     23      item => !!item.thread && !!item.children.length
     24    );
     25 
     26    if (projectDirectoryRoot) {
     27      const directory = getDirectoryForUniquePath(
     28        projectDirectoryRoot,
     29        threadItems
     30      );
     31      if (directory) {
     32        return directory.children;
     33      }
     34      return [];
     35    }
     36 
     37    return threadItems;
     38  }
     39 );
     40 
     41 // This is used by QuickOpen UI
     42 /**
     43 * Main selector for the QuickOpen dialog.
     44 *
     45 * The returns the list of all the reducer's source objects
     46 * that are possibly displayed in the Source Tree.
     47 * This doesn't return Source Tree Items, but the source objects.
     48 */
     49 export const getDisplayedSourcesList = createSelector(
     50  getSourcesTreeSources,
     51  roots => {
     52    const sources = [];
     53    function walk(item) {
     54      if (item.type == "source") {
     55        sources.push(item.source);
     56      } else {
     57        for (const child of item.children) {
     58          walk(child);
     59        }
     60      }
     61    }
     62    for (const root of roots) {
     63      walk(root);
     64    }
     65    return sources;
     66  }
     67 );
     68 
     69 export function getExpandedState(state) {
     70  return state.sourcesTree.expanded;
     71 }
     72 
     73 export function getFocusedSourceItem(state) {
     74  return state.sourcesTree.focusedItem;
     75 }
     76 
     77 export function getProjectDirectoryRoot(state) {
     78  return state.sourcesTree.projectDirectoryRoot;
     79 }
     80 
     81 export function getProjectDirectoryRootName(state) {
     82  return state.sourcesTree.projectDirectoryRootName;
     83 }
     84 
     85 export function getProjectDirectoryRootFullName(state) {
     86  return state.sourcesTree.projectDirectoryRootFullName;
     87 }
     88 
     89 export function getMainThreadProjectDirectoryRoots(state) {
     90  return state.sourcesTree.mainThreadProjectDirectoryRoots;
     91 }
     92 
     93 /**
     94 * Lookup for project root item, matching the given "unique path".
     95 */
     96 function getDirectoryForUniquePath(projectRoot, threadItems) {
     97  const sections = projectRoot.split("|");
     98  const thread = sections.shift();
     99 
    100  const threadItem = threadItems.find(item => item.uniquePath == thread);
    101  if (!threadItem) {
    102    dump(
    103      `No thread item for: ${projectRoot} -- ${thread} -- ${Object.keys(
    104        threadItems
    105      )}\n`
    106    );
    107    return null;
    108  }
    109 
    110  // If we selected a thread, the project root is for a Thread Item
    111  // and it only contains `${thread}`
    112  if (!sections.length) {
    113    return threadItem;
    114  }
    115 
    116  const group = sections.shift();
    117  for (const child of threadItem.children) {
    118    if (child.groupName != group) {
    119      continue;
    120    }
    121    // In case we picked a group, return it...
    122    // project root looked like this `${thread}|${group}`
    123    if (!sections.length) {
    124      return child;
    125    }
    126    // ..otherwise, we picked a directory, so look for it by traversing the tree
    127    // project root looked like this `${thread}|${group}|${directoryPath}`
    128    const path = sections.shift();
    129    return findPathInDirectory(child, path);
    130  }
    131  return null;
    132 
    133  function findPathInDirectory(directory, path) {
    134    for (const child of directory.children) {
    135      if (child.type == "directory") {
    136        // `path` should be the absolute path from the group/domain
    137        if (child.path == path) {
    138          return child;
    139        }
    140        // Ignore folders which doesn't match the beginning of the lookup path
    141        if (!path.startsWith(child.path)) {
    142          continue;
    143        }
    144        const match = findPathInDirectory(child, path);
    145        if (match) {
    146          return match;
    147        }
    148      }
    149    }
    150    return null;
    151  }
    152 }