summaryrefslogtreecommitdiff
path: root/public/assets/javascripts/ui
diff options
context:
space:
mode:
Diffstat (limited to 'public/assets/javascripts/ui')
-rw-r--r--public/assets/javascripts/ui/_router.js86
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintEditor.js129
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintInfo.js92
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintNotice.js62
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintScaler.js158
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintSettings.js123
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintToolbar.js97
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintUploader.js147
-rw-r--r--public/assets/javascripts/ui/blueprint/BlueprintView.js106
-rw-r--r--public/assets/javascripts/ui/builder/BuilderInfo.js4
-rw-r--r--public/assets/javascripts/ui/builder/BuilderSettings.js2
-rw-r--r--public/assets/javascripts/ui/builder/BuilderToolbar.js3
-rw-r--r--public/assets/javascripts/ui/editor/EditorSettings.js17
-rw-r--r--public/assets/javascripts/ui/editor/EditorView.js17
-rw-r--r--public/assets/javascripts/ui/editor/SculptureEditor.js237
-rw-r--r--public/assets/javascripts/ui/lib/AnimatedView.js31
-rw-r--r--public/assets/javascripts/ui/lib/ConfirmModal.js24
-rw-r--r--public/assets/javascripts/ui/lib/FormView.js9
-rw-r--r--public/assets/javascripts/ui/lib/LabColorPicker.js26
-rw-r--r--public/assets/javascripts/ui/lib/ModalView.js5
-rw-r--r--public/assets/javascripts/ui/lib/ToggleableView.js19
-rw-r--r--public/assets/javascripts/ui/lib/Toolbar.js22
-rw-r--r--public/assets/javascripts/ui/reader/MediaPlayer.js2
-rw-r--r--public/assets/javascripts/ui/reader/ReaderView.js22
-rw-r--r--public/assets/javascripts/ui/reader/Tracker.js14
-rw-r--r--public/assets/javascripts/ui/reader/_router.js24
-rw-r--r--public/assets/javascripts/ui/site/EditSubscriptionModal.js290
-rw-r--r--public/assets/javascripts/ui/site/HomeView.js2
-rw-r--r--public/assets/javascripts/ui/site/LayoutsIndex.js85
-rw-r--r--public/assets/javascripts/ui/site/LayoutsModal.js172
-rw-r--r--public/assets/javascripts/ui/site/NewProjectModal.js118
-rw-r--r--public/assets/javascripts/ui/site/StaffView.js47
32 files changed, 2028 insertions, 164 deletions
diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js
index 3532428..61b1d1b 100644
--- a/public/assets/javascripts/ui/_router.js
+++ b/public/assets/javascripts/ui/_router.js
@@ -9,6 +9,7 @@ var SiteRouter = Router.extend({
"click [data-role='new-project-modal']": 'newProject',
"click [data-role='edit-project-modal']": 'editProject',
"click [data-role='edit-profile-modal']": 'editProfile',
+ "click [data-role='edit-subscription-modal']": 'editSubscription',
"click [data-role='new-document-modal']": 'newDocument',
"click [data-role='edit-document-modal']": 'editDocument',
"click [data-role='destroy-document-modal']": 'destroyDocument',
@@ -17,31 +18,38 @@ var SiteRouter = Router.extend({
},
routes: {
- "/": 'home',
- "/home": 'home',
- "/login": 'signin',
- "/signin": 'signin',
- "/signup": 'signup',
+ "/": 'home',
+ "/home": 'home',
+ "/login": 'signin',
+ "/signin": 'signin',
+ "/signup": 'signup',
- "/auth/usernameTaken": 'usernameTaken',
- "/auth/password": 'passwordReset',
- "/auth/forgotPassword": 'passwordForgot',
+ "/auth/usernameTaken": 'usernameTaken',
+ "/auth/password": 'passwordReset',
+ "/auth/forgotPassword": 'passwordForgot',
- "/profile": 'profile',
- "/profile/edit": 'editProfile',
- "/profile/:name": 'profile',
- "/about/:name/edit": 'editDocument',
- "/about/new": 'newDocument',
+ "/profile": 'profile',
+ "/profile/edit": 'editProfile',
+ "/profile/billing": 'editSubscription',
+ "/profile/:name": 'profile',
+ "/about/:name/edit": 'editDocument',
+ "/about/new": 'newDocument',
- "/layout": 'layoutPicker',
- "/layout/:name": 'layoutEditor',
+ "/layout": 'layoutPicker',
+ "/layout/:name": 'layoutEditor',
- "/project": 'projectPicker',
- "/project/new": 'newProject',
- "/project/new/:layout": 'projectNewWithLayout',
- "/project/:name": 'projectViewer',
- "/project/:name/edit": 'projectEditor',
- "/project/:name/view": 'projectViewer',
+ "/blueprint": 'blueprintEditor',
+ "/blueprint/:name": 'blueprintEditor',
+
+ "/project": 'projectPicker',
+ "/project/new": 'newProject',
+ "/project/blueprint/:blueprint": 'projectNewWithBlueprint',
+ "/project/new/:layout": 'projectNewWithLayout',
+ "/project/:name": 'projectViewer',
+ "/project/:name/edit": 'projectEditor',
+ "/project/:name/view": 'projectViewer',
+
+ "/test/blueprint": 'blueprintEditor',
},
mobileRoutes: {
@@ -56,6 +64,7 @@ var SiteRouter = Router.extend({
"/profile": 'profile',
"/profile/edit": 'editProfile',
+ "/profile/billing": 'editSubscription',
"/profile/:name": 'profile',
"/project/:name": 'projectViewer',
@@ -69,6 +78,7 @@ var SiteRouter = Router.extend({
this.newProjectModal = new NewProjectModal()
this.editProjectModal = new EditProjectModal()
this.editProfileModal = new EditProfileModal()
+ this.editSubscriptionModal = new EditSubscriptionModal()
this.passwordForgotModal = new PasswordForgot()
this.documentModal = new DocumentModal()
this.profileView = new ProfileView()
@@ -83,7 +93,9 @@ var SiteRouter = Router.extend({
})
}
- $("body").removeClass("loading")
+ setTimeout(function(){
+ $("body").removeClass("loading")
+ }, 200)
},
layoutEditor: function(e, name){
@@ -112,6 +124,22 @@ var SiteRouter = Router.extend({
window.history.pushState(null, document.title, "/project/new")
this.newProjectModal.load()
},
+
+ projectNewWithBlueprint: function(e, blueprint){
+ e && e.preventDefault()
+
+ Rooms.shapesMode = true
+
+ app.mode.editor = true
+ app.launch()
+ if (app.unsupported) return
+
+ blueprint = slugify(blueprint)
+
+ window.history.pushState(null, document.title, "/project/blueprint/" + blueprint)
+ this.editorView = app.controller = new EditorView()
+ this.editorView.loadBlueprint(blueprint)
+ },
projectNewWithLayout: function(e, layout){
e && e.preventDefault()
@@ -153,6 +181,15 @@ var SiteRouter = Router.extend({
this.readerView = app.controller = new ReaderView()
this.readerView.load(name)
},
+
+ blueprintEditor: function(e, name){
+ environment.init = environment.minimal
+ app.launch()
+ if (app.unsupported) return
+
+ this.blueprintView = app.controller = new BlueprintView ()
+ this.blueprintView.load(name)
+ },
signup: function(e){
e && e.preventDefault()
@@ -195,7 +232,12 @@ var SiteRouter = Router.extend({
this.editProfileModal.load()
},
+ editSubscription: function(e){
+ e && e.preventDefault()
+ window.history.pushState(null, document.title, "/profile/billing")
+ this.editSubscriptionModal.load()
+ },
newDocument: function(e){
e && e.preventDefault()
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintEditor.js b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js
new file mode 100644
index 0000000..7704689
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js
@@ -0,0 +1,129 @@
+
+var wallHeight = 180
+var shapes = new ShapeList
+var last_point = new vec2 (0,0)
+
+var BlueprintEditor = View.extend(AnimatedView.prototype).extend({
+
+ regions: [],
+
+ initialize: function(opt){
+ this.parent = opt.parent
+
+ $(window).resize(this.resize.bind(this))
+
+ scene = new MX.Scene().addTo("#perspective")
+ scene.camera.radius = 20
+ cam = scene.camera
+
+ scene.width = window.innerWidth/2
+ scene.height = window.innerHeight
+ scene.perspective = window.innerHeight
+
+ movements = new MX.Movements(cam, viewHeight)
+ movements.init()
+ movements.lock()
+
+ app.on("move", function(pos){
+ cam.x = pos.x
+ cam.y = pos.y
+ cam.z = pos.z
+ })
+
+ var floorplan = this.floorplan = new MX.Image({
+ backface: true,
+ })
+ scene.add(this.floorplan)
+
+ // recenter perspective view by rightclicking map
+ this.floorplan.el.addEventListener("contextmenu", function(e){
+ e.preventDefault()
+ var offset = offsetFromPoint(e, this)
+ var x = (offset.left - 0.5) * floorplan.width * floorplan.scale
+ var z = (offset.top - 0.5) * floorplan.height * floorplan.scale
+ controls.opt.center.x = -x
+ controls.opt.center.y = 0
+ controls.opt.center.z = z
+ }, true)
+
+ scene.update()
+
+ controls = new MX.OrbitCamera({
+ el: scene.el,
+ radius: 3000,
+ radiusRange: [ 10, 10000 ],
+ rotationX: PI/4,
+ rotationY: PI/2,
+ })
+ controls.init()
+ },
+
+ resize: function(){
+ if (this.parent.orbiting) {
+ scene.width = window.innerWidth/2
+ scene.height = window.innerHeight
+ this.parent.map.resize( window.innerWidth/2, window.innerHeight )
+ this.parent.map.canvas.style.display = "block"
+ }
+ else {
+ scene.width = window.innerWidth
+ scene.height = window.innerHeight
+ this.parent.map.canvas.style.display = "none"
+ }
+ },
+
+ loadFloorplan: function(media){
+ // console.log(media)
+ this.floorplan.load({
+ media: media,
+ keepImage: true,
+ rotationX: -PI/2,
+ rotationY: PI,
+ scale: media.scale,
+ })
+ this.startAnimating()
+ this.regions = RegionList.buildByShape()
+ },
+
+ animate: function(t, dt){
+ map.update(t)
+
+ movements.update(dt)
+ controls.update()
+ scene.update()
+
+ map.draw.ctx.save()
+ map.draw.translate()
+
+ this.floorplan.draw(map.draw.ctx, true)
+
+ map.draw.coords()
+
+ if (shapes.workline) {
+ shapes.workline.draw(map.draw.ctx, "rgba(255,255,0,0.1)", "#f80")
+ if (map.ui.placing && last_point) {
+ shapes.workline.draw_line( map.draw.ctx, last_point )
+ }
+ }
+
+ shapes.draw(map.draw.ctx, "rgba(255,255,0,0.1)", "#f80")
+
+ map.draw.ctx.strokeStyle = "#f00";
+ map.draw.x_at( this.parent.startPosition )
+ map.draw.mouse(map.ui.mouse.cursor)
+ map.draw.camera(scene.camera)
+
+// var colors = ["rgba(0,0,0,0.1)"]
+// var colors = ["rgba(255,255,255,1)"]
+
+// map.draw.regions(this.regions, colors, "#000")
+
+// this.regions.forEach(function(room,i){
+// map.draw.ctx.fillStyle = colors[i % colors.length]
+// map.draw.ctx.fillRect( room.x.a, room.y.a, room.width(), room.height() )
+// })
+
+ map.draw.ctx.restore()
+ },
+
+})
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintInfo.js b/public/assets/javascripts/ui/blueprint/BlueprintInfo.js
new file mode 100644
index 0000000..51b310e
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintInfo.js
@@ -0,0 +1,92 @@
+
+var BlueprintInfo = View.extend({
+ el: "#blueprintInfo",
+
+ events: {
+ "mousedown": "stopPropagation",
+ "keydown": 'stopPropagation',
+ "change [name=height]": 'changeHeight',
+ "keydown [name=height]": 'enterHeight',
+ "change [name=units]": 'changeUnits',
+ "keydown [name=viewHeight]": 'enterViewHeight',
+ "change [name=viewHeight]": 'changeViewHeight',
+ "click .openScaler": 'openScaler',
+ },
+
+ initialize: function(opt){
+ this.parent = opt.parent
+ this.$height = this.$("[name=height]")
+ this.$units = this.$("[name=units]")
+ this.$viewHeight = this.$("[name=viewHeight]")
+ this.$unitName = this.$(".unitName")
+ this.$blueprintScaleDisplay = this.$("#blueprintScaleDisplay")
+ },
+
+ load: function(data){
+ this.$viewHeight.unitVal( window.viewHeight = data.viewHeight || app.defaults.viewHeight )
+ this.$height.unitVal( window.wallHeight = data.wallHeight || app.defaults.wallHeight )
+ this.$units.val( data.units )
+ this.$('span.units').html( data.units )
+ this.$unitName.html( data.units )
+
+ var resolution
+ switch (data.units) {
+ case 'ft':
+ resolution = app.defaults.footResolution
+ break
+ case 'm':
+ resolution = app.defaults.meterResolution
+ break
+ case 'px':
+ default:
+ resolution = 1
+ break
+ }
+ this.$blueprintScaleDisplay.html( ((1/data.scale) * resolution).toFixed(1) )
+ this.show()
+ },
+
+ toggle: function(state){
+ this.$el.toggleClass("active", state)
+ this.$viewHeight.unitVal( window.viewHeight )
+ },
+
+ openScaler: function(){
+ this.parent.scaler.pick( this.parent.data, true )
+ this.parent.scaler.show()
+ },
+
+ show: function(){
+ this.toggle(true)
+ },
+
+ hide: function(){
+ this.toggle(false)
+ },
+
+ deselect: function(){
+ this.toggle(true)
+ },
+
+ enterHeight: function(e){
+ if (e.keyCode == 13) this.changeHeight(e)
+ },
+ changeHeight: function(e){
+ e.stopPropagation()
+ window.wallHeight = this.$height.unitVal()
+ shapes.forEach(function(line){
+ line.mx.set_height( window.wallHeight )
+ })
+ },
+ changeUnits: function(){
+ app.units = this.$units.val()
+ this.$('.units').resetUnitVal()
+ },
+ enterViewHeight: function(e){
+ if (e.keyCode == 13) this.changeViewHeight(e)
+ },
+ changeViewHeight: function(){
+ window.viewHeight = this.$viewHeight.unitVal()
+ }
+
+})
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintNotice.js b/public/assets/javascripts/ui/blueprint/BlueprintNotice.js
new file mode 100644
index 0000000..4b799a6
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintNotice.js
@@ -0,0 +1,62 @@
+var BlueprintNotice = View.extend(ToggleableView.prototype).extend({
+
+ el: "#blueprintNotice",
+
+ events: {
+ "click .next": "next",
+ },
+
+ initialize: function(opt){
+ this.parent = opt.parent
+ this.$notice = this.$(".notice")
+ this.$next = this.$(".next")
+ },
+
+ notice: function(msg){
+ this.$notice.html(msg)
+ },
+
+ showCreateProjectNotice: function(){
+ this.notice("<a href='/project/blueprint/" + this.parent.data.slug +
+ "'>Start a new project</a> with this blueprint.")
+ this.$next.hide()
+ this.nextFn = null
+ this.show()
+ },
+
+ showStartPositionNotice: function(){
+ this.parent.settings.hide()
+ this.notice("First, click the map to set the starting location.")
+ this.$next.show().html("Next")
+ this.show()
+ this.nextFn = this.showStartAngleNotice.bind(this)
+ },
+
+ showStartAngleNotice: function(){
+ this.parent.settings.hide()
+ this.notice("Next, rotate the camera to the desired orientation.")
+ this.$next.show().html("Done")
+ this.show()
+ this.nextFn = this.doneSettingPosition.bind(this)
+ this.parent.toolbar.toggleOrbitMode(false)
+ },
+
+ doneSettingPosition: function(){
+ this.nextFn = null
+ this.$next.hide()
+ this.hide()
+ this.parent.settings.show()
+ this.parent.startPosition.rotationX = cam.rotationX
+ this.parent.startPosition.rotationY = cam.rotationY
+ this.parent.toolbar.toggleOrbitMode(true)
+ this.parent.toolbar.orthoPolylineMode()
+ },
+
+ nextFn: null,
+ next: function(){
+ if (this.nextFn) {
+ this.nextFn()
+ }
+ },
+
+}) \ No newline at end of file
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintScaler.js b/public/assets/javascripts/ui/blueprint/BlueprintScaler.js
new file mode 100644
index 0000000..cd370ef
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintScaler.js
@@ -0,0 +1,158 @@
+
+var BlueprintScaler = ModalFormView.extend(AnimatedView.prototype).extend({
+ el: ".blueprintScaler",
+
+ fixedClose: true,
+
+ action: "/api/blueprint/scale",
+
+ events: {
+ "change [name=blueprint-dimensions]": "changeDimensions",
+ "change [name=blueprint-units]": "changeUnits",
+ "click .uploadNewBlueprint": "showUploader",
+ },
+
+ initialize: function(opt){
+ this.parent = opt.parent
+
+ this.$blueprintMap = this.$("#blueprintMap")
+ this.$blueprintDimensionsRapper = this.$("#blueprintDimensions")
+ this.$dimensions = this.$("[name=blueprint-dimensions]")
+ this.$pixels = this.$("[name=blueprint-pixels]")
+ this.$units = this.$("[name=blueprint-units]")
+ this.$save = this.$("#saveBlueprint")
+
+ this.map = new Map ({
+ type: "ortho",
+ el: this.$blueprintMap.get(0),
+ width: window.innerWidth,
+ height: window.innerHeight,
+ zoom: -2,
+ zoom_min: -7.0,
+ zoom_max: 2,
+ })
+ this.lineTool = new LineTool
+ this.map.ui.add_tool("line", this.lineTool)
+ this.map.ui.set_tool("line")
+
+ scene = scene || { camera: { x: 0, y: 0, z: 0 } }
+
+ this.floorplan = new MX.Image ()
+ },
+
+ showUploader: function(){
+ this.parent.uploader.show()
+ },
+
+ pick: function(media, shouldEdit){
+ this.media = media
+
+ this.floorplan.load({ media: media, scale: 1, keepImage: true })
+
+ if (!! media.units && ! shouldEdit) {
+ this.parent.ready(media)
+ this.hide()
+ this.stopAnimating()
+ return
+ }
+
+ if (media.units && media.line && media.scale) {
+ var points = media.line.split(",")
+ this.lineTool.line[0] = new vec2( +points[0], +points[1] )
+ this.lineTool.line[1] = new vec2( +points[2], +points[3] )
+
+ app.units = media.units
+ this.$units.val( media.units )
+ this.$dimensions.unitVal( media.scale * this.lineLength() )
+ }
+
+ this.startAnimating()
+ },
+
+ animate: function(t, dt){
+ this.map.update(t)
+
+ this.map.draw.ctx.save()
+ this.map.draw.translate()
+
+ this.floorplan.draw(this.map.draw.ctx, true)
+
+ this.map.draw.ctx.save()
+ this.map.draw.ctx.strokeStyle = "#f00"
+ this.map.draw.ctx.lineWidth = 1/map.zoom
+ switch (this.lineTool.line.length) {
+ case 1:
+ this.map.draw.line(
+ this.lineTool.line[0].a,
+ this.lineTool.line[0].b,
+ this.lineTool.cursor.x.a,
+ this.lineTool.cursor.y.a
+ )
+ break
+ case 2:
+ this.map.draw.line(
+ this.lineTool.line[0].a,
+ this.lineTool.line[0].b,
+ this.lineTool.line[1].a,
+ this.lineTool.line[1].b
+ )
+ break
+ }
+ this.map.draw.ctx.restore()
+
+ this.map.draw.coords()
+
+ this.map.draw.mouse(this.map.ui.mouse.cursor)
+
+ this.map.draw.ctx.restore()
+ },
+
+ changeDimensions: function(){
+ app.units = this.$units.val()
+ this.$dimensions.unitVal()
+ },
+ changeUnits: function(){
+ app.units = this.$units.val()
+ this.$dimensions.resetUnitVal()
+ },
+ lineLength: function(){
+ if (this.lineTool.line.length !== 2) return 0
+ var line = this.lineTool.line
+ return dist( line[0].a, line[0].b, line[1].a, line[1].b )
+ },
+
+ validate: function(){
+ var val = this.$dimensions.unitVal()
+ var errors = []
+ if (! this.lineLength()) {
+ errors.push("no line")
+ this.$dimensions.val("")
+ alert("Please click two corners of a wall and then specify how long it is in feet or meters.")
+ }
+ else if (val == 0) {
+ errors.push("no measurement")
+ alert("Please tell us how long the wall is in feet or meters.")
+ }
+ return errors
+ },
+
+ showErrors: function(){},
+
+ serialize: function(){
+ var fd = new FormData(), line = this.lineTool.line
+ fd.append( "_id", this.media._id)
+ fd.append( "units", this.$units.val() )
+ fd.append( "scale", this.$dimensions.unitVal() / this.lineLength() )
+ fd.append( "line", [line[0].a,line[0].b,line[1].a,line[1].b].join(",") )
+ fd.append( "_csrf", $("[name=_csrf]").val())
+ return fd
+ },
+
+ success: function(){
+ this.media.scale = this.$dimensions.unitVal() / this.lineLength()
+ this.stopAnimating()
+ this.parent.ready(this.media)
+ this.hide()
+ },
+
+})
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintSettings.js b/public/assets/javascripts/ui/blueprint/BlueprintSettings.js
new file mode 100644
index 0000000..8addb9c
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintSettings.js
@@ -0,0 +1,123 @@
+
+var BlueprintSettings = FormView.extend(ToggleableView.prototype).extend({
+ el: "#blueprintSettings",
+
+ action: "/api/blueprint/edit",
+ destroyAction: "/api/blueprint/destroy",
+
+ events: {
+ "mousedown": "stopPropagation",
+ "keydown": 'stopPropagation',
+ "keydown [name=name]": 'enterSubmit',
+ "click [data-role='save-layout']": 'clickSave',
+ "click [data-role='clear-layout']": 'clear',
+ "click [data-role='destroy-layout']": 'destroy',
+ },
+
+ initialize: function(opt){
+ this.parent = opt.parent
+ this.__super__.initialize.call(this)
+
+ this.$id = this.$("[name=_id]")
+ this.$csrf = this.$("[name=_csrf]")
+ this.$name = this.$("[name=name]")
+ },
+
+ load: function(data){
+ this.$id.val(data._id)
+ if (data.name) {
+ this.$name.val(data.name)
+ this.hide()
+ }
+ else {
+ this.$name.val("")
+ }
+ if (data.shapes) {
+ shapes.destroy()
+ shapes.deserialize( data.shapes )
+ shapes.build()
+ }
+ },
+
+ clear: function(){
+ shapes.destroy()
+ },
+
+ destroy: function(){
+ var msg = "Are you sure you want to delete the blueprint " + sanitize(this.$name.val()) + "?"
+ ConfirmModal.confirm(msg, function(){
+ $.ajax({
+ url: this.destroyAction,
+ type: "delete",
+ data: { _id: this.$id.val(), _csrf: this.$csrf.val() },
+ success: function(data){
+ window.location.href = "/layout"
+ }
+ })
+ }.bind(this))
+ },
+
+ enterSubmit: function (e) {
+ e.stopPropagation()
+ var base = this
+ if (e.keyCode == 13) {
+ setTimeout(function(){ base.save(e) }, 100)
+ }
+ },
+
+ validate: function(){
+ var errors = []
+ var name = this.$name.val()
+ if (! name || ! name.length) {
+ errors.push("Blueprint needs a name.")
+ }
+ if (shapes.count() == 0) {
+ errors.push("Please add some walls.")
+ }
+ return errors
+ },
+
+ showErrors: function(errors){
+ var $errors = $("<span>")
+ errors.forEach(function(err){
+ var $row = $("<div>")
+ $row.html(err)
+ $errors.append( $row )
+ })
+ ErrorModal.alert($errors)
+ },
+
+ serialize: function(){
+ var fd = new FormData()
+ fd.append( "_csrf", this.$csrf.val() )
+ fd.append( "_id", this.$id.val() )
+ fd.append( "name", this.$name.val() )
+ fd.append( "shapes", JSON.stringify( shapes.serialize() ) )
+ fd.append( "startPosition", JSON.stringify( this.parent.quantizeStartPosition() ) )
+ fd.append( "wallHeight", this.parent.info.$height.unitVal() )
+ fd.append( "units", this.parent.info.$units.val() )
+ return fd
+ },
+
+ clickSave: function(){
+ this.toggle(false)
+ this.save()
+ },
+
+ success: function(data){
+ this.parent.data = data
+
+ this.$id.val(data._id)
+ this.$name.val(data.name)
+ this.action = this.updateAction
+
+ this.hide()
+ this.parent.notice.showCreateProjectNotice()
+
+ Minotaur.unwatch(this)
+ Minotaur.hide()
+
+ window.history.pushState(null, document.title, "/blueprint/" + data.slug)
+ },
+
+})
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintToolbar.js b/public/assets/javascripts/ui/blueprint/BlueprintToolbar.js
new file mode 100644
index 0000000..458357d
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintToolbar.js
@@ -0,0 +1,97 @@
+var BlueprintToolbar = View.extend({
+
+ el: "#blueprintToolbar",
+
+ events: {
+ "click [data-role=upload-floorplan]": 'showUploader',
+ "click [data-role=toggle-orbit-mode]": 'toggleOrbitMode',
+ "click [data-role=arrow-mode]": 'arrowMode',
+ "click [data-role=polyline-mode]": 'polylineMode',
+ "click [data-role=ortho-polyline-mode]": 'orthoPolylineMode',
+ "click [data-role=eraser-mode]": 'eraserMode',
+ "click [data-role=start-position-mode]": 'startPositionMode',
+ "click [data-role=toggle-layout-settings]": 'toggleSettings',
+ },
+
+ initialize: function(opt){
+ this.parent = opt.parent
+
+ this.$modes = this.$('.mode')
+ this.$toggleOrbitMode = this.$('[data-role=toggle-orbit-mode]')
+ this.$arrowMode = this.$('[data-role=arrow-mode]')
+ this.$polylineMode = this.$('[data-role=polyline-mode]')
+ this.$orthoPolylineMode = this.$('[data-role=ortho-polyline-mode]')
+ this.$eraserMode = this.$('[data-role=eraser-mode]')
+ this.$startPositionMode = this.$('[data-role=start-position-mode]')
+
+ keys.on('escape', function(){
+ app.controller.toolbar.toggleOrbitMode()
+ })
+
+ this.arrowMode()
+ },
+
+ showUploader: function(){
+ this.parent.scaler.show()
+ this.parent.uploader.show()
+ },
+
+ toggleOrbitMode: function(state){
+ this.parent.orbiting = typeof state == "boolean" ? state : ! this.parent.orbiting
+ this.$toggleOrbitMode.toggleClass("inuse", ! this.parent.orbiting)
+ this.parent.editor.resize()
+ if (this.parent.orbiting) {
+ controls.toggle(true)
+ movements.lock()
+ }
+ else {
+ controls.toggle(false)
+ movements.unlock()
+ movements.gravity(true)
+ var pos = this.parent.quantizeStartPosition()
+ cam.rotationX = pos.rotationX
+ cam.rotationY = pos.rotationY
+ cam.x = pos.x
+ cam.y = viewHeight
+ cam.z = pos.z
+ }
+ },
+
+ toggleSettings: function(){
+ this.parent.settings.toggle()
+ this.parent.notice.toggle( ! this.parent.data.isNew && ! this.parent.settings.visible() )
+ },
+
+ setActiveMode: function( $el ) {
+ this.$modes.removeClass('active')
+ $el.addClass('active')
+ },
+
+ arrowMode: function(){
+ this.setActiveMode( this.$arrowMode )
+ this.parent.map.ui.set_tool("arrow")
+ },
+
+ polylineMode: function(){
+ this.setActiveMode( this.$polylineMode )
+ this.parent.map.ui.set_tool("polyline")
+ },
+
+ orthoPolylineMode: function(){
+ this.setActiveMode( this.$orthoPolylineMode )
+ this.parent.map.ui.set_tool("ortho-polyline")
+ },
+
+ eraserMode: function(){
+ this.setActiveMode( this.$eraserMode )
+ this.parent.map.ui.set_tool("eraser")
+ },
+
+ startPositionMode: function(){
+ this.setActiveMode( this.$startPositionMode )
+ this.parent.map.ui.set_tool("start-position")
+ this.parent.settings.hide()
+ this.parent.notice.showStartPositionNotice()
+ },
+
+}) \ No newline at end of file
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintUploader.js b/public/assets/javascripts/ui/blueprint/BlueprintUploader.js
new file mode 100644
index 0000000..aa62a4c
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintUploader.js
@@ -0,0 +1,147 @@
+
+var BlueprintUploader = UploadView.extend({
+ el: ".blueprintUploader",
+
+ mediaTag: "blueprint",
+ createAction: "/api/blueprint/new",
+ uploadAction: "/api/blueprint/upload",
+ listAction: "/api/blueprint/user",
+ destroyAction: "/api/blueprint/destroy",
+
+ events: {
+ "mousedown": 'stopPropagation',
+ "change .url": "enterUrl",
+ "keydown .url": "enterSetUrl",
+
+ "click .blueprint": "pick",
+ "click .remove": "destroy",
+ },
+
+ initialize: function(opt){
+ this.parent = opt.parent
+ this.__super__.initialize.call(this)
+
+ this.$url = this.$(".url")
+ this.$blueprints = this.$(".blueprints")
+ },
+
+ loaded: false,
+ nameToShow: null,
+ load: function(name){
+ this.nameToShow = name || ""
+ $.get(this.listAction, { tag: this.mediaTag }, this.populate.bind(this))
+ },
+
+ populate: function(data){
+ this.loaded = true
+ if (data && data.length) {
+ this.$blueprints.show()
+ data.forEach(this.append.bind(this))
+ if (this.nameToShow === "new") {
+ // don't pick anything..
+ this.show()
+ }
+ else if (! this.nameToShow) {
+ this.hide()
+ data.some(function(el){
+ if (el.slug == this.nameToShow) {
+ this.parent.scaler.pick(el)
+ return true
+ }
+ }.bind(this))
+ }
+ else {
+ this.hide()
+ this.parent.scaler.pick(data[0])
+ }
+ }
+ else {
+ this.parent.scaler.hideClose()
+ this.show()
+ }
+ },
+
+ pick: function(e){
+ var $el = $(e.currentTarget)
+ var media = $el.data("media")
+ this.hide()
+ this.parent.scaler.pick(media)
+ if (media.slug) {
+ window.history.pushState(null, document.title, "/blueprint/" + media.slug)
+ }
+ },
+
+ destroy: function(e){
+ e.stopPropagation()
+ var $el = $(e.currentTarget)
+ var _id = $el.closest(".blueprint").data("id")
+ $el.remove()
+ $.ajax({
+ type: "delete",
+ url: this.destroyAction,
+ data: { _id: _id, _csrf: $("[name=_csrf]").val() }
+ }).complete(function(){
+ })
+ },
+
+ show: function(){
+ this.toggle(true)
+ },
+ hide: function(){
+ this.toggle(false)
+ },
+ toggle: function (state) {
+ this.$el.toggleClass("active", state)
+ },
+
+ addUrl: function (url){
+ Parser.loadImage(url, function(media){
+ if (! media) return
+ media._csrf = $("[name=_csrf]").val()
+ media.tag = this.mediaTag
+
+ var request = $.ajax({
+ type: "post",
+ url: this.createAction,
+ data: media,
+ })
+ request.done(this.add.bind(this))
+
+ }.bind(this))
+ },
+ enterUrl: function(){
+ var url = this.$url.sanitize()
+ this.addUrl(url)
+ this.$url.val("")
+ },
+ enterSetUrl: function (e) {
+ e.stopPropagation()
+ if (e.keyCode == 13) {
+ setTimeout(this.enterUrl.bind(this), 100)
+ }
+ },
+
+ add: function(media){
+ this.$blueprints.show()
+ this.append(media)
+ this.hide()
+ this.parent.scaler.pick(media, true)
+ },
+
+ append: function(media){
+ var $el = $("<span>")
+ var img = new Image ()
+ img.src = media.url
+ var remove = document.createElement("span")
+ remove.className = "remove"
+ remove.innerHTML = "<span>x</span>"
+
+ $el.data("id", media._id)
+ $el.data("media", media)
+ $el.append(img)
+ $el.append(remove)
+ $el.addClass("blueprint")
+ this.$blueprints.append($el)
+ },
+
+})
diff --git a/public/assets/javascripts/ui/blueprint/BlueprintView.js b/public/assets/javascripts/ui/blueprint/BlueprintView.js
new file mode 100644
index 0000000..1858c3d
--- /dev/null
+++ b/public/assets/javascripts/ui/blueprint/BlueprintView.js
@@ -0,0 +1,106 @@
+
+var BlueprintView = View.extend({
+ el: "#blueprintView",
+
+ action: "/api/blueprint/show/",
+
+ events: {
+ },
+
+ initialize: function(){
+// this.colorControl = new ColorControl ({ parent: this })
+// this.cursor = new HelpCursor({ parent: this })
+ this.map = this.buildMap()
+ this.editor = new BlueprintEditor ({ parent: this })
+ this.toolbar = new BlueprintToolbar ({ parent: this })
+ this.uploader = new BlueprintUploader ({ parent: this })
+ this.scaler = new BlueprintScaler ({ parent: this })
+ this.info = new BlueprintInfo ({ parent: this })
+ this.settings = new BlueprintSettings ({ parent: this })
+ this.notice = new BlueprintNotice ({ parent: this })
+ Rooms.shapesMode = true
+ },
+
+ load: function(name){
+ name = sanitize(name) || "new"
+ this.uploader.load(name)
+// name = sanitize(name)
+// $.get(this.action + name, this.ready.bind(this))
+ },
+
+ orbiting: true,
+ startPosition: {},
+ quantizeStartPosition: function(){
+ //
+ var regions = RegionList.build()
+ var pos = this.startPosition
+ var startPositionIsInARoom = regions.some(function(region){
+ return region.contains(pos.x, pos.z)
+ })
+ if (startPositionIsInARoom) {
+ return this.startPosition
+ }
+ else if (! regions.length) {
+ return {
+ x: 0,
+ y: viewHeight,
+ z: 0,
+ rotationX: 0,
+ rotationY: Math.PI/2,
+ }
+ }
+ else {
+ var center = regions[0].center()
+ return {
+ x: center.a,
+ y: viewHeight,
+ z: center.b,
+ rotationX: 0,
+ rotationY: Math.PI/2,
+ }
+ }
+ },
+
+ buildMap: function(){
+ // i forget if this has to be global
+ map = new Map ({
+ type: "ortho",
+ el: document.querySelector("#orthographic"),
+ width: window.innerWidth/2,
+ height: window.innerHeight,
+ zoom: -2,
+ zoom_min: -6.2,
+ zoom_max: 1,
+ })
+ map.ui.add_tool("arrow", new ArrowTool)
+ map.ui.add_tool("polyline", new PolylineTool)
+ map.ui.add_tool("ortho-polyline", new OrthoPolylineTool)
+ map.ui.add_tool("eraser", new EraserTool)
+ map.ui.add_tool("position", new PositionTool)
+ map.ui.add_tool("start-position", new StartPositionTool)
+ map.ui.placing = false
+ return map
+ },
+
+ ready: function(data){
+ this.data = data
+ this.info.load(data)
+ this.settings.load(data)
+ this.editor.loadFloorplan(data)
+ if (! data.shapes || data.shapes.length == 0) {
+ this.startPosition = { x: 0, y: 0, z: 0, rotationX: 0, rotationY: Math.PI/2 }
+ }
+ else {
+ this.startPosition = data.startPosition
+ }
+ this.notice.hide()
+ this.settings.show()
+ },
+
+ hideExtras: function(){
+ },
+
+ pickWall: function(wall, pos){
+ },
+
+})
diff --git a/public/assets/javascripts/ui/builder/BuilderInfo.js b/public/assets/javascripts/ui/builder/BuilderInfo.js
index 9a7dbf9..aa58d6e 100644
--- a/public/assets/javascripts/ui/builder/BuilderInfo.js
+++ b/public/assets/javascripts/ui/builder/BuilderInfo.js
@@ -40,8 +40,8 @@ var BuilderInfo = View.extend({
load: function(data){
this.$viewHeight.unitVal( window.viewHeight = data.viewHeight || app.defaults.viewHeight )
- this.$units.val( "ft" )
- this.$unitName.html( "ft" )
+ this.$units.val( data.units || "ft" )
+ this.$unitName.html( data.units || "ft" )
if (Rooms.regions.length == 0) {
this.changeHeightGlobal(true)
diff --git a/public/assets/javascripts/ui/builder/BuilderSettings.js b/public/assets/javascripts/ui/builder/BuilderSettings.js
index c8c8880..256bffe 100644
--- a/public/assets/javascripts/ui/builder/BuilderSettings.js
+++ b/public/assets/javascripts/ui/builder/BuilderSettings.js
@@ -52,7 +52,7 @@ var BuilderSettings = FormView.extend({
this.$name.val( names.join(" ") )
this.action = this.createAction
- window.history.pushState(null, document.title, "/builder/new")
+ window.history.pushState(null, document.title, "/layout/new")
},
clear: function(){
diff --git a/public/assets/javascripts/ui/builder/BuilderToolbar.js b/public/assets/javascripts/ui/builder/BuilderToolbar.js
index 6c218be..e9dcce3 100644
--- a/public/assets/javascripts/ui/builder/BuilderToolbar.js
+++ b/public/assets/javascripts/ui/builder/BuilderToolbar.js
@@ -60,6 +60,9 @@ var BuilderToolbar = View.extend({
var state = map.ui.permissions.toggle("destroy")
$(".inuse").removeClass("inuse")
$(e.currentTarget).toggleClass("inuse", state)
+ if (! state) {
+ this.resetPermissions()
+ }
},
})
diff --git a/public/assets/javascripts/ui/editor/EditorSettings.js b/public/assets/javascripts/ui/editor/EditorSettings.js
index b319404..5aa88e9 100644
--- a/public/assets/javascripts/ui/editor/EditorSettings.js
+++ b/public/assets/javascripts/ui/editor/EditorSettings.js
@@ -41,7 +41,12 @@ var EditorSettings = FormView.extend({
this.action = data.isNew ? this.createAction : this.updateAction
this.parent.data = data
- data.rooms && Rooms.deserialize(data.rooms, data.walls)
+ if (data.shapes && data.shapes.length) {
+ Rooms.deserializeFromShapes(data, data.walls)
+ }
+ else if (data.rooms) {
+ Rooms.deserialize(data.rooms, data.walls)
+ }
if (data.startPosition) {
scene.camera.move(data.startPosition)
this.startPosition = data.startPosition
@@ -77,6 +82,7 @@ var EditorSettings = FormView.extend({
data.privacy && this.$privacy.find("[value=" + data.privacy + "]").prop("checked", "checked")
data.media && Scenery.deserialize(data.media)
+ data.sculpture && Sculpture.deserialize(data.sculpture)
}
},
@@ -112,6 +118,7 @@ var EditorSettings = FormView.extend({
clear: function(e){
e.preventDefault()
Scenery.removeAll()
+ Sculpture.removeAll()
},
destroy: function(){
@@ -187,10 +194,16 @@ var EditorSettings = FormView.extend({
fd.append( "description", this.$description.val() )
fd.append( "privacy", this.$privacy.filter(":checked").val() == "private" )
fd.append( "viewHeight", window.viewHeight )
- fd.append( "rooms", JSON.stringify( Rooms.serialize() ) )
+ if (Rooms.shapesMode) {
+ fd.append( "shapes", JSON.stringify( shapes.serialize() ) )
+ }
+ else {
+ fd.append( "rooms", JSON.stringify( Rooms.serialize() ) )
+ }
fd.append( "walls", JSON.stringify( Walls.serialize() ) )
fd.append( "colors", JSON.stringify( Walls.colors ) )
fd.append( "media", JSON.stringify( Scenery.serialize() ) )
+ fd.append( "sculpture", JSON.stringify( Sculpture.serialize() ) )
fd.append( "startPosition", JSON.stringify( this.startPosition || false ) )
fd.append( "lastPosition", JSON.stringify( app.position(scene.camera) ) )
diff --git a/public/assets/javascripts/ui/editor/EditorView.js b/public/assets/javascripts/ui/editor/EditorView.js
index 50d3650..c05b373 100644
--- a/public/assets/javascripts/ui/editor/EditorView.js
+++ b/public/assets/javascripts/ui/editor/EditorView.js
@@ -2,6 +2,7 @@
var EditorView = View.extend({
el: "#editorView",
+ blueprintAction: "/api/blueprint/user/",
projectAction: "/api/project/",
layoutAction: "/api/layout/",
@@ -17,6 +18,7 @@ var EditorView = View.extend({
this.mediaUpload = new MediaUpload ({ parent: this })
this.mediaTumblr = new MediaTumblr ({ parent: this })
this.mediaEditor = new MediaEditor ({ parent: this })
+ this.sculptureEditor = new SculptureEditor ({ parent: this })
this.wallpaperPicker = new WallpaperPicker ({ parent: this })
this.colorControl = new ColorControl ({ parent: this })
this.textEditor = new TextEditor ({ parent: this })
@@ -40,6 +42,10 @@ var EditorView = View.extend({
$.get(this.layoutAction + layout, this.readyLayout.bind(this))
},
+ loadBlueprint: function(blueprint){
+ $.get(this.blueprintAction + blueprint, this.readyLayout.bind(this))
+ },
+
ready: function(data){
$("#map").hide()
@@ -56,12 +62,19 @@ var EditorView = View.extend({
},
pick: function(scenery){
- if (scenery.type == "text") {
+ if (scenery.isSculpture) {
+ this.mediaEditor.hide()
+ this.textEditor.hide()
+ this.sculptureEditor.pick(scenery)
+ }
+ else if (scenery.type == "text") {
this.mediaEditor.hide()
+ this.sculptureEditor.hide()
this.textEditor.pick(scenery)
}
else {
this.textEditor.hide()
+ this.sculptureEditor.hide()
this.mediaEditor.pick(scenery)
}
},
@@ -72,9 +85,11 @@ var EditorView = View.extend({
},
hideExtras: function(){
+ this.sculptureEditor.hide()
this.mediaEditor.hide()
this.textEditor.hide()
this.share.hide()
+ Sculpture.resize.hide()
Scenery.resize.hide()
Scenery.hovering = false
}
diff --git a/public/assets/javascripts/ui/editor/SculptureEditor.js b/public/assets/javascripts/ui/editor/SculptureEditor.js
new file mode 100644
index 0000000..953260c
--- /dev/null
+++ b/public/assets/javascripts/ui/editor/SculptureEditor.js
@@ -0,0 +1,237 @@
+
+var SculptureEditor = FormView.extend({
+ el: "#sculptureEditor",
+
+ events: {
+ "keydown": 'taint',
+ "focus [name]": "clearMinotaur",
+ "click [data-role=play-media]": "togglePaused",
+ "mousedown [name=keyframe]": "stopPropagation",
+ "mousedown": "stopPropagation",
+ "change [name=keyframe]": "seek",
+ "change [name=autoplay]": "setAutoplay",
+ "change [name=billboard]": "setBillboard",
+ "change [name=outline]": "setOutline",
+ "change [name=outlineColor]": "setOutlineColor",
+ "change [name=loop]": "setLoop",
+ "change [name=mute]": "setMute",
+ "change [name=width]": 'changeWidth',
+ "change [name=height]": 'changeHeight',
+ "change [name=depth]": 'changeDepth',
+ "change [name=units]": 'changeUnits',
+ "click [data-role=destroy-sculpture]": "destroy",
+ },
+
+ initialize: function(opt){
+ this.parent = opt.parent
+ this.__super__.initialize.call(this)
+
+ this.$name = this.$("[name=name]")
+ this.$description = this.$("[name=description]")
+
+ this.$billboard = this.$("[name=billboard]")
+ this.$outline = this.$("[name=outline]")
+ this.$outlineColor = this.$("[name=outlineColor]")
+
+ // image fields
+ this.$width = this.$("[name=width]")
+ this.$height = this.$("[name=height]")
+ this.$depth = this.$("[name=depth]")
+ this.$units = this.$("[name=units]")
+
+ // video fields
+ this.$playButton = this.$("[data-role=play-media]")
+ this.$autoplay = this.$("[name=autoplay]")
+ this.$loop = this.$("[name=loop]")
+ this.$mute = this.$("[name=mute]")
+ this.$keyframe = this.$("[name=keyframe]")
+ },
+
+ toggle: function(state) {
+ if (state) {
+ this.parent.settings.toggle()
+ }
+ this.$el.toggleClass("active", state);
+ },
+
+ togglePaused: function(state){
+ var state = this.sculpture.toggle(state)
+ this.$playButton.toggleClass("paused", ! state)
+ },
+
+ pick: function(sculpture) {
+ if (this.sculpture && sculpture !== this.sculpture) {
+ this.unbind()
+ }
+
+ this.bind(sculpture)
+ this.$el.addClass("active")
+
+// app.controller.toolbar.resetMode()
+ app.controller.toolbar.resetControls()
+ Sculpture.resize.show(sculpture)
+ Sculpture.hovering = true
+
+ var media = sculpture.media
+
+ // console.log(media)
+ this.$name.val(media.title || "") // || filenameFromUrl(media.url) )
+ this.$description.val(media.description || "")
+ this.setDimensions()
+ this.$units.val( "ft" )
+
+ this.$outline.prop( 'checked', !! sculpture.outline )
+ this.$outlineColor.val( sculpture.outlineColor || "#000000" )
+ this.$billboard.prop( 'checked', !! sculpture.billboard )
+
+ switch (media.type) {
+ case "image":
+ this.$(".video").hide()
+ this.$(".audio").hide()
+ this.$(".image").show()
+ break
+
+ case "youtube":
+ case "vimeo":
+ case "video":
+ this.$(".image").hide()
+ this.$(".audio").hide()
+ this.$(".video").show()
+
+ this.$playButton.toggleClass("paused", ! this.sculpture.paused())
+ this.$autoplay.prop('checked', !! media.autoplay)
+ this.$loop.prop('checked', !! media.loop)
+ this.$mute.prop('checked', !! media.mute)
+ this.$keyframe.val( Number(media.keyframe || 0) )
+ break
+
+ case "soundcloud":
+ this.$(".image").hide()
+ this.$(".video").hide()
+ this.$(".audio").show()
+ this.$playButton.toggleClass("paused", ! this.sculpture.paused())
+ this.$autoplay.prop('checked', !! media.autoplay)
+ this.$loop.prop('checked', !! media.loop)
+ break
+ }
+ },
+
+ hide: function(sculpture){
+ if (this.sculpture) {
+ this.unbind()
+ }
+ this.toggle(false)
+ },
+
+ seek: function(){
+ var n = parseFloat( this.$keyframe.val() )
+ this.sculpture.seek(n)
+ this.tainted = true
+
+ this.sculpture.media.keyframe = n
+ },
+ setAutoplay: function(){
+ var checked = this.$autoplay.prop('checked')
+ this.sculpture.media.autoplay = checked
+ this.tainted = true
+ if (checked && this.sculpture.paused()) {
+ this.togglePaused()
+ }
+ },
+ setLoop: function(){
+ var checked = this.$loop.prop('checked')
+ this.sculpture.setLoop(checked)
+ this.tainted = true
+ },
+ setMute: function(){
+ var checked = this.$mute.prop('checked')
+ this.sculpture.media.mute = checked
+ this.sculpture.mute(checked)
+ this.tainted = true
+ },
+
+ setBillboard: function(){
+ var checked = this.$billboard.prop('checked')
+ this.sculpture.setBillboard(checked)
+ this.tainted = true
+ },
+ setOutline: function(){
+ var checked = this.$outline.prop('checked')
+ this.sculpture.setOutline(checked)
+ this.tainted = true
+ },
+ setOutlineColor: function(){
+ var color = this.$outlineColor.val()
+ this.sculpture.setOutlineColor(color)
+ this.tainted = true
+ },
+
+ setDimensions: function(){
+ if (! this.sculpture) return
+ this.$width.unitVal( Number(this.sculpture.naturalDimensions.a * this.sculpture.scale) || "" )
+ this.$height.unitVal( Number(this.sculpture.naturalDimensions.b * this.sculpture.scale) || "" )
+ this.$depth.unitVal( Number(this.sculpture.naturalDimensions.c * this.sculpture.scale) || "" )
+ this.tainted = true
+ },
+ changeWidth: function(e){
+ e.stopPropagation()
+ this.sculpture.set_scale( this.$width.unitVal() / this.sculpture.naturalDimensions.a )
+ this.setDimensions()
+ this.sculpture.updateOutline()
+ },
+ changeHeight: function(e){
+ e.stopPropagation()
+ this.sculpture.set_scale( this.$height.unitVal() / this.sculpture.naturalDimensions.b )
+ this.setDimensions()
+ this.sculpture.updateOutline()
+ },
+ changeDepth: function(e){
+ e.stopPropagation()
+ this.sculpture.set_depth( this.$depth.unitVal() )
+ this.$depth.unitVal( Number(this.sculpture.naturalDimensions.c * this.sculpture.scale) || "" )
+ this.sculpture.updateOutline()
+ },
+ changeUnits: function(){
+ app.units = this.$units.val()
+ this.$('.units').resetUnitVal()
+ },
+
+ taint: function(e){
+ e.stopPropagation()
+ this.tainted = true
+ },
+
+ bind: function(sculpture){
+ this.sculpture = sculpture
+ this.sculpture.mx.bound = true
+ this.sculpture.mx.el.classList.add("picked")
+ },
+
+ unbind: function(){
+ if (this.sculpture) {
+ this.sculpture.focused = false
+ if (this.tainted && this.sculpture.media) {
+ this.sculpture.media.title = this.$name.val()
+ this.sculpture.media.description = this.$description.val()
+ Minotaur.watch( app.router.editorView.settings )
+ }
+ if (this.sculpture.mx) {
+ this.sculpture.mx.bound = false
+ this.sculpture.mx.el.classList.remove("picked")
+ }
+ }
+ this.tainted = false
+ this.sculpture = null
+ },
+
+ destroy: function(){
+ var sculpture = this.sculpture
+ this.hide()
+
+ sculpture.remove()
+
+ this.tainted = false
+ this.sculpture = null
+ },
+
+})
diff --git a/public/assets/javascripts/ui/lib/AnimatedView.js b/public/assets/javascripts/ui/lib/AnimatedView.js
new file mode 100644
index 0000000..3c50b0a
--- /dev/null
+++ b/public/assets/javascripts/ui/lib/AnimatedView.js
@@ -0,0 +1,31 @@
+var AnimatedView = View.extend({
+
+ _animating: false,
+ last_t: 0,
+
+ startAnimating: function(){
+ if (this._animating) return
+ this._animating = true
+ this._animate()
+ },
+
+ stopAnimating: function(){
+ this._animating = false
+ },
+
+ _animate: function(t){
+ if (! this._animating) return
+
+ requestAnimationFrame(this._animate.bind(this))
+
+ var dt = t - this.last_t
+ this.last_t = t
+
+ if (! t) return
+
+ this.animate(t, dt)
+ },
+
+ animate: function(t, dt){},
+
+}) \ No newline at end of file
diff --git a/public/assets/javascripts/ui/lib/ConfirmModal.js b/public/assets/javascripts/ui/lib/ConfirmModal.js
index a72b31e..7d9da67 100644
--- a/public/assets/javascripts/ui/lib/ConfirmModal.js
+++ b/public/assets/javascripts/ui/lib/ConfirmModal.js
@@ -4,21 +4,31 @@ var ConfirmModal = new( ModalFormView.extend({
el: ".mediaDrawer.confirm",
events: {
- "click .yes": "advance",
- "click .no": "hide",
+ "click .yes": "agree",
+ "click .no": "cancel",
},
- confirm: function(question, callback){
+ confirm: function(question, agreeCallback, cancelCallback){
this.$(".question").empty().append(question)
- this.callback = callback
+ this.agreeCallback = agreeCallback
+ this.cancelCallback = cancelCallback
this.show()
},
- advance: function(e){
+ agree: function(e){
e && e.preventDefault()
this.hide()
- this.callback && this.callback()
- this.callback = null
+ this.agreeCallback && this.agreeCallback()
+ this.agreeCallback = null
+ this.cancelCallback = null
+ },
+
+ cancel: function(e){
+ e && e.preventDefault()
+ this.hide()
+ this.cancelCallback && this.cancelCallback()
+ this.agreeCallback = null
+ this.cancelCallback = null
}
}) ) \ No newline at end of file
diff --git a/public/assets/javascripts/ui/lib/FormView.js b/public/assets/javascripts/ui/lib/FormView.js
index f5845e7..a952ecb 100644
--- a/public/assets/javascripts/ui/lib/FormView.js
+++ b/public/assets/javascripts/ui/lib/FormView.js
@@ -63,13 +63,15 @@ var FormView = View.extend({
save: function(e, successCallback, errorCallback){
e && e.preventDefault()
- this.$errors.hide().css("opacity", 0.0);
+ this.$errors && this.$errors.hide().css("opacity", 0.0);
if (this.validate) {
var errors = this.validate()
if (errors && errors.length) {
if (errorCallback) {
- errorCallback(errors)
+ setTimeout(function(){
+ errorCallback(errors)
+ })
}
else {
this.showErrors(errors)
@@ -77,7 +79,6 @@ var FormView = View.extend({
return
}
}
-
var action = typeof this.action == "function" ? this.action() : this.action
if (! action) return
@@ -112,7 +113,9 @@ var FormView = View.extend({
return
}
else {
+ console.log("ok")
if (successCallback) {
+ console.log("use cb")
successCallback(response)
}
if (this.success) {
diff --git a/public/assets/javascripts/ui/lib/LabColorPicker.js b/public/assets/javascripts/ui/lib/LabColorPicker.js
index 7ddcdd5..2c8fb90 100644
--- a/public/assets/javascripts/ui/lib/LabColorPicker.js
+++ b/public/assets/javascripts/ui/lib/LabColorPicker.js
@@ -1,9 +1,12 @@
var LabColorPicker = function (parent, w, h) {
var base = this
var canvas = this.canvas = document.createElement('canvas')
- var ctx = this.ctx = canvas.getContext('2d')
- var imageData = ctx.createImageData(w,h)
- var data = imageData.data
+ canvas.width = w
+ canvas.height = h
+ var ctx = this.ctx = canvas.getContext('2d-lodpi')
+// canvas.className = "colorPicker"
+// var imageData = ctx.createImageData(w, h)
+// var data = imageData.data
var cursor = this.cursor = document.createElement("div")
cursor.className = "colorPickerCursor"
@@ -15,10 +18,6 @@ var LabColorPicker = function (parent, w, h) {
brightnessControl.setAttribute("max", "110")
brightnessControl.setAttribute("value", "0")
- canvas.width = w
- canvas.height = h
- canvas.className = "colorPicker"
-
var ww = w-1
var hh = h-1
@@ -84,11 +83,14 @@ var LabColorPicker = function (parent, w, h) {
}
this.paint = function() {
val = clamp(val, L_range[0], L_range[1])
- var x, y, t
- for (var i = 0; i < w; i++) {
- for (var j = 0; j < h; j++) {
- x = mix( i/ww, a_range[0], a_range[1] )
- y = mix( j/hh, b_range[0], b_range[1] )
+ var imageData = ctx.createImageData(canvas.width, canvas.height)
+ var data = imageData.data
+ var x, y, t, cw = imageData.width, ch = imageData.height
+ var cww = cw-1, chh = ch-1
+ for (var i = 0; i < cw; i++) {
+ for (var j = 0; j < ch; j++) {
+ x = mix( i/cww, a_range[0], a_range[1] )
+ y = mix( j/chh, b_range[0], b_range[1] )
t = (j*w + i) * 4
rgb = xyz2rgb(hunterlab2xyz(val, x, y))
data[t] = Math.round( rgb[0] )
diff --git a/public/assets/javascripts/ui/lib/ModalView.js b/public/assets/javascripts/ui/lib/ModalView.js
index 6f1c729..e0070ce 100644
--- a/public/assets/javascripts/ui/lib/ModalView.js
+++ b/public/assets/javascripts/ui/lib/ModalView.js
@@ -35,6 +35,11 @@ var ModalView = View.extend({
$("body").removeClass("noOverflow");
},
+ hideClose: function(){
+ $("#fixed_close").removeClass("active")
+ $("#fixed_close").unbind("click", this.hide.bind(this))
+ },
+
close: function(){
if (window.isModalView) {
window.location.pathname = "/"
diff --git a/public/assets/javascripts/ui/lib/ToggleableView.js b/public/assets/javascripts/ui/lib/ToggleableView.js
new file mode 100644
index 0000000..371629f
--- /dev/null
+++ b/public/assets/javascripts/ui/lib/ToggleableView.js
@@ -0,0 +1,19 @@
+var ToggleableView = View.extend({
+
+ toggle: function(state){
+ this.$el.toggleClass("active", state)
+ },
+
+ show: function(){
+ this.toggle(true)
+ },
+
+ hide: function(){
+ this.toggle(false)
+ },
+
+ visible: function(){
+ return this.$el.hasClass("active")
+ }
+
+}) \ No newline at end of file
diff --git a/public/assets/javascripts/ui/lib/Toolbar.js b/public/assets/javascripts/ui/lib/Toolbar.js
new file mode 100644
index 0000000..a9ce51c
--- /dev/null
+++ b/public/assets/javascripts/ui/lib/Toolbar.js
@@ -0,0 +1,22 @@
+var Toolbar = Fiber.extend(function(base){
+ var exports = {}
+ exports.init = function(rapper){
+ this.rapper = (typeof rapper == "string") ? $(rapper)[0] : rapper
+ this.tools = {}
+ this.els = {}
+ }
+ exports.add = function(role, fn){
+ var self = this
+ this.tools[role] = fn
+ this.els[role] = $("[data-role=" + role + "]", self.rapper)
+ this.els[role].click(function(){
+ $(".active", self.rapper).removeClass('active')
+ $(this).addClass('active')
+ fn()
+ })
+ }
+ exports.pick = function(role){
+ this.els[role].trigger("click")
+ }
+ return exports
+}) \ No newline at end of file
diff --git a/public/assets/javascripts/ui/reader/MediaPlayer.js b/public/assets/javascripts/ui/reader/MediaPlayer.js
index 8424d9c..8e65976 100644
--- a/public/assets/javascripts/ui/reader/MediaPlayer.js
+++ b/public/assets/javascripts/ui/reader/MediaPlayer.js
@@ -1,5 +1,5 @@
-var MediaPlayer = FormView.extend({
+var MediaPlayer = View.extend({
el: "#mediaPlayer",
events: {
diff --git a/public/assets/javascripts/ui/reader/ReaderView.js b/public/assets/javascripts/ui/reader/ReaderView.js
index 617a145..43e81d8 100644
--- a/public/assets/javascripts/ui/reader/ReaderView.js
+++ b/public/assets/javascripts/ui/reader/ReaderView.js
@@ -31,7 +31,12 @@ var ReaderView = View.extend({
this.tracker = new Tracker ({ mode: mode })
- $.get(this.projectAction + name, this.ready.bind(this))
+ if ('vvalls_data' in window) {
+ this.ready(window.vvalls_data)
+ }
+ else {
+ $.get(this.projectAction + name, this.ready.bind(this))
+ }
},
getQS: function(){
@@ -71,9 +76,15 @@ var ReaderView = View.extend({
},
build: function(data){
- data.rooms && Rooms.deserialize(data.rooms)
+ if (data.shapes.length) {
+ Rooms.deserializeFromShapes(data)
+ }
+ else {
+ Rooms.deserialize(data.rooms)
+ }
data.walls && Walls.deserialize(data.walls)
data.media && Scenery.deserialize(data.media)
+ data.sculpture && Sculpture.deserialize(data.sculpture)
data.startPosition && scene.camera.move(data.startPosition)
cam.y = window.viewHeight = data.viewHeight || app.defaults.viewHeight
@@ -84,9 +95,12 @@ var ReaderView = View.extend({
Walls.setColor[mode](colors[mode])
})
- editor.permissions.clear()
+ window.editor && editor.permissions.clear()
- this.listen()
+ // disable until we start using spinning again
+ // this.listen()
+
+ app.tube("site-ready")
},
listen: function(){
diff --git a/public/assets/javascripts/ui/reader/Tracker.js b/public/assets/javascripts/ui/reader/Tracker.js
index ce32c59..d2dec39 100644
--- a/public/assets/javascripts/ui/reader/Tracker.js
+++ b/public/assets/javascripts/ui/reader/Tracker.js
@@ -1,8 +1,12 @@
-(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
-(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
-m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
-})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
-
+if (window.location.host.indexOf("lvh.me") === -1) {
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+}
+else {
+ ga = function(){}
+}
ga('create', 'UA-56883705-1', 'auto');
ga('send', 'pageview');
diff --git a/public/assets/javascripts/ui/reader/_router.js b/public/assets/javascripts/ui/reader/_router.js
new file mode 100644
index 0000000..f3b121b
--- /dev/null
+++ b/public/assets/javascripts/ui/reader/_router.js
@@ -0,0 +1,24 @@
+
+var SiteRouter = Router.extend({
+ el: "body",
+
+ initialize: function(){
+ app.launch()
+ if (app.unsupported) return
+
+ this.readerView = app.controller = new ReaderView()
+ this.readerView.load()
+
+ $("body").removeClass("loading")
+ }
+
+})
+
+var editor = {
+ permissions: new Permissions({
+ 'pick': true,
+ 'move': true,
+ 'resize': true,
+ 'destroy': false,
+ })
+}
diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js
new file mode 100644
index 0000000..c1dc9f8
--- /dev/null
+++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js
@@ -0,0 +1,290 @@
+
+var EditSubscriptionModal = ModalView.extend({
+ el: ".mediaDrawer.editSubscription",
+ action: "/api/subscription",
+ syncAction: "/api/subscription/sync",
+ updateAction: "/api/subscription",
+ destroyAction: "/api/subscription/destroy",
+
+ fixedClose: true,
+ editing: false,
+ subscriber: null,
+ tempSubscriber: null,
+
+ events: {
+ "click [data-role='addLayouts']": 'addLayouts',
+ "click [data-role='changePlan']": 'changePlan',
+ "click [data-role='cancelSubscription']": 'destroy',
+ "click .gear": 'sync',
+ "click .planList button": 'followLink',
+
+ "click [data-role=showEditMenu]": "editMode",
+
+ "click [data-role=closeMenu]": "resetMode",
+
+ "input [data-role=basicLayoutInput]": "updateQuantity",
+ "input [data-role=proLayoutInput]": "updateQuantity",
+ "click [data-role=saveChanges]": "saveChanges",
+
+ "change [name=planRadio]": "updatePlan",
+ "click [data-role=savePlan]": "savePlan",
+
+ "submit form": "preventDefault",
+ },
+
+ initialize: function(){
+ // this.parent = opt.parent
+ this.__super__.initialize.call(this)
+
+ // two sections
+ this.$freePlan = this.$(".freePlan")
+ this.$paidPlan = this.$(".paidPlan")
+
+ // subscription table
+ this.$planInfo = this.$(".planInfo")
+ this.$planRow = this.$(".planRow")
+ this.$basicLayoutRow = this.$(".basicLayoutRow")
+ this.$proLayoutRow = this.$(".proLayoutRow")
+ this.$totalRow = this.$(".totalRow")
+ this.$planList = this.$(".planList")
+
+ this.$billingInterval = this.$("[data-role=billingInterval]")
+
+ // plan stuff
+ this.$planName = this.$("[data-role=planName]")
+ this.$planCost = this.$("[data-role=planCost]")
+ this.$planTotal = this.$("[data-role=planTotal]")
+
+ this.$basicPlanName = this.$("[data-role=basicPlanName]")
+ this.$basicPlanCost = this.$("[data-role=basicPlanCost]")
+
+ this.$proPlanName = this.$("[data-role=proPlanName]")
+ this.$proPlanCost = this.$("[data-role=proPlanCost]")
+
+ // basic + pro layout stuff
+ this.$basicLayoutCost = this.$("[data-role=basicLayoutCost]")
+ this.$basicLayoutQuantity = this.$("[data-role=basicLayoutQuantity]")
+ this.$basicLayoutTotal = this.$("[data-role=basicLayoutTotal]")
+
+ this.$proLayoutCost = this.$("[data-role=proLayoutCost]")
+ this.$proLayoutQuantity = this.$("[data-role=proLayoutQuantity]")
+ this.$proLayoutTotal = this.$("[data-role=proLayoutTotal]")
+
+ // menus.. main menu
+ this.$showEditMenu = this.$("[data-role=showEditMenu]")
+ this.$cancelSubscription = this.$("[data-role=cancelSubscription]")
+
+ // three submenus
+ this.$editMenu = this.$("[data-role=editMenu]")
+ this.$planMenu = this.$("[data-role=planMenu]")
+
+ this.$buyLayouts = this.$("[data-role=buyLayouts]")
+ this.$closeMenu = this.$("[data-role=closeMenu]")
+ this.$changePlan = this.$("[data-role=changePlan]")
+
+ // input fields
+ this.$basicLayoutInput = this.$("[data-role=basicLayoutInput]")
+ this.$proLayoutInput = this.$("[data-role=proLayoutInput]")
+ this.$planRadio = this.$("[name=planRadio]")
+ this.$basicPlanInput = this.$("[data-role=basicPlanInput]")
+ this.$proPlanInput = this.$("[data-role=proPlanInput]")
+
+ this.$gear = this.$(".gear")
+ },
+
+ plan_levels: {
+ free: 0,
+ basic: 1,
+ pro: 2,
+ custom: 3,
+ artist: 4,
+ },
+
+ loaded: false,
+ load: function(){
+ if (this.loaded) { return this.show() }
+ $.get(this.action, this.didLoad.bind(this))
+ },
+ didLoad: function(data){
+ this.loaded = true
+ this.plans = data.plans
+ if (data.subscription) {
+ this.subscriber = data.subscription
+ }
+ else if (data.error) {
+ // ...no subscription found
+ this.subscriber = null
+ }
+ return this.show()
+ },
+ followLink: function(e){
+ e.preventDefault();
+ window.location.href = $(e.target).closest("a").attr("href")
+ },
+
+ show: function(){
+ this.$gear.removeClass("turning")
+ if (! this.subscriber) {
+ this.$freePlan.show()
+ this.$paidPlan.hide()
+ this.$planList.load("/partials/plans", function(){
+ this.$(".free_plan_info").remove()
+ this.__super__.show.call(this)
+ }.bind(this))
+ return
+ }
+
+ this.$freePlan.hide()
+ this.$paidPlan.show()
+
+ this.resetMode()
+
+ this.__super__.show.call(this)
+ },
+ reset: function(){
+ var subscriber = this.subscriber
+ var plan = this.getPlan(subscriber.plan_type)
+ this.displayTotals(subscriber, plan)
+ },
+ getPlan: function(plan_type){
+ return this.plans[ this.plan_levels[ plan_type ] ]
+ },
+ calculateTotals: function(subscriber, plan){
+ var t = {}
+ t.is_pro = subscriber.plan_type == "pro"
+ t.is_monthly = subscriber.plan_period == "monthly"
+ t.plan_price = t.is_monthly ? plan.monthly_price : plan.yearly_price
+ t.basic_layout_price = t.is_monthly ? plan.basic_layout_monthly_price : plan.basic_layout_yearly_price
+ t.basic_layout_total = subscriber.basic_layouts * t.basic_layout_price
+ t.pro_layout_price = t.is_monthly ? plan.pro_layout_monthly_price : plan.pro_layout_yearly_price
+ t.pro_layout_total = t.is_pro ? subscriber.pro_layouts * t.pro_layout_price : 0
+ t.plan_total = t.plan_price + t.basic_layout_total + t.pro_layout_total
+ return t
+ },
+ displayTotals: function(subscriber, plan){
+ var totals = this.calculateTotals(subscriber, plan)
+
+ this.$basicPlanName.html ( this.plans[1].name )
+ this.$proPlanName.html ( this.plans[2].name )
+ this.$basicPlanCost.toDollars ( totals.is_monthly ? this.plans[1].monthly_price : this.plans[2].yearly_price)
+ this.$proPlanCost.toDollars ( totals.is_monthly ? this.plans[2].monthly_price : this.plans[2].yearly_price)
+
+ this.$planName.html ( plan.name )
+ this.$planCost.toDollars ( totals.plan_price )
+
+ this.$billingInterval.html ( totals.is_monthly ? "mo." : "yr." )
+ this.$basicLayoutRow.toggle ( subscriber.basic_layouts > 0 )
+ this.$proLayoutRow.toggle ( totals.is_pro && subscriber.pro_layouts > 0)
+
+ this.$basicLayoutCost.toDollars ( totals.basic_layout_price )
+ this.$basicLayoutQuantity.html ( subscriber.basic_layouts )
+ this.$basicLayoutTotal.toDollars ( totals.basic_layout_total )
+
+ this.$proLayoutCost.toDollars ( totals.pro_layout_price )
+ this.$proLayoutQuantity.html ( subscriber.pro_layouts )
+ this.$proLayoutTotal.toDollars ( totals.pro_layout_total )
+
+ this.$planTotal.toDollars ( totals.plan_total )
+ },
+
+ editMode: function(e){
+ e && e.preventDefault()
+
+ this.editing = true
+ this.$el.addClass("editing")
+ this.tempSubscriber = defaults({}, this.subscriber)
+ this.$basicLayoutInput.val( this.subscriber.basic_layouts )
+ this.$proLayoutInput.val( this.subscriber.pro_layouts )
+ this.$basicLayoutRow.show()
+ this.$proLayoutRow.toggle(this.subscriber.plan_type == "pro")
+ switch (this.subscriber.plan_type) {
+ case 'basic': this.$basicPlanInput.prop('checked', true); break;
+ case 'pro': this.$proPlanInput.prop('checked', true); break;
+ }
+ },
+ resetMode: function(e){
+ e && e.preventDefault()
+ this.editing = false
+ this.$el.removeClass("editing")
+ this.reset()
+ },
+
+ updateQuantity: function(e){
+ e && e.preventDefault()
+ var plan = this.getPlan( this.tempSubscriber.plan_type )
+ this.tempSubscriber.basic_layouts = clamp( this.$basicLayoutInput.int() || 0, 0, 100)
+ this.tempSubscriber.pro_layouts = clamp( this.$proLayoutInput.int() || 0, 0, 100)
+
+ this.$basicLayoutInput.val(this.tempSubscriber.basic_layouts)
+ this.$proLayoutInput.val(this.tempSubscriber.pro_layouts)
+ this.displayTotals(this.tempSubscriber, plan)
+ this.$basicLayoutRow.show()
+ this.$proLayoutRow.toggle(this.tempSubscriber.plan_type == "pro")
+ },
+ saveChanges: function(e){
+ e && e.preventDefault()
+ var is_changed = false
+ var diff = {}
+ "plan_type basic_layouts pro_layouts".split(" ").forEach(function(field){
+ diff[field] = this.tempSubscriber[field]
+ if (this.tempSubscriber[field] != this.subscriber[field]) {
+ is_changed = true
+ }
+ }.bind(this))
+
+ if (is_changed) {
+ this.update(diff)
+ }
+ this.subscriber = this.tempSubscriber
+ this.resetMode()
+ },
+
+ updatePlan: function(e){
+ e && e.preventDefault()
+ this.tempSubscriber.plan_type = this.$("[name=planRadio]:checked").val()
+ this.updateQuantity()
+ },
+
+ sync: function(){
+ this.$gear.addClass("turning")
+ $.ajax({
+ url: this.syncAction,
+ type: "put",
+ data: { _csrf: $("[name=_csrf]").val() },
+ success: this.didLoad.bind(this)
+ })
+ },
+
+ update: function(data){
+ data['_csrf'] = $("[name=_csrf]").val()
+ this.$gear.addClass("turning")
+ $.ajax({
+ url: this.updateAction,
+ type: "put",
+ data: data,
+ success: function(data){
+ this.$gear.removeClass("turning")
+ }.bind(this)
+ })
+ },
+
+ destroy: function(e){
+ e.preventDefault()
+ var msg = "Are you sure you want to cancel your subscription?"
+ ConfirmModal.confirm(msg, function(){
+ $.ajax({
+ url: this.destroyAction,
+ type: "delete",
+ data: { _csrf: $("[name=_csrf]").val() },
+ success: function(data){
+ this.subscriber = null
+ this.didLoad(data)
+ }.bind(this)
+ })
+ }.bind(this),
+ function(){
+ this.show()
+ }.bind(this))
+ },
+
+})
diff --git a/public/assets/javascripts/ui/site/HomeView.js b/public/assets/javascripts/ui/site/HomeView.js
index a04bac1..20452bd 100644
--- a/public/assets/javascripts/ui/site/HomeView.js
+++ b/public/assets/javascripts/ui/site/HomeView.js
@@ -22,7 +22,7 @@ var HomeView = View.extend({
player.api('play')
})
- $('.videoModal .ion-ios7-close-empty').click( function(){
+ $('.videoModal .ion-ios-close-empty').click( function(){
player.api('pause')
hide()
})
diff --git a/public/assets/javascripts/ui/site/LayoutsIndex.js b/public/assets/javascripts/ui/site/LayoutsIndex.js
new file mode 100644
index 0000000..f7272bb
--- /dev/null
+++ b/public/assets/javascripts/ui/site/LayoutsIndex.js
@@ -0,0 +1,85 @@
+
+var LayoutsIndex = View.extend({
+
+ initialize: function(){
+ this.$templates = this.$(".templates")
+ this.$templatesList = this.$(".templates-list")
+ this.$noTemplates = this.$(".no-templates")
+ this.$form = this.$("form")
+
+ this.$userTemplatesList = this.$(".userTemplatesList")
+ this.$blueprintsList = this.$(".blueprintsList")
+ this.$newBlueprintButton = this.$("[data-role='create-new-blueprint']")
+ },
+
+ load: function(type){
+ this.$templates.children("span").remove()
+
+ $.get(this.action, this.populate.bind(this))
+ },
+
+ populate: function(data){
+ if (! data.layouts.length) {
+ this.$templates.hide()
+ this.$form.hide()
+ this.$noTemplates.show()
+ }
+ this.$templatesList.empty()
+ data.layouts.forEach(function(room){
+ var $span = $("<span>")
+ $span.data("slug", room.slug)
+
+ var $label = $("<label>")
+ $label.html( room.name )
+
+ var $image = $("<span>")
+ $image.addClass("image").css("background-image", "url(" + room.photo + ")")
+
+ $span.append( $image )
+ $span.append( $label )
+
+ this.$templatesList.append($span)
+ }.bind(this))
+ this.show()
+ }
+
+})
+
+
+
+var ProjectsModal = ModalView.extend(LayoutsIndex.prototype).extend({
+ el: ".mediaDrawer.projects",
+
+ action: "/api/project",
+
+ events: {
+ "click .templates span": 'toggleActive',
+ "submit form": 'newProject',
+ },
+
+ populate: function(data){
+ if (! data.length) {
+ app.router.newProject()
+ }
+ else {
+ this.__super__.populate.call(this, data)
+ }
+ },
+
+ toggleActive: function(e){
+ e.preventDefault()
+ this.$(".templates .active").removeClass("active")
+ var $layout = $(e.currentTarget)
+ $layout.addClass("active")
+
+ // actually do
+ window.location.pathname = "/project/" + $layout.data("slug") + "/edit"
+ },
+
+ newProject: function(e){
+ e && e.preventDefault()
+ window.location.pathname = "/project/new"
+ }
+
+})
+
diff --git a/public/assets/javascripts/ui/site/LayoutsModal.js b/public/assets/javascripts/ui/site/LayoutsModal.js
index 5974fc3..0222077 100644
--- a/public/assets/javascripts/ui/site/LayoutsModal.js
+++ b/public/assets/javascripts/ui/site/LayoutsModal.js
@@ -1,27 +1,52 @@
+var LayoutsModal = ModalView.extend(LayoutsIndex.prototype).extend({
+ el: ".mediaDrawer.layouts",
-var LayoutsIndex = View.extend({
+ action: "/api/layout",
- initialize: function(){
- this.$templates = this.$(".templates")
- this.$templatesList = this.$(".templates-list")
- this.$noTemplates = this.$(".no-templates")
- this.$form = this.$("form")
+ events: {
+ "click [data-role='create-new-layout']": 'createNewLayout',
+ "click [data-role='create-new-blueprint']": 'createNewBlueprint',
+ "click .templates span": 'pick',
},
+
+ pick: function(e){
+ e.preventDefault()
+ var layout = $(e.currentTarget).data("slug")
+ var isBlueprint = $(e.currentTarget).data("blueprint")
- load: function(type){
- this.$templates.children("span").remove()
+ if (! layout || ! layout.length) return
- $.get(this.action, this.populate.bind(this))
+ if (isBlueprint) {
+ window.location.pathname = "/blueprint/" + layout
+ }
+ else {
+ window.location.pathname = "/layout/" + layout
+ }
+ },
+
+ createNewLayout: function(e){
+ e.preventDefault()
+ window.location.pathname = "/layout/new"
+ },
+
+ createNewBlueprint: function(e){
+ e.preventDefault()
+ window.location.pathname = "/blueprint/new"
},
populate: function(data){
- if (! data.length) {
+/*
+ if (data.user.plan_level < 1 && data.projectCount == 1) {
+ // show lockout message
+ }
+*/
+ if (! data.layouts.length) {
this.$templates.hide()
this.$form.hide()
this.$noTemplates.show()
}
this.$templatesList.empty()
- data.forEach(function(room){
+ data.layouts.forEach(function(room){
var $span = $("<span>")
$span.data("slug", room.slug)
@@ -36,103 +61,46 @@ var LayoutsIndex = View.extend({
this.$templatesList.append($span)
}.bind(this))
- this.show()
- }
-
-})
-var ProjectsModal = ModalView.extend(LayoutsIndex.prototype).extend({
- el: ".mediaDrawer.projects",
-
- action: "/api/project",
-
- events: {
- "click .templates span": 'toggleActive',
- "submit form": 'newProject',
- },
-
- populate: function(data){
- if (! data.length) {
- app.router.newProject()
- }
- else {
- this.__super__.populate.call(this, data)
- }
- },
-
- toggleActive: function(e){
- e.preventDefault()
- this.$(".templates .active").removeClass("active")
- var $layout = $(e.currentTarget)
- $layout.addClass("active")
-
- // actually do
- window.location.pathname = "/project/" + $layout.data("slug") + "/edit"
- },
-
- newProject: function(e){
- e && e.preventDefault()
- window.location.pathname = "/project/new"
- }
-
-})
-
-
-var LayoutsModal = ModalView.extend(LayoutsIndex.prototype).extend({
- el: ".mediaDrawer.layouts",
-
- action: "/api/layout",
-
- events: {
- "click .templates span": 'toggleActive',
- "submit form": 'newLayout',
- },
-
- toggleActive: function(e){
- e.preventDefault()
- this.$(".templates .active").removeClass("active")
- var $layout = $(e.currentTarget)
- $layout.addClass("active")
+ data.user_layouts.forEach(function(room){
+ var $span = $("<span>")
+ $span.data("slug", room.slug)
+
+ var $label = $("<label>")
+ $label.html( room.name )
+
+ var $image = $("<span>")
+ $image.addClass("image").css("background-image", "url(" + room.photo + ")")
+
+ $span.append( $image )
+ $span.append( $label )
+
+ this.$templatesList.append($span)
+ }.bind(this))
+
+ data.blueprints.forEach(function(blueprint){
+ var $span = $("<span>")
+ $span.data("slug", blueprint.slug)
+ $span.data("blueprint", true)
+
+ var $label = $("<label>")
+ $label.html( blueprint.name )
+
+ var $image = $("<span>")
+ $image.addClass("image").css("background-image", "url(" + blueprint.url + ")")
+
+ $span.append( $image )
+ $span.append( $label )
+
+ this.$templatesList.append($span)
+ }.bind(this))
- // actually do
- window.location.pathname = "/layout/" + $layout.data("slug")
+ this.show()
},
-
+
newLayout: function(e){
e && e.preventDefault()
window.location.pathname = "/layout/new"
}
})
-
-
-var NewProjectModal = ModalView.extend(LayoutsIndex.prototype).extend({
- el: ".mediaDrawer.newProject",
-
- action: "/api/layout",
-
- events: {
- "click [data-role='create-new-layout']": 'createNewLayout',
- "click .templates span": 'choose',
- "submit form": 'choose',
- },
-
- toggleActive: function(e){
- e.preventDefault()
- this.$(".templates .active").removeClass("active")
- $(e.currentTarget).addClass("active")
- },
-
- choose: function(e){
- e && e.preventDefault()
-// var layout = this.$(".templates .active").data("slug")
- var layout = $(e.currentTarget).data("slug")
- if (! layout || ! layout.length) return
- window.location.pathname = "/project/new/" + layout
- },
-
- createNewLayout: function(){
- window.location.pathname = "/project/new/empty"
- },
-
-})
diff --git a/public/assets/javascripts/ui/site/NewProjectModal.js b/public/assets/javascripts/ui/site/NewProjectModal.js
new file mode 100644
index 0000000..31675ba
--- /dev/null
+++ b/public/assets/javascripts/ui/site/NewProjectModal.js
@@ -0,0 +1,118 @@
+var NewProjectModal = ModalView.extend(LayoutsIndex.prototype).extend({
+ el: ".mediaDrawer.newProject",
+
+ action: "/api/layout",
+
+ events: {
+ "click [data-role='create-new-layout']": 'createNewLayout',
+ "click [data-role='create-new-blueprint']": 'createNewBlueprint',
+ "click .templates span": 'pick',
+ },
+
+ toggleActive: function(e){
+ e.preventDefault()
+ this.$(".templates .active").removeClass("active")
+ $(e.currentTarget).addClass("active")
+ },
+
+ pick: function(e){
+ e && e.preventDefault()
+// var layout = this.$(".templates .active").data("slug")
+ var layout = $(e.currentTarget).data("slug")
+ var isBlueprint = $(e.currentTarget).data("blueprint")
+ if (! layout || ! layout.length) return
+
+ if (isBlueprint) {
+ window.location.pathname = "/project/blueprint/" + layout
+ }
+ else {
+ window.location.pathname = "/project/new/" + layout
+ }
+ },
+
+ createNewLayout: function(e){
+ e.preventDefault()
+ window.location.pathname = "/project/new/empty"
+ },
+
+ createNewBlueprint: function(e){
+ e.preventDefault()
+ window.location.pathname = "/blueprint/new"
+ },
+
+ populate: function(data){
+/*
+ if (data.user.plan_level < 1 && data.projectCount == 1) {
+ // show lockout message
+ this.$newBlueprintButton.hide()
+ }
+*/
+ if (! data.layouts.length) {
+ this.$templates.hide()
+ this.$form.hide()
+ this.$noTemplates.show()
+ }
+ if (! data.blueprints.length) {
+ this.$blueprintsList.parent().hide()
+ }
+ if (! data.user_layouts.length) {
+ this.$userTemplatesList.parent().hide()
+ }
+
+ this.$templatesList.empty()
+ data.layouts.forEach(function(room){
+ var $span = $("<span>")
+ $span.data("slug", room.slug)
+
+ var $label = $("<label>")
+ $label.html( room.name )
+
+ var $image = $("<span>")
+ $image.addClass("image").css("background-image", "url(" + room.photo + ")")
+
+ $span.append( $image )
+ $span.append( $label )
+
+ this.$templatesList.append($span)
+ }.bind(this))
+
+ data.user_layouts.forEach(function(room){
+ var $span = $("<span>")
+ $span.data("slug", room.slug)
+
+ var $label = $("<label>")
+ $label.html( room.name )
+
+ var $image = $("<span>")
+ $image.addClass("image").css("background-image", "url(" + room.photo + ")")
+
+ $span.append( $image )
+ $span.append( $label )
+
+ this.$templatesList.append($span)
+ }.bind(this))
+
+ data.blueprints.forEach(function(blueprint){
+ if (! blueprint.slug) { return }
+
+ var $span = $("<span>")
+ $span.data("blueprint", true)
+ $span.data("slug", blueprint.slug)
+
+ var $label = $("<label>")
+ $label.html( blueprint.name )
+
+ var $image = $("<span>")
+ $image.addClass("image").css("background-image", "url(" + blueprint.url + ")")
+
+ $span.append( $image )
+ $span.append( $label )
+
+ this.$templatesList.append($span)
+ }.bind(this))
+
+ this.show()
+ },
+
+
+}) \ No newline at end of file
diff --git a/public/assets/javascripts/ui/site/StaffView.js b/public/assets/javascripts/ui/site/StaffView.js
index 0398f71..97f86c2 100644
--- a/public/assets/javascripts/ui/site/StaffView.js
+++ b/public/assets/javascripts/ui/site/StaffView.js
@@ -4,11 +4,15 @@ var StaffView = View.extend({
events: {
"click #toggle-staff": "toggleStaff",
"click #toggle-featured": "toggleFeatured",
+ "click #toggle-stock": "toggleStock",
+ "click #toggle-artist": "toggleArtist",
},
initialize: function() {
this.$toggleStaff = $("#toggle-staff")
this.$toggleFeatured = $("#toggle-featured")
+ this.$toggleStock = $("#toggle-stock")
+ this.$toggleArtist = $("#toggle-artist")
this.$mediaEmbed = $("#media-embed")
if (this.$toggleStaff.length && this.$toggleStaff.data().isstaff) {
this.$toggleStaff.html("Is Staff")
@@ -16,6 +20,12 @@ var StaffView = View.extend({
if (this.$toggleFeatured.length && this.$toggleFeatured.data().featured) {
this.$toggleFeatured.html("Featured Project")
}
+ if (this.$toggleStock.length && this.$toggleStock.data().stock) {
+ this.$toggleStock.html("Layout is Stock")
+ }
+ if (this.$toggleArtist.length && this.$toggleArtist.data().isartist) {
+ this.$toggleArtist.html("Is Artist")
+ }
if (this.$mediaEmbed.length) {
var media = this.$mediaEmbed.data()
this.$mediaEmbed.html( Parser.tag( media ) )
@@ -67,6 +77,41 @@ var StaffView = View.extend({
$("#isFeaturedProject").html(data.state ? "yes" : "no")
}.bind(this)
})
- },
+ },
+
+ toggleStock: function(){
+ var state = ! this.$toggleStock.data().stock
+ $.ajax({
+ type: "put",
+ dataType: "json",
+ url: window.location.href + "/stock",
+ data: {
+ state: state,
+ _csrf: $("#_csrf").val(),
+ },
+ success: function(data){
+ this.$toggleStock.data("stock", data.state)
+ this.$toggleStock.html(data.state ? "Stock Layout" : "Make this layout Stock")
+ $("#isStockLayout").html(data.state ? "yes" : "no")
+ }.bind(this)
+ })
+ },
+ toggleArtist: function(){
+ var state = ! this.$toggleArtist.data().isartist
+ $.ajax({
+ type: "put",
+ dataType: "json",
+ url: window.location.href + "/artist",
+ data: {
+ state: state,
+ _csrf: $("#_csrf").val(),
+ },
+ success: function(data){
+ this.$toggleArtist.data("stock", data.state)
+ this.$toggleArtist.html(data.state ? "Is Artist" : "Make Artist")
+ $("#isArtist").html(data.state ? "yes" : "no")
+ }.bind(this)
+ })
+ },
})