瀏覽代碼

At last putting everything back up

Benoît Hubert 8 年之前
父節點
當前提交
94212ba8c9
共有 9 個文件被更改,包括 20672 次插入365 次删除
  1. 13 8
      html/index.mustache.html
  2. 8 8
      html/template.mustache.html
  3. 0 162
      js/menu.js
  4. 20271 0
      js/vendor/ace/ace.js
  5. 64 38
      js/editor.js
  6. 1 1
      js/ws-events.js
  7. 171 0
      js/ws-menu.js
  8. 81 96
      js/ws-ui-parts.js
  9. 63 52
      sandboxApp.js

+ 13 - 8
html/index.mustache.html

@@ -88,7 +88,7 @@
     <div class="splitter">
     </div>
 
-    <iframe class="panel-right" src="/html/start-iframe.html"></iframe>
+    <iframe id="sandbox-iframe" class="panel-right" {{#example}}src="/examples/{{repo.path}}/{{example.slug}}"{{/example}}{{^example}}src="/html/start-iframe.html"{{/example}}></iframe>
 </div>
 
 {{=<% %>=}}
@@ -109,11 +109,17 @@
 </script>
 
 <script data-tmpl-for="tabs" id="tabs-tmpl" type="text/x-mustache-tmpl">
-  <ul id="tabs">{{#files}}
+  {{#files}}
     <li class="tab-{{type}}" data-type="{{type}}">{{name}}</li>
   {{/files}}
   <li>+</li>
-  </ul>
+</script>
+
+<script data-tmpl-for="details-repo" id="details-example-repo" type="text/x-mustache-tmpl">
+{{#repo}}
+    <strong>{{_.collection}} </strong><span>{{title}}</span>
+    <button id="add-example-btn"><span class="icon-plus rounded"></span> {{_.add}}</button>
+{{/repo}}
 </script>
 <%={{ }}=%>
 
@@ -127,6 +133,7 @@
 <script src="/js/vendor/mustache.min.js" ></script>
 <script src="/js/vendor/lodash.min.js" ></script>
 <script src="/js/vendor/loadJS.js" ></script>
+<script src="/js/vendor/ace/ace.js" type="text/javascript" charset="utf-8"></script>
 <script src="/js/plugins.js"></script>
 <script src="/js/main.js"></script>
 
@@ -136,13 +143,11 @@ window._ws = {
   files: {{{filesJSON}}}
 };
 </script>
+<script src="/js/req-promise.js"></script>
 <script src="/js/ws-ui-parts.js"></script>
 <script src="/js/ws-events.js"></script>
-<script src="/js/menu.js"></script>
-<!-- <script src="/js/ws-navigator.js"></script> -->
-<script src="/js/vendor/ace/ace.min.js" type="text/javascript" charset="utf-8"></script>
-<script src="/js/req-promise.js"></script>
+<script src="/js/ws-menu.js"></script>
 <script src="/js/editor-local-storage.js"></script>
-<script src="/js/editor.js"></script>
+<script src="/js/ws-editor.js"></script>
 </body>
 </html>

+ 8 - 8
html/template.mustache.html

@@ -3,15 +3,15 @@
   <head>
   <title>{{ title }} - Sandbox iframe</title>
     <!-- HTML5 Boilerplate CSS -->
-    <link rel="stylesheet" href="../css/normalize.css">
-    <link rel="stylesheet" href="../css/main.css">
+    <link rel="stylesheet" href="/css/normalize.css">
+    <link rel="stylesheet" href="/css/main.css">
     <!-- Vendor CSS -->
     {{#libsCss}}
-    <link rel="stylesheet" href="../css/vendor/{{ . }}">
+    <link rel="stylesheet" href="/css/vendor/{{ . }}">
     {{/libsCss}}
     <!-- Example's CSS -->
     {{#css}}
-    <link rel="stylesheet" href="../exemples/jquery/{{ slug }}/{{ . }}">
+    <link rel="stylesheet" href="/exemples/{{ repoSlug }}/{{ slug }}/{{ . }}">
     {{/css}}
     <style type="text/css" media="screen">
     body {
@@ -26,15 +26,15 @@
     </div>
 
     <!-- HTML5 Boilerplate JS -->
-    <script src="../js/vendor/modernizr-3.5.0.min.js"></script>
-    <script src="../js/plugins.js"></script>
+    <script src="/js/vendor/modernizr-3.5.0.min.js"></script>
+    <script src="/js/plugins.js"></script>
     <!-- Vendor JS -->
     {{#libsJs}}
-    <script src="../js/vendor/{{ . }}" ></script>
+    <script src="/js/vendor/{{ . }}" ></script>
     {{/libsJs}}
     <!-- Example's JS -->
     {{#js}}
-    <script src="../exemples/jquery/{{ slug }}/{{ . }}"></script>
+    <script src="/exemples/{{ repoSlug }}/{{ slug }}/{{ . }}"></script>
     {{/js}}
 
   </body>

+ 0 - 162
js/menu.js

@@ -1,162 +0,0 @@
-"use strict";
-(function($) {
-  $(document).ready(function() {
-
-    function SandboxNavigator() {
-      _ws.makeView('menu-example', {
-        events: {
-          'click a': function(e) {
-            e.preventDefault();
-            console.log('I was clicked', e.target, this);
-            $(this).css('color', 'red');
-          }
-        }
-      });
-      console.log(_ws.ui);
-
-      this.$menu = $('#nav-menus');
-      this.$menuBtn = $('#menu-btn');
-      this.$menuExample = $('#menu-example');
-      this.$menuBtn.click(this.toggleMenu.bind(this));
-      this.$links = $('#nav-menus a,#nav-back-home');
-      this.init();
-    }
-
-    SandboxNavigator.prototype.init = function() {
-      this.nav = this.parsePath();
-      this.bindAllLinksEvents();
-    };
-
-    SandboxNavigator.prototype.toggleMenu = function() {
-      this.$menu.toggleClass('in');
-    };
-
-    SandboxNavigator.prototype.bindAllLinksEvents = function() {
-      this.$links.each(this.bindLinkEvents.bind(this));
-    };
-
-    SandboxNavigator.prototype.bindLinkEvents = function(idx, linkEl) {
-      var self = this;
-      $(linkEl).click(function(e) {
-        e.preventDefault();
-        var $link = $(this);
-        var originalColor = $link.css('backgroundColor');
-        self.toggleMenu();
-        $link.animate({
-          backgroundColor: '#aaa',
-        }, 70);
-        $link.animate({
-          backgroundColor: originalColor,
-        }, 70);
-        self.navigateTo($link.prop('href'));
-      });
-    };
-
-    SandboxNavigator.prototype.parsePath = function() {
-      const path = window.location.pathname.substr(1);
-      const bits = path.split('/');
-      return {
-        repo: bits[0],
-        example: bits.length === 1 ? '' : bits[1]
-      };
-    };
-
-
-    SandboxNavigator.prototype.navigateTo = function(path) {
-      history.pushState({}, 'New path', path);
-      var oldNav = this.nav;
-      this.nav = this.parsePath();
-      console.log(this.nav, oldNav);
-
-      if(this.nav.repo !== oldNav.repo) {
-        console.log('nav: repo changed');
-        _ws.events.emit('navToRepo', this.nav.repo);
-        rp.get('/parts/' + this.nav.repo, 'json')
-        .then(function(parts) {
-          // renderMenuExample(parts.menuExample);
-          _ws.ui.menuExample.render(parts);
-        });
-      }
-      else if(this.nav.example !== oldNav.example) {
-        console.log('nav: example changed');
-        _ws.events.emit('navToExample', this.nav.example);
-        rp.get('/parts/' + this.nav.repo + '/' + this.nav.example, 'json')
-        .then(function(parts) {
-          console.log(parts);
-          renderDetailsExample(parts);
-          // renderTabs(parts);
-          _ws.ui.tabs.render(parts);
-
-        });
-      }
-
-
-      // if(this.nav.repo === oldNav.repo && this.nav.example === oldNav.example) {
-      //   console.log('nav: nop');
-      // }
-      // // else if(this.nav.repo !== oldNav.repo && this.nav.example !== oldNav.example) {
-      // //   console.log('nav: repo&example');
-      // // }
-      // else if(this.nav.repo === oldNav.repo) {
-      //   if(this.nav.example === '') {
-      //     console.log('nav: example empty');
-      //     console.log(_ws.events);
-      //     _ws.events.emit('navToRepoRoot');
-      //   }
-      //   else {
-      //     console.log('nav: example changed');
-      //     _ws.events.emit('navToExample', this.nav.repo); 
-      //   }
-      // }
-      // else if(this.nav.example === oldNav.example) {
-      //   if(this.nav.repo === '') {
-      //     console.log('nav: repo empty');
-      //     _ws.events.emit('navToRoot');
-      //   }
-      //   else {
-      //   }
-      // }
-
-    };
-
-    function renderInto(id, parts) {
-      var tmpl = $('#' + id + '-tmpl').html();
-      console.log(tmpl);
-      $('#' + id).html( Mustache.render( tmpl, parts ) );
-    }
-
-    // function renderTabs(parts) {
-    //   renderInto('tabs', parts);
-    //   _ws.events.emit('rendered:tabs');
-    // }
-
-    function renderDetailsExample(parts) {
-      var tmpl = $('#details-example-tmpl').html();
-      console.log(tmpl);
-      $('#details-example').html( Mustache.render( tmpl, parts ) );
-    }
-    function renderMenuExample(menuExample) {
-      var tmpl = $('#menu-example-tmpl').html();
-      console.log(tmpl);
-      $('#menu-example').html( Mustache.render( tmpl, { menuExample: menuExample } ) );
-    }
-
-    window._ws.navigator = new SandboxNavigator();
-    console.log('navigator init', _ws);
-
-    //     var $exMenuItem = $('<li><a href="/' + repoSlug + '/' + example.slug + '">' + example.title + '</a></li>')
-    //     .appendTo( $('#cat-' + example.category) );
-    //     notify('success', "Exemple créé !");
-    //     navigateTo('/'+ repoSlug + '/' + example.slug);
-    //   })
-    //   .catch(errText => notify('error', 'Erreur: ' + errText));
-    // }
-
-    // function clearAndCloseEditor() {
-    //   $exampleFormIn.val('');
-    //   toggleEditor();
-    // }
-
-
-  });
-})(jQuery);

文件差異過大導致無法顯示
+ 20271 - 0
js/vendor/ace/ace.js


+ 64 - 38
js/editor.js

@@ -1,17 +1,10 @@
+/* global window,$,ace,setTimeout,rp,_ws */
 "use strict";
 $(document).ready(function() {
+  console.log('ws: init editor');
 
   var $editorWrapper = $('#editor-wrapper');
   var $editor        = $('#editor');
-  // var $editorJs      = $('#editor-javascript');
-  // var $editorHtml    = $('#editor-html');
-  // var $editorCss     = $('#editor-css');
-
-  // var $htmlContent   = $('#html-content');  // replaced by iframe
-
-
-  // var $selectorNav   = $('#selector');
-  // var $fileSelect    = $('#file-select');
 
   var $addExampleBtn = $('#add-example-btn');
   var $exampleForm   = $('#add-example-form');
@@ -54,7 +47,7 @@ $(document).ready(function() {
   _ws.events.on('navToRepo', function(repoSlug) {
     console.log('got navToRepo', repoSlug);
     $editorWrapper.hide();
-    $detailsRepo.hide();
+    $detailsRepo.show();
     $detailsExmp.hide();
 
   });
@@ -65,32 +58,16 @@ $(document).ready(function() {
   //   bindEditorTabs();
   // });
 
-  if(_ws.files.length === 0) {
-    return;
-  }
-
 
-  // /**
-  //  * Make the left panel resizable
-  //  */
-  // $panelLeft.resizable({
-  //   handleSelector: ".splitter",
-  //   resizeHeight: false,
-  //   onDrag: function(e) {
-  //     $editor.width($panelLeft.width());
-  //   }
-  // });
 
+  function setDefaultEditorContent() {
+    if(_ws.files.length > 0) {
+      editorSession.setMode("ace/mode/html");
+      var firstHtml = _ws.files.find(f => (f.type === 'html'));
+      editorSession.setValue(firstHtml.content);
+    }
+  }
 
-  // /**
-  //  * Handle window resize
-  //  */
-  // function onResize() {
-  //   $editor.width($panelLeft.width());
-  //   $panelWrap.height($window.height());
-  // }
-  // $window.resize(onResize);
-  // onResize();
 
   function initEditor() {
     editor = ace.edit("editor");
@@ -98,11 +75,7 @@ $(document).ready(function() {
     editor.setTheme("ace/theme/eclipse");
     editor.$blockScrolling = Infinity;
     editorSession.setUseWrapMode(true);
-    if(_ws.files) {
-      editorSession.setMode("ace/mode/html");
-      var firstHtml = _ws.files.find(f => (f.type === 'html'));
-      editorSession.setValue(firstHtml.content);
-    }
+    setDefaultEditorContent();
   }
 
 
@@ -126,6 +99,24 @@ $(document).ready(function() {
     }
   })
 
+  _ws.makeView('editor', {
+    render: function() {
+      console.log('render editor', this);
+      setDefaultEditorContent();
+      $editorWrapper.show();
+    }
+  });
+
+  _ws.makeView('sandbox-iframe', {
+    render: function(navState) {
+      console.log('change iframe src', '/examples/' + navState.repo + '/' + navState.example);
+      this.$elem.prop('src',
+        '/examples/' + navState.repo + '/' + navState.example
+      );
+    }
+  });
+      
+
   /**
    * File list tabs click handler
    */
@@ -373,3 +364,38 @@ $(document).ready(function() {
   initEditor();
 
 });
+
+
+
+  // var $editorJs      = $('#editor-javascript');
+  // var $editorHtml    = $('#editor-html');
+  // var $editorCss     = $('#editor-css');
+
+  // var $htmlContent   = $('#html-content');  // replaced by iframe
+
+
+  // var $selectorNav   = $('#selector');
+  // var $fileSelect    = $('#file-select');
+
+
+  // /**
+  //  * Make the left panel resizable
+  //  */
+  // $panelLeft.resizable({
+  //   handleSelector: ".splitter",
+  //   resizeHeight: false,
+  //   onDrag: function(e) {
+  //     $editor.width($panelLeft.width());
+  //   }
+  // });
+
+
+  // /**
+  //  * Handle window resize
+  //  */
+  // function onResize() {
+  //   $editor.width($panelLeft.width());
+  //   $panelWrap.height($window.height());
+  // }
+  // $window.resize(onResize);
+  // onResize();

+ 1 - 1
js/ws-events.js

@@ -1,7 +1,7 @@
 "use strict";
 (function($) {
   $(document).ready(function() {
+    console.log('ws: init events');
     _ws.events = new EventEmitter();
-    console.log('log events from events', _ws);
   });
 })(jQuery);

+ 171 - 0
js/ws-menu.js

@@ -0,0 +1,171 @@
+"use strict";
+(function($) {
+  $(document).ready(function() {
+    console.log('ws: init menu');
+
+    /**
+     * Main menu
+     */
+    var $mainMenu = $('#nav-menus');
+
+
+    /**
+     * Main menu toggle button
+     */
+    var $menuBtn = $('#menu-btn');
+    $menuBtn.click(toggleMainMenu);
+
+    /**
+     * Navigation state
+     */
+    var navState = parsePath();
+
+
+    /**
+     * Previous navigation state
+     */
+    var prevNavState;
+
+
+    /**
+     * Toggle main menu
+     */
+    function toggleMainMenu() {
+      $mainMenu.toggleClass('in');
+    };
+
+
+    /**
+     * Extract bits (repo&example slugs) from requested url path
+     */
+    function parsePath() {
+      const path = window.location.pathname.substr(1);
+      const bits = path.split('/');
+      return {
+        repo: bits[0],
+        example: bits.length === 1 ? '' : bits[1]
+      };
+    }
+
+    /**
+     * Handle navigation
+     */
+     function navigateTo(path) {
+      history.pushState({}, 'New path', path);
+      prevNavState = navState;
+      navState = parsePath();
+      console.log('previous&new nav states', prevNavState, navState);
+
+      if(navState.repo !== prevNavState.repo) {
+        if(navState.repo === '') {
+          console.log('nav: back to root');
+          _ws.events.emit('navToRoot');
+        }
+        else {
+          console.log('nav: repo changed');
+          rp.get('/parts/' + navState.repo, 'json')
+          .then(function(parts) {
+            // renderMenuExample(parts.menuExample);
+            console.log('render with parts', parts);
+            _ws.ui.detailsRepo.render(parts);
+            _ws.ui.menuExample.render(parts);
+            _ws.events.emit('navToRepo', navState.repo);
+          });
+        }
+      }
+      else if(navState.example !== prevNavState.example) {
+        rp.get('/parts/' + navState.repo + '/' + navState.example, 'json')
+        .then(function(parts) {
+          console.log('nav: example changed');
+          _ws.files = parts.files;
+          console.log(_ws.ui);
+          // renderDetailsExample(parts);
+          _ws.ui.detailsExample.render(parts);
+          _ws.ui.editor.render(parts);
+          _ws.ui.tabs.render(parts);
+          _ws.ui.sandboxIframe.render(navState);
+        });
+      }
+    }
+
+
+    function menuItemClicked(e) {
+      e.preventDefault();
+      var $link = $(this);
+      console.log($link.prop('href'));
+      var originalColor = $link.css('backgroundColor');
+      toggleMainMenu();
+      $link.animate({
+        backgroundColor: '#aaa',
+      }, 70);
+      $link.animate({
+        backgroundColor: originalColor,
+      }, 70);
+      navigateTo($link.prop('href'));
+    }
+
+
+    /**
+     * Initialize menu-example view
+     */
+    _ws.makeView('menu-example', {
+      events: {
+        'click a': menuItemClicked
+      }
+    });
+
+
+    /**
+     * Initialize menu-example view
+     */
+    // _ws.makeView('menu-repo', {
+    //   events: {
+    //     'click a': menuItemClicked
+    //   }
+    // });
+
+    /**
+     * Handle click on links outside #menu-example
+     */
+    $('#menu-repo a').click(menuItemClicked);
+    $('#nav-back-home').click(function(e) {
+      e.preventDefault();
+      $mainMenu.removeClass('in');
+      navigateTo('/');
+    });
+
+
+    /**
+     * Initialize details-example view
+     */
+    _ws.makeView('details-example');
+
+
+    /**
+     * Initialize details-repo view
+     */
+    _ws.makeView('details-repo');
+
+
+
+
+
+    // window._ws.navigator = new SandboxNavigator();
+    // console.log('navigator init', _ws);
+
+    //     var $exMenuItem = $('<li><a href="/' + repoSlug + '/' + example.slug + '">' + example.title + '</a></li>')
+    //     .appendTo( $('#cat-' + example.category) );
+    //     notify('success', "Exemple créé !");
+    //     navigateTo('/'+ repoSlug + '/' + example.slug);
+    //   })
+    //   .catch(errText => notify('error', 'Erreur: ' + errText));
+    // }
+
+    // function clearAndCloseEditor() {
+    //   $exampleFormIn.val('');
+    //   toggleEditor();
+    // }
+
+
+  });
+})(jQuery);

+ 81 - 96
js/ws-ui-parts.js

@@ -1,132 +1,117 @@
 "use strict";
 (function($) {
   $(document).ready(function() {
+    console.log('ws: init UI parts');
 
 
-    var eventBinders = {
-
-      menuExample: function() {
-        console.log('eventBinder for menuExample', this);
-        this.$elem.find('a').click(function(e) {
-          e.preventDefault();
-          var $link = $(this);
-          console.log('menu item clicked', $link.prop('href'));
-          var originalColor = $link.css('backgroundColor');
-          // self.toggleMenu();
-          $link.animate({
-            backgroundColor: '#aaa',
-          }, 70);
-          $link.animate({
-            backgroundColor: originalColor,
-          }, 70);
-          _ws.navigator.navigateTo($link.prop('href'));
-        });
+    /**
+     * Initialize an empty object to be populated as follows:
+     *   - key is an UI element's id
+     *   - value associated is an obj containing: tmpl (the template) and $elem (jQueried target element)
+     */
+    _ws.ui = {};
+
+
+    /**
+     * Generic template-based rendering function
+     */
+    function viewDefaultRender(data) {
+      if(! data) {
+        console.log('WARNING! You should provide data for #' + elemId + "'s render()");
+      }
+      this.$elem.html( Mustache.render( this.tmpl, data ) );
+      this.$elem.show();
+      this.bindEvents();
+    }
+
+
+    /**
+     * Wrapper around provided render function (show elem after render)
+     */
+    function viewRenderWrapper(data) {
+      this._render(data);
+      this.$elem.show();
+    }
+
+
+
+    /**
+     * Bind events
+     */
+    function viewBindEvents() {
+      var events = this.props.events;
+      for(var descriptor in events) {
+        var handler = events[descriptor];
+        var bits = descriptor.split(' ');
+        var evtName = bits.shift();
+        var selector = bits.join(' ');
+        console.log('#### bind', descriptor, 'e:' + evtName, 's:' + selector);
+        this.$elem.find(selector).on(evtName, handler);
       }
+    }
+
 
+    /**
+     * Bind events: nop
+     */
+    function viewBindEventsNop() {
+      console.log(this.partName, 'bindEvents:nop');
+    }
+
+
+    /**
+     * Show view element
+     */
+    function viewElemShow() {
+      this.$elem.show();
     }
 
+
     /**
-     * Render an UI part
+     * Hide view element
      */
-    function renderPart(partName, data) {
-      var part = _ws.ui[partName];
-      part.$elem.html( Mustache.render( part.tmpl, data ) );
+    function hideElemShow() {
+      this.$elem.hide();
     }
 
 
+    /**
+     * Build a view
+     */
     _ws.makeView = function(elemId, props) {
+      console.log('** makeView', elemId);
       var v = {};
       v.props = props || {};
 
       v.$elem = $('#' + elemId);
       v.partName = _.camelCase(elemId);
+      console.log('adding', elemId, v.partName);
       _ws.ui[v.partName] = v;
 
-      // Assign a default render function if none given
-      if(! v.props.render) {
-        var $tmplEl = $('script[data-tmpl-for="' + elemId + '"]');
-        v.tmpl = $tmplEl.html();
-        v.render = (function(data) {
-          if(! data) {
-            console.log('WARNING! You should provide data for #' + elemId + "'s render()");
-          }
-          // var eventBinder = eventBinders[v.partName];
-          this.$elem.html( Mustache.render( this.tmpl, data ) );
-          // if(eventBinder) {
-          //   eventBinder = eventBinder.bind(this);
-          //   console.log('bind events for', v.partName);
-          //   eventBinder();
-          // }
-          console.log('rebind events after render', this);
-          this.bindEvents();
-        }).bind(v);
+      // Bind the provided render function
+      if(v.props.render) {
+        v._render = props.render.bind(v);
+        v.render = viewRenderWrapper.bind(v);
       }
-      // Otherwise bind the provided one
+      // Otherwise assign the default render function
       else {
-        v.render = props.render.bind(v);
+        var $tmplEl = $('script[data-tmpl-for="' + elemId + '"]');
+        v.tmpl = $tmplEl.html();
+        v.render = viewDefaultRender.bind(v);
       }
 
       // Set event handlers
       if(v.props.events) {
-        v.bindEvents = (function() {
-          var events = this.props.events;
-          for(var descriptor in events) {
-            var handler = events[descriptor];
-            var bits = descriptor.split(' ');
-            var evtName = bits.shift();
-            var selector = bits.join(' ');
-            console.log('#### bind', descriptor, 'e:' + evtName, 's:' + selector, handler.toString())
-            v.$elem.find(selector).on(evtName, handler);
-          }
-        }).bind(v);
+        v.bindEvents = viewBindEvents.bind(v);
         v.bindEvents();
       }
       else {
-        v.bindEvents = function() {};
+        v.bindEvents = viewBindEventsNop.bind(v);
       }
-    }
-
-
-    /**
-     * Initialize an empty object to be populated as follows:
-     *   - key is an UI element's id
-     *   - value associated is an obj containing: tmpl (the template) and $elem (jQueried target element)
-     */
-    _ws.ui = {};
-
-    // Iterate over the template script elements
-    var $templateElems = $('script[data-tmpl-for]');
-    $templateElems.each(function(idx, el) {
-      return;
-
-
-      // Get the script element content and target element id
-      var $script = $(el);
-      var tmpl = $script.html();
-      var elemId = $script.data('tmpl-for');
-      var $elem = $('#' + elemId);
-      var partName = _.camelCase(elemId);
-
-      // Populate the uiParts object
-      _ws.ui[partName] = {
-        tmpl: tmpl,
-        $elem: $elem,
-        render: (function(_name) {
-          return function(data) {
-            var eventBinder = eventBinders[_name];
-            renderPart(_name, data);
-            if(eventBinder) {
-              eventBinder = eventBinder.bind(this);
-              console.log('bind events for', _name);
-              eventBinder();
-            }
-          };
-        })(partName)
-      };
-    });
-
-    // console.log(_.map(_ws.uiParts, p => (p.render.toString())));
 
+      v.show = viewElemShow.bind(v);
+      v.hide = hideElemShow.bind(v);
+    };
 
 
   });

+ 63 - 52
sandboxApp.js

@@ -101,64 +101,75 @@ app.get('/:repoSlug', getIndexRepo);
 app.get('/:repoSlug/:exampleSlug', getIndexExample);
 
 
-
-/**
- * Create a new example for specified repo
- */
-app.post('/:repoSlug/examples', function(req, res) {
-
-  // Check for title and extract params
-  if(! req.body || ! req.body.title) {
-    res.status(400).send('Le titre ne peut pas être vide !');
-  }
-  const { title }    = req.body;
+function checkRepoExists(req, res, next) {
   const { repoSlug } = req.params;
-
+console.log('### checkRepoExists', repoSlug);
   // Get repo from store
-  var repo = exStore.getRepo(repoSlug);
-  if(! repo) {
+  req.repo = exStore.getRepo(repoSlug);
+  if(! req.repo) {
     res.status(404).send("Repo " + repoSlug + "not found");
   }
+  next();
+}
 
-  // Prevent duplicate title
-  var existingTitle = _.find(repo.examples, { title: title });
-  if(existingTitle) {
-    res.status(400).send("L'exemple '" + title + "' existe déjà !");
+/**
+ * Create a new example for specified repo
+ */
+app.post('/:repoSlug/examples', 
+  checkRepoExists,
+  function(req, res) {
+
+    // Check for title and extract params
+    if(! req.body || ! req.body.title) {
+      res.status(400).send('Le titre ne peut pas être vide !');
+    }
+    const { title }    = req.body;
+    const { repoSlug } = req.params;
+
+    // Prevent duplicate title
+    var existingTitle = _.find(req.repo.examples, { title: title });
+    if(existingTitle) {
+      res.status(400).send("L'exemple '" + title + "' existe déjà !");
+    }
+    var exampleSlug = slug(req.body.title.toLowerCase());
+
+    // Prepare config
+    var config = Object.assign({
+      slug: exampleSlug,
+      title,
+      category: req.repo.defaultCategory
+    }, exampleTmpl);
+
+    // Prepare files to write
+    var targetDir = __dirname + '/exemples/' + repoSlug + '/' + exampleSlug;
+    var files = mapObjToArray({
+      'example.html': '<!-- ' + title + '-->\n',
+      'script.js': '// ' + title,
+      'config.json': beautify(config, null, 2, 100)
+    }, 'file', 'content');
+    fs.mkdirAsync(targetDir)
+    .then(() => Promise.map(
+      files, ({ file, content }) => fs.writeFileAsync(targetDir + '/' + file, content)
+    ))
+    .then(files => req.repo.examples.push(config))
+    .then(() => res.json(config));
   }
-  var exampleSlug = slug(req.body.title.toLowerCase());
-
-  // Prepare config
-  var config = Object.assign({
-    slug: exampleSlug,
-    title,
-    category: repo.defaultCategory
-  }, exampleTmpl);
-
-  // Prepare files to write
-  var targetDir = __dirname + '/exemples/' + repoSlug + '/' + exampleSlug;
-  var files = mapObjToArray({
-    'example.html': '<!-- ' + title + '-->\n',
-    'script.js': '// ' + title,
-    'config.json': beautify(config, null, 2, 100)
-  }, 'file', 'content');
-  fs.mkdirAsync(targetDir)
-  .then(() => Promise.map(
-    files, ({ file, content }) => fs.writeFileAsync(targetDir + '/' + file, content)
-  ))
-  .then(files => repo.examples.push(config))
-  .then(() => res.json(config));
-});
-
-app.get('/examples/:slug', function(req, res) {
-  const { slug } = req.params;
-  const config = readConfigJson(slug);
-  const { title, html, js, css, libsCss, libsJs } = config;
-  readFileAsync(__dirname + '/exemples/' + slug + '/example.html')
-  .then(body =>
-    Mustache.render(sandboxTpml, { body, slug, title, js, css, libsCss, libsJs })
-  )
-  .then(html => res.send(html));
-});
+);
+
+app.get('/examples/:repoSlug/:slug',
+  checkRepoExists,
+  function(req, res) {
+    const { repoSlug, slug } = req.params;
+    var example = _.find(req.repo.examples, { slug });
+    const { title, html, js, css, libsCss, libsJs } = example;
+    console.log(example, title, html, js, css, libsCss, libsJs);
+    readFileAsync(__dirname + '/exemples/' + repoSlug + '/' + slug + '/example.html')
+    .then(body =>
+      Mustache.render(sandboxTpml, { body, repoSlug, slug, title, js, css, libsCss, libsJs })
+    )
+    .then(html => res.send(html));
+  }
+);
 
 app.get('/menu', (rea, res) => {
   res.send(exStore.getMenu());