SlideShare ist ein Scribd-Unternehmen logo
1 von 49
Downloaden Sie, um offline zu lesen
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
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();	
  
	
  	
  	
  	
  }	
  
	
  
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

Weitere ähnliche Inhalte

Was ist angesagt?

Magento Dependency Injection
Magento Dependency InjectionMagento Dependency Injection
Magento Dependency Injection
Anton Kril
 
Render API - Pavel Makhrinsky
Render API - Pavel MakhrinskyRender API - Pavel Makhrinsky
Render API - Pavel Makhrinsky
DrupalCampDN
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
Luka Zakrajšek
 

Was ist angesagt? (19)

Drupal Javascript for developers
Drupal Javascript for developersDrupal Javascript for developers
Drupal Javascript for developers
 
Magento Dependency Injection
Magento Dependency InjectionMagento Dependency Injection
Magento Dependency Injection
 
Java Assignment Help
Java  Assignment  HelpJava  Assignment  Help
Java Assignment Help
 
Introduction to Web Components
Introduction to Web ComponentsIntroduction to Web Components
Introduction to Web Components
 
Drupal & javascript
Drupal & javascriptDrupal & javascript
Drupal & javascript
 
Hibernate
HibernateHibernate
Hibernate
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Beyond DOMReady: Ultra High-Performance Javascript
Beyond DOMReady: Ultra High-Performance JavascriptBeyond DOMReady: Ultra High-Performance Javascript
Beyond DOMReady: Ultra High-Performance Javascript
 
Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8
 
Functionality Focused Code Organization
Functionality Focused Code OrganizationFunctionality Focused Code Organization
Functionality Focused Code Organization
 
Render API - Pavel Makhrinsky
Render API - Pavel MakhrinskyRender API - Pavel Makhrinsky
Render API - Pavel Makhrinsky
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
 
AngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesAngularJS - $http & $resource Services
AngularJS - $http & $resource Services
 
jQuery Presentasion
jQuery PresentasionjQuery Presentasion
jQuery Presentasion
 
HirshHorn theme: how I created it
HirshHorn theme: how I created itHirshHorn theme: how I created it
HirshHorn theme: how I created it
 
Drupal 8: Fields reborn
Drupal 8: Fields rebornDrupal 8: Fields reborn
Drupal 8: Fields reborn
 
Geodaten & Drupal 7
Geodaten & Drupal 7Geodaten & Drupal 7
Geodaten & Drupal 7
 
AngularJS Compile Process
AngularJS Compile ProcessAngularJS Compile Process
AngularJS Compile Process
 
Opencast Admin UI - Introduction to developing using AngularJS
Opencast Admin UI - Introduction to developing using AngularJSOpencast Admin UI - Introduction to developing using AngularJS
Opencast Admin UI - Introduction to developing using AngularJS
 

Andere mochten auch

React Webinar Slides
React Webinar SlidesReact Webinar Slides
React Webinar Slides
Kateryna Porshnieva
 

Andere mochten auch (11)

Intro to ReactJS
Intro to ReactJSIntro to ReactJS
Intro to ReactJS
 
React Webinar Slides
React Webinar SlidesReact Webinar Slides
React Webinar Slides
 
React Next Conference slides: ReactJS Worst practices
React Next Conference slides: ReactJS Worst practicesReact Next Conference slides: ReactJS Worst practices
React Next Conference slides: ReactJS Worst practices
 
Starting with Reactjs
Starting with ReactjsStarting with Reactjs
Starting with Reactjs
 
React.js in real world apps.
React.js in real world apps. React.js in real world apps.
React.js in real world apps.
 
An Introduction to ReactJS
An Introduction to ReactJSAn Introduction to ReactJS
An Introduction to ReactJS
 
React js
React jsReact js
React js
 
React in Native Apps - Meetup React - 20150409
React in Native Apps - Meetup React - 20150409React in Native Apps - Meetup React - 20150409
React in Native Apps - Meetup React - 20150409
 
Why Play Framework is fast
Why Play Framework is fastWhy Play Framework is fast
Why Play Framework is fast
 
Rethinking Best Practices
Rethinking Best PracticesRethinking Best Practices
Rethinking Best Practices
 
React JS and why it's awesome
React JS and why it's awesomeReact JS and why it's awesome
React JS and why it's awesome
 

Ähnlich wie Simplifying JavaScript Projects with ReactJS

BlackBerry DevCon 2011 - PhoneGap and WebWorks
BlackBerry DevCon 2011 - PhoneGap and WebWorksBlackBerry DevCon 2011 - PhoneGap and WebWorks
BlackBerry DevCon 2011 - PhoneGap and WebWorks
mwbrooks
 
jQuery: out with the old, in with the new
jQuery: out with the old, in with the newjQuery: out with the old, in with the new
jQuery: out with the old, in with the new
Remy Sharp
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
Jarod Ferguson
 

Ähnlich wie Simplifying JavaScript Projects with ReactJS (20)

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

Kürzlich hochgeladen

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
masabamasaba
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 

Kürzlich hochgeladen (20)

%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 

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
  • 4.
  • 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();          }    
  • 19.
  • 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