{ | { | ||||
"title": "Spus", | "title": "Spus", | ||||
"base_url": "http://example.com", | "base_url": "http://example.com", | ||||
"webroot": "web", | |||||
"port": 8081, | "port": 8081, | ||||
"db": { | "db": { | ||||
"host": "localhost", | "host": "localhost", | ||||
"minify": true, | "minify": true, | ||||
"session_timeout": 1800000, | "session_timeout": 1800000, | ||||
"dir": { | "dir": { | ||||
"imgs": "imgs" | |||||
"imgs": "imgs", | |||||
"web": "web | |||||
}, | }, | ||||
"debug": false, | "debug": false, | ||||
"max_runs": 9999, | "max_runs": 9999, |
var fs = require("fs"); | var fs = require("fs"); | ||||
var zlib = require("zlib"); | var zlib = require("zlib"); | ||||
var browserPrefix = require("browser-prefix"); | |||||
var minify = require("./minify.js"); | var minify = require("./minify.js"); | ||||
var includeHtml = require("./includeHtml.js"); | var includeHtml = require("./includeHtml.js"); | ||||
//Prepare endpoints | //Prepare endpoints | ||||
var errs = false; | var errs = false; | ||||
Object.keys(endpoints).forEach(function(i) { | |||||
var ep = endpoints[i]; | |||||
var eps = Object.keys(endpoints).map(function(i) { | |||||
var ep = { | |||||
path: endpoints[i], | |||||
url: i | |||||
} | |||||
try { | try { | ||||
//The endpoint is a function if the file ends with .node.js | //The endpoint is a function if the file ends with .node.js | ||||
if (/\.node\.js$/.test(ep)) { | |||||
res.endpoints[i] = require("../"+conf.webroot+"/"+ep); | |||||
if (/\.node\.js$/.test(ep.path)) { | |||||
ep.func = require("../"+conf.dir.web+"/"+ep.path); | |||||
return ep; | |||||
//If it doesn't end with .node.js, it's a regular text file and will | //If it doesn't end with .node.js, it's a regular text file and will | ||||
//just be served as is | //just be served as is | ||||
} else { | } else { | ||||
var str = fs.readFileSync(conf.webroot+"/"+ep, "utf8"); | |||||
ep.str = fs.readFileSync(conf.dir.web+"/"+ep.path, "utf8"); | |||||
//If it's an HTML file, we minify it | |||||
if (!conf.minify) { | |||||
//Don't minify unless the conf tells us to | |||||
} else if (/\.html$/.test(ep)) { | |||||
str = minify.html(str); | |||||
} else if (/\.js$/.test(ep)) { | |||||
str = minify.js(str); | |||||
} else if (/\.css$/.test(ep)) { | |||||
str = minify.css(str); | |||||
//Add browser prefixes | |||||
if (/\.css$/.test(ep.path)) { | |||||
ep.str = browserPrefix(ep.str); | |||||
ep.mimeType = "text/css"; | |||||
if (conf.minify) ep.str = minify.css(ep.str); | |||||
} else if (/\.html$/.test(ep.path)) { | |||||
ep.mimeType = "text/html"; | |||||
if (conf.minify) ep.str = minify.html(ep.str); | |||||
} else if (/\.js$/.test(ep.path)) { | |||||
ep.mimeType = "application/javascript"; | |||||
if (conf.minify) ep.str = minify.js(ep.str); | |||||
} | } | ||||
res.endpoints[i] = str; | |||||
return ep; | |||||
} | } | ||||
//Errors will usually be because an endpoint doesn't exist | //Errors will usually be because an endpoint doesn't exist | ||||
//No need to proceed if some endpoints don't exist | //No need to proceed if some endpoints don't exist | ||||
if (errs) process.exit(); | if (errs) process.exit(); | ||||
eps.forEach(function(ep) { | |||||
res.endpoints[ep.url] = ep; | |||||
}); | |||||
//Prepare all templates | //Prepare all templates | ||||
var templates = {}; | var templates = {}; | ||||
fs.readdirSync("templates").forEach(function(f) { | fs.readdirSync("templates").forEach(function(f) { |
}, | }, | ||||
"license": "GPLv2", | "license": "GPLv2", | ||||
"dependencies": { | "dependencies": { | ||||
"browser-prefix": "^0.1.0", | |||||
"formidable": "^1.0.17", | "formidable": "^1.0.17", | ||||
"html-minifier": "^0.7.2", | "html-minifier": "^0.7.2", | ||||
"pg": "^4.4.0", | "pg": "^4.4.0", |
} | } | ||||
//Execute if it's a .node.js, or just respond with the contents of the file | //Execute if it's a .node.js, or just respond with the contents of the file | ||||
if (typeof ep == "function") { | |||||
ep(ctx); | |||||
if (ep.func) { | |||||
ep.func(ctx); | |||||
} else { | } else { | ||||
//Cache content for a while | //Cache content for a while | ||||
ctx.setHeader("Cache-Control", "public, max-age="+conf.cache_max_age); | ctx.setHeader("Cache-Control", "public, max-age="+conf.cache_max_age); | ||||
//Set appropriate content-type headers | |||||
if (ep.mimeType) | |||||
ctx.setHeader("Content-Type", ep.mimeType); | |||||
//Gzip and such | //Gzip and such | ||||
if (ctx.shouldGzip && gzipCache[req.url]) { | if (ctx.shouldGzip && gzipCache[req.url]) { | ||||
ctx.end(gzipCache[req.url], true); | ctx.end(gzipCache[req.url], true); | ||||
} else if (ctx.shouldGzip) { | } else if (ctx.shouldGzip) { | ||||
zlib.gzip(ep, function(err, res) { | |||||
zlib.gzip(ep.str, function(err, res) { | |||||
gzipCache[req.url] = res; | gzipCache[req.url] = res; | ||||
ctx.end(res, true); | ctx.end(res, true); | ||||
}); | }); | ||||
} else { | } else { | ||||
ctx.end(ep); | |||||
ctx.end(ep.str); | |||||
} | } | ||||
} | } | ||||
} | } |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> | <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> | ||||
<link rel="stylesheet" href="/{{env#view}}/style.css?{{conf#current_run}}"> | <link rel="stylesheet" href="/{{env#view}}/style.css?{{conf#current_run}}"> | ||||
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script> | |||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> | |||||
<script src="/global.js?{{conf#current_run}}"></script> | |||||
<script src="/{{env#view}}/script.js?{{conf#current_run}}"></script> | |||||
<script src="https://code.jquery.com/jquery-2.1.4.min.js" defer></script> | |||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" defer></script> | |||||
<script src="/global.js?{{conf#current_run}}" defer></script> | |||||
<script src="/{{env#view}}/script.js?{{conf#current_run}}" defer></script> |
var fs = require("fs"); | var fs = require("fs"); | ||||
var zlib = require("zlib"); | |||||
var gzipped; | |||||
var favicon = fs.readFileSync("favicon.ico"); | |||||
zlib.gzip(favicon, function(err, res) { | |||||
gzipped = res; | |||||
}); | |||||
module.exports = function(ctx) { | module.exports = function(ctx) { | ||||
var readStream = fs.createReadStream("favicon.ico"); | |||||
readStream.pipe(ctx.res); | |||||
readStream.on("error", function(err) { | |||||
if (err.code === "ENOENT") | |||||
ctx.end(ctx.view("404")); | |||||
else | |||||
ctx.end(err.toString()); | |||||
}); | |||||
if (favicon) { | |||||
ctx.res.setHeader( | |||||
"Cache-Control", | |||||
"public, max-age="+ctx.conf.cache_max_age | |||||
); | |||||
} | |||||
if (gzipped && ctx.shouldGzip) { | |||||
ctx.res.setHeader("Content-Encoding", "gzip"); | |||||
ctx.res.end(gzipped); | |||||
} else if (favicon) { | |||||
ctx.res.end(favicon); | |||||
} else { | |||||
ctx.res.writeHead(404); | |||||
ctx.end(ctx.view("404")); | |||||
} | |||||
} | } |
} | } | ||||
#notify-box { | #notify-box { | ||||
transition: max-height 0.2s; | |||||
@prefix transition: max-height 0.2s; | |||||
max-height: 0px; | max-height: 0px; | ||||
background-color: #F8F8F8; | background-color: #F8F8F8; | ||||
position: fixed; | position: fixed; | ||||
bottom: 0px; | bottom: 0px; | ||||
width: 100%; | width: 100%; | ||||
box-sizing: content-box; | |||||
@prefix box-sizing: content-box; | |||||
} | } | ||||
#notify-box .close { | #notify-box .close { | ||||
max-height: 48px; | max-height: 48px; | ||||
} | } | ||||
#notify-box.active:hover { | #notify-box.active:hover { | ||||
transition: max-height 0.6s; | |||||
@prefix transition: max-height 0.6s; | |||||
max-height: 200px; | max-height: 200px; | ||||
} | } |
border-radius: 4px; | border-radius: 4px; | ||||
padding: 6px 12px; | padding: 6px 12px; | ||||
} | } | ||||
#uploader-select-files, #uploader-collection-name, #uploader-upload { | |||||
height: 34px; | |||||
} |