//Viewer files | //Viewer files | ||||
"/viewer": "viewer/index.node.js", | "/viewer": "viewer/index.node.js", | ||||
"/viewer/script.js": "viewer/script.js", | "/viewer/script.js": "viewer/script.js", | ||||
"/viewer/style.css": "viewer/style.css" | |||||
"/viewer/style.css": "viewer/style.css", | |||||
//API files | |||||
"/api/upload": "api/upload.node.js" | |||||
} | } | ||||
var loaded = loader.load(endpoints, conf); | var loaded = loader.load(endpoints, conf); |
var formidable = require("formidable"); | |||||
function templatify(str, args) { | function templatify(str, args) { | ||||
if (args == undefined) | if (args == undefined) | ||||
return str; | return str; | ||||
this.res.end(str); | this.res.end(str); | ||||
}, | }, | ||||
succeed: function(obj) { | |||||
obj = obj || {}; | |||||
obj.success = true; | |||||
this.end(JSON.stringify(obj)); | |||||
}, | |||||
fail: function(err) { | |||||
obj = obj || {}; | |||||
obj.success = false; | |||||
obj.error = error; | |||||
this.end(JSON.stringify(obj)); | |||||
}, | |||||
template: function(name, args) { | template: function(name, args) { | ||||
var str = this.templates[name]; | var str = this.templates[name]; | ||||
if (!str) | if (!str) | ||||
}, | }, | ||||
getPostData: function(cb) { | getPostData: function(cb) { | ||||
if (this.req.method != "POST") | |||||
if (this.req.method.toUpperCase() != "POST") | |||||
return cb(new Error("Expected POST request, got "+this.req.method)); | return cb(new Error("Expected POST request, got "+this.req.method)); | ||||
if (this._postData) | |||||
return cb(null, this._postData); | |||||
var str = ""; | |||||
this.req.on("data", function(data) { | |||||
str += data; | |||||
}); | |||||
this.req.on("end", function() { | |||||
try { | |||||
var obj = JSON.parse(str); | |||||
} catch (err) { | |||||
return cb(err); | |||||
} | |||||
this._postData = obj; | |||||
cb(null, obj); | |||||
}); | |||||
var form = new formidable.IncomingForm(); | |||||
form.parse(this.req, cb); | |||||
} | } | ||||
} | } |
res.endpoints[i] = fs.readFileSync(conf.webroot+"/"+ep, "utf8"); | res.endpoints[i] = fs.readFileSync(conf.webroot+"/"+ep, "utf8"); | ||||
//If it's an HTML file, we minify it | //If it's an HTML file, we minify it | ||||
if (/\.html$/.test(ep)) { | |||||
if (!conf.minify) { | |||||
//Don't minify unless the conf tells us to | |||||
} else if (/\.html$/.test(ep)) { | |||||
res.endpoints[i] = minify.html(res.endpoints[i]); | res.endpoints[i] = minify.html(res.endpoints[i]); | ||||
} else if (/\.js$/.test(ep)) { | } else if (/\.js$/.test(ep)) { | ||||
res.endpoints[i] = minify.js(res.endpoints[i]); | res.endpoints[i] = minify.js(res.endpoints[i]); |
}, | }, | ||||
"license": "GPLv2", | "license": "GPLv2", | ||||
"dependencies": { | "dependencies": { | ||||
"formidable": "^1.0.17", | |||||
"html-minifier": "^0.7.2", | "html-minifier": "^0.7.2", | ||||
"pg": "^4.4.0", | "pg": "^4.4.0", | ||||
"uglify-js": "^2.4.24", | "uglify-js": "^2.4.24", |
CREATE TABLE users ( | |||||
id SERIAL PRIMARY KEY, | |||||
username VARCHAR(64) UNIQUE NOT NULL, | |||||
pass_hash CHAR(128) NOT NULL, | |||||
date_created TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT NOW() | |||||
) | |||||
CREATE TABLE collections ( | |||||
id SERIAL PRIMARY KEY, | |||||
name VARCHAR(64), | |||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE | |||||
) | |||||
CREATE TABLE images ( | |||||
id SERIAL PRIMARY KEY, | |||||
name VARCHAR(64) NOT NULL, | |||||
description TEXT, | |||||
extension VARCHAR(16) NOT NULL, | |||||
collection_id INTEGER NOT NULL REFERENCES collections(id) ON DELETE CASCADE | |||||
) |
<button class="btn btn-default" onclick="$('#uploader-input').click()"> | <button class="btn btn-default" onclick="$('#uploader-input').click()"> | ||||
Select Files | Select Files | ||||
</button> | </button> | ||||
<button class="btn btn-default" id="uploader-upload"> | |||||
<button class="btn btn-default" id="uploader-upload" disabled> | |||||
Upload | Upload | ||||
</button> | </button> | ||||
module.exports = function(ctx) { | |||||
ctx.getPostData(function(err, data, files) { | |||||
if (err) return console.log(err); | |||||
ctx.succeed(); | |||||
}); | |||||
} |
.replace(/>/g, "<") | .replace(/>/g, "<") | ||||
.replace(/"/g, """); | .replace(/"/g, """); | ||||
} | } | ||||
util.api = function(name, data, cb, getXhr) { | |||||
var fd = new FormData(); | |||||
for (var i in data) { | |||||
console.log(i); | |||||
fd.append(i, data[i]); | |||||
} | |||||
return $.ajax({ | |||||
method: "POST", | |||||
url: "/api/"+name, | |||||
data: fd, | |||||
processData: false, | |||||
contentType: false, | |||||
xhr: function() { | |||||
var xhr = new XMLHttpRequest(); | |||||
if (getXhr) | |||||
getXhr(xhr); | |||||
return xhr; | |||||
} | |||||
}).done(function(res) { | |||||
var obj = JSON.parse(res); | |||||
if (obj.success) | |||||
cb(null, obj); | |||||
else | |||||
cb(obj.error); | |||||
}); | |||||
} | |||||
})(); | })(); |
files.forEach(function(f, i) { | files.forEach(function(f, i) { | ||||
output.push( | output.push( | ||||
'<li class="file list-group-item" data-index='+i+'>'+ | '<li class="file list-group-item" data-index='+i+'>'+ | ||||
'<span class="name">'+util.htmlEntities(f.name)+'</span>'+ | |||||
'<div class="progress-bar"></div>'+ | |||||
'<button class="btn btn-default delete" onclick="uploaderDelete(this.parentNode)">X</button>'+ | '<button class="btn btn-default delete" onclick="uploaderDelete(this.parentNode)">X</button>'+ | ||||
'<img class="thumbnail" src="'+f.thumbnail+'">'+ | |||||
'<span class="name">'+util.htmlEntities(f.name)+'</span>'+ | |||||
'</li>' | '</li>' | ||||
); | ); | ||||
}); | }); | ||||
var files = []; | var files = []; | ||||
$("#uploader-input").on("change", function(evt) { | $("#uploader-input").on("change", function(evt) { | ||||
//Enable upload button | |||||
$("#uploader-upload").removeAttr("disabled") | |||||
console.log("making uploader button not disabled"); | |||||
var inputFiles = evt.target.files; | var inputFiles = evt.target.files; | ||||
for (var i = 0; i < inputFiles.length; ++i) { | |||||
for (var i = 0; i < inputFiles.length; ++i) (function() { | |||||
var f = inputFiles[i]; | |||||
f.thumbnail = ""; | |||||
var reader = new FileReader(); | |||||
reader.readAsDataURL(f); | |||||
reader.onload = function(evt) { | |||||
f.thumbnail = reader.result; | |||||
draw(files); | |||||
} | |||||
files.push(inputFiles[i]); | files.push(inputFiles[i]); | ||||
} | |||||
})(); | |||||
draw(files); | draw(files); | ||||
}); | }); | ||||
draw(files); | draw(files); | ||||
} | } | ||||
//Upload things when the upload button is clicked | |||||
$("#uploader-upload").on("click", function(evt) { | $("#uploader-upload").on("click", function(evt) { | ||||
console.log(output); | |||||
//First, disable all buttons | |||||
$("#uploader button.btn").prop("disabled", true); | |||||
console.log("making buttons disabled"); | |||||
var elems = []; | |||||
$("#uploader-list .file").each(function() { | |||||
var elem = $(this); | |||||
elems[elem.data("index")] = elem; | |||||
}); | |||||
files.forEach(function(f, i) { | |||||
var progressBar = elems[i].children(".progress-bar"); | |||||
function getXhr(xhr) { | |||||
xhr.upload.addEventListener("progress", function(evt) { | |||||
if (!evt.lengthComputable) | |||||
return; | |||||
var percent = (evt.loaded / evt.total) * 100; | |||||
progressBar.css({width: percent+"%"}); | |||||
}, false); | |||||
} | |||||
var ajax = util.api("upload", { | |||||
name: f.name, | |||||
data: f | |||||
}, function(err, res) { | |||||
console.log(res); | |||||
}, getXhr); | |||||
}); | |||||
}); | }); | ||||
})(); | })(); |
#uploader-list .file { | |||||
text-align: right !important; | |||||
#uploader-list .file .delete { | |||||
float: right; | |||||
margin-right: -5px; | |||||
} | |||||
#uploader-list .file .thumbnail { | |||||
display: inline; | |||||
margin: 0px; | |||||
margin-right: 10px; | |||||
height: 100px; | |||||
image-orientation: from-image; | |||||
} | } | ||||
#uploader-list .file .name { | #uploader-list .file .name { | ||||
float: left; | |||||
margin-top: 6px; | |||||
display: inline-block; | |||||
} | |||||
#uploader-list .file .progress-bar { | |||||
height: 0px; | |||||
position: absolute; | |||||
background: none; | |||||
border-top: 3px solid green; | |||||
margin-top: -3px; | |||||
max-width: calc(100% - 25px); | |||||
} | } | ||||
#uploader-upload { | #uploader-upload { | ||||
float: right; | float: right; | ||||
} | } |