alm
Version:
The best IDE for TypeScript
1,028 lines • 51.2 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
var socketClient_1 = require("../socket/socketClient");
var types = require("../common/types");
var React = require("react");
var csx = require("./base/csx");
var ReactDOM = require("react-dom");
var ui_1 = require("./ui");
var ui = require("./ui");
var utils = require("../common/utils");
var styles = require("./styles/styles");
var state = require("./state/state");
var react_redux_1 = require("react-redux");
var icon_1 = require("./components/icon");
var commands = require("./commands/commands");
var DraggableCore = ui.DraggableCore;
var utils_1 = require("../common/utils");
var robocop_1 = require("./components/robocop");
var inputDialog_1 = require("./dialogs/inputDialog");
var Mousetrap = require("mousetrap");
var clipboard = require("./components/clipboard");
var appTabsContainer_1 = require("./tabs/v2/appTabsContainer");
var settings = require("./state/settings");
var typestyle = require("typestyle");
var utils_2 = require("../common/utils");
var dirSelected = { isDir: true };
var fileSelected = { isDir: false };
var resizerWidth = 5;
var resizerStyle = {
background: 'radial-gradient(#444,transparent)',
width: resizerWidth + 'px',
cursor: 'ew-resize',
color: '#666',
};
var treeListStyle = {
color: '#eee',
fontSize: '.7rem',
padding: '3px',
};
var treeScrollClassName = typestyle.style({
border: '1px solid grey',
$nest: {
'&:focus': {
outline: 'none',
border: '1px solid ' + styles.highlightColor
}
}
});
var treeItemClassName = typestyle.style({
whiteSpace: 'nowrap',
cursor: 'pointer',
padding: '3px',
userSelect: 'none',
fontSize: '.9em',
opacity: .8,
$nest: {
'&:focus': {
outline: 'none',
}
}
});
var treeItemSelectedStyle = {
backgroundColor: styles.selectedBackgroundColor,
};
var treeItemInProjectStyle = {
color: 'rgb(0, 255, 183)',
opacity: 1,
};
var treeItemIsGeneratedStyle = {
fontSize: '.6em'
};
var currentSelectedItemCopyStyle = {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'pre',
cursor: 'pointer',
marginLeft: '2px',
fontSize: '.6rem',
fontWeight: 'bold',
color: '#CCC',
textShadow: '0 0 3px rgba(255, 255, 255, 0.5)',
};
var helpRowStyle = {
margin: '5px',
lineHeight: '18px'
};
var FileTree = /** @class */ (function (_super) {
__extends(FileTree, _super);
function FileTree(props) {
var _this = _super.call(this, props) || this;
/** can't be pure right now because of how we've written `selectedState` */
// shouldComponentUpdate = pure.shouldComponentUpdate;
/** makes it easier to lookup directories */
_this.dirLookup = {};
_this.loading = true; // guilty till proven innocent
_this.refNames = {
__treeroot: '__treeroot',
__treeViewScroll: '__treeViewScroll',
};
_this.handleDrag = function (evt, ui) {
_this.setState({ width: ui.deltaX + ui.lastX + resizerWidth });
};
_this.handleDragStop = function () {
var width = _this.state.width;
settings.fileTreeWidth.set(width);
};
_this.setupTree = utils_2.throttle(function (props) {
var filePaths = props.filePaths.filter(function (fp) { return fp.type == types.FilePathType.File; }).map(function (fp) { return fp.filePath; });
// initial boot up
if (!filePaths.length) {
return;
}
_this.loading = false;
var rootDirPath = props.rootDir;
var rootDir = {
name: utils.getFileName(rootDirPath),
filePath: rootDirPath,
subDirs: [],
files: []
};
// Always expand root
_this.state.expansionState[rootDirPath] = true;
_this.dirLookup = {};
_this.dirLookup[rootDirPath] = rootDir;
// if not found creates a new dir and set its parent
// (recursively e.g. last was /foo and new is /foo/bar/baz/quz)
var createDirAndMakeSureAllParentExits = function (dir) {
var dirTree = {
name: utils_1.getFileName(dir),
filePath: dir,
subDirs: [],
files: []
};
_this.dirLookup[dir] = dirTree;
var parentDir = utils_1.getDirectory(dir);
var parentDirTree = _this.dirLookup[parentDir];
if (!parentDirTree) {
parentDirTree = createDirAndMakeSureAllParentExits(parentDir);
}
parentDirTree.subDirs.push(dirTree);
return dirTree;
};
for (var _i = 0, filePaths_1 = filePaths; _i < filePaths_1.length; _i++) {
var filePath = filePaths_1[_i];
var dir = utils_1.getDirectory(filePath);
var fileName = utils_1.getFileName(filePath);
var subItem = {
name: fileName,
filePath: filePath,
};
// lookup existing dir
var treeDir = _this.dirLookup[dir];
if (!treeDir) {
treeDir = createDirAndMakeSureAllParentExits(dir);
}
treeDir.files.push(subItem);
}
_this.setState({ treeRoot: rootDir, expansionState: _this.state.expansionState });
/** Also add the folders that may have no files */
var dirs = props.filePaths.filter(function (fp) { return fp.type == types.FilePathType.Dir; }).map(function (fp) { return fp.filePath; });
dirs.forEach(function (dirPath) {
var treeDir = _this.dirLookup[dirPath];
if (!treeDir) {
createDirAndMakeSureAllParentExits(dirPath);
}
});
/**
* keep the selected file paths in sync with all the items that are available
*/
// A map for easier lookup
var filePathMap = utils.createMap(filePaths);
var oldSelectedPaths = Object.keys(_this.state.selectedPaths);
var newSelectedPaths = {};
oldSelectedPaths.forEach(function (path) {
var isDir = _this.state.selectedPaths[path].isDir;
if (!filePathMap[path]) {
return;
}
newSelectedPaths[path] = { isDir: isDir };
});
// If there is no selected path select the root
if (Object.keys(newSelectedPaths).length === 0) {
newSelectedPaths[rootDirPath] = { isDir: true };
}
_this.setState({ selectedPaths: newSelectedPaths });
/**
* Loading had focus. Transfer focus to root
*/
if (document.activeElement === _this.refs['loading']) {
setTimeout(function () {
var selectedPaths = (_a = {},
_a[_this.state.treeRoot.filePath] = dirSelected,
_a);
_this.setState({ selectedPaths: selectedPaths });
_this.focusOnPath(_this.state.treeRoot.filePath);
var _a;
}, 500);
}
}, 1000);
_this.handleToggleDir = function (evt, item) {
evt.stopPropagation();
var dirPath = item.filePath;
var selectedPaths = (_a = {},
_a[dirPath] = dirSelected,
_a);
_this.state.expansionState[dirPath] = !_this.state.expansionState[dirPath];
_this.setState({ expansionState: _this.state.expansionState, selectedPaths: selectedPaths });
var _a;
};
_this.handleSelectFile = function (evt, item) {
evt.stopPropagation();
var filePath = item.filePath;
var selectedPaths = (_a = {},
_a[filePath] = fileSelected,
_a);
_this.setState({ selectedPaths: selectedPaths });
commands.doOpenOrActivateFileTab.emit({ filePath: filePath });
var _a;
};
_this.state = {
width: 200,
expansionState: {},
selectedPaths: {},
treeRoot: { name: 'loading', filePath: 'loading', subDirs: [], files: [] },
treeScrollHasFocus: false,
};
_this.setupTree(props);
return _this;
// debug
// this.state.shown = true; // debug
}
FileTree.prototype.componentWillReceiveProps = function (props) {
this.setupTree(props);
};
FileTree.prototype.componentDidMount = function () {
var _this = this;
settings.fileTreeWidth.get().then(function (res) {
var width = res || _this.state.width;
width = Math.min(window.innerWidth - 100, width);
_this.setState({ width: width });
});
var handleFocusRequestBasic = function (shown) {
if (!shown) {
state.expandFileTree({});
}
var selectedFilePaths = Object.keys(_this.state.selectedPaths);
var pathToFocus = selectedFilePaths.length > 0 && _this.ref(selectedFilePaths[selectedFilePaths.length - 1])
? selectedFilePaths[selectedFilePaths.length - 1]
: _this.state.treeRoot.filePath;
_this.focusOnPath(pathToFocus);
return false;
};
this.disposible.add(commands.esc.on(function () {
if (_this.state.showHelp) {
_this.setState({ showHelp: false });
setTimeout(function () { return _this.focusOnPath(_this.state.treeRoot.filePath); }, 150);
}
}));
this.disposible.add(commands.treeViewToggle.on(function () {
var shown = _this.props.fileTreeShown;
shown ? state.collapseFileTree({}) : state.expandFileTree({});
if (!shown) {
handleFocusRequestBasic(true);
}
else {
commands.esc.emit({});
}
}));
this.disposible.add(commands.treeViewRevealActiveFile.on(function () {
if (!_this.props.fileTreeShown) {
state.expandFileTree({});
}
var selectedTab = appTabsContainer_1.tabState.getSelectedTab();
if (selectedTab && selectedTab.url.startsWith('file://')) {
var filePath = utils.getFilePathFromUrl(selectedTab.url);
// expand the tree to make sure this file is visible
var root = _this.state.treeRoot.filePath;
var remainderAfterRoot = filePath.substr(root.length + 1 /* for `/` */);
var dirPortionsAfterRoot = utils.getDirectory(remainderAfterRoot).split('/');
var runningPortion = '';
var expanded = {};
expanded[root] = true;
for (var _i = 0, dirPortionsAfterRoot_1 = dirPortionsAfterRoot; _i < dirPortionsAfterRoot_1.length; _i++) {
var portion = dirPortionsAfterRoot_1[_i];
runningPortion = runningPortion + '/' + portion;
var fullPath = root + runningPortion;
expanded[fullPath] = true;
}
var expansionState = csx.extend(_this.state.expansionState, expanded);
// also only select this node
var selectedPaths = (_a = {},
_a[filePath] = fileSelected,
_a);
_this.setState({ expansionState: expansionState, selectedPaths: selectedPaths });
_this.focusOnPath(filePath);
}
else {
handleFocusRequestBasic(true);
}
return false;
var _a;
}));
this.disposible.add(commands.treeViewFocus.on(function () {
handleFocusRequestBasic(_this.props.fileTreeShown);
}));
/**
* Utility: takes the selected state to the last item selected
* If no item selected it selects the root
*/
var goDownToSmallestSelection = function () {
var selectedFilePaths = Object.keys(_this.state.selectedPaths);
if (selectedFilePaths.length == 0) {
var selectedPaths = (_a = {},
_a[_this.state.treeRoot.filePath] = fileSelected,
_a);
_this.setState({ selectedPaths: selectedPaths });
}
else if (selectedFilePaths.length > 1) {
var path = selectedFilePaths[selectedFilePaths.length - 1];
var selectedPaths = (_b = {},
_b[path] = _this.state.selectedPaths[path],
_b);
_this.setState({ selectedPaths: selectedPaths });
}
else {
// already single selection :)
}
var selectedFilePath = Object.keys(_this.state.selectedPaths)[0];
var selectedFilePathDetails = _this.state.selectedPaths[selectedFilePath];
return { selectedFilePath: selectedFilePath, isDir: selectedFilePathDetails.isDir };
var _a, _b;
};
/**
* Utility : gets you the last item selected if any, otherwise the root dir
* Does not modify state
*/
var getLastSelected = function () {
var selectedFilePaths = Object.keys(_this.state.selectedPaths);
var last = selectedFilePaths[selectedFilePaths.length - 1];
if (!last) {
return { filePath: _this.state.treeRoot.filePath, isDir: true };
}
var selectedFilePathDetails = _this.state.selectedPaths[last];
return { filePath: last, isDir: selectedFilePathDetails.isDir };
};
/** Utility : set an item as the only selected */
var setAsOnlySelectedNoFocus = function (filePath, isDir) {
var selectedPaths = (_a = {},
_a[filePath] = { isDir: isDir },
_a);
_this.setState({ selectedPaths: selectedPaths });
var _a;
};
var setAsOnlySelected = function (filePath, isDir) {
setAsOnlySelectedNoFocus(filePath, isDir);
_this.focusOnPath(filePath);
};
/**
* Used in handling keyboard for tree items
*/
var treeRoot = this.ref('__treeroot');
var handlers = new Mousetrap(treeRoot);
/**
* file action handlers
*/
handlers.bind(commands.treeAddFile.config.keyboardShortcut, function () {
if (_this.loading)
return;
var lastSelected = getLastSelected();
var dirPath = lastSelected.isDir ? lastSelected.filePath : utils.getDirectory(lastSelected.filePath);
inputDialog_1.inputDialog.open({
header: "Enter a file name",
onOk: function (value) {
var filePath = value;
socketClient_1.server.addFile({ filePath: filePath }).then(function (res) {
commands.doOpenOrFocusFile.emit({ filePath: filePath });
});
},
onEsc: function () {
setTimeout(handleFocusRequestBasic, 150);
},
filterValue: dirPath + '/',
});
return false;
});
handlers.bind(commands.treeAddFolder.config.keyboardShortcut, function () {
if (_this.loading)
return;
var lastSelected = getLastSelected();
var dirPath = lastSelected.isDir ? lastSelected.filePath : utils.getDirectory(lastSelected.filePath);
inputDialog_1.inputDialog.open({
header: "Enter a folder name",
onOk: function (value) {
var filePath = value;
socketClient_1.server.addFolder({ filePath: filePath }).then(function (res) {
ui.notifyInfoQuickDisappear('Folder created');
});
},
onEsc: function () {
setTimeout(handleFocusRequestBasic, 150);
},
filterValue: dirPath + '/',
});
return false;
});
handlers.bind(commands.treeDuplicateFile.config.keyboardShortcut, function () {
if (_this.loading)
return;
var selection = goDownToSmallestSelection();
if (!selection) {
ui.notifyInfoNormalDisappear('Nothing selected');
return false;
}
var parentDir = utils.getDirectory(selection.selectedFilePath);
if (selection.isDir) {
inputDialog_1.inputDialog.open({
header: "Enter a new directory name",
onOk: function (value) {
var filePath = value;
socketClient_1.server.duplicateDir({ src: selection.selectedFilePath, dest: filePath });
setAsOnlySelectedNoFocus(filePath, true);
_this.state.expansionState[filePath] = true;
_this.setState({ expansionState: _this.state.expansionState });
},
onEsc: function () {
setTimeout(handleFocusRequestBasic, 150);
},
filterValue: parentDir + '/',
});
}
else {
inputDialog_1.inputDialog.open({
header: "Enter a new file name",
onOk: function (value) {
var filePath = value;
socketClient_1.server.duplicateFile({ src: selection.selectedFilePath, dest: filePath });
commands.doOpenOrFocusFile.emit({ filePath: filePath });
setAsOnlySelectedNoFocus(filePath, false);
},
onEsc: function () {
setTimeout(handleFocusRequestBasic, 150);
},
filterValue: parentDir + '/',
});
}
return false;
});
handlers.bind([commands.treeMoveFile.config.keyboardShortcut, commands.treeRenameFile.config.keyboardShortcut], function () {
if (_this.loading)
return;
var selection = goDownToSmallestSelection();
if (!selection) {
ui.notifyInfoNormalDisappear('Nothing selected');
return false;
}
inputDialog_1.inputDialog.open({
header: "Enter a new location",
onOk: function (value) {
var filePath = value;
socketClient_1.server.movePath({ src: selection.selectedFilePath, dest: filePath }).then(function (res) {
if (res.error) {
ui.notifyWarningNormalDisappear("Failed to move: " + res.error);
return;
}
if (selection.isDir) {
setAsOnlySelectedNoFocus(filePath, true);
_this.state.expansionState[filePath] = true;
_this.setState({ expansionState: _this.state.expansionState });
commands.closeFilesDirs.emit({ files: [], dirs: [selection.selectedFilePath] });
}
else {
commands.doOpenOrFocusFile.emit({ filePath: filePath });
setAsOnlySelectedNoFocus(filePath, false);
commands.closeFilesDirs.emit({ files: [selection.selectedFilePath], dirs: [] });
}
});
},
onEsc: function () {
setTimeout(handleFocusRequestBasic, 150);
},
filterValue: selection.selectedFilePath,
});
return false;
});
handlers.bind([commands.treeDeleteFile.config.keyboardShortcut, "backspace"], function () {
if (_this.loading)
return;
var selectedFilePaths = Object.keys(_this.state.selectedPaths);
var selectedFilePathsDetails = selectedFilePaths.map(function (fp) {
return {
filePath: fp,
isDir: _this.state.selectedPaths[fp].isDir
};
});
if (selectedFilePaths.length == 0) {
ui.notifyInfoNormalDisappear('Nothing selected');
return false;
}
if (selectedFilePaths.some(function (fp) { return fp == _this.state.treeRoot.filePath; })) {
ui.notifyWarningNormalDisappear("You cannot delete the root working directory");
return false;
}
inputDialog_1.inputDialog.open({
hideInput: true,
header: "Delete " + (selectedFilePaths.length > 1 ? selectedFilePaths.length + ' items' : utils.getFileName(selectedFilePaths[0])) + "?",
onOk: function () {
var files = selectedFilePathsDetails.filter(function (x) { return !x.isDir; }).map(function (x) { return x.filePath; });
var dirs = selectedFilePathsDetails.filter(function (x) { return x.isDir; }).map(function (x) { return x.filePath; });
socketClient_1.server.deleteFromDisk({ files: files, dirs: dirs }).then(function (res) {
commands.closeFilesDirs.emit({ files: files, dirs: dirs });
// Leave selection in a useful state
var lastSelectedDetails = selectedFilePathsDetails[selectedFilePathsDetails.length - 1].filePath;
setAsOnlySelected(utils.getDirectory(lastSelectedDetails), true);
});
},
onEsc: function () {
setTimeout(handleFocusRequestBasic, 150);
}
});
return false;
});
handlers.bind(commands.treeOpenInExplorerFinder.config.keyboardShortcut, function () {
if (_this.loading)
return;
var selection = goDownToSmallestSelection();
if (!selection) {
ui.notifyInfoNormalDisappear('Nothing selected');
return false;
}
var dirFilePath = selection.selectedFilePath;
if (!selection.isDir) {
dirFilePath = utils.getDirectory(dirFilePath);
}
socketClient_1.server.launchDirectory({ filePath: dirFilePath });
ui.notifySuccessNormalDisappear("Command to open sent: " + dirFilePath);
return false;
});
handlers.bind(commands.treeOpenInCmdTerminal.config.keyboardShortcut, function () {
if (_this.loading)
return;
var selection = goDownToSmallestSelection();
if (!selection) {
ui.notifyInfoNormalDisappear('Nothing selected');
return false;
}
var dirFilePath = selection.selectedFilePath;
if (!selection.isDir) {
dirFilePath = utils.getDirectory(dirFilePath);
}
socketClient_1.server.launchTerminal({ filePath: dirFilePath });
ui.notifySuccessNormalDisappear("Command to open cmd/terminal sent: " + dirFilePath);
return false;
});
/**
* navigation handlers
*/
handlers.bind('enter', function () {
if (_this.loading)
return;
var _a = goDownToSmallestSelection(), selectedFilePath = _a.selectedFilePath, isDir = _a.isDir;
if (isDir) {
_this.state.expansionState[selectedFilePath] = !_this.state.expansionState[selectedFilePath];
_this.setState({ expansionState: _this.state.expansionState });
}
else {
commands.doOpenOrFocusFile.emit({ filePath: selectedFilePath });
}
return false;
});
handlers.bind('up', function () {
if (_this.loading)
return;
var _a = goDownToSmallestSelection(), selectedFilePath = _a.selectedFilePath, isDir = _a.isDir;
// if root do nothing
if (selectedFilePath == _this.state.treeRoot.filePath) {
return;
}
// find the parent dir &&
// find this in the parent dir
var parentDirFilePath = utils.getDirectory(selectedFilePath);
var parentDirTreeItem = _this.dirLookup[parentDirFilePath];
var indexInParentDir = isDir
? parentDirTreeItem.subDirs.map(function (x) { return x.filePath; }).indexOf(selectedFilePath)
: parentDirTreeItem.files.map(function (x) { return x.filePath; }).indexOf(selectedFilePath);
/** Goes to the bottom file / folder */
var gotoBottomOfFolder = function (closestDir) {
while (true) {
if (!_this.state.expansionState[closestDir.filePath]) {
setAsOnlySelected(closestDir.filePath, true);
break;
}
if (closestDir.files.length) {
setAsOnlySelected(closestDir.files[closestDir.files.length - 1].filePath, false);
break;
}
else if (closestDir.subDirs.length) {
closestDir = closestDir.subDirs[closestDir.subDirs.length - 1];
continue;
}
else {
setAsOnlySelected(closestDir.filePath, true);
break;
}
}
};
// if first
if (indexInParentDir == 0) {
if (isDir) {
setAsOnlySelected(parentDirFilePath, true);
}
else if (parentDirTreeItem.subDirs.length == 0) {
setAsOnlySelected(parentDirFilePath, true);
}
else {
gotoBottomOfFolder(parentDirTreeItem.subDirs[parentDirTreeItem.subDirs.length - 1]);
}
}
else if (!isDir) {
setAsOnlySelected(parentDirTreeItem.files[indexInParentDir - 1].filePath, false);
}
else {
var closestDir = parentDirTreeItem.subDirs[indexInParentDir - 1];
gotoBottomOfFolder(closestDir);
}
return false;
});
handlers.bind('down', function () {
if (_this.loading)
return;
var _a = goDownToSmallestSelection(), selectedFilePath = _a.selectedFilePath, isDir = _a.isDir;
/** Goes to next sibling on any (recursive) parent folder */
var gotoNextSiblingHighUp = function (treeItem) {
// Special handling for root. Don't change selection :)
if (treeItem.filePath == _this.state.treeRoot.filePath) {
return;
}
var parentDirFilePath = utils.getDirectory(treeItem.filePath);
var parentTreeItem = _this.dirLookup[parentDirFilePath];
var indexInParent = parentTreeItem.subDirs.map(function (x) { return x.filePath; }).indexOf(treeItem.filePath);
if (indexInParent !== (parentTreeItem.subDirs.length - 1)) {
setAsOnlySelected(parentTreeItem.subDirs[indexInParent + 1].filePath, true);
}
else if (parentTreeItem.files.length) {
setAsOnlySelected(parentTreeItem.files[0].filePath, false);
}
else {
gotoNextSiblingHighUp(parentTreeItem);
}
};
if (isDir) {
var dirTreeItem = _this.dirLookup[selectedFilePath];
// If expanded and has children, select first relevant child
if (_this.state.expansionState[selectedFilePath]
&& (dirTreeItem.files.length || dirTreeItem.subDirs.length)) {
dirTreeItem.subDirs[0]
? setAsOnlySelected(dirTreeItem.subDirs[0].filePath, true)
: setAsOnlySelected(dirTreeItem.files[0].filePath, false);
}
else {
// Else find the next sibling dir
gotoNextSiblingHighUp(dirTreeItem);
}
}
else {
var parentDirFilePath = utils.getDirectory(selectedFilePath);
var parentTreeItem = _this.dirLookup[parentDirFilePath];
var indexInParent = parentTreeItem.files.map(function (f) { return f.filePath; }).indexOf(selectedFilePath);
// if not last select next sibling
if (indexInParent !== (parentTreeItem.files.length - 1)) {
setAsOnlySelected(parentTreeItem.files[indexInParent + 1].filePath, false);
}
else {
gotoNextSiblingHighUp(parentTreeItem);
}
}
return false;
});
handlers.bind('left', function () {
if (_this.loading)
return;
var _a = goDownToSmallestSelection(), selectedFilePath = _a.selectedFilePath, isDir = _a.isDir;
if (isDir) {
// if expanded then collapse
if (_this.state.expansionState[selectedFilePath]) {
delete _this.state.expansionState[selectedFilePath];
_this.setState({ expansionState: _this.state.expansionState });
return;
}
// if root ... leave
if (_this.state.treeRoot.filePath == selectedFilePath) {
return;
}
}
// Goto the parent directory
setAsOnlySelected(utils.getDirectory(selectedFilePath), true);
return false;
});
handlers.bind('right', function () {
if (_this.loading)
return;
var _a = goDownToSmallestSelection(), selectedFilePath = _a.selectedFilePath, isDir = _a.isDir;
if (isDir) {
// just expand
_this.state.expansionState[selectedFilePath] = true;
_this.setState({ expansionState: _this.state.expansionState });
return false;
}
return false;
});
handlers.bind('h', function () {
_this.setState({ showHelp: !_this.state.showHelp });
});
handlers.bind('c', function () {
var copyButtonRef = _this.ref('copypath');
if (!copyButtonRef) {
ui.notifyInfoNormalDisappear('Nothing selected');
return;
}
var copypathDom = ReactDOM.findDOMNode(copyButtonRef);
copypathDom.click();
});
/**
* TS to js and JS to ts
*/
handlers.bind('t', function () {
if (_this.loading)
return;
var selection = goDownToSmallestSelection();
if (!selection) {
ui.notifyInfoNormalDisappear('Nothing selected');
return false;
}
var filePath = selection.selectedFilePath;
if (selection.isDir ||
(!filePath.endsWith('.js')) && !filePath.endsWith('.jsx')) {
ui.notifyInfoNormalDisappear('Please select a `.js`/`jsx` file');
return false;
}
var newFilePath = filePath.replace(/\.js$/g, '.ts').replace(/\.jsx$/g, '.tsx');
socketClient_1.server.movePath({ src: filePath, dest: newFilePath }).then(function (res) {
commands.doOpenOrFocusFile.emit({ filePath: newFilePath });
setAsOnlySelectedNoFocus(newFilePath, false);
commands.closeFilesDirs.emit({ files: [filePath], dirs: [] });
ui.notifySuccessNormalDisappear('File extension changed to be TypeScript');
});
return false;
});
handlers.bind('j', function () {
if (_this.loading)
return;
var selection = goDownToSmallestSelection();
if (!selection) {
ui.notifyInfoNormalDisappear('Nothing selected');
return false;
}
var filePath = selection.selectedFilePath;
if (selection.isDir ||
(!filePath.endsWith('.ts')) && !filePath.endsWith('.tsx')) {
ui.notifyInfoNormalDisappear('Please select a `.ts`/`tsx` file');
return false;
}
var newFilePath = filePath.replace(/\.ts$/g, '.js').replace(/\.tsx$/g, '.jsx');
socketClient_1.server.movePath({ src: filePath, dest: newFilePath }).then(function (res) {
commands.doOpenOrFocusFile.emit({ filePath: newFilePath });
setAsOnlySelectedNoFocus(newFilePath, false);
commands.closeFilesDirs.emit({ files: [filePath], dirs: [] });
ui.notifySuccessNormalDisappear('File extension changed to be JavaScript');
});
return false;
});
};
FileTree.prototype.render = function () {
var _this = this;
var singlePathSelected = Object.keys(this.state.selectedPaths).length == 1
&& Object.keys(this.state.selectedPaths)[0];
var hideStyle = !this.props.fileTreeShown && { display: 'none' };
var haveFocus = this.state.treeScrollHasFocus;
var helpOpacity = haveFocus ? 1 : 0;
return (React.createElement("div", { ref: this.refNames.__treeroot, className: "alm-tree-root", style: csx.extend(csx.flexRoot, csx.horizontal, { width: this.state.width, zIndex: 6 }, hideStyle) },
React.createElement("div", { style: csx.extend(csx.flex, csx.vertical, treeListStyle, styles.someChildWillScroll, csx.newLayerParent) },
React.createElement("div", { ref: this.refNames.__treeViewScroll, className: treeScrollClassName, style: csx.extend(csx.flex, csx.scroll), tabIndex: 0, onFocus: function () { return _this.setState({ treeScrollHasFocus: true }); }, onBlur: function () { return _this.setState({ treeScrollHasFocus: false }); } }, this.renderDir(this.state.treeRoot)),
this.props.filePathsCompleted || React.createElement(robocop_1.Robocop, null),
singlePathSelected
&& React.createElement("div", { style: csx.extend(csx.content, csx.horizontal, csx.center, csx.centerJustified, { paddingTop: '5px', paddingBottom: '5px', width: this.state.width - 15 + 'px' }) },
React.createElement(clipboard.Clipboard, { ref: 'copypath', text: singlePathSelected }),
React.createElement("span", { className: "hint--top", "data-hint": "Click to copy the file path to clipboard", "data-clipboard-text": singlePathSelected, style: currentSelectedItemCopyStyle, onClick: function () { return ui.notifyInfoQuickDisappear("Path copied to clipboard"); } }, singlePathSelected)),
React.createElement("div", { style: csx.extend(csx.content, csx.centerCenter, { fontSize: '.7em', lineHeight: '2em', opacity: helpOpacity, transition: 'opacity .2s' }) },
React.createElement("span", null,
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "H"),
" to toggle tree view help")),
this.state.showHelp
&& React.createElement("div", { style: csx.extend(csx.newLayer, csx.centerCenter, csx.flex, { background: 'rgba(0,0,0,.7)' }), onClick: function () { return _this.setState({ showHelp: false }); } },
React.createElement("div", { style: csx.extend(csx.flexRoot, csx.vertical) },
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "ESC"),
" to hide help"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "A"),
" to add a file"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "Shift + A"),
" to add a folder"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "D"),
" to duplicate file / folder"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "M"),
" to move file / folder"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "R"),
" to rename file / folder"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "C"),
" to copy path to clipboard"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "O"),
" to open in explorer/finder"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "Shift + O"),
" to open in cmd/terminal"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "T"),
" to change .js to .ts"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "J"),
" to change .ts to .js"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "arrow keys"),
" to browse"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "del or backspace"),
" to delete"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle }, "enter"),
" to open file / expand dir"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle },
commands.modName,
" + \\"),
" to toggle tree view"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle },
"Shift + ",
commands.modName,
" + \\"),
" to locate open file in view"),
React.createElement("div", { style: helpRowStyle },
"Tap ",
React.createElement("span", { style: styles.Tip.keyboardShortCutStyle },
" ",
commands.modName,
" + 0"),
" to focus on tree view")))),
React.createElement(DraggableCore, { onDrag: this.handleDrag, onStop: this.handleDragStop },
React.createElement("div", { style: csx.extend(csx.flexRoot, csx.centerCenter, resizerStyle) },
React.createElement(icon_1.Icon, { name: "ellipsis-v" })))));
};
FileTree.prototype.renderDir = function (item, depth) {
if (depth === void 0) { depth = 0; }
var expanded = this.state.expansionState[item.filePath];
var sub = expanded ? this.renderDirSub(item, depth) : [];
var selected = !!this.state.selectedPaths[item.filePath];
return ([React.createElement(TreeNode.Dir, { key: item.filePath, ref: item.filePath, item: item, depth: depth, selected: selected, expanded: expanded, handleToggleDir: this.handleToggleDir, activeProjectFilePathTruthTable: this.props.activeProjectFilePathTruthTable })].concat(sub));
};
FileTree.prototype.renderDirSub = function (item, depth) {
var _this = this;
return item.subDirs.map(function (item) { return _this.renderDir(item, depth + 1); })
.concat(item.files.map(function (file) { return _this.renderFile(file, depth + 1); }));
};
FileTree.prototype.renderFile = function (item, depth) {
var selected = !!this.state.selectedPaths[item.filePath];
return (React.createElement(TreeNode.File, { ref: item.filePath, key: item.filePath, item: item, depth: depth, selected: selected, handleSelectFile: this.handleSelectFile, activeProjectFilePathTruthTable: this.props.activeProjectFilePathTruthTable }));
};
FileTree.prototype.focusOnPath = function (filePath) {
if (!this.ref(filePath))
return;
this.refs['__treeViewScroll'].focus();
this.ref(filePath).focus();
};
FileTree.prototype.componentWillUpdate = function (nextProps, nextState) {
if (nextState.width !== this.state.width
|| nextProps.fileTreeShown !== this.props.fileTreeShown) {
appTabsContainer_1.tabState.debouncedResize();
}
};
FileTree = __decorate([
react_redux_1.connect(function (state) {
return {
filePaths: state.filePaths,
filePathsCompleted: state.filePathsCompleted,
rootDir: state.rootDir,
activeProjectFilePathTruthTable: state.activeProjectFilePathTruthTable,
fileTreeShown: state.fileTreeShown,
};
}),
__metadata("design:paramtypes", [Object])
], FileTree);
return FileTree;
}(ui_1.BaseComponent));
exports.FileTree = FileTree;
var TreeNode;
(function (TreeNode) {
var Dir = /** @class */ (function (_super) {
__extends(Dir, _super);
function Dir() {
return _super !== null && _super.apply(this, arguments) || this;
}
Dir.prototype.focus = function (filePath) {
this.refs['root'].scrollIntoViewIfNeeded(false);
};
Dir.prototype.render = function () {
var _this = this;
var _a = this.props, item = _a.item, depth = _a.depth, expanded = _a.expanded;
var icon = expanded ? 'folder-open' : 'folder';
var selectedStyle = this.props.selected ? treeItemSelectedStyle : {};
var inProjectStyle = this.props.activeProjectFilePathTruthTable[item.filePath] ? treeItemInProjectStyle : {};
return (React.createElement("div", { className: treeItemClassName, style: csx.extend(selectedStyle, inProjectStyle), key: item.filePath, ref: 'root', tabIndex: -1, onClick: function (evt) { return _this.props.handleToggleDir(evt, item); } },
React.createElement("div", { style: { marginLeft: depth * 10 } },
" ",
React.createElement(icon_1.Icon, { name: icon }),
" ",
item.name)));
};
return Dir;
}(React.PureComponent));
TreeNode.Dir = Dir;
/**
* File Name Based Icon
*/
var FileNameBasedIcon = /** @class */ (function (_super) {
__extends(FileNameBasedIcon, _super);
function FileNameBasedIcon() {
return _super !== null && _super.apply(this, arguments) || this;
}
FileNameBasedIcon.prototype.render = function () {
var fileName = this.props.fileName.toLowerCase();
var ext = utils.getExt(fileName);
// Default
var iconName = 'file-text-o';
if (ext == 'md') {
iconName = 'book';
}
else if (ext == 'json') {
iconName = 'database';
}
else if (ext == 'html' || ext == 'htm') {
iconName = 'file-code-o';
}
else if (ext == 'css' || ext == 'less' || ext == 'scss' || ext == 'sass') {
iconName = 'css3';
}
else if (ext.startsWith('git')) {
iconName = 'github';
}
else if (ext.endsWith('sh') || ext == 'bat' || ext == 'batch') {
iconName = 'terminal';
}
else if (ext.endsWith('coffee')) {
iconName = 'coffee';
}
else if (utils.isTs(fileName)) {
iconName = 'rocket';
}
else if (utils.isJs(fileName)) {
iconName = 'plane';
}
else if (utils.isImage(fileName)) {
iconName = 'file-image-o';
}
var icon = React.createElement(icon_1.Icon, { name: iconName });
return React.createElement("div", null,
icon,
" ",
this.props.fileName);
};
return FileNameBasedIcon;
}(React.PureComponent));
/** Renders the file item */
var File = /** @class */ (function (_super) {
__extends(File, _super);
function File() {
return _super !== null && _super.apply(this, arguments) || this;
}
File.prototype.focus = function () {
this.refs['root'].scrollIntoViewIfNeeded(false);
};
File.prototype.render = function () {
var _this = this;
var filePath = this.props.item.filePath;
var selectedStyle = this.props.selected ? treeItemSelectedStyle : {};
var inProjectStyle = this.props.activeProjectFilePathTruthTable[filePath] ? treeItemInProjectStyle : {};
/** Determine if generated