sandboxApp.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* global __dirname */
  2. /* jshint strict:false */
  3. "use strict";
  4. var express = require('express');
  5. var bodyParser = require('body-parser');
  6. var slug = require('slug');
  7. var beautify = require("json-beautify");
  8. var _ = require('lodash');
  9. var fs = require('fs');
  10. var path = require('path');
  11. var Promise = require('bluebird');
  12. var Mustache = require('mustache');
  13. var app = express();
  14. var ExampleStore = require('./lib/ExampleStore');
  15. var indexTpml = fs.readFileSync(__dirname + '/html/index.mustache.html').toString();
  16. var sandboxTpml = fs.readFileSync(__dirname + '/html/template.mustache.html').toString();
  17. Promise.promisifyAll(fs);
  18. var exStore = new ExampleStore(__dirname + '/exemples');
  19. exStore.init()
  20. .then(() => console.log(exStore.getMenu()));
  21. // Initialize Express app: root folder as static, body parsers
  22. app.use(express.static(__dirname));
  23. app.use(bodyParser.json());
  24. app.use(bodyParser.urlencoded({ extended: true }));
  25. function addExample(slug, title) {
  26. examples.push({ slug: slug, title: title });
  27. return fs.writeFileAsync(examplesJSON, beautify(examples, null, 2, 100));
  28. }
  29. function readConfigJson(exampleSlug) {
  30. console.log(exampleSlug);
  31. return require('./exemples/jquery/' + exampleSlug + '/config.json');
  32. }
  33. function readFileAsync(file) {
  34. return fs.readFileAsync(file)
  35. .then(buf => (buf.toString()));
  36. }
  37. function readFilesAsync(fullPath, files) {
  38. // console.log('reading files', files, 'from path', path);
  39. return Promise.reduce(files,
  40. (carry, f) => readFileAsync(fullPath + '/' + f)
  41. .then(content =>
  42. (carry.concat([{
  43. type: path.extname(f).substr(1),
  44. name: f,
  45. content
  46. }]))
  47. ),
  48. []
  49. );
  50. }
  51. function readExampleFiles(repoSlug, exampleSlug, config) {
  52. const exampleDir = __dirname + '/exemples/' + repoSlug + '/' + exampleSlug;
  53. const libsCssDir = __dirname + '/css/vendor';
  54. const libsJsDir = __dirname + '/js/vendor';
  55. const { html, js, css } = config; // libsCss, libsJs
  56. const files = [].concat(html, js, css);
  57. return readFilesAsync(exampleDir, files);
  58. }
  59. /**
  60. * Index page: render with only repo list in menu
  61. */
  62. app.get('/', function(req, res) {
  63. const menuRepo = exStore.getRepoMenu();
  64. // const title = 'Home';
  65. console.log(menuRepo);
  66. res.send(Mustache.render(indexTpml, {
  67. title,
  68. menuRepo
  69. }));
  70. });
  71. /**
  72. * Repo page: render with repo list and selected repo's example list in menu
  73. */
  74. app.get('/:repoSlug',
  75. function(req, res) {
  76. const repo = exStore.getRepo(req.params.repoSlug);
  77. if(! repo) {
  78. return res.status(404).send('Repo ' + req.params.repoSlug + ' not found');
  79. }
  80. const menuRepo = exStore.getRepoMenu();
  81. const menuExample = exStore.getExampleMenu(repo.path);
  82. // const title = 'Home';
  83. console.log(menuExample);
  84. res.send(Mustache.render(indexTpml, {
  85. // title,
  86. menuRepo,
  87. menuExample
  88. }));
  89. });
  90. /**
  91. * Example page: render with repo list and selected repo's example list in menu,
  92. * and the editor with the selected example
  93. */
  94. app.get('/:repoSlug/:exampleSlug',
  95. function(req, res) {
  96. const repo = exStore.getRepo(req.params.repoSlug);
  97. if(! repo) {
  98. return res.status(404).send('Repo ' + req.params.repoSlug + ' not found');
  99. }
  100. const menuRepo = exStore.getRepoMenu();
  101. const menuExample = exStore.getExampleMenu(repo.path);
  102. const example = _.find(repo.examples, { slug: req.params.exampleSlug });
  103. if(! example) {
  104. return res.status(404).send('Example ' + req.params.repoSlug + '/' + req.params.exampleSlug + ' not found');
  105. }
  106. // const title = 'Home';
  107. console.log(menuExample);
  108. const { repoSlug, exampleSlug } = req.params;
  109. readExampleFiles(repoSlug, exampleSlug, example)
  110. .then(files => {
  111. // console.log('example files', html, js, css);
  112. res.send(Mustache.render(indexTpml, {
  113. // title,
  114. menuRepo,
  115. menuExample,
  116. files,
  117. filesJSON: JSON.stringify(files)
  118. }));
  119. });
  120. });
  121. app.post('/examples', function(req, res) {
  122. var title = req.body.title;
  123. if(! req.body.title) {
  124. res.status(400).send('Le titre ne peut pas être vide !');
  125. }
  126. var existingTitle = _.find(examples, { title: title });
  127. if(existingTitle) {
  128. res.status(400).send("L'exemple '" + title + "' existe déjà !");
  129. }
  130. var exampleSlug = slug(req.body.title.toLowerCase());
  131. var targetDir = __dirname + '/exemples/' + exampleSlug;
  132. fs.mkdirAsync(targetDir)
  133. .then(() => Promise.map(
  134. ['contenu.html', 'script.js'], f => fs.writeFileAsync(targetDir + '/' + f, '')
  135. ))
  136. .then(files => addExample(exampleSlug, title))
  137. .then(() => res.json({ slug: exampleSlug, title: title }));
  138. });
  139. app.get('/examples/:slug', function(req, res) {
  140. const { slug } = req.params;
  141. const config = readConfigJson(slug);
  142. const { title, html, js, css, libsCss, libsJs } = config;
  143. readFileAsync(__dirname + '/exemples/' + slug + '/example.html')
  144. .then(body =>
  145. Mustache.render(sandboxTpml, { body, slug, title, js, css, libsCss, libsJs })
  146. )
  147. .then(html => res.send(html));
  148. });
  149. app.get('/menu', (rea, res) => {
  150. res.send(exStore.getMenu());
  151. });
  152. app.get('/list/:repoPath', function(req, res) {
  153. const { repoPath } = req.params;
  154. const repo = exStore.getList(repoPath);
  155. if(! repo) {
  156. return res.status(404).send('Repo ' + repoPath + ' not found');
  157. }
  158. console.log('found repo', repo);
  159. const data = repo.examples.map(e => (
  160. { slug: e.slug, title: e.title }
  161. ));
  162. res.json(data);
  163. });
  164. app.put('/examples/:slug', function(req, res) {
  165. var slug = req.params.slug;
  166. var existing = _.find(examples, { slug: slug });
  167. if(! existing) {
  168. res.status(404).send("L'exemple avec l'identifiant '" + slug + "' est introuvable !");
  169. }
  170. var targetDir = __dirname + '/exemples/' + slug;
  171. if(req.body.html) {
  172. fs.writeFileSync(targetDir + '/contenu.html', req.body.html);
  173. }
  174. if(req.body.javascript) {
  175. fs.writeFileSync(targetDir + '/script.js', req.body.javascript);
  176. }
  177. var theDate = new Date();
  178. console.log(theDate.getHours() + ':' + theDate.getMinutes() + " - Sauvegarde de l'exemple '" + existing.title + " effectuée'");
  179. res.json({ success: true });
  180. });
  181. module.exports = app;