summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulie Lala <jules@okfoc.us>2014-08-15 09:26:10 -0400
committerJulie Lala <jules@okfoc.us>2014-08-15 09:26:10 -0400
commitaecaf2de2b4ed5277b34e9209a0f31602e8a7999 (patch)
tree78e46648032b91ebb0267e38f39f6227da7d8732
parent02bde51c24ae1c6e189d031b80226e6a9f7cbc59 (diff)
parent1be685f9fe4a7f3a3e947d45f865fe07c03ddbaf (diff)
Merge branch 'walls' of github.com:okfocus/vvalls into walls
-rw-r--r--public/assets/img/destroy-cursor.pngbin0 -> 1082 bytes
-rw-r--r--public/assets/javascripts/mx/extensions/mx.movements.js4
-rw-r--r--public/assets/javascripts/mx/primitives/mx.image.js1
-rw-r--r--public/assets/javascripts/mx/primitives/mx.video.js3
-rw-r--r--public/assets/javascripts/mx/primitives/mx.vimeo.js24
-rw-r--r--public/assets/javascripts/mx/primitives/mx.youtube.js3
-rw-r--r--public/assets/javascripts/rectangles/_env.js14
-rw-r--r--public/assets/javascripts/rectangles/engine/map/draw.js4
-rw-r--r--public/assets/javascripts/rectangles/engine/map/ui_editor.js106
-rw-r--r--public/assets/javascripts/rectangles/engine/rooms/grouper.js73
-rw-r--r--public/assets/javascripts/rectangles/engine/scenery/_scenery.js11
-rw-r--r--public/assets/javascripts/rectangles/engine/scenery/move.js24
-rw-r--r--public/assets/javascripts/rectangles/engine/scenery/resize.js16
-rw-r--r--public/assets/javascripts/rectangles/engine/scenery/types/_object.js9
-rw-r--r--public/assets/javascripts/rectangles/engine/scenery/types/image.js8
-rw-r--r--public/assets/javascripts/rectangles/engine/scenery/types/video.js11
-rw-r--r--public/assets/javascripts/rectangles/engine/scenery/undo.js118
-rw-r--r--public/assets/javascripts/rectangles/models/rect.js4
-rw-r--r--public/assets/javascripts/rectangles/models/room.js8
-rw-r--r--public/assets/javascripts/rectangles/models/vec2.js4
-rw-r--r--public/assets/javascripts/rectangles/models/wall.js30
-rw-r--r--public/assets/javascripts/rectangles/util/constants.js6
-rw-r--r--public/assets/javascripts/rectangles/util/keys.js6
-rw-r--r--public/assets/javascripts/rectangles/util/measurement.js82
-rw-r--r--public/assets/javascripts/rectangles/util/minotaur.js64
-rw-r--r--public/assets/javascripts/rectangles/util/permissions.js17
-rw-r--r--public/assets/javascripts/rectangles/util/undostack.js (renamed from public/assets/javascripts/rectangles/util/undo.js)18
-rw-r--r--public/assets/javascripts/ui/_router.js1
-rw-r--r--public/assets/javascripts/ui/builder/BuilderInfo.js83
-rw-r--r--public/assets/javascripts/ui/builder/BuilderSettings.js3
-rw-r--r--public/assets/javascripts/ui/builder/BuilderToolbar.js21
-rw-r--r--public/assets/javascripts/ui/editor/EditorSettings.js29
-rw-r--r--public/assets/javascripts/ui/editor/MediaEditor.js43
-rw-r--r--public/assets/javascripts/ui/lib/FormView.js28
-rw-r--r--public/assets/javascripts/ui/lib/ModalView.js7
-rw-r--r--public/assets/javascripts/ui/lib/Parser.js4
-rw-r--r--public/assets/javascripts/ui/lib/View.js17
-rwxr-xr-xpublic/assets/stylesheets/app.css85
-rw-r--r--server/lib/api/projects.js23
-rw-r--r--server/lib/middleware.js2
-rw-r--r--server/lib/views.js2
-rw-r--r--test/06-test-grouper.js15
-rw-r--r--test/07-test-surface.js34
-rw-r--r--test/09-test-undo.js27
-rw-r--r--views/controls/builder/toolbar.ejs2
-rw-r--r--views/controls/editor/media-editor.ejs20
-rw-r--r--views/partials/header.ejs4
-rw-r--r--views/partials/scripts.ejs4
-rw-r--r--views/projects/list-projects.ejs9
-rw-r--r--views/reader.ejs2
50 files changed, 863 insertions, 270 deletions
diff --git a/public/assets/img/destroy-cursor.png b/public/assets/img/destroy-cursor.png
new file mode 100644
index 0000000..eebe3cd
--- /dev/null
+++ b/public/assets/img/destroy-cursor.png
Binary files differ
diff --git a/public/assets/javascripts/mx/extensions/mx.movements.js b/public/assets/javascripts/mx/extensions/mx.movements.js
index 191088f..3b7d3e2 100644
--- a/public/assets/javascripts/mx/extensions/mx.movements.js
+++ b/public/assets/javascripts/mx/extensions/mx.movements.js
@@ -149,7 +149,8 @@ MX.Movements = function (cam) {
case 32: // space
moveUp = moveDown = false
break
-
+
+/*
case 48: // 0
cam.rotationX = 0
cam.rotationY = 0
@@ -157,6 +158,7 @@ MX.Movements = function (cam) {
cam.y = viewHeight
cam.z = 0
break
+*/
}
})
diff --git a/public/assets/javascripts/mx/primitives/mx.image.js b/public/assets/javascripts/mx/primitives/mx.image.js
index 278fa1e..a640620 100644
--- a/public/assets/javascripts/mx/primitives/mx.image.js
+++ b/public/assets/javascripts/mx/primitives/mx.image.js
@@ -14,6 +14,7 @@ MX.Image = MX.Object3D.extend({
ops.className && this.el.classList.add(ops.className)
this.backface && this.el.classList.add("backface-visible")
this.el.classList.add("image")
+ this.el.classList.add("mx-scenery")
this.el.style.backgroundRepeat = 'no-repeat'
diff --git a/public/assets/javascripts/mx/primitives/mx.video.js b/public/assets/javascripts/mx/primitives/mx.video.js
index cdb92c8..12d3dcb 100644
--- a/public/assets/javascripts/mx/primitives/mx.video.js
+++ b/public/assets/javascripts/mx/primitives/mx.video.js
@@ -19,10 +19,9 @@ MX.Video = MX.Object3D.extend({
ops.className && this.el.classList.add(ops.className)
this.backface && this.el.classList.add("backface-visible")
this.el.classList.add("video")
+ this.el.classList.add("mx-scenery")
this.paused = !! this.media.autoplay
this.muted = app.muted || !! this.media.mute
-
- this.load()
},
load: function(ops){
diff --git a/public/assets/javascripts/mx/primitives/mx.vimeo.js b/public/assets/javascripts/mx/primitives/mx.vimeo.js
index 64d9103..4922519 100644
--- a/public/assets/javascripts/mx/primitives/mx.vimeo.js
+++ b/public/assets/javascripts/mx/primitives/mx.vimeo.js
@@ -19,11 +19,10 @@ MX.Vimeo = MX.Object3D.extend({
ops.className && this.el.classList.add(ops.className)
this.backface && this.el.classList.add("backface-visible")
this.el.classList.add("video")
+ this.el.classList.add("mx-scenery")
this.paused = !! this.media.autoplay
this.muted = app.muted || !! this.media.mute
this.started = false
-
- this.load()
},
load: function (ops) {
@@ -41,23 +40,24 @@ MX.Vimeo = MX.Object3D.extend({
this.el.appendChild(preload)
this.player = $f(preload)
- this.player.addEvent('ready', this.ready.bind(this))
+ this.player.addEvent('ready', $.proxy(this.ready, this))
},
ready: function(){
console.log("vimeo ready")
+
this.started = true
// wait until ready before binding events. other events: play, pause
- this.player.addEvent('play', this.onPlay.bind(this))
- this.player.addEvent('pause', this.onPause.bind(this))
- this.player.addEvent('finish', this.finished.bind(this))
+ this.player.addEvent('play', $.proxy(this.onPlay, this))
+ this.player.addEvent('pause', $.proxy(this.onPause, this))
+ this.player.addEvent('finish', $.proxy(this.finished, this))
// this is async on vimeo so call it asap
- this.player.api('getDuration', function(n){
+ this.player.api('getDuration', $.proxy(function(n){
console.log("vimeo duration", n)
this.player.duration = n
- }.bind(this))
+ }, this))
if (this.media.mute) {
this.mute()
@@ -90,9 +90,9 @@ MX.Vimeo = MX.Object3D.extend({
seek: function(n){
// defer seek until we have duration
if (! this.duration()) {
- setTimeout(function(){
+ setTimeout($.proxy(function(){
this.seek(n)
- }.bind(this), 300)
+ }, this), 300)
return
}
@@ -108,9 +108,9 @@ MX.Vimeo = MX.Object3D.extend({
this.paused = false
this.play()
this.pause()
- setTimeout(function(){
+ setTimeout($.proxy(function(){
this.pause()
- }.bind(this), 100)
+ }, this), 100)
}
},
diff --git a/public/assets/javascripts/mx/primitives/mx.youtube.js b/public/assets/javascripts/mx/primitives/mx.youtube.js
index f7f00aa..873348f 100644
--- a/public/assets/javascripts/mx/primitives/mx.youtube.js
+++ b/public/assets/javascripts/mx/primitives/mx.youtube.js
@@ -19,10 +19,9 @@ MX.Youtube = MX.Object3D.extend({
ops.className && this.el.classList.add(ops.className)
this.backface && this.el.classList.add("backface-visible")
this.el.classList.add("video")
+ this.el.classList.add("mx-scenery")
this.paused = !! this.media.autoplay
this.muted = app.muted || !! this.media.mute
-
- this.load()
},
load: function (ops) {
diff --git a/public/assets/javascripts/rectangles/_env.js b/public/assets/javascripts/rectangles/_env.js
index 3cfe969..4b14a21 100644
--- a/public/assets/javascripts/rectangles/_env.js
+++ b/public/assets/javascripts/rectangles/_env.js
@@ -35,6 +35,20 @@ environment.init = function(){
zoom: -4.8
})
}
+
+ keys.on("z", function(e){
+ e.preventDefault()
+ if (e.ctrlKey || e.metaKey) {
+ if (e.shiftKey) {
+ var canRedo = UndoStack.redo()
+ console.log("can redo", canRedo)
+ }
+ else {
+ var canUndo = UndoStack.undo()
+ console.log("can undo", canUndo)
+ }
+ }
+ })
}
environment.update = function(t){
map.update()
diff --git a/public/assets/javascripts/rectangles/engine/map/draw.js b/public/assets/javascripts/rectangles/engine/map/draw.js
index 8e1fe5a..3e185d2 100644
--- a/public/assets/javascripts/rectangles/engine/map/draw.js
+++ b/public/assets/javascripts/rectangles/engine/map/draw.js
@@ -29,7 +29,7 @@ Map.Draw = function(map, opt){
ctx.translate( map.center.a, map.center.b )
ctx.scale( -1, 1 )
- draw.regions(Rooms.regions, colors)
+ draw.regions(Rooms.regions, [ "#f8f8f8" ])
draw.mouse(map.ui.mouse.cursor)
draw.coords()
scene && draw.camera(scene.camera)
@@ -55,7 +55,7 @@ Map.Draw = function(map, opt){
}
draw.clear = function(){
- ctx.fillStyle = "rgba(255,255,255,0.9)"
+ ctx.fillStyle = "rgba(255,255,255,0.98)"
ctx.clearRect(0, 0, map.dimensions.a, map.dimensions.b)
ctx.fillRect(0, 0, map.dimensions.a, map.dimensions.b)
}
diff --git a/public/assets/javascripts/rectangles/engine/map/ui_editor.js b/public/assets/javascripts/rectangles/engine/map/ui_editor.js
index 577ea32..9a557b9 100644
--- a/public/assets/javascripts/rectangles/engine/map/ui_editor.js
+++ b/public/assets/javascripts/rectangles/engine/map/ui_editor.js
@@ -30,6 +30,7 @@ Map.UI.Editor = function(map){
//
function down (e, cursor){
+ var room
cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom).add(map.center.a)
cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom).sub(map.center.b)
@@ -52,22 +53,28 @@ Map.UI.Editor = function(map){
if (intersects.length && base.permissions.destroy) {
base.mouse.down = false
- Rooms.remove(intersects[0])
- app.tube("builder-destroy-room", intersects[0])
+
+ room = intersects[0]
+
+ UndoStack.push({
+ type: "destroy-room",
+ undo: room.copy(),
+ redo: { id: room.id },
+ })
+
+ Rooms.remove(room)
+ app.tube("builder-destroy-room", room)
return
}
- else if (intersects.length && (base.permissions.move || base.permissions.resize)) {
+ else if (intersects.length) {
base.dragging = intersects[0]
- base.resizing = base.permissions.resize && base.dragging.rect.nearEdge(cursor.x.a, cursor.y.a, resize_margin / map.zoom)
+ base.resizing = base.dragging.rect.nearEdge(cursor.x.a, cursor.y.a, resize_margin / map.zoom)
base.dragging.rect.translation.sides = base.resizing
app.tube("builder-pick-room", intersects[0])
}
else if (base.permissions.create) {
base.creating = true
}
- else if (intersects.length) {
- app.tube("builder-pick-room", intersects[0])
- }
if (e.shiftKey && base.dragging) {
base.dragging.rect.quantize(10/map.zoom)
@@ -77,6 +84,45 @@ Map.UI.Editor = function(map){
function move (e, cursor) {
cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom).add(map.center.a)
cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom).sub(map.center.b)
+
+ var intersects = Rooms.filter(function(r){
+ return r.rect.contains(cursor.x.a, cursor.y.a)
+ })
+
+ if (base.permissions.destroy) {
+ map.el.className = "destroy"
+ }
+ else if (intersects.length) {
+ var edges = intersects[0].rect.nearEdge(cursor.x.a, cursor.y.a, resize_margin / map.zoom)
+ switch (edges) {
+ case FRONT_LEFT:
+ case BACK_RIGHT:
+ map.el.className = "nesw-resize"
+ break
+
+ case FRONT_RIGHT:
+ case BACK_LEFT:
+ map.el.className = "nwse-resize"
+ break
+
+ case FRONT:
+ case BACK:
+ map.el.className = "ns-resize"
+ break
+
+ case LEFT:
+ case RIGHT:
+ map.el.className = "ew-resize"
+ break
+
+ default:
+ map.el.className = "move"
+ break
+ }
+ }
+ else {
+ map.el.className = ""
+ }
}
function drag (e, cursor) {
@@ -115,20 +161,40 @@ Map.UI.Editor = function(map){
cursor.x.abs().quantize(1)
cursor.y.abs().quantize(1)
var room = Rooms.add_with_rect( cursor )
+
+ UndoStack.push({
+ type: "create-room",
+ undo: { id: room.id },
+ redo: room.copy()
+ })
+
app.tube("builder-pick-room", room)
}
}
- if (base.resizing) {
- base.dragging.rect.resize()
- }
- else if (base.dragging) {
- base.dragging.rect.translate()
- }
+ if (base.resizing || base.dragging) {
+ var oldState = base.dragging.copy()
+
+ if (base.resizing) {
+ base.dragging.rect.resize()
+ }
+ else if (base.dragging) {
+ base.dragging.rect.translate()
+ }
+
+ UndoStack.push({
+ type: "update-room",
+ undo: oldState,
+ redo: base.dragging.copy()
+ })
+ }
+
base.creating = base.dragging = base.resizing = false
}
+ var wheelState, wheelTimeout
+
function mousewheel (e, val, delta){
var cursor = base.mouse.cursor
@@ -137,8 +203,20 @@ Map.UI.Editor = function(map){
})
if (intersects.length) {
+ wheelState = wheelState || intersects[0].copy()
+
intersects[0].height = clamp( ~~(intersects[0].height - delta), height_min, height_max )
- Rooms.clipper.update()
+
+ clearTimeout(wheelTimeout)
+ wheelTimeout = setTimeout(function(){
+ UndoStack.push({
+ type: "update-room",
+ undo: wheelState,
+ redo: intersects[0].copy()
+ })
+ Rooms.clipper.update()
+ wheelState = null
+ }, 500)
}
else {
map.set_zoom(map.zoom_exponent - delta/20)
diff --git a/public/assets/javascripts/rectangles/engine/rooms/grouper.js b/public/assets/javascripts/rectangles/engine/rooms/grouper.js
index 4ad3bd8..cde9fbb 100644
--- a/public/assets/javascripts/rectangles/engine/rooms/grouper.js
+++ b/public/assets/javascripts/rectangles/engine/rooms/grouper.js
@@ -1,6 +1,6 @@
(function(){
- var vec2, Rect, Rooms, UidGenerator, Wall, Surface, sort
+ var vec2, Rect, Rooms, UidGenerator, Wall, Surface, sort, _
if ('window' in this) {
vec2 = window.vec2
Rect = window.Rect
@@ -9,6 +9,7 @@
UidGenerator = window.UidGenerator
Wall = window.Wall
sort = window.sort
+ _ = window._
}
else {
Rooms = require('./_rooms')
@@ -18,6 +19,7 @@
Wall = require('../../models/wall')
Surface = require('../../models/surface')
sort = require('../../util/sort')
+ _ = require('lodash')
FRONT = 0x1, BACK = 0x2, LEFT = 0x4, RIGHT = 0x8, FLOOR = 0x10, CEILING = 0x20
PI = Math.PI
HALF_PI = PI/2
@@ -82,6 +84,7 @@
collection.sort( useX ? sort.compare_zx : sort.compare_xz )
collection.forEach(function(mx){
if (last_mx && last_mx.rect.eq(mx.rect)) {
+ // culls half-walls
if (last_mx.rect.id == mx.rect.id) {
last_mx.height += mx.height/2
last_mx.y += mx.height/4
@@ -103,41 +106,53 @@
}
base.group = function(walls, collections, side){
var collection = collections[side]
- var wall
var useX = side & FRONT_BACK
- var useA = side & (FRONT | RIGHT)
+ var useA = side & (FRONT | LEFT)
// collection.sort( useX ? sort.compare_zx : sort.compare_xz )
+ var planes = {}
+
collection.forEach(function(mx){
if (mx.culled) return
- var coplanar = wall && wall.edge == mx.rect[useX ? 'y': 'x'][useA ? 'a': 'b']
-
- if (wall && coplanar) {
- if (useX && wall.vec.b == mx.rect.x.a) {
- wall.vec.b = mx.rect.x.b
- wall.mx.push(mx)
- wall.surface.add(mx.face)
- return
- }
- else if (! useX && wall.vec.b == mx.rect.y.a) {
- wall.vec.b = mx.rect.y.b
- wall.mx.push(mx)
- wall.surface.add(mx.face)
- return
- }
- }
- wall = new Wall ({
- id: base.uid(),
- side: side,
- mx: [ mx ],
- surface: new Surface( mx.face ),
- vec: mx.rect[ useX ? 'x' : 'y' ].clone(),
- edge: mx.rect[ useX ? 'y' : 'x' ][ useA ? 'a' : 'b' ],
- })
- walls.push(wall)
+ var edge = mx.rect[useX ? 'y': 'x'][ useA ? 'a': 'b']
+ planes[edge] = planes[edge] || []
+ planes[edge].push(mx)
})
-
+
+ var edges = _.keys(planes)
+ edges.forEach(function(edge){
+
+ var wall
+
+ planes[edge].forEach(function(mx){
+
+ if (wall) {
+ if (useX && wall.vec.b == mx.rect.x.a) {
+ wall.vec.b = mx.rect.x.b
+ wall.mx.push(mx)
+ wall.surface.add(mx.face)
+ return
+ }
+ else if (! useX && wall.vec.b == mx.rect.y.a) {
+ wall.vec.b = mx.rect.y.b
+ wall.mx.push(mx)
+ wall.surface.add(mx.face)
+ return
+ }
+ }
+ wall = new Wall ({
+ id: base.uid(),
+ side: side,
+ mx: [ mx ],
+ surface: new Surface( mx.face ),
+ vec: mx.rect[ useX ? 'x' : 'y' ].clone(),
+ edge: mx.rect[ useX ? 'y' : 'x' ][ useA ? 'a' : 'b' ],
+ })
+ walls.push(wall)
+ })
+ })
+
return walls
}
diff --git a/public/assets/javascripts/rectangles/engine/scenery/_scenery.js b/public/assets/javascripts/rectangles/engine/scenery/_scenery.js
index 137c74a..b4a38f8 100644
--- a/public/assets/javascripts/rectangles/engine/scenery/_scenery.js
+++ b/public/assets/javascripts/rectangles/engine/scenery/_scenery.js
@@ -14,7 +14,7 @@ var Scenery = new function(){
base.add = function(opt){
var scene_media
- switch (media.type) {
+ switch (opt.media.type) {
case 'image':
scene_media = new Scenery.types.image (opt)
break
@@ -36,8 +36,13 @@ var Scenery = new function(){
mx: mx
})
base.nextMedia = null
+ return media
}
-
+
+ base.find = function(id){
+ return base.list[id] || null
+ }
+
base.remove = function(id){
var media = base.list[id]
delete base.list[id]
@@ -69,11 +74,11 @@ var Scenery = new function(){
scenery_data.forEach(function(data){
var wall = Rooms.walls[data.wall_id]
var scene_media = base.add({
+ data: data,
wall: wall,
media: data.media,
id: data.id
})
- scene_media.deserialize(data)
})
}
diff --git a/public/assets/javascripts/rectangles/engine/scenery/move.js b/public/assets/javascripts/rectangles/engine/scenery/move.js
index cc5b014..f2d37d8 100644
--- a/public/assets/javascripts/rectangles/engine/scenery/move.js
+++ b/public/assets/javascripts/rectangles/engine/scenery/move.js
@@ -3,6 +3,7 @@ Scenery.move = function(base){
var x, y, z, bounds
var dragging = false
+ var oldState
this.bind = function(){
Scenery.mouse.bind_el(base.mx.el)
@@ -23,6 +24,15 @@ Scenery.move = function(base){
function down (e, cursor){
if (e.target != base.mx.el) return;
if (editor.permissions.destroy) {
+ UndoStack.push({
+ type: 'destroy-scenery',
+ undo: base.serialize(),
+ redo: { id: base.id },
+ })
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+
Scenery.remove(base.id)
return
}
@@ -39,6 +49,7 @@ Scenery.move = function(base){
y = base.mx.y
z = base.mx.z
bounds = base.bounds
+ oldState = base.serialize()
document.body.classList.add("dragging")
}
@@ -63,8 +74,21 @@ Scenery.move = function(base){
}
function up (e, cursor){
+ if (! dragging || ! oldState) return
+
dragging = false
document.body.classList.remove("dragging")
+
+ UndoStack.push({
+ type: 'update-scenery',
+ undo: oldState,
+ redo: base.serialize(),
+ })
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+
+ oldState = null
}
function switch_wall (e, new_wall, cursor){
diff --git a/public/assets/javascripts/rectangles/engine/scenery/resize.js b/public/assets/javascripts/rectangles/engine/scenery/resize.js
index df058bb..6b2e52c 100644
--- a/public/assets/javascripts/rectangles/engine/scenery/resize.js
+++ b/public/assets/javascripts/rectangles/engine/scenery/resize.js
@@ -7,6 +7,7 @@ Scenery.resize = new function(){
var x, y, z, bounds
var dragging = false
var dimensions, position, scale
+ var oldState
var dots = [], dot, selected_dot
@@ -54,7 +55,7 @@ Scenery.resize = new function(){
}
// move all the dots to the object's current position
- base.move_dots = function(){
+ base.move_dots = function(){
x = obj.mx.x + sin(rotationY) * dot_distance_from_picture
y = obj.mx.y
z = obj.mx.z - cos(rotationY) * dot_distance_from_picture
@@ -88,7 +89,7 @@ Scenery.resize = new function(){
// pick a new object to focus on and show the dots
base.show = function(new_object) {
- if (obj === new_object) return
+ // if (obj === new_object) return
obj = new_object
base.add_dots()
@@ -151,6 +152,7 @@ Scenery.resize = new function(){
dimensions = obj.dimensions
position = new vec3(obj.mx.x, obj.mx.y, obj.mx.z)
scale = obj.mx.scale
+ oldState = obj.serialize()
document.body.classList.add("dragging")
}
@@ -191,6 +193,16 @@ Scenery.resize = new function(){
if (! editor.permissions.resize) { return }
obj.scale = obj.mx.ops.scale = obj.mx.scale
obj.set_wall()
+
+ UndoStack.push({
+ type: 'update-scenery',
+ undo: oldState,
+ redo: obj.serialize(),
+ })
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+
document.body.classList.remove("dragging")
}
diff --git a/public/assets/javascripts/rectangles/engine/scenery/types/_object.js b/public/assets/javascripts/rectangles/engine/scenery/types/_object.js
index aa1fefb..6bd5863 100644
--- a/public/assets/javascripts/rectangles/engine/scenery/types/_object.js
+++ b/public/assets/javascripts/rectangles/engine/scenery/types/_object.js
@@ -62,8 +62,12 @@ Scenery.types.base = Fiber.extend(function(base){
set_wall: function(wall, mx){
this.wall = wall || this.wall
- this.bounds = this.wall.bounds_for(this.media, this.scale)
- this.center = this.wall.center()
+ // this.bounds = this.wall.bounds_for(this.media, this.scale)
+ // this.center = this.wall.center()
+ },
+
+ set_scale: function(scale){
+ this.scale = this.mx.scale = this.mx.ops.scale = scale || 1.0
},
recenter: function(){
@@ -79,7 +83,6 @@ Scenery.types.base = Fiber.extend(function(base){
serialize: function(){
var data = {
id: this.id,
- room_id: this.wall.room_id,
wall_id: this.wall.id,
side: this.wall.side,
dimensions: this.dimensions.serialize(),
diff --git a/public/assets/javascripts/rectangles/engine/scenery/types/image.js b/public/assets/javascripts/rectangles/engine/scenery/types/image.js
index 99c1810..576242e 100644
--- a/public/assets/javascripts/rectangles/engine/scenery/types/image.js
+++ b/public/assets/javascripts/rectangles/engine/scenery/types/image.js
@@ -10,7 +10,13 @@ Scenery.types.image = Scenery.types.base.extend(function(base){
this.build()
this.bind()
this.set_wall()
- this.recenter()
+
+ if (opt.data) {
+ this.deserialize(opt.data)
+ }
+ else {
+ this.recenter()
+ }
},
build: function(){
diff --git a/public/assets/javascripts/rectangles/engine/scenery/types/video.js b/public/assets/javascripts/rectangles/engine/scenery/types/video.js
index 79cfb1c..0bd5c06 100644
--- a/public/assets/javascripts/rectangles/engine/scenery/types/video.js
+++ b/public/assets/javascripts/rectangles/engine/scenery/types/video.js
@@ -10,7 +10,13 @@ Scenery.types.video = Scenery.types.base.extend(function(base){
this.build()
this.bind()
this.set_wall()
- this.recenter()
+
+ if (opt.data) {
+ this.deserialize(opt.data)
+ }
+ else {
+ this.recenter()
+ }
},
build: function(){
@@ -34,7 +40,8 @@ Scenery.types.video = Scenery.types.base.extend(function(base){
y: this.scale * this.media.height/2,
backface: false,
})
- scene.add( this.mx )
+ scene.add(this.mx)
+ this.mx.load()
},
play: function(){
diff --git a/public/assets/javascripts/rectangles/engine/scenery/undo.js b/public/assets/javascripts/rectangles/engine/scenery/undo.js
new file mode 100644
index 0000000..54ab755
--- /dev/null
+++ b/public/assets/javascripts/rectangles/engine/scenery/undo.js
@@ -0,0 +1,118 @@
+(function(){
+ UndoStack.register([
+ {
+ type: "create-scenery",
+ undo: function(state){
+ Scenery.remove(state.id)
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+ },
+ redo: function(state){
+ Scenery.deserialize([ state ])
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+ },
+ },
+ {
+ type: "update-scenery",
+ undo: function(state){
+ var scenery = Scenery.find(state.id)
+ scenery.deserialize(state)
+ scenery.set_wall(Rooms.walls[ state.wall_id ])
+
+ if (editor.permissions.resize) {
+ Scenery.resize.show(scenery)
+ }
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+ },
+ redo: function(state){
+ var scenery = Scenery.find(state.id)
+ scenery.deserialize(state)
+ scenery.set_wall(Rooms.walls[ state.wall_id ])
+
+ if (editor.permissions.resize) {
+ Scenery.resize.show(scenery)
+ Scenery.resize.rotate_dots()
+ Scenery.resize.move_dots()
+ }
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+ },
+ },
+ {
+ type: "destroy-scenery",
+ undo: function(state){
+ Scenery.deserialize([ state ])
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+ },
+ redo: function(state){
+ Scenery.remove(state.id)
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
+ },
+ },
+
+ //
+
+ {
+ type: "create-room",
+ undo: function(room){
+ Rooms.remove(room)
+ Rooms.clipper.update()
+ },
+ redo: function(room){
+ Rooms.add(new Room(room))
+ Rooms.clipper.update()
+ app.tube("builder-pick-room", room)
+ },
+ },
+ {
+ type: "update-room",
+ undo: function(state){
+ var room = Rooms.list[state.id]
+ room.rect.assign( state.rect )
+ room.height = state.height
+ Rooms.clipper.update()
+ app.tube("builder-pick-room", room)
+ },
+ redo: function(state){
+ var room = Rooms.list[state.id]
+ room.rect.assign( state.rect )
+ room.height = state.height
+ Rooms.clipper.update()
+ app.tube("builder-pick-room", room)
+ },
+ },
+ {
+ type: "destroy-room",
+ undo: function(room){
+ Rooms.add(new Room(room))
+ Rooms.clipper.update()
+ app.tube("builder-pick-room", room)
+ },
+ redo: function(room){
+ Rooms.remove(room)
+ Rooms.clipper.update()
+ },
+ },
+
+ //
+
+ {
+ type: "update-wallpaper",
+ undo: function(state){
+ },
+ redo: function(state){
+ },
+ },
+
+ ])
+})()
diff --git a/public/assets/javascripts/rectangles/models/rect.js b/public/assets/javascripts/rectangles/models/rect.js
index ec32ab7..5952f6a 100644
--- a/public/assets/javascripts/rectangles/models/rect.js
+++ b/public/assets/javascripts/rectangles/models/rect.js
@@ -39,6 +39,10 @@
Rect.prototype.clone = function(){
return new Rect( this.x.clone(), this.y.clone() )
}
+ Rect.prototype.assign = function(r) {
+ this.x.assign(r.x)
+ this.y.assign(r.y)
+ }
Rect.prototype.center = function(){
return new vec2(this.x.midpoint(), this.y.midpoint())
}
diff --git a/public/assets/javascripts/rectangles/models/room.js b/public/assets/javascripts/rectangles/models/room.js
index 937c928..33a94d0 100644
--- a/public/assets/javascripts/rectangles/models/room.js
+++ b/public/assets/javascripts/rectangles/models/room.js
@@ -40,6 +40,14 @@
this.focused = false
}
+ Room.prototype.copy = function(){
+ return {
+ id: this.id,
+ rect: this.rect.clone(),
+ height: this.height,
+ }
+ }
+
Room.prototype.toString = function(){
return this.rect.toString()
}
diff --git a/public/assets/javascripts/rectangles/models/vec2.js b/public/assets/javascripts/rectangles/models/vec2.js
index 104c6f7..214feb9 100644
--- a/public/assets/javascripts/rectangles/models/vec2.js
+++ b/public/assets/javascripts/rectangles/models/vec2.js
@@ -17,6 +17,10 @@
vec2.prototype.clone = function(){
return new vec2(this.a, this.b)
}
+ vec2.prototype.assign = function(v){
+ this.a = v.a
+ this.b = v.b
+ }
vec2.prototype.abs = function(){
if (this.b < this.a) {
this.invert()
diff --git a/public/assets/javascripts/rectangles/models/wall.js b/public/assets/javascripts/rectangles/models/wall.js
index fdc91fd..460963b 100644
--- a/public/assets/javascripts/rectangles/models/wall.js
+++ b/public/assets/javascripts/rectangles/models/wall.js
@@ -52,7 +52,16 @@
// base.randomize_colors()
// console.log(sidesToString(base.side))
if (Scenery.nextMedia) {
- Scenery.addNextToWall(base, mx)
+ var scenery = Scenery.addNextToWall(base)
+
+ UndoStack.push({
+ type: 'create-scenery',
+ undo: { id: scenery.id },
+ redo: scenery.serialize(),
+ })
+
+ // TODO: watch individual scenery object here
+ Minotaur.watch( app.router.editorView.settings )
}
else if (Scenery.nextWallpaper) {
base.wallpaper()
@@ -135,18 +144,15 @@
Wall.prototype.wallpaper = function(){
var useX = this.side & FRONT_BACK
var shouldFlip = this.side & (LEFT | BACK)
- this.siblings().forEach(function(w){
- w.mx.forEach(function(mx){
-
- var partitionOffset = useX ? mx.x : mx.z
- if (shouldFlip) partitionOffset *= -1
- partitionOffset += mx.width/2
- var floorOffset = mx.y + mx.height/2
+ this.mx.forEach(function(mx){
+ var partitionOffset = useX ? mx.x : mx.z
+ if (shouldFlip) partitionOffset *= -1
+ partitionOffset += mx.width/2
+ var floorOffset = mx.y + mx.height/2
- mx.el.style.backgroundImage = Scenery.nextWallpaper
- mx.el.style.backgroundPosition = (~~partitionOffset) + "px " + (~~floorOffset) + "px"
- })
- })
+ mx.el.style.backgroundImage = Scenery.nextWallpaper
+ mx.el.style.backgroundPosition = (~~partitionOffset) + "px " + (~~floorOffset) + "px"
+ })
}
Wall.prototype.outline = function(){
diff --git a/public/assets/javascripts/rectangles/util/constants.js b/public/assets/javascripts/rectangles/util/constants.js
index 58cb1a5..b9485ca 100644
--- a/public/assets/javascripts/rectangles/util/constants.js
+++ b/public/assets/javascripts/rectangles/util/constants.js
@@ -8,6 +8,12 @@ var TOP = CEILING, BOTTOM = FLOOR,
BOTTOM_RIGHT = BOTTOM | RIGHT,
TOP_BOTTOM = TOP | BOTTOM
+var FRONT_LEFT = FRONT | LEFT,
+ FRONT_RIGHT = FRONT | RIGHT,
+ BACK_LEFT = BACK | LEFT,
+ BACK_RIGHT = BACK | RIGHT
+
+
var height_min = 200,
height_max = 2000,
side_min = 10,
diff --git a/public/assets/javascripts/rectangles/util/keys.js b/public/assets/javascripts/rectangles/util/keys.js
index 5a5c9d2..62d763f 100644
--- a/public/assets/javascripts/rectangles/util/keys.js
+++ b/public/assets/javascripts/rectangles/util/keys.js
@@ -19,7 +19,7 @@ var keys = (function(){
break;
default:
if (keys.debug) console.log(key)
- base.tube(key)
+ base.tube(key, e)
break;
}
})
@@ -158,8 +158,8 @@ var keys = (function(){
'backslash' : '220',
'closebracket' : '221',
'single_quote' : '222'
- }
- var KEY_NAMES = invert_hash(KEYCODES)
+ },
+ KEY_NAMES = invert_hash(KEYCODES)
return base
})() \ No newline at end of file
diff --git a/public/assets/javascripts/rectangles/util/measurement.js b/public/assets/javascripts/rectangles/util/measurement.js
new file mode 100644
index 0000000..d6a0b35
--- /dev/null
+++ b/public/assets/javascripts/rectangles/util/measurement.js
@@ -0,0 +1,82 @@
+$.fn.resetUnitVal = function(){
+ this.each(function(){
+ var n = $(this).data("px")
+ $(this).unitVal(n)
+ });
+}
+
+$.fn.unitVal = function(n){
+ var s
+ if (typeof n === "undefined") {
+ s = $(this).val()
+ n = stringToMeasurement( s )
+ if (! n || isNaN(n)) {
+ n = $(this).data("px")
+ }
+ }
+ s = measurementToString( n )
+ $(this).val( s ).data("px", n)
+ return n
+}
+
+function measurementToString( n ) {
+ var s, ft, inch
+ switch (app.units) {
+ case 'm':
+ s = round(n/36 * 0.3048 * 100) / 100 + " m"
+ break
+ case 'ft':
+ ft = floor(n / 36)
+ inch = abs(round((n % 36) / 3))
+ s = ft + "'"
+ if (inch > 0) {
+ s += " " + inch + '"'
+ }
+ break
+ case 'px':
+ default:
+ s = round(n) + " px"
+ break
+ }
+ return s
+}
+function stringToMeasurement( s ) {
+ var ft, inch, ft_in, type
+ if (! s.match(/[0-9]/)) {
+ return NaN
+ }
+ if (s.indexOf("'") !== -1 || s.indexOf('"') !== -1 || s.indexOf('ft') !== -1) {
+ ft_in = s.match(/[0-9.]+/g)
+ if (ft_in.length >= 2) {
+ ft = parseFloat( ft_in[0] )
+ inch = parseFloat( ft_in[1] )
+ }
+ else if (ft_in.length == 1) {
+ if (s.indexOf('"') !== -1) {
+ ft = 0
+ inch = parseFloat( ft_in[0] )
+ }
+ else {
+ ft = parseFloat( ft_in[0] )
+ inch = 0
+ }
+ }
+ else {
+ ft = inch = 0
+ }
+ n = ft * 36 + inch * 3
+ }
+ else if (s.indexOf("m") !== -1) {
+ n = parseFloat(s.match(/[0-9.]+/)) * 36 / 0.3048
+ }
+ else if (s.indexOf("px") !== -1) {
+ n = parseFloat(s.match(/[0-9.]+/))
+ }
+ else {
+ n = abs( stringToMeasurement( s + app.units ) )
+ }
+ if (s.indexOf('-') !== -1) {
+ n *= -1
+ }
+ return n
+}
diff --git a/public/assets/javascripts/rectangles/util/minotaur.js b/public/assets/javascripts/rectangles/util/minotaur.js
new file mode 100644
index 0000000..039a053
--- /dev/null
+++ b/public/assets/javascripts/rectangles/util/minotaur.js
@@ -0,0 +1,64 @@
+(function(){
+
+ var Monitor = function () {
+ var base = this
+ base.$el = $("#minotaur")
+ base.timeout = null
+ base.delay = 500
+ base.objects = {}
+
+ base.init = function () {
+ base.$el.removeClass()
+ base.$el.click(base.save)
+ }
+
+ base.watch = function (object) {
+ base.objects[object.type] = base.objects[object.type] || {}
+ base.objects[object.type][object._id] = object
+ base.clear()
+ base.timeout = setTimeout(base.save, base.delay)
+ }
+
+ base.unwatch = function (object) {
+ if (base.objects[object.type] && base.objects[object.type][object._id]) {
+ delete base.objects[object.type][object._id]
+ }
+ }
+
+ base.clear = function () {
+ if (base.timeout) clearTimeout(base.timeout)
+ base.timeout = false
+ }
+
+ base.save = function () {
+ var saving = false
+ base.clear()
+
+ for (var type in base.objects) {
+ for (var id in base.objects[type]) {
+ var obj = base.objects[type][id]
+ if (obj) {
+ obj.save(null, function(){ base.hide() }, function(){})
+ }
+ delete base.objects[type][id]
+ saving = true
+ }
+ }
+
+ saving ? base.show() : base.hide()
+ }
+
+ base.show = function () {
+ base.$el.removeClass().addClass('saving')
+ }
+
+ base.hide = function () {
+ base.$el.removeClass()
+ }
+
+ base.init();
+ }
+
+ window.Minotaur = new Monitor ();
+
+})()
diff --git a/public/assets/javascripts/rectangles/util/permissions.js b/public/assets/javascripts/rectangles/util/permissions.js
index adb2498..1b5a1b5 100644
--- a/public/assets/javascripts/rectangles/util/permissions.js
+++ b/public/assets/javascripts/rectangles/util/permissions.js
@@ -24,9 +24,26 @@ Permissions.prototype.assign = function (key, state) {
return state
}
+Permissions.prototype.add = function (key) {
+ var base = this
+ base[key] = true
+}
+
+Permissions.prototype.remove = function (key) {
+ var base = this
+ base[key] = true
+}
+
Permissions.prototype.clear = function () {
var base = this
base.keys.forEach(function(op){
base[op] = false
})
}
+
+Permissions.prototype.log = function () {
+ var base = this
+ base.keys.forEach(function(op){
+ console.log(op, base[op])
+ })
+} \ No newline at end of file
diff --git a/public/assets/javascripts/rectangles/util/undo.js b/public/assets/javascripts/rectangles/util/undostack.js
index 3700817..b93c79e 100644
--- a/public/assets/javascripts/rectangles/util/undo.js
+++ b/public/assets/javascripts/rectangles/util/undostack.js
@@ -1,6 +1,7 @@
(function(){
var UndoStack = function(){
+ this.debug = true
this.stack = []
this.types = {}
this.pointer = -1
@@ -17,7 +18,8 @@
UndoStack.prototype.undo = function(){
if (this.pointer == -1) return false
var action = this.stack[this.pointer]
- this.types[ action.type ].undo(action)
+ this.debug && console.log("undo", action.type)
+ this.types[ action.type ].undo(action.undo)
this.pointer--
return this.pointer > -1
}
@@ -25,13 +27,21 @@
if (this.pointer == this.stack.length-1) return false
this.pointer++
var action = this.stack[this.pointer]
- this.types[ action.type ].redo(action)
+ this.debug && console.log("redo", action.type)
+ this.types[ action.type ].redo(action.redo)
return this.pointer < this.stack.length-1
}
UndoStack.prototype.register = function(actionType){
- this.types[ actionType.type ] = actionType
+ if (actionType.length) {
+ actionType.forEach(this.registerOne.bind(this))
+ }
+ else {
+ this.registerOne(actionType)
+ }
}
-
+ UndoStack.prototype.registerOne = function(actionType){
+ this.types[ actionType.type ] = actionType
+ }
if ('window' in this) {
window.UndoStack = new UndoStack
}
diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js
index d07810e..794079e 100644
--- a/public/assets/javascripts/ui/_router.js
+++ b/public/assets/javascripts/ui/_router.js
@@ -27,6 +27,7 @@ var SiteRouter = Router.extend({
"/profile": 'profile',
"/profile/edit": 'editProfile',
+ "/profile/:name": 'profile',
"/about/:name/edit": 'editDocument',
"/about/new": 'newDocument',
diff --git a/public/assets/javascripts/ui/builder/BuilderInfo.js b/public/assets/javascripts/ui/builder/BuilderInfo.js
index 56f1338..2fffdba 100644
--- a/public/assets/javascripts/ui/builder/BuilderInfo.js
+++ b/public/assets/javascripts/ui/builder/BuilderInfo.js
@@ -96,86 +96,3 @@ var BuilderInfo = View.extend({
},
})
-
-$.fn.resetUnitVal = function(){
- this.each(function(){
- var n = $(this).data("px")
- $(this).unitVal(n)
- });
-}
-
-$.fn.unitVal = function(n){
- var s
- if (typeof n === "undefined") {
- s = $(this).val()
- n = stringToMeasurement( s )
- if (! n || isNaN(n)) {
- n = $(this).data("px")
- }
- }
- s = measurementToString( n )
- $(this).val( s ).data("px", n)
- return n
-}
-
-function measurementToString( n ) {
- var s, ft, inch
- switch (app.units) {
- case 'm':
- s = round(n/36 * 0.3048 * 100) / 100 + " m"
- break
- case 'ft':
- ft = floor(n / 36)
- inch = abs(round((n % 36) / 3))
- s = ft + "'"
- if (inch > 0) {
- s += " " + inch + '"'
- }
- break
- case 'px':
- default:
- s = round(n) + " px"
- break
- }
- return s
-}
-function stringToMeasurement( s ) {
- var ft, inch, ft_in, type
- if (! s.match(/[0-9]/)) {
- return NaN
- }
- if (s.indexOf("'") !== -1 || s.indexOf('"') !== -1 || s.indexOf('ft') !== -1) {
- ft_in = s.match(/[0-9.]+/g)
- if (ft_in.length >= 2) {
- ft = parseFloat( ft_in[0] )
- inch = parseFloat( ft_in[1] )
- }
- else if (ft_in.length == 1) {
- if (s.indexOf('"') !== -1) {
- ft = 0
- inch = parseFloat( ft_in[0] )
- }
- else {
- ft = parseFloat( ft_in[0] )
- inch = 0
- }
- }
- else {
- ft = inch = 0
- }
- n = ft * 36 + inch * 3
- }
- else if (s.indexOf("m") !== -1) {
- n = parseFloat(s.match(/[0-9.]+/)) * 36 / 0.3048
- }
- else if (s.indexOf("px") !== -1) {
- n = parseFloat(s.match(/[0-9.]+/))
- }
- else {
- n = abs( stringToMeasurement( s + app.units ) )
- }
- if (s.indexOf('-') !== -1) {
- n *= -1
- }
- return n
-} \ No newline at end of file
diff --git a/public/assets/javascripts/ui/builder/BuilderSettings.js b/public/assets/javascripts/ui/builder/BuilderSettings.js
index c551f95..0091454 100644
--- a/public/assets/javascripts/ui/builder/BuilderSettings.js
+++ b/public/assets/javascripts/ui/builder/BuilderSettings.js
@@ -122,6 +122,9 @@ var BuilderSettings = FormView.extend({
this.$name.val(data.name)
this.action = this.updateAction
+ Minotaur.unwatch(this)
+ Minotaur.hide()
+
window.history.pushState(null, document.title, "/layout/" + data.slug)
},
diff --git a/public/assets/javascripts/ui/builder/BuilderToolbar.js b/public/assets/javascripts/ui/builder/BuilderToolbar.js
index df98ab0..2eb7590 100644
--- a/public/assets/javascripts/ui/builder/BuilderToolbar.js
+++ b/public/assets/javascripts/ui/builder/BuilderToolbar.js
@@ -6,15 +6,22 @@ var BuilderToolbar = View.extend({
"click [data-role='toggle-map-view']": 'toggleMap',
"click [data-role='toggle-layout-settings']": 'toggleSettings',
"click [data-role='undo']": 'undo',
- "click [data-role='create-mode']": 'create',
- "click [data-role='resize-mode']": 'resize',
- "click [data-role='move-mode']": 'move',
+// "click [data-role='create-mode']": 'create',
+// "click [data-role='resize-mode']": 'resize',
+// "click [data-role='move-mode']": 'move',
"click [data-role='destroy-mode']": 'destroy',
},
initialize: function(opt){
this.parent = opt.parent
- map.ui.permissions.toggle()
+ this.resetPermissions()
+ },
+
+ resetPermissions: function(){
+ map.ui.permissions.clear()
+ map.ui.permissions.add("create")
+ map.ui.permissions.add("move")
+ map.ui.permissions.add("resize")
},
toggleMap: function(){
@@ -27,7 +34,8 @@ var BuilderToolbar = View.extend({
undo: function(){
},
-
+
+/*
create: function(e){
var state = map.ui.permissions.toggle("create")
$(".inuse").removeClass("inuse")
@@ -45,7 +53,8 @@ var BuilderToolbar = View.extend({
$(".inuse").removeClass("inuse")
$(e.currentTarget).toggleClass("inuse", state)
},
-
+*/
+
destroy: function(e){
var state = map.ui.permissions.toggle("destroy")
$(".inuse").removeClass("inuse")
diff --git a/public/assets/javascripts/ui/editor/EditorSettings.js b/public/assets/javascripts/ui/editor/EditorSettings.js
index d6a79fb..e9239e4 100644
--- a/public/assets/javascripts/ui/editor/EditorSettings.js
+++ b/public/assets/javascripts/ui/editor/EditorSettings.js
@@ -5,7 +5,7 @@ var EditorSettings = FormView.extend({
createAction: "/api/project/new",
updateAction: "/api/project/edit",
destroyAction: "/api/project/destroy",
-
+
events: {
"keydown": 'stopPropagation',
"keydown [name=name]": 'enterSubmit',
@@ -32,13 +32,17 @@ var EditorSettings = FormView.extend({
data.rooms && Rooms.deserialize(data.rooms)
data.startPosition && scene.camera.move(data.startPosition)
- if (! data.isNew) {
+ if (data.isNew) {
+ this.$name.val( "Room " + moment().format("DD/MM/YYYY ha") )
+ }
+ else {
// console.log(data)
+ this.thumbnailIsStale()
this.$id.val( data._id )
this.$name.val( data.name )
this.$description.val( data.description )
- data.privacy && this.$privacy.find("[value=" + data.privacy + "]").prop('checked', "checked")
+ data.privacy && this.$privacy.find("[value=" + data.privacy + "]").prop("checked", "checked")
data.media && Scenery.deserialize(data.media)
}
@@ -121,15 +125,32 @@ var EditorSettings = FormView.extend({
fd.append( "walls", JSON.stringify( Rooms.serializeWalls() ) )
fd.append( "media", JSON.stringify( Scenery.serialize() ) )
fd.append( "startPosition", JSON.stringify( app.position(scene.camera) ) )
- fd.append( "thumbnail", dataUriToBlob(map.canvas.toDataURL()) )
+
+ if (this.thumbnailIsStale()) {
+ fd.append( "thumbnail", dataUriToBlob(map.canvas.toDataURL()) )
+ }
return fd
},
+ thumbnailState: null,
+ thumbnailIsStale: function(){
+ var newState = JSON.stringify( Rooms.serialize() )
+
+ if (newState !== this.thumbnailState) {
+ this.thumbnailState = newState
+ return true
+ }
+ return false
+ },
+
success: function(data){
this.$id.val(data._id)
this.$name.val(data.name)
this.action = this.updateAction
+ Minotaur.unwatch(this)
+ Minotaur.hide()
+
window.history.pushState(null, document.title, "/project/" + data.slug + "/edit")
},
diff --git a/public/assets/javascripts/ui/editor/MediaEditor.js b/public/assets/javascripts/ui/editor/MediaEditor.js
index cd8fb63..cc924da 100644
--- a/public/assets/javascripts/ui/editor/MediaEditor.js
+++ b/public/assets/javascripts/ui/editor/MediaEditor.js
@@ -4,6 +4,7 @@ var MediaEditor = FormView.extend({
events: {
"keydown": 'stopPropagation',
+ "focus [name]": "clearMinotaur",
"click [data-role=play-media]": "togglePaused",
"mousedown [name=keyframe]": "stopPropagation",
"mousedown": "stopPropagation",
@@ -11,6 +12,9 @@ var MediaEditor = FormView.extend({
"change [name=autoplay]": "setAutoplay",
"change [name=loop]": "setLoop",
"change [name=mute]": "setMute",
+ "change [name=width]": 'changeWidth',
+ "change [name=height]": 'changeHeight',
+ "change [name=units]": 'changeUnits',
"click [data-role=destroy-media]": "destroy",
},
@@ -22,8 +26,8 @@ var MediaEditor = FormView.extend({
this.$description = this.$("[name=description]")
// image fields
- this.$widthDimension = this.$("[name=width]")
- this.$heightDimension = this.$("[name=height]")
+ this.$width = this.$("[name=width]")
+ this.$height = this.$("[name=height]")
this.$units = this.$("[name=units]")
// video fields
@@ -55,16 +59,14 @@ var MediaEditor = FormView.extend({
this.$name.val(media.title)
this.$description.val(media.description)
+ this.setDimensions()
+ this.$units.val( "ft" )
switch (media.type) {
case "image":
this.$(".image").show()
this.$(".video").hide()
-
- this.$widthDimension.val( Number(media.widthDimension) || "" )
- this.$heightDimension.val( Number(media.heightDimension) || "" )
- this.$units.val( media.units || "cm" )
-
+
break
case "youtube":
@@ -113,18 +115,39 @@ var MediaEditor = FormView.extend({
this.scenery.mute(checked)
},
+ setDimensions: function(){
+ this.$width.unitVal( Number(this.scenery.dimensions.a * this.scenery.scale) || "" )
+ this.$height.unitVal( Number(this.scenery.dimensions.b * this.scenery.scale) || "" )
+ },
+ changeWidth: function(e){
+ e.stopPropagation()
+ this.scenery.set_scale( this.$width.unitVal() / this.scenery.dimensions.a )
+ this.setDimensions()
+ },
+ changeHeight: function(e){
+ e.stopPropagation()
+ this.scenery.set_scale( this.$height.unitVal() / this.scenery.dimensions.b )
+ this.setDimensions()
+ },
+ changeUnits: function(){
+ app.units = this.$units.val()
+ this.$('.units').resetUnitVal()
+ },
+
bind: function(scenery){
this.scenery = scenery
this.scenery.mx.bound = true
},
unbind: function(){
- this.scenery.mx.bound = false
- this.scenery = null
+ if (this.scenery && this.scenery.mx) {
+ this.scenery.mx.bound = false
+ }
+ this.scenery = null
},
destroy: function(){
- ConfirmModal.confirm("Are you sure you want to this media?", function(){
+ ConfirmModal.confirm("Are you sure you want delete to this media?", function(){
var scenery = this.scenery
this.hide()
Scenery.remove(scenery.id)
diff --git a/public/assets/javascripts/ui/lib/FormView.js b/public/assets/javascripts/ui/lib/FormView.js
index 219952d..ab33bc0 100644
--- a/public/assets/javascripts/ui/lib/FormView.js
+++ b/public/assets/javascripts/ui/lib/FormView.js
@@ -54,15 +54,20 @@ var FormView = View.extend({
return fd
},
- save: function(e){
- e.preventDefault()
+ save: function(e, successCallback, errorCallback){
+ e && e.preventDefault()
this.$errors.hide().css("opacity", 0.0);
if (this.validate) {
var errors = this.validate()
if (errors && errors.length) {
- this.showErrors(errors)
+ if (errorCallback) {
+ errorCallback(errors)
+ }
+ else {
+ this.showErrors(errors)
+ }
return
}
}
@@ -74,18 +79,29 @@ var FormView = View.extend({
dataType: "json",
processData: false,
contentType: false,
- });
+ })
+
request.done($.proxy(function (response) {
if (response.error) {
var errors = []
for (var key in response.error.errors) {
errors.push(response.error.errors[key].message);
}
- this.showErrors(errors)
+ if (errorCallback) {
+ errorCallback(errors)
+ }
+ else {
+ this.showErrors(errors)
+ }
return
}
else {
- this.success && this.success(response)
+ if (successCallback) {
+ successCallback(response)
+ }
+ if (this.success) {
+ this.success(response)
+ }
}
}, this));
}
diff --git a/public/assets/javascripts/ui/lib/ModalView.js b/public/assets/javascripts/ui/lib/ModalView.js
index 957a54d..937c1e9 100644
--- a/public/assets/javascripts/ui/lib/ModalView.js
+++ b/public/assets/javascripts/ui/lib/ModalView.js
@@ -11,9 +11,10 @@ var ModalView = View.extend({
},
show: function(){
- $(".mediaDrawer").removeClass("active");
- this.$el.addClass("active");
- $("body").addClass("noOverflow");
+ $(".mediaDrawer").removeClass("active")
+ $(".fileUpload").removeClass("active")
+ this.$el.addClass("active")
+ $("body").addClass("noOverflow")
},
hide: function(){
diff --git a/public/assets/javascripts/ui/lib/Parser.js b/public/assets/javascripts/ui/lib/Parser.js
index dfff7b2..1cf0418 100644
--- a/public/assets/javascripts/ui/lib/Parser.js
+++ b/public/assets/javascripts/ui/lib/Parser.js
@@ -86,6 +86,10 @@ var Parser = {
success: function(result){
if (result.length == 0) { return done(id, "", 640, 360) }
var res = result[0]
+ if (res.embed_privacy != "anywhere") {
+ AlertModal.alert("Sorry, the author of this video has marked it private, preventing it from being embedded.", function(){})
+ return
+ }
done({
token: id,
thumbnail: res.thumbnail_large,
diff --git a/public/assets/javascripts/ui/lib/View.js b/public/assets/javascripts/ui/lib/View.js
index 999a0e5..d94e6db 100644
--- a/public/assets/javascripts/ui/lib/View.js
+++ b/public/assets/javascripts/ui/lib/View.js
@@ -1,13 +1,14 @@
var View = (function($, _){
var View = function(options) {
- this.cid = _.uniqueId('view');
+ this._id = _.uniqueId('view')
+ this.type = "view"
options || (options = {});
- _.extend(this, _.pick(options, viewOptions));
- this._ensureElement();
- this.initialize.apply(this, arguments);
- this.delegateEvents();
- };
+ _.extend(this, _.pick(options, viewOptions))
+ this._ensureElement()
+ this.initialize.apply(this, arguments)
+ this.delegateEvents()
+ }
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
@@ -58,7 +59,7 @@ var View = (function($, _){
var match = key.match(delegateEventSplitter);
var eventName = match[1], selector = match[2];
method = _.bind(method, this);
- eventName += '.delegateEvents' + this.cid;
+ eventName += '.delegateEvents' + this._id;
if (selector === '') {
this.$el.on(eventName, method);
} else {
@@ -70,7 +71,7 @@ var View = (function($, _){
// Clears all callbacks previously bound to the view with `delegateEvents`.
undelegateEvents: function() {
- this.$el.off('.delegateEvents' + this.cid);
+ this.$el.off('.delegateEvents' + this._id);
return this;
},
diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css
index de9cce6..1c48eee 100755
--- a/public/assets/stylesheets/app.css
+++ b/public/assets/stylesheets/app.css
@@ -158,13 +158,15 @@ h5 {
.page .profile {
color:white;
}
-.page table{
- width:100%;
- height:400px;
- border-top:1px solid;
- margin:40px 0 0 0;
+.page table {
+ width: 100%;
+ border-top: 1px solid;
+ margin: 40px 0 0 0;
border-spacing: 0;
- clear:both;
+ clear:nboth;
+}
+.page tr {
+ height: 400px;
}
.page table.showcase {
height:70vh;
@@ -230,6 +232,12 @@ iframe.embed {
color:white;
}
+#projectList .editBtn {
+ position: absolute;
+ right: 10px;
+ top: 10px;
+}
+
/*
.room1 {
position: relative;
@@ -240,12 +248,6 @@ iframe.embed {
background-image:url(https://s3.amazonaws.com/luckyplop/fd4ebe8a7a4246c8273fc999fb1ef0d6a8260b8c.png);
}
-.room1 .editBtn {
- position: absolute;
- right: 10px;
- top: 10px;
-}
-
.room1 form textarea {
width: 226px;
}
@@ -526,20 +528,25 @@ iframe.embed {
position:fixed;
top:0;
left:0;
- cursor: -webkit-grab;
- cursor: -moz-grab;
z-index: 1;
position: fixed;
top: 50%;
left: 50%;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
- cursor:pointer;
+ cursor: -webkit-grab;
+ cursor: -moz-grab;
}
.mx-scene:active{
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
+.mx-scenery {
+ cursor: pointer;
+}
+.mx-scenery:active {
+ cursor: pointer;
+}
.mx-object3d.image,
.mx-object3d.video,
.mx-object3d iframe,
@@ -573,6 +580,28 @@ iframe.embed {
z-index: 10;
}
+#map {
+ cursor: crosshair;
+}
+#map.move {
+ cursor: move;
+}
+#map.ew-resize {
+ cursor: ew-resize;
+}
+#map.ns-resize {
+ cursor: ns-resize;
+}
+#map.nesw-resize {
+ cursor: nesw-resize;
+}
+#map.nwse-resize {
+ cursor: nwse-resize;
+}
+#map.destroy {
+ cursor: url(/assets/img/destroy-cursor.png) 12 12, auto;
+}
+
.face {
background-color: #fff;
transition: 0.1s background-color ease;
@@ -600,7 +629,24 @@ iframe.embed {
background-size: 100% 100%;
}
-
+#minotaur {
+ position: absolute;
+ top: 26px;
+ right: 260px;
+ opacity: 0;
+}
+#minotaur .label:after {
+ padding: 6px;
+ font-size: 13px;
+ font-weight: 300;
+}
+#minotaur.saving {
+ background: #8fd;
+ opacity: 1;
+}
+#minotaur.saving .label:after {
+ content: 'SAVING';
+}
.rapper {
position:relative;
@@ -1268,6 +1314,13 @@ input[type="range"]::-webkit-slider-thumb {
top: 0px;
}
+#mediaEditor .setting.number label {
+ width: 40px;
+}
+#mediaEditor .setting.number [type=text] {
+ width: 140px;
+}
+
.playButton,.muteButton {
color: white;
background: black;
diff --git a/server/lib/api/projects.js b/server/lib/api/projects.js
index fc54a5f..bd3cb81 100644
--- a/server/lib/api/projects.js
+++ b/server/lib/api/projects.js
@@ -72,15 +72,20 @@ var projects = {
data.slug = util.slugify(data.name)
data.description = util.sanitize(data.description)
- upload.put("projects", req.files.thumbnail, {
- unacceptable: function(err){
- res.json({ error: { errors: { thumbnail: { message: "Problem saving thumbnail: " + err } } } })
- },
- success: function(url){
- data.photo = url
- done()
- }
- })
+ if (req.files.thumbnail) {
+ upload.put("projects", req.files.thumbnail, {
+ unacceptable: function(err){
+ res.json({ error: { errors: { thumbnail: { message: "Problem saving thumbnail: " + err } } } })
+ },
+ success: function(url){
+ data.photo = url
+ done()
+ }
+ })
+ }
+ else {
+ done()
+ }
function done() {
Project.findOne({ _id: _id }, function(err, doc){
diff --git a/server/lib/middleware.js b/server/lib/middleware.js
index aec54ad..27b9c04 100644
--- a/server/lib/middleware.js
+++ b/server/lib/middleware.js
@@ -36,7 +36,7 @@ var middleware = {
ensureLocals: function (req, res, next) {
res.locals.token = req.csrfToken();
res.locals.logged_in = req.isAuthenticated()
- res.locals.user = req.user || {}
+ res.locals.user = req.user || { id: undefined }
res.locals.config = config
res.locals.profile = null
res.locals.opt = {}
diff --git a/server/lib/views.js b/server/lib/views.js
index 27b7446..b776582 100644
--- a/server/lib/views.js
+++ b/server/lib/views.js
@@ -36,6 +36,7 @@ views.editor = function (req, res) {
date: moment(req.project.updated_at).format("M/DD/YYYY"),
author: user.displayName,
authorlink: "/profile/" + user.username,
+ noui: !! (req.query.noui === '1'),
})
})
}
@@ -60,6 +61,7 @@ views.reader = function (req, res) {
date: moment(req.project.updated_at).format("M/DD/YYYY"),
author: user.displayName,
authorlink: "/profile/" + user.username,
+ noui: !! (req.query.noui === '1'),
})
})
}
diff --git a/test/06-test-grouper.js b/test/06-test-grouper.js
index 0f14217..184a3d7 100644
--- a/test/06-test-grouper.js
+++ b/test/06-test-grouper.js
@@ -194,8 +194,8 @@ describe('grouper(rect,corner,peninsula)', function(){
it("left has 3 walls", function(){
assert.equal(3, left_walls.length)
})
- it("right has 4 walls", function(){
- assert.equal(4, right_walls.length)
+ it("right has 3 walls", function(){
+ assert.equal(3, right_walls.length)
})
it("front has 2 walls", function(){
assert.equal(2, front_walls.length)
@@ -229,14 +229,15 @@ describe('grouper(rect,corner,peninsula_taller)', function(){
var front_walls = Rooms.grouper.group([], collections, FRONT)
var back_walls = Rooms.grouper.group([], collections, BACK)
var left_walls = Rooms.grouper.group([], collections, LEFT)
+ Rooms.grouper.debug = true
var right_walls = Rooms.grouper.group([], collections, RIGHT)
+ Rooms.grouper.debug = false
- it("left has 4 walls", function(){
- assert.equal(4, left_walls.length)
+ it("left has 3 walls", function(){
+ assert.equal(3, left_walls.length)
})
- it("right has 5 walls", function(){
- assert.equal(5, right_walls.length)
- // console.log(right_walls.map(function(m){ return m.vec + " " + m.edge + " " + m.surface +"" }))
+ it("right has 3 walls", function(){
+ assert.equal(3, right_walls.length)
})
it("front has 3 walls", function(){
assert.equal(3, front_walls.length)
diff --git a/test/07-test-surface.js b/test/07-test-surface.js
index 8f69e77..b2e4769 100644
--- a/test/07-test-surface.js
+++ b/test/07-test-surface.js
@@ -9,6 +9,36 @@ var Surface = require("../public/assets/javascripts/rectangles/models/surface.js
describe('basic surface', function(){
var surface = new Surface ()
+ surface.add( new Rect( new vec2(1, 5), new vec2(0, 4) ) )
+
+ var small = new vec2(2, 2)
+ var oblong = new vec2(4, 1)
+
+ // describe placement
+ // describe dragging up (clamp at top edge)
+ // describe dragging down (clamp at bottom edge)
+ // describe dragging left (clamp at left edge)
+ // describe dragging right (clamp at right edge)
+})
+
+describe('two-level surface', function(){
+ var surface = new Surface ()
+ surface.add( new Rect( new vec2(1, 3), new vec2(0, 4) ) )
+ surface.add( new Rect( new vec2(3, 5), new vec2(0, 6) ) )
+
+ var small = new vec2(2, 2)
+ var oblong = new vec2(4, 1)
+
+ // describe placement/centering
+ // describe dragging up (clamp at top edge)
+ // describe dragging down (clamp at bottom edge)
+ // describe dragging left (clamp at left edge)
+ // describe dragging right (clamp at right edge)
+ // describe dragging up and right (clamp at top edge, then pop into peninsula space)
+})
+
+describe('door surface', function(){
+ var surface = new Surface ()
surface.add( new Rect( new vec2(1, 3), new vec2(0, 4) ) )
surface.add( new Rect( new vec2(3, 4), new vec2(2, 4) ) )
surface.add( new Rect( new vec2(4, 6), new vec2(0, 4) ) )
@@ -43,11 +73,11 @@ describe('basic surface', function(){
describe('#place()', function(){
it("fits a small element on the top left", function(){
var bounds = surface.place(small, new vec2(1,3))
- console.log(bounds)
+// console.log(bounds)
})
it("places a small element on the right", function(){
var bounds = surface.place(small, new vec2(4,6))
- console.log(bounds)
+// console.log(bounds)
})
})
diff --git a/test/09-test-undo.js b/test/09-test-undo.js
index 84b5d09..60fbbb6 100644
--- a/test/09-test-undo.js
+++ b/test/09-test-undo.js
@@ -1,5 +1,6 @@
var assert = require("assert")
-var UndoStack = require("../public/assets/javascripts/rectangles/util/undo.js")
+var UndoStack = require("../public/assets/javascripts/rectangles/util/undostack.js")
+UndoStack.debug = false
describe('undo', function(){
@@ -9,11 +10,11 @@ describe('undo', function(){
UndoStack.register({
type: "demo",
- undo: function(action){
- state = action.prev
+ undo: function(myState){
+ state = myState
},
- redo: function(action){
- state = action.next
+ redo: function(myState){
+ state = myState
},
})
@@ -33,22 +34,22 @@ describe('undo', function(){
UndoStack.push({
type: "demo",
- prev: state,
- next: "one"
+ undo: state,
+ redo: "one"
})
state = "one"
UndoStack.push({
type: "demo",
- prev: state,
- next: "two"
+ undo: state,
+ redo: "two"
})
state = "two"
UndoStack.push({
type: "demo",
- prev: state,
- next: "three"
+ undo: state,
+ redo: "three"
})
state = "three"
@@ -122,8 +123,8 @@ describe('undo', function(){
UndoStack.push({
type: "demo",
- prev: state,
- next: "four"
+ undo: state,
+ redo: "four"
})
state = "four"
diff --git a/views/controls/builder/toolbar.ejs b/views/controls/builder/toolbar.ejs
index 98aee1e..a00249c 100644
--- a/views/controls/builder/toolbar.ejs
+++ b/views/controls/builder/toolbar.ejs
@@ -3,6 +3,7 @@
data-role='toggle-map-view'
data-info="toggle map view"
class="icon-ios7-photos-outline"></span>
+<!--
<span
data-role='create-mode'
data-info="draw"
@@ -15,6 +16,7 @@
data-role='resize-mode'
data-info="resize"
class="icon-arrow-resize"></span>
+-->
<span
data-role='destroy-mode'
data-info="delete"
diff --git a/views/controls/editor/media-editor.ejs b/views/controls/editor/media-editor.ejs
index 5db1fb2..7f8f299 100644
--- a/views/controls/editor/media-editor.ejs
+++ b/views/controls/editor/media-editor.ejs
@@ -34,13 +34,19 @@
<input type="range" min="0" max="1" value="0" step="0.01" name="keyframe" id="video-keyframe">
</div>
- <div class="image setting">
- Dimensions<br>
- <input type="text" name="width" placeholder="width" class="number">
- <input type="text" name="height" placeholder="height" class="number">
- <select name="units">
- <option value="inch">inch</option>
- <option value="cm">cm</option>
+ <div class="setting number">
+ <label for="scenery-width">width</label>
+ <input type="text" class="units" name="width" id="scenery-width">
+ </div>
+ <div class="setting number">
+ <label for="scenery-height">height</label>
+ <input type="text" class="units" name="height" id="scenery-height">
+ </div>
+ <div class="setting number">
+ <select id="builder-units" name="units">
+ <option value="px">pixels</option>
+ <option value="ft">foot</option>
+ <option value="m">meter</option>
</select>
</div>
diff --git a/views/partials/header.ejs b/views/partials/header.ejs
index e83f42a..6697aff 100644
--- a/views/partials/header.ejs
+++ b/views/partials/header.ejs
@@ -1,5 +1,9 @@
<a href="/" class="logo"><img src="/assets/img/logo4.svg"></a>
+<div id="minotaur">
+ <span class="label"></span>
+</div>
+
<span class="topLinks">
[[ if (logged_in) { ]]
diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs
index 3d783b0..6d85699 100644
--- a/views/partials/scripts.ejs
+++ b/views/partials/scripts.ejs
@@ -23,11 +23,14 @@
<script type="text/javascript" src="/assets/javascripts/rectangles/util/colors.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/util/debug.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/util/permissions.js"></script>
+<script type="text/javascript" src="/assets/javascripts/rectangles/util/measurement.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/util/sort.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/util/uid.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/util/wheel.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/util/mouse.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/util/keys.js"></script>
+<script type="text/javascript" src="/assets/javascripts/rectangles/util/undostack.js"></script>
+<script type="text/javascript" src="/assets/javascripts/rectangles/util/minotaur.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/models/vec2.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/models/vec3.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/models/mat4.js"></script>
@@ -46,6 +49,7 @@
<script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/_scenery.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/move.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/resize.js"></script>
+<script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/undo.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/types/_object.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/types/image.js"></script>
<script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/types/video.js"></script>
diff --git a/views/projects/list-projects.ejs b/views/projects/list-projects.ejs
index d2c0447..c78bf9f 100644
--- a/views/projects/list-projects.ejs
+++ b/views/projects/list-projects.ejs
@@ -14,10 +14,13 @@
<td class="border room1">
[[ } ]]
<iframe src="/project/[[- project.slug ]]/view?noui=1&mute=1" class="embed"></iframe>
- [[ if (profile && profile._id == project.user_id) { ]]
- <div class="editBtn">edit</div>
+ [[ if (String(user._id) == String(project.user_id)) { ]]
+ <a href="/project/[[- project.slug ]]/edit"><div class="editBtn">edit</div></a>
[[ } ]]
- <a href="/project/[[- project.slug ]]" class="roomName">[[- project.name ]]<br>[[- project.date ]]</a>
+ <a href="/project/[[- project.slug ]]" class="roomName">
+ [[- project.name ]]<br>
+ [[- project.date ]]
+ </a>
</td>
[[ }) ]]
diff --git a/views/reader.ejs b/views/reader.ejs
index 44fb2dd..7c31766 100644
--- a/views/reader.ejs
+++ b/views/reader.ejs
@@ -8,6 +8,7 @@
<div id="scene"></div>
+ [[ if (! noui) { ]]
<div class="rapper">
[[ include partials/header ]]
@@ -16,6 +17,7 @@
[[ include controls/reader/media-player ]]
</div>
</div>
+ [[ } ]]
[[ include partials/confirm-modal ]]
[[ include projects/layouts-modal ]]