This is the view layer (template) for the file tree in the sidebar. It takes a FileTreeViewModel and renders it to the given element using React. User actions are signaled via an ActionCreator (in the Flux sense).
var _extensions = Immutable.Map();
// Constants
// Time range from first click to second click to invoke renaming.
var CLICK_RENAME_MINIMUM = 500,
RIGHT_MOUSE_BUTTON = 2,
LEFT_MOUSE_BUTTON = 0;
var directoryRenameInput = React.createFactory(React.createClass({
mixins: [renameBehavior],
Mixin for components that support the "icons" and "addClass" extension points.
fileNode
and directoryNode
support this.
var extendable = {
var fileNode = React.createFactory(React.createClass({
mixins: [contextSettable, pathComputer, extendable],
var fileRenameInput = React.createFactory(React.createClass({
mixins: [renameBehavior],
Displays the absolutely positioned box for the selection or context in the file tree. Its position is determined by passed-in info about the scroller in which the tree resides and the top of the selected node (as reported by the node itself).
Props:
var fileSelectionBox = React.createFactory(React.createClass({
Mixin that allows a component to compute the full path to its directory entry.
var pathComputer = {
This is a mixin that provides rename input behavior. It is responsible for taking keyboard input and invoking the correct action based on that input.
var renameBehavior = {
On Windows and Linux, the selection bar in the tree does not extend over the scroll bar. The selectionExtension sits on top of the scroll bar to make the selection bar appear to span the whole width of the sidebar.
Props:
var selectionExtension = React.createFactory(React.createClass({
function _addExtension(category, callback) {
if (!callback || typeof callback !== "function") {
console.error("Attempt to add FileTreeView", category, "extension without a callback function");
return;
}
var callbackList = _extensions.get(category);
if (!callbackList) {
callbackList = Immutable.List();
}
callbackList = callbackList.push(callback);
_extensions = _extensions.set(category, callbackList);
}
function _buildDirsFirstComparator(contents) {
function _dirsFirstCompare(a, b) {
var aIsFile = FileTreeViewModel.isFile(contents.get(a)),
bIsFile = FileTreeViewModel.isFile(contents.get(b));
if (!aIsFile && bIsFile) {
return -1;
} else if (aIsFile && !bIsFile) {
return 1;
} else {
return FileUtils.compareFilenames(a, b);
}
}
return _dirsFirstCompare;
}
function _getName(fullname, extension) {
return extension !== "" ? fullname.substring(0, fullname.length - extension.length - 1) : fullname;
}
function _measureText(text) {
var measuringElement = $("<span />", { css : { "position" : "absolute", "top" : "-200px", "left" : "-1000px", "visibility" : "hidden", "white-space": "pre" } }).appendTo("body");
measuringElement.text("pW" + text);
var width = measuringElement.width();
measuringElement.remove();
return width;
}
function _sortDirectoryContents(contents, dirsFirst) {
if (dirsFirst) {
return contents.keySeq().sort(_buildDirsFirstComparator(contents));
} else {
return contents.keySeq().sort(FileUtils.compareFilenames);
}
}
// Forward references to keep JSLint happy.
var directoryNode, directoryContents;
function addClassesProvider(callback) {
_addExtension("addClass", callback);
}
// Private API for testing
exports._sortFormattedDirectory = _sortDirectoryContents;
exports._fileNode = fileNode;
exports._directoryNode = directoryNode;
exports._directoryContents = directoryContents;
exports._fileTreeView = fileTreeView;
// Public API
exports.addIconProvider = addIconProvider;
exports.addClassesProvider = addClassesProvider;
exports.render = render;
});
function isDefined(value) {
return value !== undefined;
}
Renders the file tree to the given element.
function render(element, viewModel, projectRoot, actions, forceRender, platform) {
if (!projectRoot) {
return;
}
React.render(fileTreeView({
treeData: viewModel.treeData,
selectionViewInfo: viewModel.selectionViewInfo,
sortDirectoriesFirst: viewModel.sortDirectoriesFirst,
parentPath: projectRoot.fullPath,
actions: actions,
extensions: _extensions,
platform: platform,
forceRender: forceRender
}),
element);
}