diff options
| author | Jules Laplace <jules@okfoc.us> | 2014-06-11 13:31:33 -0400 |
|---|---|---|
| committer | Jules Laplace <jules@okfoc.us> | 2014-06-11 13:31:33 -0400 |
| commit | 50ba987880d90f40a5bf4d7e9e125b453723882b (patch) | |
| tree | 1f3aa2730e381cb8f7fd872d5ee84fe602b23ca7 | |
| parent | 7e72bf7d028c2d95555b1132251103eac4dacec9 (diff) | |
store layouts and retrieve them
| -rw-r--r-- | public/assets/javascripts/rectangles/engine/map/_map.js | 5 | ||||
| -rw-r--r-- | public/assets/javascripts/rectangles/engine/map/draw.js | 6 | ||||
| -rw-r--r-- | public/assets/javascripts/rectangles/engine/rooms/_rooms.js | 9 | ||||
| -rw-r--r-- | public/assets/javascripts/ui/builder/BuilderSettings.js | 44 | ||||
| -rw-r--r-- | public/assets/javascripts/ui/builder/BuilderView.js | 7 | ||||
| -rw-r--r-- | public/assets/javascripts/ui/site/LayoutsModal.js | 25 | ||||
| -rw-r--r-- | public/assets/javascripts/vendor/dataUriToBlob.js | 47 | ||||
| -rwxr-xr-x | public/assets/stylesheets/app.css | 2 | ||||
| -rw-r--r-- | server/index.js | 2 | ||||
| -rw-r--r-- | server/lib/api.js | 82 | ||||
| -rw-r--r-- | server/lib/upload.js | 2 | ||||
| -rw-r--r-- | server/lib/util.js | 2 | ||||
| -rw-r--r-- | views/controls/builder/settings.ejs | 9 | ||||
| -rw-r--r-- | views/partials/scripts.ejs | 1 |
14 files changed, 178 insertions, 65 deletions
diff --git a/public/assets/javascripts/rectangles/engine/map/_map.js b/public/assets/javascripts/rectangles/engine/map/_map.js index 3046d1d..5e00eab 100644 --- a/public/assets/javascripts/rectangles/engine/map/_map.js +++ b/public/assets/javascripts/rectangles/engine/map/_map.js @@ -1,7 +1,7 @@ /* */ -window.ctx = window.w = window.h = null; +window.w = window.h = null; var Map = function(){ var base = this @@ -26,8 +26,7 @@ var Map = function(){ base.zoom = pow(2, base.zoom_exponent) } - var canvas = document.createElement("canvas") - var ctx = window.ctx = canvas.getContext("2d") + var canvas = base.canvas = document.createElement("canvas") var w = window.w = canvas.width = base.dimensions.a var h = window.h = canvas.height = base.dimensions.b document.querySelector("#map").appendChild(canvas) diff --git a/public/assets/javascripts/rectangles/engine/map/draw.js b/public/assets/javascripts/rectangles/engine/map/draw.js index 75e8ad1..7f55e51 100644 --- a/public/assets/javascripts/rectangles/engine/map/draw.js +++ b/public/assets/javascripts/rectangles/engine/map/draw.js @@ -2,10 +2,12 @@ var MapDraw = function(map){ var draw = this + + var ctx = map.canvas.getContext("2d") draw.animate = function(){ ctx.save() - draw.clear_canvas() + draw.clear() draw.ruler() ctx.translate( map.bounds.a * 1/2, map.bounds.b * 1/2) @@ -21,7 +23,7 @@ var MapDraw = function(map){ ctx.restore() } - draw.clear_canvas = function(){ + draw.clear = function(){ ctx.fillStyle = "rgba(255,255,255,0.9)" ctx.clearRect(0,0,w,h) ctx.fillRect(0,0,w,h) diff --git a/public/assets/javascripts/rectangles/engine/rooms/_rooms.js b/public/assets/javascripts/rectangles/engine/rooms/_rooms.js index a51edb9..bcfffcc 100644 --- a/public/assets/javascripts/rectangles/engine/rooms/_rooms.js +++ b/public/assets/javascripts/rectangles/engine/rooms/_rooms.js @@ -22,7 +22,7 @@ var Rooms = new function(){ base.add_with_rect = function(rect){ var room = new Room({ rect: rect, - height: 500 // quantize(randrange(300,800), 50), + height: 500 }) base.add(room) } @@ -38,6 +38,7 @@ var Rooms = new function(){ base.forEach = function(f){ return base.values().forEach(f) } + base.map = function(f){ return base.values().map(f) } @@ -50,12 +51,11 @@ var Rooms = new function(){ var rooms = base.map(function(room){ return room.serialize() }) - var rooms_data = { rooms: rooms } - return rooms_data + return rooms } base.deserialize = function(rooms_data){ - rooms_data.rooms.forEach(function(data){ + rooms_data.forEach(function(data){ var rect = new Rect(data.rect.x[0], data.rect.y[0], data.rect.x[1], data.rect.y[1]) var room = new Room({ id: data.id, @@ -64,6 +64,7 @@ var Rooms = new function(){ }) base.add(room) }) + Rooms.clipper.update() } base.uid = (function(){ diff --git a/public/assets/javascripts/ui/builder/BuilderSettings.js b/public/assets/javascripts/ui/builder/BuilderSettings.js index a7a0555..0eb5dfa 100644 --- a/public/assets/javascripts/ui/builder/BuilderSettings.js +++ b/public/assets/javascripts/ui/builder/BuilderSettings.js @@ -6,6 +6,7 @@ var BuilderSettings = FormView.extend({ updateAction: "/api/layouts/edit", events: { + "keydown [name=name]": 'enterSubmit', "click [data-role='save-layout']": 'save', }, @@ -13,21 +14,36 @@ var BuilderSettings = FormView.extend({ this.parent = opt.parent this.__super__.initialize.call(this) + this.$id = this.$("[name=_id]") + this.$csrf = this.$("[name=_csrf]") this.$name = this.$("[name=name]") - this.$newName = this.$("[name=new_name]") this.$privacy = this.$("[name=privacy]") }, load: function(data){ + this.$id.val(data._id) this.$name.val(data.name) - this.$newName.val(data.name) - this.$privacy.find("[value=" + data.privacy + "]").prop('checked', true); + this.$privacy.find("[value=" + data.privacy + "]").prop('checked', true) + + console.log(data) + data.rooms && Rooms.deserialize(data.rooms) + data.startPosition && scene.camera.move(data.startPosition) + + this.action = data.isNew ? this.createAction : this.updateAction }, toggle: function(){ this.$el.toggleClass("active") }, - + + enterSubmit: function (e) { + e.stopPropagation() + var base = this + if (e.keyCode == 13) { + setTimeout(this.save.bind(this), 100) + } + }, + validate: function(){ var errors = [] var name = this.$name.val() @@ -52,15 +68,23 @@ var BuilderSettings = FormView.extend({ serialize: function(){ var fd = new FormData() - fd.append("name", this.$name.val()) - fd.append("new_name", this.$newName.val()) - fd.append("privacy", this.$privacy.val()) - fd.append("rooms", Rooms.serialize()) - fd.append("startPosition", app.position(scene.camera)) + fd.append( "_csrf", this.$csrf.val() ) + fd.append( "_id", this.$id.val() ) + fd.append( "name", this.$name.val() ) + fd.append( "privacy", this.$privacy.val() ) + fd.append( "rooms", JSON.stringify( Rooms.serialize() ) ) + fd.append( "startPosition", JSON.stringify( app.position(scene.camera) ) ) + fd.append( "thumbnail", dataUriToBlob(map.canvas.toDataURL()) ) return fd }, - success: function(){ + success: function(data){ + console.log(data) + this.$id.val(data._id) + this.$name.val(data.name) + this.action = this.updateAction + + window.history.pushState(null, document.title, "/builder/" + data.slug) }, }) diff --git a/public/assets/javascripts/ui/builder/BuilderView.js b/public/assets/javascripts/ui/builder/BuilderView.js index 9c0f236..33aface 100644 --- a/public/assets/javascripts/ui/builder/BuilderView.js +++ b/public/assets/javascripts/ui/builder/BuilderView.js @@ -14,11 +14,12 @@ var BuilderView = View.extend({ load: function(name){ if (! name || name == "new") { - this.isNew = true - this.ready({}) + this.ready({ isNew: true, _id: "new", name: "" }) return } - + + name = sanitize(name) + $.get(this.action + name, $.proxy(this.ready, this)) }, diff --git a/public/assets/javascripts/ui/site/LayoutsModal.js b/public/assets/javascripts/ui/site/LayoutsModal.js index 2766a44..0a03878 100644 --- a/public/assets/javascripts/ui/site/LayoutsModal.js +++ b/public/assets/javascripts/ui/site/LayoutsModal.js @@ -1,21 +1,28 @@ var LayoutsIndex = View.extend({ - load: function(type){ - this.show() + initialize: function(){ + this.$templates = this.$(".templates") + }, + load: function(type){ + this.$templates.children("span").remove() + $.get("/api/layouts", $.proxy(function(data){ - console.log(data) + data.forEach($.proxy(function(room){ var $span = $("<span>") - $span.html(JSON.stringify(room)) - this.$(".templates").append($span) + // $span.html(JSON.stringify(room)) + $span.data("slug", room.slug) + $span.css("background-image", "url(" + room.photo + ")") + + this.$templates.append($span) }, this)) + this.show() }, this)) } - }) @@ -30,10 +37,11 @@ var LayoutsModal = ModalView.extend(LayoutsIndex.prototype).extend({ toggleActive: function(e){ e.preventDefault() this.$(".templates .active").removeClass("active") - $(e.currentTarget).addClass("active") + var $layout = $(e.currentTarget) + $layout.addClass("active") // actually do - // window.location.pathname = "/builder/" + $(this).data("name") + window.location.pathname = "/builder/" + $layout.data("slug") }, newBuilder: function(e){ @@ -44,7 +52,6 @@ var LayoutsModal = ModalView.extend(LayoutsIndex.prototype).extend({ }) - var NewProjectModal = ModalView.extend(LayoutsIndex.prototype).extend({ el: ".mediaDrawer.newProject", diff --git a/public/assets/javascripts/vendor/dataUriToBlob.js b/public/assets/javascripts/vendor/dataUriToBlob.js new file mode 100644 index 0000000..582aecb --- /dev/null +++ b/public/assets/javascripts/vendor/dataUriToBlob.js @@ -0,0 +1,47 @@ +window.dataUriToBlob = (function(){ +/** + * Blob constructor. + */ + +var Blob = window.Blob; + +/** + * ArrayBufferView support. + */ + +var hasArrayBufferView = new Blob([new Uint8Array(100)]).size == 100; + +/** + * Return a `Blob` for the given data `uri`. + * + * @param {String} uri + * @return {Blob} + * @api public + */ + +var dataUriToBlob = function(uri){ + var data = uri.split(',')[1]; + var bytes = atob(data); + var buf = new ArrayBuffer(bytes.length); + var arr = new Uint8Array(buf); + for (var i = 0; i < bytes.length; i++) { + arr[i] = bytes.charCodeAt(i); + } + + if (!hasArrayBufferView) arr = buf; + var blob = new Blob([arr], { type: mime(uri) }); + blob.slice = blob.slice || blob.webkitSlice; + return blob; +}; + +/** + * Return data uri mime type. + */ + +function mime(uri) { + return uri.split(';')[0].slice(5); +} + +return dataUriToBlob; + +})() diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 582f627..0135573 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1358,7 +1358,7 @@ form h3 { .errorList { font-weight: 300; } -.errors div, form .errors div { +.errors div, form .errors div, form .errorList div { float: none; } form li div div { diff --git a/server/index.js b/server/index.js index 6c33f3a..1455068 100644 --- a/server/index.js +++ b/server/index.js @@ -112,7 +112,7 @@ site.route = function () { app.get('/builder/:name', middleware.ensureAuthenticated, views.builder) app.get('/api/layouts', middleware.ensureAuthenticated, api.layout.index) - app.get('/api/layouts/:name', middleware.ensureAuthenticated, api.layout.show) + app.get('/api/layouts/:slug', middleware.ensureAuthenticated, api.layout.show) app.post('/api/layouts/new', middleware.ensureAuthenticated, api.layout.create) app.post('/api/layouts/edit', middleware.ensureAuthenticated, api.layout.update) app.delete('/api/layouts/destroy', middleware.ensureAuthenticated, api.layout.destroy) diff --git a/server/lib/api.js b/server/lib/api.js index 9d14651..f7be925 100644 --- a/server/lib/api.js +++ b/server/lib/api.js @@ -41,11 +41,7 @@ var api = { if (req.files.avatar) { upload.put("avatars", req.files.avatar, { - acceptable: function(){ - console.log("acceptable") - }, unacceptable: function(err){ - console.log("unacceptable") res.json({ error: { errors: { avatar: { message: "Problem saving avatar: " + err } } } }) }, success: function(url){ @@ -133,56 +129,90 @@ var api = { }, show: function(req, res){ - Layout.findOne({ name: req.query.name }, function(err, doc){ + Layout.findOne({ slug: req.params.slug }, function(err, doc){ if (doc) { res.json(doc) + return } else { - var name = util.sanitize(req.query.name) + var name = util.sanitize(req.params.slug) if (name == "new") { name = "" } - res.json({ name: name, isNew: true }) + res.json({ _id: "new", name: name, isNew: true }) } }) }, create: function(req, res){ var data = util.cleanQuery(req.body) - data.name = util.sanitize(data.new_name) - data.displayName = util.sanitize(data.displayName) + data.name = util.sanitize(data.name) + data.slug = util.slugify(data.name) data.user_id = req.user._id - delete data.new_name - new Layout(data).save(function(err, doc){ - if (err || ! doc) { return res.json({ error: err }) } - res.json(doc) + data.rooms = JSON.parse(data.rooms) + data.startPosition = JSON.parse(data.startPosition) + + upload.put("layouts", req.files.thumbnail, { + unacceptable: function(err){ + res.json({ error: { errors: { thumbnail: { message: "Problem saving thumbnail: " + err } } } }) + }, + success: function(url){ + data.photo = url + done() + } }) + + function done() { + new Layout(data).save(function(err, doc){ + if (err || ! doc) { return res.json({ error: err }) } + res.json(doc) + }) + } }, update: function(req, res){ - var data = util.cleanQuery(req.body) - if (data.name == "new") { + var _id = req.body._id + if (_id == "new") { return api.docs.create(req, res) } - Layout.findOne({ name: data.name }, function(err, doc){ - if (err || ! doc) { return res.json({ error: err }) } - data.name = data.new_name - delete data.new_name - _.extend(doc, data) - doc.save(function(err, doc){ + + var data = util.cleanQuery(req.body) + data.name = util.sanitize(data.name) + data.slug = util.slugify(data.name) + data.user_id = req.user._id + + upload.put("layouts", req.files.thumbnail, { + unacceptable: function(err){ + res.json({ error: { errors: { thumbnail: { message: "Problem saving thumbnail: " + err } } } }) + }, + success: function(url){ + data.photo = url + done() + } + }) + + function done() { + Layout.findOne({ _id: _id }, function(err, doc){ if (err || ! doc) { return res.json({ error: err }) } - res.json(doc) + _.extend(doc, data) + doc.rooms = JSON.parse(data.rooms) + doc.startPosition = JSON.parse(data.startPosition) + + doc.save(function(err, doc){ + if (err || ! doc) { return res.json({ error: err }) } + res.json(doc) + }) }) - }) + } }, destroy: function(req, res){ - var name = util.sanitize(req.body.name) - if (! name || ! name.length) { + var _id = req.body._id + if (! id || ! id.length) { res.json({ error: 404 }) return } - Layout.remove({ name: name }, function(err){ + Layout.remove({ _id: _id }, function(err){ res.json({ status: "OK" }) }) }, diff --git a/server/lib/upload.js b/server/lib/upload.js index 4346a99..a5d7871 100644 --- a/server/lib/upload.js +++ b/server/lib/upload.js @@ -20,7 +20,7 @@ module.exports.put = function (key, file, opt) { var fileSize, fileType, filename var err var now = new Date() - + var ts = moment().format('YYYYMMDD') var extension = acceptableuploadTypes[file.mimetype] diff --git a/server/lib/util.js b/server/lib/util.js index c8771dc..2ff4e16 100644 --- a/server/lib/util.js +++ b/server/lib/util.js @@ -13,7 +13,7 @@ var util = {} util.trim = function (s){ return (s || "").replace(whitespaceHead,"").replace(whitespaceTail,"") } util.slugify = function (s){ - return (s || "").replace(whitespace,"-").replace(nonAlphanumerics, '-').replace(consecutiveDashes,"-") + return (s || "").toLowerCase().replace(whitespace,"-").replace(nonAlphanumerics, '-').replace(consecutiveDashes,"-") } util.sanitize = function (s){ diff --git a/views/controls/builder/settings.ejs b/views/controls/builder/settings.ejs index 76bb0d1..1061b67 100644 --- a/views/controls/builder/settings.ejs +++ b/views/controls/builder/settings.ejs @@ -1,5 +1,6 @@ <div class="vvbox settings active" id="builderSettings"> - <input type="hidden" name="name"> + <input type="hidden" name="_csrf" value="[[- token ]]"> + <input type="hidden" name="_id" value="new"> <div class="setting"> <a href="#" id="startpoint"> @@ -9,7 +10,7 @@ </div> <div class="setting"> - <input type="text" name="new_name" placeholder="layout name"> + <input type="text" name="name" placeholder="layout name"> </div> <div class="setting"> @@ -30,8 +31,8 @@ </div> <div class="setting subButtons"> - <a href="#">Clear</a> - <a href="#" id="deleteRoom">Delete</a> + <a href="#" data-role="clear-layout">Clear</a> + <a href="#" data-role="delete-layout">Delete</a> </div> </div> diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index b977dc6..bf04547 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -5,6 +5,7 @@ <script type="text/javascript" src="/assets/javascripts/vendor/loader.js"></script> <script type="text/javascript" src="/assets/javascripts/vendor/polyfill.js"></script> <script type="text/javascript" src="/assets/javascripts/vendor/sha1.js"></script> +<script type="text/javascript" src="/assets/javascripts/vendor/dataUriToBlob.js"></script> <script type="text/javascript" src="/assets/javascripts/util.js"></script> <script type="text/javascript" src="/assets/javascripts/rectangles/_env.js"></script> |
