SlideShare a Scribd company logo
Simplifying JavaScript Projects
with ReactJS and Friends
Kevin Dangoor, Sr. Computer Scientist, Adobe
1DevDay Detroit 2014
A modern, open source text editor that understands web design.
Brackets
• MIT-licensed open source
• Sponsored by Adobe with hundreds of contributors and a number of
non-Adobe committers
• 13th most starred project
• Hundreds of extensions are available
• 1.0 just released 10 days ago, with Extract for Brackets
Simplifying JavaScript Projects with ReactJS
function	
  _documentSelectionFocusChange()	
  {	
  
	
  	
  	
  	
  var	
  curFile	
  =	
  EditorManager.getCurrentlyViewedPath();	
  
	
  	
  	
  	
  if	
  (curFile	
  &&	
  _hasFileSelectionFocus())	
  {	
  
function	
  _documentSelectionFocusChange()	
  {	
  
	
  	
  	
  	
  var	
  curFile	
  =	
  EditorManager.getCurrentlyViewedPath();	
  
	
  	
  	
  	
  if	
  (curFile	
  &&	
  _hasFileSelectionFocus())	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  nodeFound	
  =	
  $("#project-­‐files-­‐container	
  li").is(function	
  (index)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  $treeNode	
  =	
  $(this),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  entry	
  =	
  $treeNode.data("entry");	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (entry	
  &&	
  entry.fullPath	
  ===	
  curFile)	
  {	
  
	
  
function	
  _documentSelectionFocusChange()	
  {	
  
	
  	
  	
  	
  var	
  curFile	
  =	
  EditorManager.getCurrentlyViewedPath();	
  
	
  	
  	
  	
  if	
  (curFile	
  &&	
  _hasFileSelectionFocus())	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  nodeFound	
  =	
  $("#project-­‐files-­‐container	
  li").is(function	
  (index)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  $treeNode	
  =	
  $(this),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  entry	
  =	
  $treeNode.data("entry");	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (entry	
  &&	
  entry.fullPath	
  ===	
  curFile)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (!_projectTree.jstree("is_selected",	
  $treeNode))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  ($treeNode.parents(".jstree-­‐closed").length)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //don't	
  auto-­‐expand	
  tree	
  to	
  show	
  file	
  -­‐	
  but	
  remember	
  it	
  if	
  parent	
  is	
  manually	
  
expanded	
  later	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  _projectTree.jstree("deselect_all");	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  _lastSelected	
  =	
  $treeNode;	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  
if	
  (!_projectTree.jstree("is_selected",	
  $treeNode))	
  {	
  
	
  	
  	
  	
  if	
  ($treeNode.parents(".jstree-­‐closed").length)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //don't	
  auto-­‐expand	
  tree	
  to	
  show	
  file	
  -­‐	
  but	
  remember	
  it	
  if	
  parent	
  is	
  manually	
  expanded	
  later	
  
	
  	
  	
  	
  	
  	
  	
  	
  _projectTree.jstree("deselect_all");	
  
	
  	
  	
  	
  	
  	
  	
  	
  _lastSelected	
  =	
  $treeNode;	
  
	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //we	
  don't	
  want	
  to	
  trigger	
  another	
  selection	
  change	
  event,	
  so	
  manually	
  deselect	
  
	
  	
  	
  	
  	
  	
  	
  	
  //and	
  select	
  without	
  sending	
  out	
  notifications	
  
	
  	
  	
  	
  	
  	
  	
  	
  _projectTree.jstree("deselect_all");	
  
	
  	
  	
  	
  	
  	
  	
  	
  _projectTree.jstree("select_node",	
  $treeNode,	
  false);	
  //	
  sets	
  _lastSelected	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
If it’s hard to test,
it won’t be tested.
http://www.infoq.com/presentations/Simple-Made-Easy
simple!
composed of one thing, not combined
complect!
interweave
function	
  _documentSelectionFocusChange()	
  {	
  
	
  	
  	
  	
  var	
  curFile	
  =	
  EditorManager.getCurrentlyViewedPath();	
  
	
  	
  	
  	
  if	
  (curFile	
  &&	
  _hasFileSelectionFocus())	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  nodeFound	
  =	
  $("#project-­‐files-­‐container	
  li").is(function	
  (index)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  $treeNode	
  =	
  $(this),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  entry	
  =	
  $treeNode.data("entry");	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (entry	
  &&	
  entry.fullPath	
  ===	
  curFile)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (!_projectTree.jstree("is_selected",	
  $treeNode))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  ($treeNode.parents(".jstree-­‐closed").length)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //don't	
  auto-­‐expand	
  tree	
  to	
  show	
  file	
  -­‐	
  but	
  remember	
  it	
  if	
  parent	
  is	
  manually	
  
expanded	
  later	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  _projectTree.jstree("deselect_all");	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  _lastSelected	
  =	
  $treeNode;	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  
Simple?
easy!
near at hand
React
https://www.destroyallsoftware.com/talks/boundaries
Functional core,
Integration shell
function	
  _documentSelectionFocusChange()	
  {	
  
	
  	
  	
  	
  var	
  curFile	
  =	
  EditorManager.getCurrentlyViewedPath();	
  
	
  	
  	
  	
  if	
  (curFile	
  &&	
  _hasFileSelectionFocus())	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  nodeFound	
  =	
  $("#project-­‐files-­‐container	
  li").is(function	
  (index)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  $treeNode	
  =	
  $(this),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  entry	
  =	
  $treeNode.data("entry");	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (entry	
  &&	
  entry.fullPath	
  ===	
  curFile)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (!_projectTree.jstree("is_selected",	
  $treeNode))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  ($treeNode.parents(".jstree-­‐closed").length)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //don't	
  auto-­‐expand	
  tree	
  to	
  show	
  file	
  -­‐	
  but	
  remember	
  it	
  if	
  parent	
  is	
  manually	
  
expanded	
  later	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  _projectTree.jstree("deselect_all");	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  _lastSelected	
  =	
  $treeNode;	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  
 	
  	
  	
  function	
  _documentSelectionFocusChange()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  curFullPath	
  =	
  MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE);	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (curFullPath	
  &&	
  _hasFileSelectionFocus())	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  actionCreator.setSelected(curFullPath,	
  true);	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  actionCreator.setSelected(null);	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  _fileViewControllerChange();	
  
	
  	
  	
  	
  }	
  
	
  
Simplifying JavaScript Projects with ReactJS
http://futurice.com/blog/reactive-mvc-and-the-virtual-dom/
ProjectModel
FileTreeViewModel
FileTreeView ActionCreator
React
 	
  	
  	
  function	
  render(element,	
  viewModel,	
  projectRoot,	
  actions,	
  forceRender,	
  platform)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (!projectRoot)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return;	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  React.renderComponent(fileTreeView({	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  treeData:	
  viewModel.treeData,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  selectionViewInfo:	
  viewModel.selectionViewInfo,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  sortDirectoriesFirst:	
  viewModel.sortDirectoriesFirst,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  parentPath:	
  projectRoot.fullPath,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  actions:	
  actions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extensions:	
  _extensions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  platform:	
  platform,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  forceRender:	
  forceRender	
  
	
  	
  	
  	
  	
  	
  	
  	
  }),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  element);	
  
	
  	
  	
  	
  }
 	
  	
  	
  var	
  fileTreeView	
  =	
  React.createClass({	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  /**	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  *	
  Update	
  for	
  any	
  change	
  in	
  the	
  tree	
  data	
  or	
  directory	
  sorting	
  preference.	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  	
  	
  	
  	
  shouldComponentUpdate:	
  function	
  (nextProps,	
  nextState)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  nextProps.forceRender	
  ||	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.props.treeData	
  !==	
  nextProps.treeData	
  ||	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.props.sortDirectoriesFirst	
  !==	
  nextProps.sortDirectoriesFirst	
  ||	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.props.extensions	
  !==	
  nextProps.extensions	
  ||	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.props.selectionViewInfo	
  !==	
  nextProps.selectionViewInfo;	
  
	
  	
  	
  	
  	
  	
  	
  	
  },
 	
  	
  	
  	
  	
  	
  	
  render:	
  function	
  ()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  contents	
  =	
  directoryContents({	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  isRoot:	
  true,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  parentPath:	
  this.props.parentPath,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  sortDirectoriesFirst:	
  this.props.sortDirectoriesFirst,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  contents:	
  this.props.treeData,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extensions:	
  this.props.extensions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  actions:	
  this.props.actions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  forceRender:	
  this.props.forceRender,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  platform:	
  this.props.platform	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  DOM.div(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  null,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  selectionBackground,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  contextBackground,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extensionForSelection,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extensionForContext,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  contents	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  );	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  });
 	
  	
  	
  directoryContents	
  =	
  React.createClass({	
  
	
  	
  	
  	
  	
  	
  	
  	
  render:	
  function	
  ()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  extensions	
  =	
  this.props.extensions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  iconClass	
  =	
  extensions	
  &&	
  extensions.get("icons")	
  ?	
  "jstree-­‐icons"	
  :	
  "jstree-­‐no-­‐
icons",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ulProps	
  =	
  this.props.isRoot	
  ?	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  className:	
  "jstree-­‐brackets	
  jstree-­‐no-­‐dots	
  "	
  +	
  iconClass	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  :	
  null;	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  contents	
  =	
  this.props.contents,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  namesInOrder	
  =	
  _sortDirectoryContents(contents,	
  this.props.sortDirectoriesFirst);
 	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  DOM.ul(ulProps,	
  namesInOrder.map(function	
  (name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  entry	
  =	
  contents.get(name);	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (FileTreeViewModel.isFile(entry))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  fileNode({	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  parentPath:	
  this.props.parentPath,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  name:	
  name,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  entry:	
  entry,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  actions:	
  this.props.actions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  extensions:	
  this.props.extensions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  forceRender:	
  this.props.forceRender,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  platform:	
  this.props.platform,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  key:	
  name	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  directoryNode({
 	
  	
  	
  directoryNode	
  =	
  React.createClass({	
  
	
  	
  	
  	
  	
  	
  	
  	
  mixins:	
  [contextSettable,	
  pathComputer,	
  extendable],	
  
	
  	
  	
  	
  	
  	
  	
  	
  render:	
  function	
  ()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  entry	
  =	
  this.props.entry,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (entry.get("rename"))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  renameInput	
  =	
  directoryRenameInput({	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  actions:	
  this.props.actions,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  entry:	
  this.props.entry,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  name:	
  this.props.name,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  parentPath:	
  this.props.parentPath	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }
 	
  	
  	
  directoryNode	
  =	
  React.createClass({	
  
	
  	
  	
  	
  	
  	
  	
  	
  render:	
  function	
  ()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  DOM.li({	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  className:	
  this.getClasses("jstree-­‐"	
  +	
  nodeClass),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  onClick:	
  this.handleClick,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  onMouseDown:	
  this.handleMouseDown	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  },	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  DOM.ins({	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  className:	
  "jstree-­‐icon"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  },	
  "	
  "),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  renameInput,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  nameDisplay,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  childNodes);	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  });
 	
  	
  	
  	
  	
  	
  	
  handleClick:	
  function	
  (event)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  isOpen	
  =	
  this.props.entry.get("open"),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  setOpen	
  =	
  isOpen	
  ?	
  false	
  :	
  true;	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (event.metaKey	
  ||	
  event.ctrlKey)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  ctrl-­‐alt-­‐click	
  toggles	
  this	
  directory	
  and	
  its	
  children	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (event.altKey)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (setOpen)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  when	
  opening,	
  we	
  only	
  open	
  the	
  immediate	
  children	
  because	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  opening	
  a	
  whole	
  subtree	
  could	
  be	
  really	
  slow	
  (consider	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  a	
  `node_modules`	
  directory,	
  for	
  example).	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.props.actions.toggleSubdirectories(this.myPath(),	
  setOpen);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.props.actions.setDirectoryOpen(this.myPath(),	
  setOpen);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  When	
  closing,	
  we	
  recursively	
  close	
  the	
  whole	
  subtree.	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.props.actions.closeSubtree(this.myPath());	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {
 	
  	
  	
  ActionCreator.prototype.toggleSubdirectories	
  =	
  function	
  (path,	
  openOrClose)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.model.toggleSubdirectories(path,	
  openOrClose).then(_saveTreeState);	
  
	
  	
  	
  	
  };
 	
  	
  	
  ProjectModel.prototype.toggleSubdirectories	
  =	
  function	
  (path,	
  openOrClose)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  self	
  =	
  this,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d	
  =	
  new	
  $.Deferred();	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.setDirectoryOpen(path,	
  true).then(function	
  ()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  projectRelativePath	
  =	
  self.makeProjectRelativeIfPossible(path),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  childNodes	
  =	
  self._viewModel.getChildDirectories(projectRelativePath);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  Async.doInParallel(childNodes,	
  function	
  (node)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  self.setDirectoryOpen(path	
  +	
  node,	
  openOrClose);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  },	
  true).then(function	
  ()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.resolve();	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  },	
  function	
  (err)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.reject(err);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  d.promise();	
  
	
  	
  	
  	
  };
 	
  	
  	
  ProjectModel.prototype.setDirectoryOpen	
  =	
  function	
  (path,	
  open)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  projectRelative	
  =	
  this.makeProjectRelativeIfPossible(path),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  needsLoading	
  	
  	
  	
  =	
  !this._viewModel.isPathLoaded(projectRelative),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  =	
  new	
  $.Deferred(),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  =	
  this;	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (open	
  &&	
  needsLoading)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  parentDirectory	
  =	
  FileUtils.getDirectoryPath(FileUtils.stripTrailingSlash(path));	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this.setDirectoryOpen(parentDirectory,	
  true).then(function	
  ()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self._getDirectoryContents(path).then(onSuccess).fail(function	
  (err)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.reject(err);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  },	
  function	
  (err)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.reject(err);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  onSuccess();	
  
	
  	
  	
  	
  	
  	
  	
  	
  }
 	
  	
  	
  	
  	
  	
  	
  function	
  onSuccess(contents)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  Update	
  the	
  view	
  model	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (contents)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self._viewModel.setDirectoryContents(projectRelative,	
  contents);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (open)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self._viewModel.openPath(projectRelative);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (self._focused)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  currentPathInProject	
  =	
  self.makeProjectRelativeIfPossible(self._currentPath);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (self._viewModel.isFilePathVisible(currentPathInProject))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self.setSelected(self._currentPath,	
  true);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self.setSelected(null);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {
branches
to test
 	
  	
  	
  FileTreeViewModel.prototype.openPath	
  =	
  function	
  (path)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this._commit(_openPath(this._treeData,	
  path));	
  
	
  	
  	
  	
  };
{	
  
	
  	
  	
  	
  "subdir":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  open:	
  true,	
  
	
  	
  	
  	
  	
  	
  	
  	
  children:	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "afile.js":	
  {},	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "subsubdir":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  children:	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "thirdsub":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  children:	
  {}	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}
subdir/subsubdir/thirdsub/
{	
  
	
  	
  	
  	
  "subdir":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  open:	
  true,	
  
	
  	
  	
  	
  	
  	
  	
  	
  children:	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "afile.js":	
  {},	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "subsubdir":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  children:	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "thirdsub":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  children:	
  {}	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}
subdir/subsubdir/thirdsub/
treeData.subdir.subsubdir.open	
  =	
  true;	
  
treeData.subdir.subsubdir.thirdsub.open	
  =	
  true;
thirdsub	
  =	
  treeData.subdir.subsubdir.thirdsub;	
  
newThirdSub	
  =	
  thirdsub.set("open",	
  true);	
  
	
  
thirdsub	
  !==	
  newThirdSub;	
  //	
  true	
  
treeData.subdir.subsubdir.thirdsub	
  !==	
  newThirdSub	
  //	
  true	
  
treeData.subdir.subsubdir.thirdsub.open	
  ===	
  undefined;	
  //	
  true
Attack of the clones
https://www.flickr.com/photos/hjmediastudios/7910348016/
thirdsub	
  =	
  treeData.subdir.subsubdir.thirdsub;	
  
newThirdSub	
  =	
  thirdsub.set("open",	
  true);	
  
	
  
thirdsub	
  !==	
  newThirdSub;	
  //	
  true	
  
treeData.subdir.subsubdir.thirdsub	
  !==	
  newThirdSub	
  //	
  true	
  
treeData.subdir.subsubdir.thirdsub.open	
  ===	
  undefined;	
  //	
  true
thirdsub	
  =	
  treeData.subdir.subsubdir.thirdsub;	
  
newThirdSub	
  =	
  thirdsub.set("open",	
  true);	
  
newSubSubDir	
  =	
  subsubdir.set("thirdsub",	
  newThirdSub);	
  
newSubDir	
  =	
  subdir.set("subsubdir",	
  newSubSubDir);	
  
treeData	
  =	
  treeData.set("subdir",	
  newSubDir);
 	
  	
  	
  function	
  _openPath(treeData,	
  path)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  objectPath	
  =	
  _filePathToObjectPath(treeData,	
  path);	
  
	
  	
  	
  	
  	
  	
  	
  	
  function	
  setOpen(node)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  node.set("open",	
  true);	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  while	
  (objectPath	
  &&	
  objectPath.length)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  var	
  node	
  =	
  treeData.getIn(objectPath);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (isFile(node))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  objectPath.pop();	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (!node.get("open"))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  treeData	
  =	
  treeData.updateIn(objectPath,	
  setOpen);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  objectPath.pop();	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (objectPath.length)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  objectPath.pop();	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  treeData;	
  
	
  	
  	
  	
  }
mutable?
 	
  	
  	
  FileTreeViewModel.prototype.openPath	
  =	
  function	
  (path)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this._commit(_openPath(this._treeData,	
  path));	
  
	
  	
  	
  	
  };
 	
  	
  	
  FileTreeViewModel.prototype._commit	
  =	
  function	
  (treeData,	
  selectionViewInfo)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  changed	
  =	
  false;	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (treeData	
  &&	
  treeData	
  !==	
  this._treeData)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this._treeData	
  =	
  treeData;	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  changed	
  =	
  true;	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (selectionViewInfo	
  &&	
  selectionViewInfo	
  !==	
  this._selectionViewInfo)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  this._selectionViewInfo	
  =	
  selectionViewInfo;	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  changed	
  =	
  true;	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (changed)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $(this).trigger(EVENT_CHANGE);	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  };
–C.A.R. Hoare
“There are two ways of constructing a software design: One way
is to make it so simple that there are obviously no
deficiencies, and the other way is to make it so complicated
that there are no obvious deficiencies. The first method is far
more difficult.”
Simple?
simple!
composed of one thing, not combined
http://www.shaffner.us/cs/papers/tarpit.pdf
Simple Architecture
• Each part does one thing with side effects in few, known places
• React lets you generate a whole UI functionally
• Immutable-JS allows you to control when data updates occur
• Every part of your application can have a consistent state
• Object identity tells you when something has changed
A modern, open source text editor that understands web design.
http://brackets.io

More Related Content

PDF
Modularity and Layered Data Model
KEY
Backbone.js Simple Tutorial
PDF
Aug 3-2012 - StiltSoft - 10 features for JIRA admin
PDF
Viastudy ef core_cheat_sheet
PPTX
AngularJS Services
KEY
JavaScript in Drupal 7: What developers need to know
PDF
First java-server-faces-tutorial-en
PDF
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
Modularity and Layered Data Model
Backbone.js Simple Tutorial
Aug 3-2012 - StiltSoft - 10 features for JIRA admin
Viastudy ef core_cheat_sheet
AngularJS Services
JavaScript in Drupal 7: What developers need to know
First java-server-faces-tutorial-en
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript

What's hot (19)

PPT
Drupal Javascript for developers
PPTX
Magento Dependency Injection
PDF
Java Assignment Help
PDF
Introduction to Web Components
PDF
Drupal & javascript
PDF
Hibernate
PDF
Virtual Madness @ Etsy
PPTX
Beyond DOMReady: Ultra High-Performance Javascript
PDF
Upgrade your javascript to drupal 8
PDF
Functionality Focused Code Organization
PPT
Render API - Pavel Makhrinsky
PDF
Django Class-based views (Slovenian)
PPTX
AngularJS - $http & $resource Services
PPTX
jQuery Presentasion
PPTX
HirshHorn theme: how I created it
PDF
Drupal 8: Fields reborn
PDF
Geodaten & Drupal 7
PPTX
AngularJS Compile Process
PDF
Opencast Admin UI - Introduction to developing using AngularJS
Drupal Javascript for developers
Magento Dependency Injection
Java Assignment Help
Introduction to Web Components
Drupal & javascript
Hibernate
Virtual Madness @ Etsy
Beyond DOMReady: Ultra High-Performance Javascript
Upgrade your javascript to drupal 8
Functionality Focused Code Organization
Render API - Pavel Makhrinsky
Django Class-based views (Slovenian)
AngularJS - $http & $resource Services
jQuery Presentasion
HirshHorn theme: how I created it
Drupal 8: Fields reborn
Geodaten & Drupal 7
AngularJS Compile Process
Opencast Admin UI - Introduction to developing using AngularJS
Ad

Viewers also liked (11)

PDF
Intro to ReactJS
PDF
React Webinar Slides
PDF
React Next Conference slides: ReactJS Worst practices
PPT
Starting with Reactjs
PDF
React.js in real world apps.
PDF
An Introduction to ReactJS
PPT
React js
PPTX
React in Native Apps - Meetup React - 20150409
PPTX
Why Play Framework is fast
PPTX
Rethinking Best Practices
PDF
React JS and why it's awesome
Intro to ReactJS
React Webinar Slides
React Next Conference slides: ReactJS Worst practices
Starting with Reactjs
React.js in real world apps.
An Introduction to ReactJS
React js
React in Native Apps - Meetup React - 20150409
Why Play Framework is fast
Rethinking Best Practices
React JS and why it's awesome
Ad

Similar to Simplifying JavaScript Projects with ReactJS (20)

PDF
JQuery In Drupal
PPTX
8 things to know about theming in drupal 8
PDF
Having Fun with Play
PDF
Unittests für Dummies
KEY
BlackBerry DevCon 2011 - PhoneGap and WebWorks
PDF
Dicoding Developer Coaching #27: Android | Membuat Aplikasi Support Online Ma...
PDF
Doctrine 2
PDF
Zend Framework 2 - Basic Components
KEY
jQuery: Tips, tricks and hints for better development and Performance
PDF
Building Large jQuery Applications
PPTX
Drupal 8 migrate!
PPT
J query b_dotnet_ug_meet_12_may_2012
PDF
Understanding backbonejs
PDF
How Kris Writes Symfony Apps
PDF
jQuery: out with the old, in with the new
PDF
Introducing jQuery
PDF
Multilingualism makes better programmers
PPTX
Drupal II: The SQL
PPTX
How to increase Performance of Web Application using JQuery
PPTX
Taming that client side mess with Backbone.js
JQuery In Drupal
8 things to know about theming in drupal 8
Having Fun with Play
Unittests für Dummies
BlackBerry DevCon 2011 - PhoneGap and WebWorks
Dicoding Developer Coaching #27: Android | Membuat Aplikasi Support Online Ma...
Doctrine 2
Zend Framework 2 - Basic Components
jQuery: Tips, tricks and hints for better development and Performance
Building Large jQuery Applications
Drupal 8 migrate!
J query b_dotnet_ug_meet_12_may_2012
Understanding backbonejs
How Kris Writes Symfony Apps
jQuery: out with the old, in with the new
Introducing jQuery
Multilingualism makes better programmers
Drupal II: The SQL
How to increase Performance of Web Application using JQuery
Taming that client side mess with Backbone.js

Recently uploaded (20)

PDF
Become an Agentblazer Champion Challenge Kickoff
PDF
Convert Thunderbird to Outlook into bulk
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
AIRLINE PRICE API | FLIGHT API COST |
PPTX
How a Careem Clone App Allows You to Compete with Large Mobility Brands
PDF
Understanding NFT Marketplace Development_ Trends and Innovations.pdf
PPTX
Materi-Enum-and-Record-Data-Type (1).pptx
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
ShowUs: Pharo Stream Deck (ESUG 2025, Gdansk)
PPTX
Save Business Costs with CRM Software for Insurance Agents
DOCX
The Five Best AI Cover Tools in 2025.docx
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
Perfecting Gamer’s Experiences with Performance Testing for Gaming Applicatio...
PPTX
Materi_Pemrograman_Komputer-Looping.pptx
PDF
Best Practices for Rolling Out Competency Management Software.pdf
PDF
Become an Agentblazer Champion Challenge
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
Build Multi-agent using Agent Development Kit
PDF
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK
Become an Agentblazer Champion Challenge Kickoff
Convert Thunderbird to Outlook into bulk
How Creative Agencies Leverage Project Management Software.pdf
Which alternative to Crystal Reports is best for small or large businesses.pdf
AIRLINE PRICE API | FLIGHT API COST |
How a Careem Clone App Allows You to Compete with Large Mobility Brands
Understanding NFT Marketplace Development_ Trends and Innovations.pdf
Materi-Enum-and-Record-Data-Type (1).pptx
How to Migrate SBCGlobal Email to Yahoo Easily
ShowUs: Pharo Stream Deck (ESUG 2025, Gdansk)
Save Business Costs with CRM Software for Insurance Agents
The Five Best AI Cover Tools in 2025.docx
Upgrade and Innovation Strategies for SAP ERP Customers
Perfecting Gamer’s Experiences with Performance Testing for Gaming Applicatio...
Materi_Pemrograman_Komputer-Looping.pptx
Best Practices for Rolling Out Competency Management Software.pdf
Become an Agentblazer Champion Challenge
PTS Company Brochure 2025 (1).pdf.......
Build Multi-agent using Agent Development Kit
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK

Simplifying JavaScript Projects with ReactJS

  • 1. Simplifying JavaScript Projects with ReactJS and Friends Kevin Dangoor, Sr. Computer Scientist, Adobe 1DevDay Detroit 2014
  • 2. A modern, open source text editor that understands web design.
  • 3. Brackets • MIT-licensed open source • Sponsored by Adobe with hundreds of contributors and a number of non-Adobe committers • 13th most starred project • Hundreds of extensions are available • 1.0 just released 10 days ago, with Extract for Brackets
  • 5. function  _documentSelectionFocusChange()  {          var  curFile  =  EditorManager.getCurrentlyViewedPath();          if  (curFile  &&  _hasFileSelectionFocus())  {  
  • 6. function  _documentSelectionFocusChange()  {          var  curFile  =  EditorManager.getCurrentlyViewedPath();          if  (curFile  &&  _hasFileSelectionFocus())  {                  var  nodeFound  =  $("#project-­‐files-­‐container  li").is(function  (index)  {                          var  $treeNode  =  $(this),                                  entry  =  $treeNode.data("entry");                          if  (entry  &&  entry.fullPath  ===  curFile)  {    
  • 7. function  _documentSelectionFocusChange()  {          var  curFile  =  EditorManager.getCurrentlyViewedPath();          if  (curFile  &&  _hasFileSelectionFocus())  {                  var  nodeFound  =  $("#project-­‐files-­‐container  li").is(function  (index)  {                          var  $treeNode  =  $(this),                                  entry  =  $treeNode.data("entry");                          if  (entry  &&  entry.fullPath  ===  curFile)  {                                  if  (!_projectTree.jstree("is_selected",  $treeNode))  {                                          if  ($treeNode.parents(".jstree-­‐closed").length)  {                                                  //don't  auto-­‐expand  tree  to  show  file  -­‐  but  remember  it  if  parent  is  manually   expanded  later                                                  _projectTree.jstree("deselect_all");                                                  _lastSelected  =  $treeNode;                                          }  else  {    
  • 8. if  (!_projectTree.jstree("is_selected",  $treeNode))  {          if  ($treeNode.parents(".jstree-­‐closed").length)  {                  //don't  auto-­‐expand  tree  to  show  file  -­‐  but  remember  it  if  parent  is  manually  expanded  later                  _projectTree.jstree("deselect_all");                  _lastSelected  =  $treeNode;          }  else  {                  //we  don't  want  to  trigger  another  selection  change  event,  so  manually  deselect                  //and  select  without  sending  out  notifications                  _projectTree.jstree("deselect_all");                  _projectTree.jstree("select_node",  $treeNode,  false);  //  sets  _lastSelected          }   }    
  • 9. If it’s hard to test, it won’t be tested.
  • 11. simple! composed of one thing, not combined complect! interweave
  • 12. function  _documentSelectionFocusChange()  {          var  curFile  =  EditorManager.getCurrentlyViewedPath();          if  (curFile  &&  _hasFileSelectionFocus())  {                  var  nodeFound  =  $("#project-­‐files-­‐container  li").is(function  (index)  {                          var  $treeNode  =  $(this),                                  entry  =  $treeNode.data("entry");                          if  (entry  &&  entry.fullPath  ===  curFile)  {                                  if  (!_projectTree.jstree("is_selected",  $treeNode))  {                                          if  ($treeNode.parents(".jstree-­‐closed").length)  {                                                  //don't  auto-­‐expand  tree  to  show  file  -­‐  but  remember  it  if  parent  is  manually   expanded  later                                                  _projectTree.jstree("deselect_all");                                                  _lastSelected  =  $treeNode;                                          }  else  {     Simple?
  • 14. React
  • 17. function  _documentSelectionFocusChange()  {          var  curFile  =  EditorManager.getCurrentlyViewedPath();          if  (curFile  &&  _hasFileSelectionFocus())  {                  var  nodeFound  =  $("#project-­‐files-­‐container  li").is(function  (index)  {                          var  $treeNode  =  $(this),                                  entry  =  $treeNode.data("entry");                          if  (entry  &&  entry.fullPath  ===  curFile)  {                                  if  (!_projectTree.jstree("is_selected",  $treeNode))  {                                          if  ($treeNode.parents(".jstree-­‐closed").length)  {                                                  //don't  auto-­‐expand  tree  to  show  file  -­‐  but  remember  it  if  parent  is  manually   expanded  later                                                  _projectTree.jstree("deselect_all");                                                  _lastSelected  =  $treeNode;                                          }  else  {    
  • 18.        function  _documentSelectionFocusChange()  {                  var  curFullPath  =  MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE);                  if  (curFullPath  &&  _hasFileSelectionFocus())  {                          actionCreator.setSelected(curFullPath,  true);                  }  else  {                          actionCreator.setSelected(null);                  }                  _fileViewControllerChange();          }    
  • 22.        function  render(element,  viewModel,  projectRoot,  actions,  forceRender,  platform)  {                  if  (!projectRoot)  {                          return;                  }                    React.renderComponent(fileTreeView({                          treeData:  viewModel.treeData,                          selectionViewInfo:  viewModel.selectionViewInfo,                          sortDirectoriesFirst:  viewModel.sortDirectoriesFirst,                          parentPath:  projectRoot.fullPath,                          actions:  actions,                          extensions:  _extensions,                          platform:  platform,                          forceRender:  forceRender                  }),                              element);          }
  • 23.        var  fileTreeView  =  React.createClass({                    /**                    *  Update  for  any  change  in  the  tree  data  or  directory  sorting  preference.                    */                  shouldComponentUpdate:  function  (nextProps,  nextState)  {                          return  nextProps.forceRender  ||                                  this.props.treeData  !==  nextProps.treeData  ||                                  this.props.sortDirectoriesFirst  !==  nextProps.sortDirectoriesFirst  ||                                  this.props.extensions  !==  nextProps.extensions  ||                                  this.props.selectionViewInfo  !==  nextProps.selectionViewInfo;                  },
  • 24.                render:  function  ()  {                          var  contents  =  directoryContents({                                          isRoot:  true,                                          parentPath:  this.props.parentPath,                                          sortDirectoriesFirst:  this.props.sortDirectoriesFirst,                                          contents:  this.props.treeData,                                          extensions:  this.props.extensions,                                          actions:  this.props.actions,                                          forceRender:  this.props.forceRender,                                          platform:  this.props.platform                                  });                                                    return  DOM.div(                                  null,                                  selectionBackground,                                  contextBackground,                                  extensionForSelection,                                  extensionForContext,                                  contents                          );                  }          });
  • 25.        directoryContents  =  React.createClass({                  render:  function  ()  {                          var  extensions  =  this.props.extensions,                                  iconClass  =  extensions  &&  extensions.get("icons")  ?  "jstree-­‐icons"  :  "jstree-­‐no-­‐ icons",                                  ulProps  =  this.props.isRoot  ?  {                                          className:  "jstree-­‐brackets  jstree-­‐no-­‐dots  "  +  iconClass                                  }  :  null;                            var  contents  =  this.props.contents,                                  namesInOrder  =  _sortDirectoryContents(contents,  this.props.sortDirectoriesFirst);
  • 26.                        return  DOM.ul(ulProps,  namesInOrder.map(function  (name)  {                                  var  entry  =  contents.get(name);                                    if  (FileTreeViewModel.isFile(entry))  {                                          return  fileNode({                                                  parentPath:  this.props.parentPath,                                                  name:  name,                                                  entry:  entry,                                                  actions:  this.props.actions,                                                  extensions:  this.props.extensions,                                                  forceRender:  this.props.forceRender,                                                  platform:  this.props.platform,                                                  key:  name                                          });                                  }  else  {                                          return  directoryNode({
  • 27.        directoryNode  =  React.createClass({                  mixins:  [contextSettable,  pathComputer,  extendable],                  render:  function  ()  {                          var  entry  =  this.props.entry,                          if  (entry.get("rename"))  {                                  renameInput  =  directoryRenameInput({                                          actions:  this.props.actions,                                          entry:  this.props.entry,                                          name:  this.props.name,                                          parentPath:  this.props.parentPath                                  });                          }
  • 28.        directoryNode  =  React.createClass({                  render:  function  ()  {                          return  DOM.li({                                  className:  this.getClasses("jstree-­‐"  +  nodeClass),                                  onClick:  this.handleClick,                                  onMouseDown:  this.handleMouseDown                          },                                  DOM.ins({                                          className:  "jstree-­‐icon"                                  },  "  "),                                  renameInput,                                  nameDisplay,                                  childNodes);                  }          });
  • 29.                handleClick:  function  (event)  {                          var  isOpen  =  this.props.entry.get("open"),                                  setOpen  =  isOpen  ?  false  :  true;                            if  (event.metaKey  ||  event.ctrlKey)  {                                  //  ctrl-­‐alt-­‐click  toggles  this  directory  and  its  children                                  if  (event.altKey)  {                                          if  (setOpen)  {                                                  //  when  opening,  we  only  open  the  immediate  children  because                                                  //  opening  a  whole  subtree  could  be  really  slow  (consider                                                  //  a  `node_modules`  directory,  for  example).                                                  this.props.actions.toggleSubdirectories(this.myPath(),  setOpen);                                                  this.props.actions.setDirectoryOpen(this.myPath(),  setOpen);                                          }  else  {                                                  //  When  closing,  we  recursively  close  the  whole  subtree.                                                  this.props.actions.closeSubtree(this.myPath());                                          }                                  }  else  {
  • 30.        ActionCreator.prototype.toggleSubdirectories  =  function  (path,  openOrClose)  {                  this.model.toggleSubdirectories(path,  openOrClose).then(_saveTreeState);          };
  • 31.        ProjectModel.prototype.toggleSubdirectories  =  function  (path,  openOrClose)  {                  var  self  =  this,                          d  =  new  $.Deferred();                    this.setDirectoryOpen(path,  true).then(function  ()  {                          var  projectRelativePath  =  self.makeProjectRelativeIfPossible(path),                                  childNodes  =  self._viewModel.getChildDirectories(projectRelativePath);                                                    Async.doInParallel(childNodes,  function  (node)  {                                  return  self.setDirectoryOpen(path  +  node,  openOrClose);                          },  true).then(function  ()  {                                  d.resolve();                          },  function  (err)  {                                  d.reject(err);                          });                  });                                    return  d.promise();          };
  • 32.        ProjectModel.prototype.setDirectoryOpen  =  function  (path,  open)  {                  var  projectRelative  =  this.makeProjectRelativeIfPossible(path),                          needsLoading        =  !this._viewModel.isPathLoaded(projectRelative),                          d                              =  new  $.Deferred(),                          self                        =  this;                  if  (open  &&  needsLoading)  {                          var  parentDirectory  =  FileUtils.getDirectoryPath(FileUtils.stripTrailingSlash(path));                          this.setDirectoryOpen(parentDirectory,  true).then(function  ()  {                                  self._getDirectoryContents(path).then(onSuccess).fail(function  (err)  {                                          d.reject(err);                                  });                          },  function  (err)  {                                  d.reject(err);                          });                  }  else  {                          onSuccess();                  }
  • 33.                function  onSuccess(contents)  {                          //  Update  the  view  model                          if  (contents)  {                                  self._viewModel.setDirectoryContents(projectRelative,  contents);                          }                            if  (open)  {                                  self._viewModel.openPath(projectRelative);                                  if  (self._focused)  {                                          var  currentPathInProject  =  self.makeProjectRelativeIfPossible(self._currentPath);                                          if  (self._viewModel.isFilePathVisible(currentPathInProject))  {                                                  self.setSelected(self._currentPath,  true);                                          }  else  {                                                  self.setSelected(null);                                          }                                  }                          }  else  { branches to test
  • 34.        FileTreeViewModel.prototype.openPath  =  function  (path)  {                  this._commit(_openPath(this._treeData,  path));          };
  • 35. {          "subdir":  {                  open:  true,                  children:  {                          "afile.js":  {},                          "subsubdir":  {                                  children:  {                                          "thirdsub":  {                                                  children:  {}                                          }                                  }                          }                  }          }   } subdir/subsubdir/thirdsub/
  • 36. {          "subdir":  {                  open:  true,                  children:  {                          "afile.js":  {},                          "subsubdir":  {                                  children:  {                                          "thirdsub":  {                                                  children:  {}                                          }                                  }                          }                  }          }   } subdir/subsubdir/thirdsub/ treeData.subdir.subsubdir.open  =  true;   treeData.subdir.subsubdir.thirdsub.open  =  true;
  • 37. thirdsub  =  treeData.subdir.subsubdir.thirdsub;   newThirdSub  =  thirdsub.set("open",  true);     thirdsub  !==  newThirdSub;  //  true   treeData.subdir.subsubdir.thirdsub  !==  newThirdSub  //  true   treeData.subdir.subsubdir.thirdsub.open  ===  undefined;  //  true
  • 38. Attack of the clones https://www.flickr.com/photos/hjmediastudios/7910348016/
  • 39. thirdsub  =  treeData.subdir.subsubdir.thirdsub;   newThirdSub  =  thirdsub.set("open",  true);     thirdsub  !==  newThirdSub;  //  true   treeData.subdir.subsubdir.thirdsub  !==  newThirdSub  //  true   treeData.subdir.subsubdir.thirdsub.open  ===  undefined;  //  true
  • 40. thirdsub  =  treeData.subdir.subsubdir.thirdsub;   newThirdSub  =  thirdsub.set("open",  true);   newSubSubDir  =  subsubdir.set("thirdsub",  newThirdSub);   newSubDir  =  subdir.set("subsubdir",  newSubSubDir);   treeData  =  treeData.set("subdir",  newSubDir);
  • 41.        function  _openPath(treeData,  path)  {                  var  objectPath  =  _filePathToObjectPath(treeData,  path);                  function  setOpen(node)  {                          return  node.set("open",  true);                  }                  while  (objectPath  &&  objectPath.length)  {                          var  node  =  treeData.getIn(objectPath);                          if  (isFile(node))  {                                  objectPath.pop();                          }  else  {                                  if  (!node.get("open"))  {                                          treeData  =  treeData.updateIn(objectPath,  setOpen);                                  }                                  objectPath.pop();                                  if  (objectPath.length)  {                                          objectPath.pop();                                  }                          }                  }                  return  treeData;          } mutable?
  • 42.        FileTreeViewModel.prototype.openPath  =  function  (path)  {                  this._commit(_openPath(this._treeData,  path));          };
  • 43.        FileTreeViewModel.prototype._commit  =  function  (treeData,  selectionViewInfo)  {                  var  changed  =  false;                  if  (treeData  &&  treeData  !==  this._treeData)  {                          this._treeData  =  treeData;                          changed  =  true;                  }                                    if  (selectionViewInfo  &&  selectionViewInfo  !==  this._selectionViewInfo)  {                          this._selectionViewInfo  =  selectionViewInfo;                          changed  =  true;                  }                  if  (changed)  {                          $(this).trigger(EVENT_CHANGE);                  }          };
  • 44. –C.A.R. Hoare “There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”
  • 46. simple! composed of one thing, not combined
  • 48. Simple Architecture • Each part does one thing with side effects in few, known places • React lets you generate a whole UI functionally • Immutable-JS allows you to control when data updates occur • Every part of your application can have a consistent state • Object identity tells you when something has changed
  • 49. A modern, open source text editor that understands web design. http://brackets.io