瀏覽代碼

Possibilité d'ajouter un exemple

Benoît Hubert 8 年之前
父節點
當前提交
25b2bae18a

二進制
css/fonts/icomoon.eot


File diff suppressed because it is too large
+ 13 - 0
css/fonts/icomoon.svg


二進制
css/fonts/icomoon.ttf


二進制
css/fonts/icomoon.woff


+ 84 - 3
css/styles.css

@@ -1,3 +1,43 @@
+/** 
+ * Pack d'icônes
+ */
+@font-face {
+  font-family: 'icomoon';
+  src:  url('fonts/icomoon.eot?vcoix9');
+  src:  url('fonts/icomoon.eot?vcoix9#iefix') format('embedded-opentype'),
+    url('fonts/icomoon.ttf?vcoix9') format('truetype'),
+    url('fonts/icomoon.woff?vcoix9') format('woff'),
+    url('fonts/icomoon.svg?vcoix9#icomoon') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+
+[class^="icon-"], [class*=" icon-"] {
+  /* use !important to prevent issues with browser extensions that change fonts */
+  font-family: 'icomoon' !important;
+  speak: none;
+  font-style: normal;
+  font-weight: normal;
+  font-variant: normal;
+  text-transform: none;
+  line-height: 1;
+
+  /* Better Font Rendering =========== */
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-plus:before {
+  content: "\ea0a";
+}
+.icon-cross:before {
+  content: "\ea0f";
+}
+.icon-checkmark:before {
+  content: "\ea10";
+}
+
+
 /**
  * Styles généraux
  */
@@ -8,6 +48,10 @@
 body {
   font-size: 130%;
 }
+
+/**
+ * Styles des panneaux gauche-droite
+ */
 #left-panel,
 #right-panel {
 	font-family: Arial, Helvetica;
@@ -29,7 +73,8 @@ body {
 .panel-inner {
   padding: 10px;
 }
-#left-panel nav {
+#left-panel nav,
+#add-example-form {
   display: inline-block;
 }
 #left-panel nav ul {
@@ -39,6 +84,29 @@ body {
 #left-panel nav ul li {
   display: inline-block;
 }
+#notification {
+  position: absolute;
+  top: -100px;
+  right: 10px;
+  transition: top 1s;
+  border-radius: 3px;
+  padding: 3px;
+}
+#notification.active {
+  top: 5px;
+}
+#notification.error {
+  border: 1px solid #d42;
+  background: #ffe8e0;
+}
+#notification.success {
+  border: 1px solid #2d4;
+  background: #e0ffe8;
+}
+
+/**
+ * Styles généraux: liens, boutons, ...
+ */
 a {
   text-decoration: none;
   color: #59d;
@@ -93,14 +161,21 @@ button {
   background: #d42;
 }
 .green {
-  background: #4d2;
+  background: #4b2;
 }
 select,
 input {
   border: 1px solid #ddd;  
-  padding: 8px;
+  padding: 12px;
   border-radius: 3px;
 }
+input.input-sm {
+  padding: 6px;
+  font-size: 70%;
+}
+select {
+  background: #fcfcfc;
+}
 a,
 button {
   margin: 5px;
@@ -116,6 +191,12 @@ button {
 #html-content p {
   margin: 10px 0;
 }
+button.rounded {
+  padding: 0;
+  width: 32px;
+  height: 32px;
+  border-radius: 16px;
+}
 
 /**
  * Styles communs pour les différents exemples

+ 1 - 0
exemples/liste.json

@@ -0,0 +1 @@
+[{"slug":"selecteurs-basiques","title":"Sélecteurs basiques"},{"slug":"selecteurs-multiples","title":"Sélecteurs multiples"}]

exemples/selecteurs-base/contenu.html → exemples/selecteurs-basiques/contenu.html


exemples/selecteurs-base/script.js → exemples/selecteurs-basiques/script.js


+ 1 - 0
exemples/selecteurs-multiples/contenu.html

@@ -0,0 +1 @@
+undefined

+ 1 - 0
exemples/selecteurs-multiples/script.js

@@ -0,0 +1 @@
+undefined

+ 9 - 4
index.html

@@ -12,12 +12,17 @@
 <body>
 
 <div id="left-panel">
+    <div id="notification"></div>
     <div class="panel-inner">
-        <nav>
-            <select id="fileSelect">
+        <button id="add-example-btn" class="icon-plus rounded blue"></button>
+        <form id="add-example-form" style="display: none;">
+            <input type="text" name="title" class="input-sm" value="" />
+            <button type="button" id="add-example-cancel" class="icon-cross rounded red"></button><!--
+            --><button type="submit" id="add-example-save" class="icon-checkmark rounded green"></button>
+        </form>
+        <nav id="selector">
+            <select id="file-select">
                 <option value="-">&mdash;</option>
-                <option value="selecteurs-base">Sélecteurs de base</option>
-                <option value="selecteurs-filtres">Sélecteurs : filtres</option>
             </select>
         </nav>
         <nav id="tabs">

+ 76 - 7
js/editor.js

@@ -1,8 +1,16 @@
 $(document).ready(function() {
-  var $editor = $('#editor');
-  var $editorJs = $('#editor-javascript');
-  var $editorHtml = $('#editor-html');
-  var $htmlContent = $('#html-content');
+  var $editor        = $('#editor');
+  var $editorJs      = $('#editor-javascript');
+  var $editorHtml    = $('#editor-html');
+  var $htmlContent   = $('#html-content');
+  var $selectorNav   = $('#selector');
+  var $fileSelect    = $('#file-select');
+  var $addExampleBtn = $('#add-example-btn');
+  var $exampleForm   = $('#add-example-form');
+  var $exampleSave   = $('#add-example-save');
+  var $exampleCancel = $('#add-example-cancel');
+  var $notification  = $('#notification');
+
   var activeTab = 'show-html';
 
   var editor;
@@ -44,12 +52,73 @@ $(document).ready(function() {
       setActiveTab('html');
       loadJS(serverPath + 'script.js');
     }, 'text');
+  }
+
+  function addFileSelectItem(item) {
+    $fileSelect.append(
+      '<option value="' + item.slug + '">' +
+        item.title +
+      '</option>'
+    );
+  }
+
+  function loadExampleList() {
+    $.get('exemples/liste.json', function(liste) {
+      liste.forEach(addFileSelectItem);
+    }, 'json');
+  }
 
-    
+  function notify(type, text) {
+    $notification
+    .addClass(type)
+    .addClass('active');
+    $notification.html(text);
+    setTimeout(function() {
+      $notification.removeClass('active');
+    }, 2000);
+    setTimeout(function() {
+      $notification.removeClass(type);
+    }, 3000);
   }
 
-  var fileSelect = $('#fileSelect');
-  fileSelect.change(loadExample);
+  function toggleEditor() {
+    $addExampleBtn.toggle();
+    $selectorNav.toggle();
+    $exampleForm.toggle();
+  }
+
+  // function ajaxPost(url, data, success, error) {}
+
+  function saveExample(e) {
+    e.preventDefault();
+    var title = $(this).find('input[name="title"]').val();
+    $.ajax({
+      type: 'POST',
+      url: '/examples',
+      data: JSON.stringify({ title }),
+      success: function(newExample) {
+        clearAndCloseEditor();
+        addFileSelectItem(newExample);
+        notify('success', "Exemple sauvegardé !");
+      },
+      error: function(jqXHR, textStatus, errorThrown ) {
+        console.log(jqXHR, textStatus, errorThrown);
+        notify('error', 'Erreur: ' + jqXHR.responseText);
+      },
+      contentType: 'application/json',
+      dataType: 'json'
+    });
+  }
+
+  function clearAndCloseEditor() {
+    $exampleForm.find('input').val('');
+    toggleEditor();
+  }
 
+  $fileSelect.change(loadExample);
+  $addExampleBtn.click(toggleEditor);
+  $exampleCancel.click(clearAndCloseEditor);
+  $exampleForm.submit(saveExample);
+  loadExampleList();
   // setActiveTab('html');
 });

+ 4 - 1
package.json

@@ -1,6 +1,9 @@
 {
   "name": "ipi-inline-editor",
   "dependencies": {
-    "express": "^4.16.2"
+    "body-parser": "^1.18.2",
+    "express": "^4.16.2",
+    "lodash": "^4.17.4",
+    "slug": "^0.9.1"
   }
 }

+ 34 - 2
server.js

@@ -1,5 +1,37 @@
-var express = require('express');
-var app     = express();
+var express      = require('express');
+var bodyParser   = require('body-parser');
+var slug         = require('slug');
+var _            = require('lodash');
+var fs           = require('fs');
+var app          = express();
+var examplesJSON = __dirname + '/exemples/liste.json';
+var examples     = require(examplesJSON);
 
 app.use(express.static(__dirname));
+app.use(bodyParser.json());
+
+function addExample(slug, title) {
+  examples.push({ slug: slug, title: title });
+  fs.writeFileSync(examplesJSON, JSON.stringify(examples));
+}
+
+app.post('/examples', function(req, res) {
+  var title = req.body.title;
+  if(! req.body.title) {
+    res.status(400).send('Le titre ne peut pas être vide !');
+  }
+  var existingTitle = _.find(examples, { title: title });
+  if(existingTitle) {
+    res.status(400).send("L'exemple '" + title + "' existe déjà !");
+  }
+  var exampleSlug = slug(req.body.title.toLowerCase());
+  var targetDir = __dirname + '/exemples/' + exampleSlug;
+
+  fs.mkdirSync(targetDir);
+  fs.writeFileSync(targetDir + '/contenu.html');
+  fs.writeFileSync(targetDir + '/script.js');
+  addExample(exampleSlug, title);
+  res.json({ slug: exampleSlug, title: title });
+});
+
 app.listen(3000);