<commit_before>/**
 * @overview Component to show files in dir
 * @module explorer
 */
import React, { Component } from "react";
import jquery from "jquery";
import camelcase from "camelcase";
import PropTypes from "prop-types";
import { join } from "path";
import { readdir, statSync } from "fs";
import { Grid } from "semantic-ui-react";
import FontAwesome from "react-fontawesome";
import { Redirect } from "react-router-dom";
import { updateDir as chdir } from "../actions";

// NOTE: From https://stackoverflow.com/questions/1828613/check-if-a-key-is-down
const keys = {};
window.onkeyup = function (event) { keys[event.keyCode] = false; };
window.onkeydown = function (event) { keys[event.keyCode] = true; };

/**
 * Truncates a filename if needed
 * @param {String} file Filename to truncate
 * @returns {String} Filename, truncated
 */
function getFileName(file) {
  const TRIM_LENGTH = 13;
  const TRIM_CAPS_LENGTH = 10;
  if (file.length > TRIM_LENGTH) {
    if (file.substring(0, TRIM_LENGTH).toUpperCase() === file.substring(0, TRIM_LENGTH)) {
      // Caps
      return `${file.substring(0, TRIM_CAPS_LENGTH)}...`;
    } else {
      return `${file.substring(0, TRIM_LENGTH)}...`;
    }
  } else {
    return file;
  }
}

/**
 * Normalises a Filename
 * @param {String} filename File path to normalize
 * @returns {String} Normalised file name
 */
function normalise(filename) {
  const camelcased = camelcase(filename);
  const specialChars = [
    ".",
    "'",
    "#",
    ":",
    ";",
    "{",
    "}",
    " ",
    "(",
    ")",
    "@",
    "%",
    "$",
    "*"
  ];
  const replaceWith = ""; // Replace special Chars with this
  let fileNormal = camelcased;
  for (let char of specialChars) {
    fileNormal = fileNormal.split(char).join(replaceWith);
    if (char === specialChars[specialChars.length - 1]) {
      return fileNormal;
    }
  }
}

export default class Dir extends Component {
  constructor(props) {
    super(props);
    this.state = {
      contents: [],
      redirect: ""
    };
    props.dispatch(chdir(props.match.params.dir));
  }
  componentDidMount() {
    // Get dirs
    this.getFiles(this.props.match.params.dir);
  }
  /**
   * Gets files in a dir & sets it to state
   * @param {String} dir dir to look
   * @returns {undefined} Nothing
   */
  getFiles(dir) {
    console.log(dir);
    readdir(dir, (err, files) => {
      if (err) {
        throw err;
      } else {
        this.setState({
          ...this.state,
          contents: files,
          dir: dir
        });
        // Check for double click
        for (let file of this.state.contents) {
          jquery(`#${normalise(file)}`).dblclick(() => {
            // HACK: Rerender the <Dir /> component.  Should work for now
            const DirContainer = require("../containers/show-dir").default;
            const newDir = join(this.props.dir.dir, file);
            global.explorerHistory.push(`/dir/${newDir}`);
            this.setState({
              ...this.state,
              redirect: (<DirContainer match={{ params: { dir: newDir } }} />),
              contents: []
            });
          });
        }
      }
    });
  }
  /**
   * Handle the onClick event
   * @param {String} id ID to look for
   * @returns {Function} onClick Event handler
   */
  handleOnClick(id) {
    return () => {
      // Handle
      if (!document.getElementById(id).className.includes("file-highlighted")) {
        document.getElementById(id).className += " file-highlighted";
        document.body.addEventListener("click", (event) => {
          // Check if this wasn't clicked
          // TODO: Add multiselect by usage of ctrl / shift
          if (event.path[0].id !== id && document.getElementById(id).className.includes("file-highlighted") && !keys[17] && !keys[16]) {
            this.handleOnClick(id)();
            document.body.removeEventListener("click", this, true);
          }
        }, true);
      } else {
        document.getElementById(id).className = document.getElementById(id).className.split(" file-highlighted").join("");
      }
    };
  }
  render() {
    return (
      <div>
        {/* Redirects */}
        { this.state.redirect !== "" ?
          this.state.redirect
          :
          <Grid className="files">
            <Grid.Row>
              <Grid.Column size={2}>
                {
                  this.state.contents.map(file => (statSync(join(this.props.dir.dir, file)).isDirectory() ? // Check if path is dir
                    <div id={normalise(file)} role="presentation" className="file-wrapper" onClick={this.handleOnClick(normalise(file))}>
                      <FontAwesome name="folder" />
                      <p>{getFileName(file)}</p>
                    </div>
                  : null))
                }
                {
                  this.state.contents.map(file => (!statSync(join(this.props.dir.dir, file)).isDirectory() ? // Check if path is file
                    <div id={normalise(file)} role="presentation" className="file-wrapper" onClick={this.handleOnClick(normalise(file))}>
                      <FontAwesome name="file" />
                      <p>{getFileName(file)}</p>
                    </div>
                  : null))
                }
              </Grid.Column>
            </Grid.Row>
          </Grid>
        }
      </div>
    );
  }
}

Dir.propTypes = {
  match: PropTypes.object.isRequired,
  dispatch: PropTypes.func.isRequired,
  dir: PropTypes.object.isRequired
};
<commit_msg>:art: Only allow folders to be opened<commit_after>/**
 * @overview Component to show files in dir
 * @module explorer
 */
import React, { Component } from "react";
import jquery from "jquery";
import camelcase from "camelcase";
import PropTypes from "prop-types";
import { join } from "path";
import { readdir, statSync } from "fs";
import { Grid } from "semantic-ui-react";
import FontAwesome from "react-fontawesome";
import { Redirect } from "react-router-dom";
import { updateDir as chdir } from "../actions";

// NOTE: From https://stackoverflow.com/questions/1828613/check-if-a-key-is-down
const keys = {};
window.onkeyup = function (event) { keys[event.keyCode] = false; };
window.onkeydown = function (event) { keys[event.keyCode] = true; };

/**
 * Truncates a filename if needed
 * @param {String} file Filename to truncate
 * @returns {String} Filename, truncated
 */
function getFileName(file) {
  const TRIM_LENGTH = 13;
  const TRIM_CAPS_LENGTH = 10;
  if (file.length > TRIM_LENGTH) {
    if (file.substring(0, TRIM_LENGTH).toUpperCase() === file.substring(0, TRIM_LENGTH)) {
      // Caps
      return `${file.substring(0, TRIM_CAPS_LENGTH)}...`;
    } else {
      return `${file.substring(0, TRIM_LENGTH)}...`;
    }
  } else {
    return file;
  }
}

/**
 * Normalises a Filename
 * @param {String} filename File path to normalize
 * @returns {String} Normalised file name
 */
function normalise(filename) {
  const camelcased = camelcase(filename);
  const specialChars = [
    ".",
    "'",
    "#",
    ":",
    ";",
    "{",
    "}",
    " ",
    "(",
    ")",
    "@",
    "%",
    "$",
    "*"
  ];
  const replaceWith = ""; // Replace special Chars with this
  let fileNormal = camelcased;
  for (let char of specialChars) {
    fileNormal = fileNormal.split(char).join(replaceWith);
    if (char === specialChars[specialChars.length - 1]) {
      return fileNormal;
    }
  }
}

export default class Dir extends Component {
  constructor(props) {
    super(props);
    this.state = {
      contents: [],
      redirect: ""
    };
    props.dispatch(chdir(props.match.params.dir));
  }
  componentDidMount() {
    // Get dirs
    this.getFiles(this.props.match.params.dir);
  }
  /**
   * Gets files in a dir & sets it to state
   * @param {String} dir dir to look
   * @returns {undefined} Nothing
   */
  getFiles(dir) {
    readdir(dir, (err, files) => {
      if (err) {
        throw err;
      } else {
        this.setState({
          ...this.state,
          contents: files,
          dir: dir
        });
        // Check for double click
        for (let file of this.state.contents) {
          if (statSync(join(dir, file)).isDirectory()) {
            jquery(`#${normalise(file)}`).dblclick(() => {
              // HACK: Rerender the <Dir /> component.  Should work for now
              const DirContainer = require("../containers/show-dir").default;
              const newDir = join(this.props.dir.dir, file);
              global.explorerHistory.push(`/dir/${newDir}`);
              this.setState({
                ...this.state,
                redirect: (<DirContainer match={{ params: { dir: newDir } }} />),
                contents: []
              });
            });
          } else {
            // Handle file opening
          }
        }
      }
    });
  }
  /**
   * Handle the onClick event
   * @param {String} id ID to look for
   * @returns {Function} onClick Event handler
   */
  handleOnClick(id) {
    return () => {
      // Handle
      if (!document.getElementById(id).className.includes("file-highlighted")) {
        document.getElementById(id).className += " file-highlighted";
        document.body.addEventListener("click", (event) => {
          // Check if this wasn't clicked
          // TODO: Add multiselect by usage of ctrl / shift
          if (event.path[0].id !== id && document.getElementById(id).className.includes("file-highlighted") && !keys[17] && !keys[16]) {
            this.handleOnClick(id)();
            document.body.removeEventListener("click", this, true);
          }
        }, true);
      } else {
        document.getElementById(id).className = document.getElementById(id).className.split(" file-highlighted").join("");
      }
    };
  }
  render() {
    return (
      <div>
        {/* Redirects */}
        { this.state.redirect !== "" ?
          this.state.redirect
          :
          <Grid className="files">
            <Grid.Row>
              <Grid.Column size={2}>
                {
                  this.state.contents.map(file => (statSync(join(this.props.dir.dir, file)).isDirectory() ? // Check if path is dir
                    <div id={normalise(file)} role="presentation" className="file-wrapper" onClick={this.handleOnClick(normalise(file))}>
                      <FontAwesome name="folder" />
                      <p>{getFileName(file)}</p>
                    </div>
                  : null))
                }
                {
                  this.state.contents.map(file => (!statSync(join(this.props.dir.dir, file)).isDirectory() ? // Check if path is file
                    <div id={normalise(file)} role="presentation" className="file-wrapper" onClick={this.handleOnClick(normalise(file))}>
                      <FontAwesome name="file" />
                      <p>{getFileName(file)}</p>
                    </div>
                  : null))
                }
              </Grid.Column>
            </Grid.Row>
          </Grid>
        }
      </div>
    );
  }
}

Dir.propTypes = {
  match: PropTypes.object.isRequired,
  dispatch: PropTypes.func.isRequired,
  dir: PropTypes.object.isRequired
};

{'fraction_non_alphanumeric': 0.15293590318242942, 'fraction_numerical': 0.003944419542805917, 'mean_word_length': 2.0766685052399336, 'pattern_counts': {'":': 2, '<': 43, '<?xml version=': 0, '>': 57, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7144558', 'n_tokens_mistral': 3357, 'n_tokens_neox': 3272, 'n_words': 718}