From 5efb0ed941ed80136e63014c4f615574b2b613d7 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 23 Jan 2015 17:58:41 -0500 Subject: edit subscription partial stub --- views/partials/edit-subscription.ejs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 views/partials/edit-subscription.ejs (limited to 'views/partials') diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs new file mode 100644 index 0000000..0aa5281 --- /dev/null +++ b/views/partials/edit-subscription.ejs @@ -0,0 +1,33 @@ +
+ X +
+
+ +
    +
  • +

    Edit Subscription

    +
  • +
  • + [[ if (! user.plan_level) { ]] + You are currently using the free plan. For access to all of Vvalls features, + consider upgrading to a paid plan. +

    + View the Plans + [[ } else { ]] + Your current plan level is XXX + You have been a member since XXX + $cost/month OR $cost/year + + You are using N basic layouts + Buy more + + You are using N pro layouts + Buy more / Upgrade your account + + Cancel your subscription + [[ } ]] +

  • +
+
+
+
-- cgit v1.2.3-70-g09d2 From 29e0f23c5ade5072851aaa74314166b0c7281272 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 23 Jan 2015 19:28:53 -0500 Subject: stub subscription modal js --- .../javascripts/ui/site/EditSubscriptionModal.js | 21 ++++++++++ views/partials/edit-subscription.ejs | 45 +++++++++++++++------- 2 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 public/assets/javascripts/ui/site/EditSubscriptionModal.js (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js new file mode 100644 index 0000000..1b3b859 --- /dev/null +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -0,0 +1,21 @@ + +var EditSubscriptionModal = ModalFormView.extend({ + el: ".mediaDrawer.editSubscription", + action: "/api/subscription", + method: "put", + + fixedClose: true, + + events: { + "click [data-role='changePasswordToggle']": 'togglePasswordFields' + }, + + load: function(){ + this.reset() + $.get("/api/subscription", function(data){ + + this.show() + }.bind(this)) + }, + +}) diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 0aa5281..1f8db62 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -7,24 +7,43 @@
  • Edit Subscription

  • -
  • - [[ if (! user.plan_level) { ]] +
    You are currently using the free plan. For access to all of Vvalls features, consider upgrading to a paid plan.

    View the Plans - [[ } else { ]] - Your current plan level is XXX - You have been a member since XXX - $cost/month OR $cost/year +

    +
    + Your current plan level is + + + + + + + + + + + + + + + + + + + + + + + + +
    Basic plan@ $/
    Additional basic layouts@ $/Buy more
    Additional PRO layouts$/Buy more
    Total$/
    + + - You are using N basic layouts - Buy more - - You are using N pro layouts - Buy more / Upgrade your account - - Cancel your subscription + [[ } ]]
  • -- cgit v1.2.3-70-g09d2 From 3059c3203d2cec4e2e745be8c21c6d3fbddb0c14 Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Wed, 28 Jan 2015 01:39:28 -0500 Subject: rigging EditSubscriptionModal --- Gruntfile.js | 1 + config.json.example | 1 - public/assets/javascripts/ui/_router.js | 10 ++++++++++ server/index.js | 1 + server/lib/api/subscription.js | 19 ++++++++++++++++--- server/lib/webhook/webhook.js | 14 ++++++++++++++ views/about/brochure.ejs | 3 +++ views/partials/edit-subscription.ejs | 1 - views/partials/scripts.ejs | 1 + 9 files changed, 46 insertions(+), 5 deletions(-) (limited to 'views/partials') diff --git a/Gruntfile.js b/Gruntfile.js index f62cc82..ed236c5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -99,6 +99,7 @@ module.exports = function(grunt) { "public/assets/javascripts/ui/site/LayoutsModal.js", "public/assets/javascripts/ui/site/EditProjectModal.js", "public/assets/javascripts/ui/site/EditProfileModal.js", + "public/assets/javascripts/ui/site/EditSubscriptionModal.js", "public/assets/javascripts/ui/site/DocumentModal.js", "public/assets/javascripts/ui/site/HomeView.js", diff --git a/config.json.example b/config.json.example index b8c310c..dc79edd 100644 --- a/config.json.example +++ b/config.json.example @@ -5,6 +5,5 @@ "socketPort": 1337, "webhookPort": 5000, "databaseHost": "lvh.me", - "pageSize": 10, "env": { "development": 1 } } diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js index 3532428..9e7ce75 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', @@ -29,6 +30,7 @@ var SiteRouter = Router.extend({ "/profile": 'profile', "/profile/edit": 'editProfile', + "/profile/billing": 'editSubscription', "/profile/:name": 'profile', "/about/:name/edit": 'editDocument', "/about/new": 'newDocument', @@ -56,6 +58,7 @@ var SiteRouter = Router.extend({ "/profile": 'profile', "/profile/edit": 'editProfile', + "/profile/billing": 'editSubscription', "/profile/:name": 'profile', "/project/:name": 'projectViewer', @@ -69,6 +72,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() @@ -195,6 +199,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){ diff --git a/server/index.js b/server/index.js index 02fea3c..475054d 100644 --- a/server/index.js +++ b/server/index.js @@ -102,6 +102,7 @@ site.route = function () { app.get('/profile', views.profile) app.get('/profile/edit', views.profile) + app.get('/profile/billing', views.profile) app.get('/profile/:username', views.profile) app.get('/about', views.docs); diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index bd19127..83644cf 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -18,16 +18,29 @@ var subscription = module.exports = { }) }, */ - show: function(req,res){ + middleware: { + fetchAccount: function(req, res, next){ + recurly.subscriptions.listByAccount(req.user._id, function(data){ + }) + }, + }, + + // synchronise an account with recurly.. + // useful when testing locally (if webhooks do not fire) + sync: function(req, res){ + // fetch req.user._id + }, + + show: function(req, res){ // fetch from recurly }, - update: function(req,res){ + update: function(req, res){ // update plan_type on recurly // update add_ons on recurly }, - destroy: function(req,res){ + destroy: function(req, res){ // destroy on recurly }, diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js index e9a7925..4f23d0b 100644 --- a/server/lib/webhook/webhook.js +++ b/server/lib/webhook/webhook.js @@ -134,7 +134,21 @@ var subscribe = module.exports = { }); }, + list: function(req, res){ + recurly.subscriptions.listByAccount(req.params.id, function(data){ + if (data.data != 404) { + res.json(data) + return + } + else { + res.json(data) + return + } + }) + }, + route: function(app){ app.post('/subscribe/webhook', subscribe.handle); + app.get('/subscribe/list/:id', subscribe.list); }, } diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs index 1c808f8..49b03db 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -123,6 +123,9 @@ text-align: center; margin-bottom: 10px; } +.about_plan ul { + margin-bottom: 60px; +} .planbox li { list-style-type: none; margin-bottom: 5px; diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 1f8db62..adc3f71 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -44,7 +44,6 @@ - [[ } ]] diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index fc94992..04bd945 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -95,6 +95,7 @@ + -- cgit v1.2.3-70-g09d2 From 5adac681bdb43b8b709795fa501689fb9ae8a4e1 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 28 Jan 2015 19:18:27 -0500 Subject: many methods --- package.json | 1 + server/lib/api/subscription.js | 124 ++++++++++++++++++++++++++++++++---- server/lib/middleware.js | 2 +- server/lib/schemas/Subscription.js | 6 +- server/lib/views/staff.js | 2 +- server/lib/webhook/webhook.js | 2 +- views/about/brochure.ejs | 15 +++-- views/partials/header.ejs | 1 + views/staff/_users.ejs | 1 + views/staff/plans/_form.ejs | 5 ++ views/staff/subscriptions/index.ejs | 2 +- views/staff/users/show.ejs | 1 + 12 files changed, 135 insertions(+), 27 deletions(-) (limited to 'views/partials') diff --git a/package.json b/package.json index 8afb96e..e89fcd9 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "express-subdomains": "0.0.5", "html-entities": "~1.0.10", "intro.js": "^0.9.0", + "js2xml": "^1.0.0", "knox": "~0.8.10", "lodash": "~2.4.1", "marked": "~0.3.2", diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index 83644cf..40aa715 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -9,7 +9,22 @@ var _ = require('lodash'), Layout = require('../schemas/Layout'), Subscription = require('../schemas/Subscription'); +var plan_levels = { + free: 0, + basic: 1, + pro: 2, +} + var subscription = module.exports = { + middleware: { + ensureSubscription: function(req, res, next){ + Subscription.findOne({ user_id: req.user._id }, function(err, data){ + if (err) { return next() } + req.subscription = data + next() + }) + }, + } /* index: function(req, res){ @@ -18,30 +33,115 @@ var subscription = module.exports = { }) }, */ - middleware: { - fetchAccount: function(req, res, next){ - recurly.subscriptions.listByAccount(req.user._id, function(data){ - }) - }, - }, // synchronise an account with recurly.. - // useful when testing locally (if webhooks do not fire) + // useful when testing locally (where webhooks cannot be received) sync: function(req, res){ - // fetch req.user._id + var subscriber = req.subscription || new Subscription () + var user = req.user + recurly.subscriptions.listByAccount(req.user._id, function(data){ + if (data.description !== 200) { + res.json({ error: "no account" }) + return + } + if (! data.subscriptions.subscription) { + res.json({ error: "account error" }) + return + } + + var plan = data.subscriptions.subscription.plan.plan_code.split("-") + var plan_type = plan[0] + var plan_period = plan[1] + + user.plan_type = plan_type + user.plan_level = plan_levels[plan_type] + + subscriber.uuid = data.subscriptions.subscription.uuid + subscriber.user_id = user._id + subscriber.plan_type = plan_type + subscriber.plan_period = plan_period + subscriber.plan_level = plan_levels[plan_type] + + var add_ons = data.subscriptions.subscription.subscription_add_ons.subscription_add_on + if (add_ons) { + if (add_ons.add_on_code) { + add_ons = [ add_ons ] + } + // TODO: handle multiple add-ons.. presumably this will work + add_ons.forEach(function(add_on){ + var add_on_type = add_on.add_on_code.split("-")[1] + if (add_on_type == "basic") { + subscriber.basic_layouts = parseInt( add_on.quantity._ ) + } + if (add_on_type == "pro") { + subscriber.pro_layouts = parseInt( add_on.quantity._ ) + } + }) + } + else { + subscriber.basic_layouts = 0 + subscriber.pro_layouts = 0 + } + + subscriber.save(function(){ + user.save(function(){ + res.render(subscriber) + }) + }) + }) }, show: function(req, res){ - // fetch from recurly + res.json(req.subscription || { error: "no subscription" }) }, update: function(req, res){ - // update plan_type on recurly - // update add_ons on recurly + if (! req.subscription ) { + return res.json({ error: "no subscription" }) + } + if (! (req.body.plan_type in plan_levels)) { + return res.json({ error: "bad input" }) + } + var subscriber = req.subscription + + // change.. + // data.plan_code + // data.subscription_add_ons = [] + // add_on.add_on_code + // add_on.quantity + var basic_layouts = max(0, parseInt(req.body.basic_layouts)) + var pro_layouts = max(0, parseInt(req.body.pro_layouts)) + + var data = {} + data.plan_code = req.body.plan_type + "_monthly" + data.subscription_add_ons = [] + + if (plan_levels[req.body.plan_type]) { + data.subscription_add_ons.push({ add_on_code: "extra-basic-layout", quantity: basic_layouts }) + } + + if (req.body.plan_type == "pro") { + data.subscription_add_ons.push({ add_on_code: "extra-pro-layout", quantity: pro_layouts }) + } + + + recurly.subscriptions.update(subscriber.uuid, data, function(){ + return res.json(subscriber) + }) }, destroy: function(req, res){ - // destroy on recurly + if (! req.subscription ) { + return res.json({ error: "no subscription" }) + } + var subscriber = req.subscription + + recurly.subscriptions.cancel(subscriber.uuid, function(){ + subscriber.remove(function(){ + req.user.plan_code = 0 + req.user.plan_type = "free" + }) + }) }, }; \ No newline at end of file diff --git a/server/lib/middleware.js b/server/lib/middleware.js index 797d677..7dfe821 100644 --- a/server/lib/middleware.js +++ b/server/lib/middleware.js @@ -59,7 +59,7 @@ var middleware = { res.locals.opt = {} next() }, - + ensureProject: function (req, res, next) { if (req.params.slug) { Project.findOne({ slug: req.params.slug }, function(err, project){ diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js index b766555..24c5096 100644 --- a/server/lib/schemas/Subscription.js +++ b/server/lib/schemas/Subscription.js @@ -13,10 +13,8 @@ var SubscriptionSchema = new mongoose.Schema({ plan_period: { type: String, default: "monthly" }, subscription_uuid: { type: String }, - subscription_add_ons: [{ - name: { type: String }, - quantity: { type: Number }, - }], + basic_layouts: { type: Number, default: 0 }, + pro_layouts: { type: Number, default: 0 }, history: [{ action: { type: String }, diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 74dd7cd..67193fe 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -154,7 +154,7 @@ var staff = module.exports = { }, ensurePlans: function(req, res, next){ - Plan.find(function (err, plans) { + Plan.find({}).sort({ 'level': -1 }).exec(function (err, plans) { res.locals.plans = (plans || []).map(staff.helpers.plan) res.locals.plans.sort(function(a,b){ return a.monthly_price }) next() diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js index 4f23d0b..a871a3a 100644 --- a/server/lib/webhook/webhook.js +++ b/server/lib/webhook/webhook.js @@ -149,6 +149,6 @@ var subscribe = module.exports = { route: function(app){ app.post('/subscribe/webhook', subscribe.handle); - app.get('/subscribe/list/:id', subscribe.list); + app.get('/subscribe/list/:id', subscribe.middleware.ensureSubscription, subscribe.list); }, } diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs index 49b03db..1dad763 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -34,12 +34,11 @@
  • VValls logo appears when embedding an exhibition on a web page
  • [[ if (! logged_in) { ]] - - [[ } else if (! user.plan_level || user.plan_level < plan.level) { ]] - + + [[ } else if (! user.plan_level) { ]] + [[ } else if (user.plan_level == plan.level) { ]] Current Level - [[ } else { ]] [[ } ]] @@ -56,11 +55,13 @@
  • No VValls logo on embed
  • [[ if (! logged_in) { ]] - - [[ } else if (! user.plan_level || user.plan_level < plan.level) { ]] - + + [[ } else if (! user.plan_level) { ]] + [[ } else if (user.plan_level == plan.level) { ]] Current Level + [[ } else if (user.plan_level < plan.level) { ]] + [[ } ]] diff --git a/views/partials/header.ejs b/views/partials/header.ejs index ce5bab9..2acf2bc 100644 --- a/views/partials/header.ejs +++ b/views/partials/header.ejs @@ -64,6 +64,7 @@ [[ if (profile && String(user._id) == String(profile._id)) { ]] Settings + Subscription [[ } else if (! profile) { ]] Profile [[ } ]] diff --git a/views/staff/_users.ejs b/views/staff/_users.ejs index d46058f..053e289 100644 --- a/views/staff/_users.ejs +++ b/views/staff/_users.ejs @@ -12,6 +12,7 @@ [view profile] + [recurly] [[- user.last_seen ]] diff --git a/views/staff/plans/_form.ejs b/views/staff/plans/_form.ejs index ae5ca5a..b55c5cd 100644 --- a/views/staff/plans/_form.ejs +++ b/views/staff/plans/_form.ejs @@ -16,6 +16,11 @@
  • +
  • + +
    +
  • +
  • diff --git a/views/staff/subscriptions/index.ejs b/views/staff/subscriptions/index.ejs index d1c0588..3efffb5 100644 --- a/views/staff/subscriptions/index.ejs +++ b/views/staff/subscriptions/index.ejs @@ -1,6 +1,6 @@ [[ include ../_header ]] -

    Users

    +

    Subscriptions

    [[ include ../_nav ]] diff --git a/views/staff/users/show.ejs b/views/staff/users/show.ejs index 4ce1d9a..d6a21d5 100644 --- a/views/staff/users/show.ejs +++ b/views/staff/users/show.ejs @@ -19,6 +19,7 @@ [view profile] [view media] + [view on recurly] -- cgit v1.2.3-70-g09d2 From 1d88890a988b255c915d0472297b18a2635f6433 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 01:26:46 -0500 Subject: ui boilerplate --- .../javascripts/ui/site/EditSubscriptionModal.js | 40 ++++++++++++++++++++-- views/partials/edit-subscription.ejs | 28 +++++++-------- 2 files changed, 52 insertions(+), 16 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 1b3b859..342e8be 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -7,15 +7,51 @@ var EditSubscriptionModal = ModalFormView.extend({ fixedClose: true, events: { - "click [data-role='changePasswordToggle']": 'togglePasswordFields' + "click [data-role='']": 'togglePasswordFields' + }, + + initialize: function(){ + this.$freePlan = this.$("#free_plan") + this.$paidPlan = this.$("#paid_plan") + this.$proLayoutRow = this.$("#proLayoutRow") + + this.$billingInterval = this.$("[data-role=billingInterval]") + + this.$planType = this.$("[data-role=planType]") + this.$planName = this.$("[data-role=planName]") + this.$planCost = this.$("[data-role=planCost]") + + this.$basicLayoutCost = this.$("[data-role=basicLayoutCost]") + this.$basicLayoutQuantity = this.$("[data-role=basicLayoutQuantity]") + + this.$proLayoutCost = this.$("[data-role=proLayoutCost]") + this.$proLayoutQuantity = this.$("[data-role=proLayoutQuantity]") + + this.$upgradeSubscription = this.$("[data-role=upgradeSubscription]") + this.$cancelSubscription = this.$("[data-role=cancelSubscription]") }, load: function(){ this.reset() $.get("/api/subscription", function(data){ - + if (data.error) { + this.$freePlan.show() + this.$paidPlan.hide() + this.show() + return + } + this.$freePlan.show() + this.$paidPlan.hide() + + var plan = data.plans[ data.subscription.plan_name ] + this.show() + + // layouts }.bind(this)) }, + + updateTotals: function(){ + }, }) diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index adc3f71..f49d791 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -13,37 +13,37 @@

    View the Plans -

    - Your current plan level is +
  • -- cgit v1.2.3-70-g09d2 From 6f792ab8b762b3a808aae8d4b6f3a2caaacfe6b1 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 02:14:21 -0500 Subject: tying in db read --- .../javascripts/ui/site/EditSubscriptionModal.js | 35 ++++++++++++++++++---- views/partials/edit-subscription.ejs | 2 +- 2 files changed, 31 insertions(+), 6 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 342e8be..711a259 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -7,7 +7,8 @@ var EditSubscriptionModal = ModalFormView.extend({ fixedClose: true, events: { - "click [data-role='']": 'togglePasswordFields' + "click [data-role='upgradeSubscription']": 'upgradeSubscription', + "click [data-role='cancelSubscription']": 'cancelSubscription', }, initialize: function(){ @@ -18,7 +19,6 @@ var EditSubscriptionModal = ModalFormView.extend({ this.$billingInterval = this.$("[data-role=billingInterval]") this.$planType = this.$("[data-role=planType]") - this.$planName = this.$("[data-role=planName]") this.$planCost = this.$("[data-role=planCost]") this.$basicLayoutCost = this.$("[data-role=basicLayoutCost]") @@ -30,6 +30,12 @@ var EditSubscriptionModal = ModalFormView.extend({ this.$upgradeSubscription = this.$("[data-role=upgradeSubscription]") this.$cancelSubscription = this.$("[data-role=cancelSubscription]") }, + + plan_levels: { + free: 0, + basic: 1, + pro: 2, + }, load: function(){ this.reset() @@ -43,15 +49,34 @@ var EditSubscriptionModal = ModalFormView.extend({ this.$freePlan.show() this.$paidPlan.hide() - var plan = data.plans[ data.subscription.plan_name ] + var subscriber = data.subscription + var plan = data.plans[ this.plan_levels[ subscriber.plan_type ] ] + var is_pro = plan.name == "pro" + var is_monthly = subscriber.plan_period == "monthly" - this.show() + this.$planType.html( plan.name ) + this.$planCost.html( is_monthly ? plan.monthly_price : plan.yearly_price ) + + this.$billingInterval.html( is_monthly ? "mo." : "yr." ) + this.$proLayoutRow.toggle( is_pro ) + + this.$basicLayoutCost.html( is_monthly ? plan.basic_layout_monthly_price : plan.basic_layout_yearly_price ) + this.$basicLayoutQuantity.html( subscriber.basic_layouts ) + + this.$proLayoutCost.html( is_monthly ? plan.pro_layout_monthly_price : plan.pro_layout_yearly_price ) + this.$proLayoutQuantity.html( subscriber.pro_layouts ) - // layouts + this.show() }.bind(this)) }, updateTotals: function(){ }, + + upgradeSubscription: function(){ + }, + + cancelSubscription: function(){ + }, }) diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index f49d791..041c6ec 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -18,7 +18,7 @@ - + -- cgit v1.2.3-70-g09d2 From 95e2eab9e43a7ea87f23aefba090df15d46d766c Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 14:00:02 -0500 Subject: calculate total --- public/assets/javascripts/ui/_router.js | 1 - .../javascripts/ui/site/EditSubscriptionModal.js | 88 +++++++++++++++------- views/partials/edit-subscription.ejs | 21 +++--- 3 files changed, 73 insertions(+), 37 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js index 9e7ce75..1bdce19 100644 --- a/public/assets/javascripts/ui/_router.js +++ b/public/assets/javascripts/ui/_router.js @@ -206,7 +206,6 @@ var SiteRouter = Router.extend({ this.editSubscriptionModal.load() }, - newDocument: function(e){ e && e.preventDefault() diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 711a259..ea86897 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -5,6 +5,7 @@ var EditSubscriptionModal = ModalFormView.extend({ method: "put", fixedClose: true, + subscriber: null, events: { "click [data-role='upgradeSubscription']": 'upgradeSubscription', @@ -12,20 +13,29 @@ var EditSubscriptionModal = ModalFormView.extend({ }, initialize: function(){ + // this.parent = opt.parent + this.__super__.initialize.call(this) + this.$freePlan = this.$("#free_plan") this.$paidPlan = this.$("#paid_plan") - this.$proLayoutRow = this.$("#proLayoutRow") + this.$planRow = this.$(".planRow") + this.$basicLayoutRow = this.$(".basicLayoutRow") + this.$proLayoutRow = this.$(".proLayoutRow") + this.$totalRow = this.$(".totalRow") this.$billingInterval = this.$("[data-role=billingInterval]") this.$planType = this.$("[data-role=planType]") this.$planCost = this.$("[data-role=planCost]") + this.$planTotal = this.$("[data-role=planTotal]") 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]") this.$upgradeSubscription = this.$("[data-role=upgradeSubscription]") this.$cancelSubscription = this.$("[data-role=cancelSubscription]") @@ -37,40 +47,66 @@ var EditSubscriptionModal = ModalFormView.extend({ pro: 2, }, + loaded: false, load: function(){ this.reset() + if (this.loaded) { return this.show() } $.get("/api/subscription", function(data){ - if (data.error) { - this.$freePlan.show() - this.$paidPlan.hide() - this.show() - return + this.loaded = true + if (data.subscriber) { + this.subscriber = data.subscription + this.plans = data.plans + } + else if (data.error) { + // ...no subscription found } + return this.show() + }.bind(this)) + }, + + show: function(){ + if (! this.subscriber) { this.$freePlan.show() this.$paidPlan.hide() - - var subscriber = data.subscription - var plan = data.plans[ this.plan_levels[ subscriber.plan_type ] ] - var is_pro = plan.name == "pro" - var is_monthly = subscriber.plan_period == "monthly" - - this.$planType.html( plan.name ) - this.$planCost.html( is_monthly ? plan.monthly_price : plan.yearly_price ) - - this.$billingInterval.html( is_monthly ? "mo." : "yr." ) - this.$proLayoutRow.toggle( is_pro ) - - this.$basicLayoutCost.html( is_monthly ? plan.basic_layout_monthly_price : plan.basic_layout_yearly_price ) - this.$basicLayoutQuantity.html( subscriber.basic_layouts ) - - this.$proLayoutCost.html( is_monthly ? plan.pro_layout_monthly_price : plan.pro_layout_yearly_price ) - this.$proLayoutQuantity.html( subscriber.pro_layouts ) - - this.show() - }.bind(this)) + this.__super__.show.call(this) + return + } + + this.$freePlan.hide() + this.$paidPlan.show() + + this.updateTotals() + + this.__super__.show.call(this) }, updateTotals: function(){ + var subscriber = this.subscriber + var plan = this.plans[ this.plan_levels[ subscriber.plan_type ] ] + var is_pro = plan.name == "pro" + var is_monthly = subscriber.plan_period == "monthly" + + var plan_price = is_monthly ? plan.monthly_price : plan.yearly_price + this.$planType.html( plan.name ) + this.$planCost.html( plan_price ) + + this.$billingInterval.html( is_monthly ? "mo." : "yr." ) + this.$proLayoutRow.toggle( is_pro ) + + var basic_layout_price = is_monthly ? plan.basic_layout_monthly_price : plan.basic_layout_yearly_price + var basic_layout_total = subscriber.basic_layouts * basic_layout_price + this.$basicLayoutCost.html( basic_layout_price ) + this.$basicLayoutQuantity.html( subscriber.basic_layouts ) + this.$basicLayoutTotal.html( basic_layout_total ) + + var pro_layout_price = is_monthly ? plan.pro_layout_monthly_price : plan.pro_layout_yearly_price + var pro_layout_total = is_pro ? subscriber.pro_layouts * pro_layout_price : 0 + this.$proLayoutCost.html( pro_layout_price ) + this.$proLayoutQuantity.html( subscriber.pro_layouts ) + this.$proLayoutTotal.html( pro_layout_total ) + + var plan_total = plan_price + basic_layout_total + pro_layout_total + this.$planTotal.html( plan_total ) }, upgradeSubscription: function(){ diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 041c6ec..bb7cc27 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -17,27 +17,28 @@ Your current plan level is
    plan @ $/
    - + - + - + + - + - - - + + + - + - - + +
    @ $/
    Additional Basic layouts @ $/$ Buy more
    Additional Pro layouts@ $/Buy more@ $/$
    Total$/$
    -- cgit v1.2.3-70-g09d2 From d86d15c60c06843f8f22cdcf5b809c3a48e6a628 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 17:05:15 -0500 Subject: plans partial, min on number fields --- .../javascripts/ui/site/EditSubscriptionModal.js | 32 +++--- public/assets/stylesheets/app.css | 60 ++++++++++- server/index.js | 2 + server/lib/api/subscription.js | 10 +- server/lib/views/index.js | 9 ++ views/about/brochure.ejs | 113 +-------------------- views/partials/edit-subscription.ejs | 17 ++-- views/staff/plans/_form.ejs | 24 ++--- 8 files changed, 114 insertions(+), 153 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 8952e42..d5eb9ac 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -47,22 +47,28 @@ var EditSubscriptionModal = ModalFormView.extend({ basic: 1, pro: 2, }, + + sync: function(){ + $.put(this.syncAction, this.didLoad.bind(this)) + }, loaded: false, load: function(){ this.reset() if (this.loaded) { return this.show() } - $.get(this.action, function(data){ - this.loaded = true - if (data.subscriber) { - this.subscriber = data.subscription - this.plans = data.plans - } - else if (data.error) { - // ...no subscription found - } - return this.show() - }.bind(this)) + $.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() }, show: function(){ @@ -122,20 +128,18 @@ var EditSubscriptionModal = ModalFormView.extend({ type: "put", data: { _csrf: this.$csrf.val() }, success: function(data){ - window.location.href = "/profile" } }) }, destroy: function(){ - var msg = "Are you sure you want to cancel your subscription " + sanitize(this.$name.val()) + "?" + var msg = "Are you sure you want to cancel your subscription?" ConfirmModal.confirm(msg, function(){ $.ajax({ url: this.destroyAction, type: "delete", data: { _csrf: this.$csrf.val() }, success: function(data){ - window.location.href = "/profile" } }) }.bind(this)) diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 0ce2c5e..5d7199c 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -156,7 +156,7 @@ a{ display: none; border-right:0px!important; } -.editProfile, .profileLink { +.profileLink { border-right:0px!important; } .editing #help-button { @@ -849,6 +849,7 @@ iframe.embed { } + .projectList.about.gopro { padding:6% 0; } @@ -900,6 +901,57 @@ iframe.embed { background:black; color:white; } + +/* PLANS BROCHURE */ +/* nb these styles should be fixed for narrower screens/mobile layout */ +.about_plan { + width: 28vw; + margin: 2vw; + float: left; + min-height: 28vw; + position: relative; +} +.about_plan button { + position: absolute; + bottom: 5%; + left: 5%; + width: 90%; +} +.about_custom { + clear: both; + width: 76vw; + margin: 2vw 10vw; +} +.planbox { + padding: 2vw; + border: 1px solid #ddd; + background: white; + border-radius: 25px; + font-size: 15px; + line-height: 23px; + text-align: center; +} +.planbox h3 { + text-align: center; + margin-bottom: 10px; +} +.about_plan ul { + margin-bottom: 60px; +} +.planbox li { + list-style-type: none; + margin-bottom: 5px; +} +.planbox.miscbox { + border: 0; + background: #f8f8f8; +} +.about_custom a { + border-bottom: 1px solid; +} + +/* LAYOUTS MODAL */ + .templates { overflow: auto; max-height: 100%; @@ -918,8 +970,8 @@ iframe.embed { } .templates::-webkit-scrollbar-thumb { -background-color: white; -border-left: 1px solid black; + background-color: white; + border-left: 1px solid black; } .templates::-webkit-scrollbar-track { @@ -990,6 +1042,8 @@ border-left: 1px solid black; float:right; } +/* MX SCENE STUFF */ + .mx-scene { position:fixed; top:0; diff --git a/server/index.js b/server/index.js index 2f6cb2d..fa7044b 100644 --- a/server/index.js +++ b/server/index.js @@ -156,6 +156,8 @@ site.route = function () { app.put('/api/subscription', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.update) app.delete('/api/subscription', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.destroy) + app.get('/partials/plans', views.partials.plans) + app.get('/test/*', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.modal) views.staff.route(app) diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index 9478d78..b7b3434 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -84,7 +84,10 @@ var subscription = module.exports = { subscriber.save(function(){ user.save(function(){ - res.render(subscriber) + res.render({ + subscription: req.subscription, + plans: res.locals.plans + }) }) }) }) @@ -98,7 +101,10 @@ var subscription = module.exports = { }) } else { - res.json({ error: "no subscription" }) + res.json({ + error: "no subscription", + plans: res.locals.plans, + }) } }, diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 0ce0357..89167f7 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -104,6 +104,15 @@ var views = module.exports = { }) }, + partials: { + plans: function (req, res){ + views_middleware.ensurePlans(req, res, function(){ + console.log("<<<<
    -
    -

    [[- plans.free.name ]]

    -
      -
    • [[- plans.free.stock_project_limit ]] exhibition with pre-designed template floor plan -
    -
    - -
    -

    [[- plans.basic.name ]]

    -
      -
    • $[[- plans.basic.monthly_price ]]/mo or $[[- plans.basic.yearly_price ]]/year -
    • Comes with [[- plans.basic.basic_layout_limit ]] basic floor plan and [[- plans.basic.basic_project_limit ]] exhibitions -
    • Each new basic floor plan costs $[[- plans.basic.basic_layout_monthly_price ]]/mo - or $[[- plans.basic.basic_layout_yearly_price ]]/year, minimum 3 months -
    • Each new floor plan can have up to [[- plans.basic.basic_project_limit ]] exhibitions -
    • VValls logo appears when embedding an exhibition on a web page -
    • - [[ if (! logged_in) { ]] - - [[ } else if (! user.plan_level) { ]] - - [[ } else if (user.plan_level == plan.level) { ]] - Current Level - [[ } ]] -
    -
    - -
    -

    [[- plans.pro.name ]]

    -
      -
    • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year -
    • Comes with [[- plans.pro.pro_layout_limit ]] pro floor plan and [[- plans.pro.pro_project_limit ]] exhibitions -
    • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo - or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months -
    • Each new pro floor plan can have up to [[- plans.pro.pro_project_limit ]] exhibitions -
    • Includes planning for 3D objects in the room -
    • No VValls logo on embed -
    • - [[ if (! logged_in) { ]] - - [[ } else if (! user.plan_level) { ]] - - [[ } else if (user.plan_level == plan.level) { ]] - Current Level - [[ } else if (user.plan_level < plan.level) { ]] - - [[ } ]] -
    -
    - -
    -
      -
    • Buying any extra floor plan unlocks collaboration. Invite an artist or curator to work on the exhibition with you. -
    • Basic Floor plan: Rectangle-based design of any dimension. -
    • Pro Floor plan: Trace an arbitrary floor plan from image. -
    -
    - -
    -

    Want Something Custom?

    -
  • We offer customized white-label options for business and educational uses. -
  • Contact us for more information. -
  • + [[ include _plans ]] - [[ include ../partials/confirm-modal ]] [[ include ../projects/layouts-modal ]] [[ include ../partials/sign-in ]] @@ -91,51 +28,3 @@ [[ include ../partials/scripts ]] - \ No newline at end of file diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index bb7cc27..2f6e4c1 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -7,15 +7,14 @@
  • Edit Subscription

  • -
    - You are currently using the free plan. For access to all of Vvalls features, +
  • + You are currently using the free version of Vvalls. For access to all of Vvalls features, consider upgrading to a paid plan. -

    - View the Plans -

  • - + +
    +

    [[- plans.basic.name ]]

    +
      +
    • $[[- plans.basic.monthly_price ]]/mo or $[[- plans.basic.yearly_price ]]/year +
    • Comes with [[- plans.basic.basic_layout_limit ]] basic floor plan and [[- plans.basic.basic_project_limit ]] exhibitions +
    • Each new basic floor plan costs $[[- plans.basic.basic_layout_monthly_price ]]/mo + or $[[- plans.basic.basic_layout_yearly_price ]]/year, minimum 3 months +
    • Each new floor plan can have up to [[- plans.basic.basic_project_limit ]] exhibitions +
    • VValls logo appears when embedding an exhibition on a web page +
    • + [[ if (! logged_in) { ]] + + [[ } else if (! user.plan_level) { ]] + + [[ } else if (user.plan_level == plan.level) { ]] + Current Level + [[ } ]] +
    +
    + +
    +

    [[- plans.pro.name ]]

    +
      +
    • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year +
    • Comes with [[- plans.pro.pro_layout_limit ]] pro floor plan and [[- plans.pro.pro_project_limit ]] exhibitions +
    • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo + or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months +
    • Each new pro floor plan can have up to [[- plans.pro.pro_project_limit ]] exhibitions +
    • Includes planning for 3D objects in the room +
    • No VValls logo on embed +
    • + [[ if (! logged_in) { ]] + + [[ } else if (! user.plan_level) { ]] + + [[ } else if (user.plan_level == plan.level) { ]] + Current Level + [[ } else if (user.plan_level < plan.level) { ]] + + [[ } ]] +
    +
    + +
    +
      +
    • Buying any extra floor plan unlocks collaboration.
      Invite an artist or curator to work on the exhibition with you. +
    • Basic Floor plan: Rectangle-based design of any dimension. +
    • Pro Floor plan: Trace an arbitrary floor plan from image. +
    +
    + +
    +

    Want Something Custom?

    +
  • We offer customized white-label options for business and educational uses. +
  • Contact us for more information. +
  • diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 2f6e4c1..cc296f6 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -1,19 +1,19 @@
    X
    -
    +
    • Edit Subscription

    • -
    • +
    • You are currently using the free version of Vvalls. For access to all of Vvalls features, consider upgrading to a paid plan.

      - +
    • -
    • Your current plan level is diff --git a/views/staff/_users.ejs b/views/staff/_users.ejs index 053e289..46811b6 100644 --- a/views/staff/_users.ejs +++ b/views/staff/_users.ejs @@ -12,7 +12,8 @@ - - @@ -44,7 +42,8 @@
      [[- user.last_seen ]] -- cgit v1.2.3-70-g09d2 From a3f3f4d370da5d38c039f6cdb36223b396eeeb77 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 17:59:29 -0500 Subject: sync gear for test purposes --- .../javascripts/ui/site/EditSubscriptionModal.js | 20 +++++++++++++++----- public/assets/stylesheets/app.css | 14 ++++++++++++++ server/index.js | 2 +- server/lib/api/subscription.js | 4 +++- views/partials/edit-subscription.ejs | 2 ++ 5 files changed, 35 insertions(+), 7 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index e7e1fa5..1637e18 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -2,6 +2,7 @@ var EditSubscriptionModal = ModalFormView.extend({ el: ".mediaDrawer.editSubscription", action: "/api/subscription", + syncAction: "/api/subscription/sync", updateAction: "/api/subscription", destroyAction: "/api/subscription/destroy", @@ -11,6 +12,7 @@ var EditSubscriptionModal = ModalFormView.extend({ events: { "click [data-role='upgradeSubscription']": 'upgradeSubscription', "click [data-role='cancelSubscription']": 'cancelSubscription', + "click .gear": 'sync', }, initialize: function(){ @@ -41,6 +43,7 @@ var EditSubscriptionModal = ModalFormView.extend({ this.$upgradeSubscription = this.$("[data-role=upgradeSubscription]") this.$cancelSubscription = this.$("[data-role=cancelSubscription]") + this.$gear = this.$(".gear") }, plan_levels: { @@ -48,10 +51,6 @@ var EditSubscriptionModal = ModalFormView.extend({ basic: 1, pro: 2, }, - - sync: function(){ - $.put(this.syncAction, this.didLoad.bind(this)) - }, loaded: false, load: function(){ @@ -74,6 +73,7 @@ var EditSubscriptionModal = ModalFormView.extend({ show: function(){ + this.$gear.removeClass("turning") if (! this.subscriber) { this.$freePlan.show() this.$paidPlan.hide() @@ -88,7 +88,7 @@ var EditSubscriptionModal = ModalFormView.extend({ this.$paidPlan.show() this.updateTotals() - + this.__super__.show.call(this) }, @@ -127,6 +127,16 @@ var EditSubscriptionModal = ModalFormView.extend({ this.$planTotal.toDollars ( totals.plan_total ) }, + sync: function(){ + this.$gear.addClass("turning") + $.ajax({ + url: this.syncAction, + type: "put", + data: { _csrf: $("[name=_csrf]").val() }, + success: this.didLoad.bind(this) + }) + }, + update: function(){ $.ajax({ url: this.updateAction, diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 8184032..981869b 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -979,6 +979,20 @@ iframe.embed { .about_custom a { border-bottom: 1px solid; } +.editSubscription .gear { + position: absolute; + top: 10px; + left: 10px; + opacity: 0.1; + cursor: pointer; + transition: all 0.3s; +} +.editSubscription .gear.turning { + opacity: 0.3; + -webkit-transform: rotate(360deg); + transform: rotate(360deg); +} + /* LAYOUTS MODAL */ diff --git a/server/index.js b/server/index.js index fa7044b..5c14d9d 100644 --- a/server/index.js +++ b/server/index.js @@ -151,9 +151,9 @@ site.route = function () { app.post('/api/media/upload', middleware.ensureAuthenticated, api.media.upload) app.delete('/api/media/destroy', middleware.ensureAuthenticated, api.media.destroy) - app.get('/api/subscription/sync', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.sync) app.get('/api/subscription', middleware.ensureAuthenticated, api.subscription.middleware.ensurePlans, api.subscription.middleware.ensureSubscription, api.subscription.show) app.put('/api/subscription', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.update) + app.put('/api/subscription/sync', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.sync) app.delete('/api/subscription', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.destroy) app.get('/partials/plans', views.partials.plans) diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index 9c77dfc..4ec7709 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -8,7 +8,9 @@ var _ = require('lodash'), Project = require('../schemas/Project'), Layout = require('../schemas/Layout'), Plan = require('../schemas/Plan'); - Subscription = require('../schemas/Subscription'); + Subscription = require('../schemas/Subscription'), + Recurly = require('node-recurly'), + recurly = new Recurly(require('../webhook/recurly-config')); var plan_levels = { free: 0, diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index cc296f6..cfd5728 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -12,6 +12,7 @@ consider upgrading to a paid plan.

      +


    • Your current plan level is @@ -43,6 +44,7 @@
    • +
      -- cgit v1.2.3-70-g09d2 From 18c81b8a5c8ac4b6d9cbc16e370fcc37e9138cd6 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 19:04:31 -0500 Subject: styling form --- .../javascripts/ui/site/EditSubscriptionModal.js | 4 ++-- public/assets/stylesheets/app.css | 27 ++++++++++++++++++++++ views/partials/edit-subscription.ejs | 27 ++++++++++++---------- 3 files changed, 44 insertions(+), 14 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 28d699c..0d54d8f 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -30,7 +30,7 @@ var EditSubscriptionModal = ModalView.extend({ this.$billingInterval = this.$("[data-role=billingInterval]") - this.$planType = this.$("[data-role=planType]") + this.$planName = this.$("[data-role=planName]") this.$planCost = this.$("[data-role=planCost]") this.$planTotal = this.$("[data-role=planTotal]") @@ -114,7 +114,7 @@ var EditSubscriptionModal = ModalView.extend({ var plan = this.plans[ this.plan_levels[ subscriber.plan_type ] ] var totals = this.calculateTotals(subscriber, plan) - this.$planType.html ( plan.name ) + this.$planName.html ( plan.name ) this.$planCost.toDollars ( totals.plan_price ) this.$billingInterval.html ( totals.is_monthly ? "mo." : "yr." ) diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 4826aef..bedf2c4 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1000,6 +1000,33 @@ iframe.embed { from { transform: rotate(0deg); } to { transform: rotate(720deg); } } +.paidPlan { + text-align: left; + font-size: 14px; +} +.planInfo { + margin: 10px 0; + width: 100%; + padding: 0; +} +.planInfo td, .planInfo th { + text-align: left; + padding: 10px 3px; + margin: 0; +} +.planInfo td:nth-child(2), +.planInfo th:nth-child(2), +.planInfo td:nth-child(3), +.planInfo td:nth-child(4), +.planInfo th:nth-child(3) { + text-align: right; +} +.planInfo [data-role="billingInterval"] { + font-size: 10px; +} +.totalRow td:nth-child(4) { + border-top: 1px solid; +} /* LAYOUTS MODAL */ diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index cfd5728..266d43b 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -16,29 +16,32 @@
    • Your current plan level is - +
      - + - + + - + - - + + - + - - + + + - - - + + + +
      @ $/$/
      Additional Basic layoutsAdditional Basic layouts @ $/$each $/$/ Buy more
      Additional Pro layoutsAdditional Pro layouts @ $/$@ $ ...$/Buy more
      Total$Total$/
      -- cgit v1.2.3-70-g09d2 From 6a9418a4256c04c327262947f0fee3b615c93029 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 20:27:42 -0500 Subject: buttonz --- .../javascripts/ui/site/EditSubscriptionModal.js | 7 ++++--- public/assets/stylesheets/app.css | 23 ++++++++++++++++++++-- views/partials/edit-subscription.ejs | 5 ++--- 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 0d54d8f..6823740 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -10,7 +10,8 @@ var EditSubscriptionModal = ModalView.extend({ subscriber: null, events: { - "click [data-role='upgradeSubscription']": 'upgradeSubscription', + "click [data-role='addLayouts']": 'addLayouts', + "click [data-role='changePlan']": 'changePlan', "click [data-role='cancelSubscription']": 'cancelSubscription', "click .gear": 'sync', "click .planList button": 'followLink', @@ -141,11 +142,11 @@ var EditSubscriptionModal = ModalView.extend({ }) }, - update: function(){ + update: function(data){ $.ajax({ url: this.updateAction, type: "put", - data: { _csrf: this.$csrf.val() }, + data: { _csrf: $("[name=_csrf]").val() }, success: function(data){ } }) diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index bedf2c4..2570bb2 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -985,12 +985,15 @@ iframe.embed { left: 10px; opacity: 0.1; cursor: pointer; + -webkit-transition: all 0.3s; + -webkit-transform-origin: 49% 53%; transition: all 0.3s; + transform-origin: 49% 53%; } .editSubscription .gear.turning { opacity: 0.3; - -webkit-animation: gear 1s; - animation: gear 1s; + -webkit-animation: gear 1s infinite linear; + animation: gear 1s infinite linear; } @-webkit-keyframes gear { from { transform: rotate(0deg); } @@ -1027,6 +1030,22 @@ iframe.embed { .totalRow td:nth-child(4) { border-top: 1px solid; } +.paidPlan button { + width: 200px; + float: none; + margin: 5px 7px; +} +.paidPlan [data-role="cancelSubscription"] { + color: red; + width: 200px; + float: none; +} +.paidPlan [data-role="cancelSubscription"]:hover { + color: white; + background: red; + border-color: red; +} + /* LAYOUTS MODAL */ diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 266d43b..8599fb5 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -28,14 +28,12 @@
    • each $/ $/Buy more
      Additional Pro layouts @ $ ... $/Buy more
      $/
      - + +
    • -- cgit v1.2.3-70-g09d2 From d08c86d68ceb22665b735054fc3bc316f85f84c1 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sat, 31 Jan 2015 08:51:55 -0500 Subject: billing link in footer --- public/assets/javascripts/ui/site/EditSubscriptionModal.js | 12 ++++++++++-- server/lib/auth/index.js | 4 ++-- views/partials/footer.ejs | 6 ++++++ 3 files changed, 18 insertions(+), 4 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 6823740..82f6903 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -12,7 +12,7 @@ var EditSubscriptionModal = ModalView.extend({ events: { "click [data-role='addLayouts']": 'addLayouts', "click [data-role='changePlan']": 'changePlan', - "click [data-role='cancelSubscription']": 'cancelSubscription', + "click [data-role='cancelSubscription']": 'destroy', "click .gear": 'sync', "click .planList button": 'followLink', }, @@ -132,6 +132,13 @@ var EditSubscriptionModal = ModalView.extend({ this.$planTotal.toDollars ( totals.plan_total ) }, + addLayouts: function(e){ + e.preventDefault() + }, + changePlan: function(e){ + e.preventDefault() + }, + sync: function(){ this.$gear.addClass("turning") $.ajax({ @@ -152,7 +159,8 @@ var EditSubscriptionModal = ModalView.extend({ }) }, - destroy: function(){ + destroy: function(e){ + e.preventDefault() var msg = "Are you sure you want to cancel your subscription?" ConfirmModal.confirm(msg, function(){ $.ajax({ diff --git a/server/lib/auth/index.js b/server/lib/auth/index.js index a9a2400..199377d 100644 --- a/server/lib/auth/index.js +++ b/server/lib/auth/index.js @@ -135,12 +135,12 @@ var auth = { deserializeUser: function (id, done) { try { var _id = mongoose.Types.ObjectId(id) - User.findOne({ _id: _id }, "_id displayName username photo isStaff", function (err, user) { + User.findOne({ _id: _id }, "_id displayName username photo isStaff plan_level", function (err, user) { done(err, user); }); } catch (e) { - User.findOne({ twitter_id: id }, "_id displayName username photo isStaff", function (err, user) { + User.findOne({ twitter_id: id }, "_id displayName username photo isStaff plan_level", function (err, user) { done(err, user); }); } diff --git a/views/partials/footer.ejs b/views/partials/footer.ejs index e3c572f..8a95fc4 100644 --- a/views/partials/footer.ejs +++ b/views/partials/footer.ejs @@ -15,6 +15,12 @@ About How To + + [[ if (logged_in && user.plan_level > 0) { ]] + Billing + [[ } else { ]] + Subscribe + [[ } ]] Terms Privacy Contact -- cgit v1.2.3-70-g09d2 From 6113063fa350114af8f39b87e96cc2c321bc2629 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sat, 31 Jan 2015 10:10:27 -0500 Subject: handle syncing when an account has been cancelled and recreated --- server/lib/api/subscription.js | 109 +++++++++++++++++++---------------- views/partials/edit-subscription.ejs | 2 +- 2 files changed, 59 insertions(+), 52 deletions(-) (limited to 'views/partials') diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index a3baf34..b8853e6 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -47,65 +47,72 @@ var subscription = module.exports = { res.json({ error: "no account" }) return } - if (! data.subscriptions.subscription) { - res.json({ error: "account error" }) - return - } - if (subscriber.state != "active") { - user.plan_type = "free" - user.plan_level = plan_levels["free"] + var subscriptions = data.subscriptions.subscription.length ? data.subscriptions.subscription : [data.subscriptions.subscription] + var is_active = subscriptions.some(function(subscription_data){ + if (subscription_data.state == "active") { + set_active(subscription_data) + return true + } + return false + }) + console.log(data.subscriptions) + if (! is_active) { + set_cancelled() + } + }) + function set_cancelled(){ + user.plan_type = "free" + user.plan_level = plan_levels["free"] - return subscriber.remove(function(){ - user.save(function(){ - res.json({ error: "account cancelled" }) - }) + return subscriber.remove(function(){ + user.save(function(){ + res.json({ error: "account cancelled" }) }) - } - else { - var plan = data.subscriptions.subscription.plan.plan_code.split("-") - var plan_type = plan[0] - var plan_period = plan[1] - - user.plan_type = plan_type - user.plan_level = plan_levels[plan_type] + }) + } + function set_active(data){ + var plan = data.plan.plan_code.split("-") + var plan_type = plan[0] + var plan_period = plan[1] + + user.plan_type = plan_type + user.plan_level = plan_levels[plan_type] - subscriber.uuid = data.subscriptions.subscription.uuid - subscriber.user_id = user._id - subscriber.plan_type = plan_type - subscriber.plan_period = plan_period - subscriber.plan_level = plan_levels[plan_type] - - var add_ons = data.subscriptions.subscription.subscription_add_ons.subscription_add_on - if (add_ons) { - if (add_ons.add_on_code) { - add_ons = [ add_ons ] - } - // TODO: handle multiple add-ons.. presumably this will work - add_ons.forEach(function(add_on){ - var add_on_type = add_on.add_on_code.split("-")[1] - if (add_on_type == "basic") { - subscriber.basic_layouts = parseInt( add_on.quantity._ ) - } - if (add_on_type == "pro") { - subscriber.pro_layouts = parseInt( add_on.quantity._ ) - } - }) - } - else { - subscriber.basic_layouts = 0 - subscriber.pro_layouts = 0 + subscriber.uuid = data.uuid + subscriber.user_id = user._id + subscriber.plan_type = plan_type + subscriber.plan_period = plan_period + subscriber.plan_level = plan_levels[plan_type] + + var add_ons = data.subscription_add_ons.subscription_add_on + if (add_ons) { + if (add_ons.add_on_code) { + add_ons = [ add_ons ] } + // TODO: handle multiple add-ons.. presumably this will work + add_ons.forEach(function(add_on){ + var add_on_type = add_on.add_on_code.split("-")[1] + if (add_on_type == "basic") { + subscriber.basic_layouts = parseInt( add_on.quantity._ ) + } + if (add_on_type == "pro") { + subscriber.pro_layouts = parseInt( add_on.quantity._ ) + } + }) + } + else { + subscriber.basic_layouts = 0 + subscriber.pro_layouts = 0 } - - subscriber.save(function(){ - user.save(function(){ - res.json({ + subscriber.save(function(){ + user.save(function(){ + res.json({ subscription: subscriber, plans: res.locals.plans }) - }) - }) - }) + }) + }) + } }, show: function(req, res){ diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 8599fb5..69ec88d 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -42,7 +42,7 @@ $/ - + -- cgit v1.2.3-70-g09d2 From ef52758ef0c27760a93ca861f1d17259dbc40fc4 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sat, 31 Jan 2015 19:10:24 -0500 Subject: adding radio buttons etc --- .../javascripts/ui/site/EditSubscriptionModal.js | 31 +++++++++++++++++-- public/assets/stylesheets/app.css | 11 +++++-- server/index.js | 2 +- server/lib/api/subscription.js | 2 +- views/partials/edit-subscription.ejs | 35 +++++++++++++++++----- 5 files changed, 68 insertions(+), 13 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 0f72995..619bff8 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -35,6 +35,11 @@ var EditSubscriptionModal = ModalView.extend({ this.$planCost = this.$("[data-role=planCost]") this.$planTotal = this.$("[data-role=planTotal]") + this.$basicPlanName = this.$("[data-role=basicPlanName]") + this.$proPlanName = this.$("[data-role=proPlanName]") + this.$basicPlanCost = this.$("[data-role=basicPlanCost]") + this.$proPlanCost = this.$("[data-role=proPlanCost]") + this.$basicLayoutCost = this.$("[data-role=basicLayoutCost]") this.$basicLayoutQuantity = this.$("[data-role=basicLayoutQuantity]") this.$basicLayoutTotal = this.$("[data-role=basicLayoutTotal]") @@ -43,8 +48,24 @@ var EditSubscriptionModal = ModalView.extend({ this.$proLayoutQuantity = this.$("[data-role=proLayoutQuantity]") this.$proLayoutTotal = this.$("[data-role=proLayoutTotal]") + this.$showLayoutsMenu = this.$("[data-role=showLayoutsMenu]") + this.$showPlanMenu = this.$("[data-role=showPlanMenu]") + + this.$layoutsMenu = this.$("[data-role=layoutsMenu]") + this.$planMenu = this.$("[data-role=planMenu]") + this.$closeMenu = this.$("[data-role=closeMenu]") + + this.$buyLayouts = this.$("[data-role=buyLayouts]") + + this.$changePlan = this.$("[data-role=changePlan]") + + this.$basicLayoutInput = this.$("[data-role=basicLayoutInput]") + this.$proLayoutInput = this.$("[data-role=proLayoutInput]") + this.$planRadio = this.$("[name=planRadio]") + this.$upgradeSubscription = this.$("[data-role=upgradeSubscription]") this.$cancelSubscription = this.$("[data-role=cancelSubscription]") + this.$gear = this.$(".gear") }, @@ -100,7 +121,7 @@ var EditSubscriptionModal = ModalView.extend({ var t = {} t.is_pro = plan.name == "pro" t.is_monthly = subscriber.plan_period == "monthly" - t.plan_price = t.is_monthly ? plan.monthly_price : plan.yearly_price + t.plan_price = t.is_monthly ? plan.basic_layout_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 @@ -113,12 +134,18 @@ var EditSubscriptionModal = ModalView.extend({ var subscriber = this.subscriber var plan = this.plans[ this.plan_levels[ subscriber.plan_type ] ] 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.$proLayoutRow.toggle ( totals.is_pro ) + 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 ) diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 082a2d4..4144b8b 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -987,6 +987,8 @@ iframe.embed { font-size: 1.9vw; padding: 0; } + +/* debug sync button */ .editSubscription .gear { position: absolute; top: 10px; @@ -1053,8 +1055,13 @@ iframe.embed { background: red; border-color: red; } - - +/* purchase mode */ +.paidPlan input[type=number] { display: none } +.paidPlan.editing input[type=number] { display: inline-block } +.paidPlan.editing input[type=number]+span { display: none } +form .paidPlan div { float: none; } +form .paidPlan label { float: none; font-size: 2vw; margin: 0 10px; } +.paidPlan .upgradeMenu div { padding: 5px 10px; } /* LAYOUTS MODAL */ diff --git a/server/index.js b/server/index.js index 3572675..8c8212f 100644 --- a/server/index.js +++ b/server/index.js @@ -72,7 +72,7 @@ site.setup = function(){ server = http.createServer(app) server.listen(app.get('port'), function () { - console.log('Vvalls server listening on port ' + app.get('port')); + console.log('VValls server listening on port ' + app.get('port')); }); // var io = websocket.listen(server) diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index 3a8403f..6f08e66 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -28,7 +28,7 @@ var subscription = module.exports = { }) }, ensurePlans: function(req, res, next){ - Plan.find({}).sort({ 'level': -1 }).exec(function (err, plans) { + Plan.find({}).sort({ 'level': 1 }).exec(function (err, plans) { res.locals.plans = (plans || []) next() }) diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 69ec88d..fcb4b94 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -8,13 +8,13 @@

      Edit Subscription

    • - You are currently using the free version of Vvalls. For access to all of Vvalls features, + You are currently using the free version of VValls. For access to all of VValls features, consider upgrading to a paid plan.




    • -
    • +
    • Your current plan level is @@ -25,13 +25,13 @@ - + - + @@ -42,9 +42,30 @@
      Additional Basic layouts each $/ $/
      Additional Pro layouts @ $ ... $/
      $/
      - - - +
      + + + +
      +
      + + +
      +
      +

      Select desired plan:

      +
      + + + $/ +
      +
      + + + $/ +
      + + +
    -- cgit v1.2.3-70-g09d2 From 97e7312439b24bfdd255f6868e8b42c469b0b38e Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 1 Feb 2015 14:49:10 -0500 Subject: basic ui --- .../javascripts/ui/site/EditSubscriptionModal.js | 60 ++++++++++++++++++++-- public/assets/stylesheets/app.css | 10 +++- views/partials/edit-subscription.ejs | 4 +- 3 files changed, 65 insertions(+), 9 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index af3b99e..539a8ae 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -8,6 +8,7 @@ var EditSubscriptionModal = ModalView.extend({ fixedClose: true, subscriber: null, + tempSubscriber: null, events: { "click [data-role='addLayouts']": 'addLayouts', @@ -19,16 +20,62 @@ var EditSubscriptionModal = ModalView.extend({ "click [data-role=showLayoutsMenu]": "layoutsMode", "click [data-role=showPlanMenu]": "planMode", - "click [data-role=closeMenu]": "reset", + "click [data-role=closeMenu]": "resetMode", "input [data-role=basicLayoutInput]": "updateQuantity", "input [data-role=proLayoutInput]": "updateQuantity", - "click [data-role=buyLayouts]": "saveLayouts", + "click [data-role=saveQuantity]": "saveQuantity", "input [name=planRadio]": "updatePlan", "click [data-role=changePlan]": "savePlan", }, - + + resetMode: function(e){ + e.preventDefault() + this.$paidPlan.removeClass("editLayouts editPlan") + this.reset() + }, + + layoutsMode: function(e){ + e.preventDefault() + this.$paidPlan.addClass("editLayouts") + this.tempSubscriber = defaults({}, this.subscriber) + this.$basicLayoutInput.val( this.subscriber.basic_layouts ) + this.$proLayoutInput.val( this.subscriber.pro_layouts ) + }, + updateQuantity: function(e){ + e.preventDefault() + this.tempSubscriber.basic_layouts = this.$proLayoutInput.int() + this.tempSubscriber.pro_layouts = this.$basicLayoutInput.int() + + var plan = this.getPlan( this.tempSubscriber.plan_type ) + this.displayTotals(this.tempSubscriber, plan) + }, + saveQuantity: function(e){ + e.preventDefault() + // blabla.. save + this.subscriber = this.tempSubscriber + this.resetMode() + }, + + planMode: function(e){ + e.preventDefault() + this.$paidPlan.addClass("editPlan") + this.$planRadio.val( this.subscriber.plan_type ) + this.tempSubscriber = defaults({}, this.subscriber) + }, + updatePlan: function(e){ + e.preventDefault() + var plan = this.getPlan( this.$("[name=planRadio]").val() ) + this.displayTotals(this.tempSubscriber, plan) + }, + savePlan: function(e){ + e.preventDefault() + this.subscriber.plan_type = this.$("[name=planRadio]").val() + this.subscriber = this.tempSubscriber + this.resetMode() + }, + initialize: function(){ // this.parent = opt.parent this.__super__.initialize.call(this) @@ -137,8 +184,11 @@ var EditSubscriptionModal = ModalView.extend({ }, reset: function(){ var subscriber = this.subscriber - var plan = this.plans[ this.plan_levels[ subscriber.plan_type ] ] - this.displayTotals(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 = {} diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 4144b8b..b3d380c 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1057,11 +1057,17 @@ iframe.embed { } /* purchase mode */ .paidPlan input[type=number] { display: none } -.paidPlan.editing input[type=number] { display: inline-block } -.paidPlan.editing input[type=number]+span { display: none } form .paidPlan div { float: none; } form .paidPlan label { float: none; font-size: 2vw; margin: 0 10px; } .paidPlan .upgradeMenu div { padding: 5px 10px; } +.paidPlan .layoutsMenu { display: none } +.paidPlan .planMenu { display: none } +.paidPlan.editLayouts .layoutsMenu { display: block } +.paidPlan.editLayouts .billingMenu { display: none } +.paidPlan.editLayouts input[type=number] { display: inline-block } +.paidPlan.editLayouts input[type=number]+span { display: none } +.paidPlan.editPlan .planMenu { display: block } +.paidPlan.editPlan .billingMenu { display: none } /* LAYOUTS MODAL */ diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index fcb4b94..086f513 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -48,7 +48,7 @@
    - +
    @@ -63,7 +63,7 @@ $/
    - +
    -- cgit v1.2.3-70-g09d2 From fbf637f2210d281c8c6f41b72cf50746939a8ece Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 1 Feb 2015 15:32:01 -0500 Subject: edit layout counts --- .../javascripts/ui/site/EditSubscriptionModal.js | 24 +++++++++++++--------- public/assets/stylesheets/app.css | 13 ++++++++++-- views/partials/edit-subscription.ejs | 4 ++-- 3 files changed, 27 insertions(+), 14 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 539a8ae..fe93499 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -31,46 +31,50 @@ var EditSubscriptionModal = ModalView.extend({ }, resetMode: function(e){ - e.preventDefault() + e && e.preventDefault() this.$paidPlan.removeClass("editLayouts editPlan") this.reset() }, layoutsMode: function(e){ - e.preventDefault() + e && e.preventDefault() this.$paidPlan.addClass("editLayouts") 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_name == "pro") }, updateQuantity: function(e){ - e.preventDefault() - this.tempSubscriber.basic_layouts = this.$proLayoutInput.int() - this.tempSubscriber.pro_layouts = this.$basicLayoutInput.int() + e && e.preventDefault() + this.tempSubscriber.basic_layouts = this.$basicLayoutInput.int() + this.tempSubscriber.pro_layouts = this.$proLayoutInput.int() var plan = this.getPlan( this.tempSubscriber.plan_type ) this.displayTotals(this.tempSubscriber, plan) + this.$basicLayoutRow.show() + this.$proLayoutRow.toggle(plan.name == "pro") }, saveQuantity: function(e){ - e.preventDefault() + e && e.preventDefault() // blabla.. save this.subscriber = this.tempSubscriber this.resetMode() }, planMode: function(e){ - e.preventDefault() + e && e.preventDefault() this.$paidPlan.addClass("editPlan") this.$planRadio.val( this.subscriber.plan_type ) this.tempSubscriber = defaults({}, this.subscriber) }, updatePlan: function(e){ - e.preventDefault() + e && e.preventDefault() var plan = this.getPlan( this.$("[name=planRadio]").val() ) this.displayTotals(this.tempSubscriber, plan) }, savePlan: function(e){ - e.preventDefault() + e && e.preventDefault() this.subscriber.plan_type = this.$("[name=planRadio]").val() this.subscriber = this.tempSubscriber this.resetMode() @@ -178,7 +182,7 @@ var EditSubscriptionModal = ModalView.extend({ this.$freePlan.hide() this.$paidPlan.show() - this.reset() + this.resetMode() this.__super__.show.call(this) }, diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index b3d380c..b58bb01 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1027,6 +1027,10 @@ iframe.embed { padding: 10px 3px; margin: 0; } +.planInfo td { + height: 60px; + vertical-align: middle; +} .planInfo td:nth-child(2), .planInfo th:nth-child(2), .planInfo td:nth-child(3), @@ -1034,6 +1038,10 @@ iframe.embed { .planInfo th:nth-child(3) { text-align: right; } +.planInfo td:nth-child(4) { + width: 90px; +} + .planInfo [data-role="billingInterval"] { font-size: 10px; } @@ -1046,7 +1054,8 @@ iframe.embed { margin: 5px 7px; } .paidPlan [data-role="cancelSubscription"] { - color: red; + color: #800; + border-color: black; width: 200px; float: none; } @@ -1056,7 +1065,7 @@ iframe.embed { border-color: red; } /* purchase mode */ -.paidPlan input[type=number] { display: none } +.paidPlan input[type=number] { display: none; float: right; } form .paidPlan div { float: none; } form .paidPlan label { float: none; font-size: 2vw; margin: 0 10px; } .paidPlan .upgradeMenu div { padding: 5px 10px; } diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 086f513..19f6851 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -43,8 +43,8 @@
    - - +
    +
    -- cgit v1.2.3-70-g09d2 From 60aa806d65a90907c6a76cb017c167c8453260b3 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 1 Feb 2015 16:58:58 -0500 Subject: plan val from radio button --- .../javascripts/ui/site/EditSubscriptionModal.js | 110 ++++++++++----------- views/partials/edit-subscription.ejs | 4 +- 2 files changed, 56 insertions(+), 58 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index fe93499..b9abd75 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -26,60 +26,10 @@ var EditSubscriptionModal = ModalView.extend({ "input [data-role=proLayoutInput]": "updateQuantity", "click [data-role=saveQuantity]": "saveQuantity", - "input [name=planRadio]": "updatePlan", + "change [name=planRadio]": "updatePlan", "click [data-role=changePlan]": "savePlan", }, - resetMode: function(e){ - e && e.preventDefault() - this.$paidPlan.removeClass("editLayouts editPlan") - this.reset() - }, - - layoutsMode: function(e){ - e && e.preventDefault() - this.$paidPlan.addClass("editLayouts") - 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_name == "pro") - }, - updateQuantity: function(e){ - e && e.preventDefault() - this.tempSubscriber.basic_layouts = this.$basicLayoutInput.int() - this.tempSubscriber.pro_layouts = this.$proLayoutInput.int() - - var plan = this.getPlan( this.tempSubscriber.plan_type ) - this.displayTotals(this.tempSubscriber, plan) - this.$basicLayoutRow.show() - this.$proLayoutRow.toggle(plan.name == "pro") - }, - saveQuantity: function(e){ - e && e.preventDefault() - // blabla.. save - this.subscriber = this.tempSubscriber - this.resetMode() - }, - - planMode: function(e){ - e && e.preventDefault() - this.$paidPlan.addClass("editPlan") - this.$planRadio.val( this.subscriber.plan_type ) - this.tempSubscriber = defaults({}, this.subscriber) - }, - updatePlan: function(e){ - e && e.preventDefault() - var plan = this.getPlan( this.$("[name=planRadio]").val() ) - this.displayTotals(this.tempSubscriber, plan) - }, - savePlan: function(e){ - e && e.preventDefault() - this.subscriber.plan_type = this.$("[name=planRadio]").val() - this.subscriber = this.tempSubscriber - this.resetMode() - }, - initialize: function(){ // this.parent = opt.parent this.__super__.initialize.call(this) @@ -135,6 +85,8 @@ var EditSubscriptionModal = ModalView.extend({ 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") }, @@ -198,7 +150,7 @@ var EditSubscriptionModal = ModalView.extend({ var t = {} t.is_pro = plan.name == "pro" t.is_monthly = subscriber.plan_period == "monthly" - t.plan_price = t.is_monthly ? plan.basic_layout_monthly_price : plan.yearly_price + 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 @@ -232,13 +184,59 @@ var EditSubscriptionModal = ModalView.extend({ this.$planTotal.toDollars ( totals.plan_total ) }, - addLayouts: function(e){ - e.preventDefault() + resetMode: function(e){ + e && e.preventDefault() + this.$paidPlan.removeClass("editLayouts editPlan") + this.reset() }, - changePlan: function(e){ - e.preventDefault() + + layoutsMode: function(e){ + e && e.preventDefault() + this.$paidPlan.addClass("editLayouts") + 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_name == "pro") + }, + updateQuantity: function(e){ + e && e.preventDefault() + var plan = this.getPlan( this.tempSubscriber.plan_type ) + this.tempSubscriber.basic_layouts = this.$basicLayoutInput.int() + this.tempSubscriber.pro_layouts = this.$proLayoutInput.int() + this.displayTotals(this.tempSubscriber, plan) + this.$basicLayoutRow.show() + this.$proLayoutRow.toggle(plan.name == "pro") + }, + saveQuantity: function(e){ + e && e.preventDefault() + this.subscriber = this.tempSubscriber + this.resetMode() + // blabla.. save }, + planMode: function(e){ + e && e.preventDefault() + this.$paidPlan.addClass("editPlan") + switch (this.subscriber.plan_type) { + case 'basic': this.$basicPlanInput.prop('checked', true); break; + case 'pro': this.$proPlanInput.prop('checked', true); break; + } + this.tempSubscriber = defaults({}, this.subscriber) + }, + updatePlan: function(e){ + e && e.preventDefault() + var plan_type = this.$("[name=planRadio]:checked").val() + var plan = this.getPlan( plan_type ) + this.displayTotals(this.tempSubscriber, plan) + }, + savePlan: function(e){ + e && e.preventDefault() + this.subscriber.plan_type = this.$("[name=planRadio]:checked").val() + this.subscriber = this.tempSubscriber + this.resetMode() + // blabla.. save + }, sync: function(){ this.$gear.addClass("turning") $.ajax({ diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 19f6851..e651187 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -54,12 +54,12 @@

    Select desired plan:

    - + $/
    - + $/
    -- cgit v1.2.3-70-g09d2 From 003f59d687d8d3d5e4e9c4a2eeb1bb167753d0c9 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 1 Feb 2015 18:22:28 -0500 Subject: check form input --- .../javascripts/ui/site/EditSubscriptionModal.js | 18 +++++++++++------- views/partials/edit-subscription.ejs | 6 +++--- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index b9abd75..384460d 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -27,7 +27,9 @@ var EditSubscriptionModal = ModalView.extend({ "click [data-role=saveQuantity]": "saveQuantity", "change [name=planRadio]": "updatePlan", - "click [data-role=changePlan]": "savePlan", + "click [data-role=savePlan]": "savePlan", + + "submit form": "preventDefault", }, initialize: function(){ @@ -148,7 +150,7 @@ var EditSubscriptionModal = ModalView.extend({ }, calculateTotals: function(subscriber, plan){ var t = {} - t.is_pro = plan.name == "pro" + 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 @@ -197,16 +199,19 @@ var EditSubscriptionModal = ModalView.extend({ this.$basicLayoutInput.val( this.subscriber.basic_layouts ) this.$proLayoutInput.val( this.subscriber.pro_layouts ) this.$basicLayoutRow.show() - this.$proLayoutRow.toggle(this.subscriber.plan_name == "pro") + this.$proLayoutRow.toggle(this.subscriber.plan_type == "pro") }, updateQuantity: function(e){ e && e.preventDefault() var plan = this.getPlan( this.tempSubscriber.plan_type ) - this.tempSubscriber.basic_layouts = this.$basicLayoutInput.int() - this.tempSubscriber.pro_layouts = this.$proLayoutInput.int() + 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(plan.name == "pro") + this.$proLayoutRow.toggle(this.tempSubscriber.plan_type == "pro") }, saveQuantity: function(e){ e && e.preventDefault() @@ -233,7 +238,6 @@ var EditSubscriptionModal = ModalView.extend({ savePlan: function(e){ e && e.preventDefault() this.subscriber.plan_type = this.$("[name=planRadio]:checked").val() - this.subscriber = this.tempSubscriber this.resetMode() // blabla.. save }, diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index e651187..1b0fc41 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -32,7 +32,7 @@ Additional Pro layouts - @ $ ... + each $/ $/ @@ -43,12 +43,12 @@
    -
    +

    - +
    -- cgit v1.2.3-70-g09d2 From 3f0ef2173b6d00ae8130b3125b63f3d9ad9e98de Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 1 Feb 2015 18:48:08 -0500 Subject: make it 1 action --- .../javascripts/ui/site/EditSubscriptionModal.js | 57 ++++++++++------------ public/assets/stylesheets/app.css | 14 +++--- views/partials/edit-subscription.ejs | 43 ++++++++-------- 3 files changed, 56 insertions(+), 58 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 384460d..6e5dc9e 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -7,6 +7,7 @@ var EditSubscriptionModal = ModalView.extend({ destroyAction: "/api/subscription/destroy", fixedClose: true, + editing: false, subscriber: null, tempSubscriber: null, @@ -17,14 +18,13 @@ var EditSubscriptionModal = ModalView.extend({ "click .gear": 'sync', "click .planList button": 'followLink', - "click [data-role=showLayoutsMenu]": "layoutsMode", - "click [data-role=showPlanMenu]": "planMode", + "click [data-role=showEditMenu]": "editMode", "click [data-role=closeMenu]": "resetMode", "input [data-role=basicLayoutInput]": "updateQuantity", "input [data-role=proLayoutInput]": "updateQuantity", - "click [data-role=saveQuantity]": "saveQuantity", + "click [data-role=saveChanges]": "saveChanges", "change [name=planRadio]": "updatePlan", "click [data-role=savePlan]": "savePlan", @@ -186,21 +186,28 @@ var EditSubscriptionModal = ModalView.extend({ this.$planTotal.toDollars ( totals.plan_total ) }, - resetMode: function(e){ - e && e.preventDefault() - this.$paidPlan.removeClass("editLayouts editPlan") - this.reset() - }, - - layoutsMode: function(e){ + editMode: function(e){ e && e.preventDefault() - this.$paidPlan.addClass("editLayouts") + + 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 ) @@ -213,34 +220,24 @@ var EditSubscriptionModal = ModalView.extend({ this.$basicLayoutRow.show() this.$proLayoutRow.toggle(this.tempSubscriber.plan_type == "pro") }, - saveQuantity: function(e){ + saveChanges: function(e){ e && e.preventDefault() + if (this.tempSubscriber.plan_type != this.subscriber.plan_type + || this.tempSubscriber.basic_layouts != this.subscriber.basic_layouts + || this.tempSubscriber.pro_layouts != this.subscriber.pro_layouts) { + // update plan_type + } this.subscriber = this.tempSubscriber this.resetMode() // blabla.. save }, - planMode: function(e){ - e && e.preventDefault() - this.$paidPlan.addClass("editPlan") - switch (this.subscriber.plan_type) { - case 'basic': this.$basicPlanInput.prop('checked', true); break; - case 'pro': this.$proPlanInput.prop('checked', true); break; - } - this.tempSubscriber = defaults({}, this.subscriber) - }, updatePlan: function(e){ e && e.preventDefault() - var plan_type = this.$("[name=planRadio]:checked").val() - var plan = this.getPlan( plan_type ) - this.displayTotals(this.tempSubscriber, plan) - }, - savePlan: function(e){ - e && e.preventDefault() - this.subscriber.plan_type = this.$("[name=planRadio]:checked").val() - this.resetMode() - // blabla.. save + this.tempSubscriber.plan_type = this.$("[name=planRadio]:checked").val() + this.updateQuantity() }, + sync: function(){ this.$gear.addClass("turning") $.ajax({ diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index b58bb01..ffb133d 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1071,12 +1071,14 @@ form .paidPlan label { float: none; font-size: 2vw; margin: 0 10px; } .paidPlan .upgradeMenu div { padding: 5px 10px; } .paidPlan .layoutsMenu { display: none } .paidPlan .planMenu { display: none } -.paidPlan.editLayouts .layoutsMenu { display: block } -.paidPlan.editLayouts .billingMenu { display: none } -.paidPlan.editLayouts input[type=number] { display: inline-block } -.paidPlan.editLayouts input[type=number]+span { display: none } -.paidPlan.editPlan .planMenu { display: block } -.paidPlan.editPlan .billingMenu { display: none } + +.editing .section_break { display: none } +.editing .paidPlan .currentPlanLevel { display: none } +.editing .paidPlan .billingMenu { display: none } +.editing .paidPlan .layoutsMenu { display: block } +.editing .paidPlan .planMenu { display: block } +.editing .paidPlan input[type=number] { display: inline-block } +.editing .paidPlan input[type=number]+span { display: none } /* LAYOUTS MODAL */ diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 1b0fc41..38c6dfc 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -14,8 +14,23 @@



    -
  • - Your current plan level is +
  • +
    + Your current plan level is +
    +
    +

    Select desired plan:

    +
    + + + $/ +
    +
    + + + $/ +
    +
    @@ -24,13 +39,13 @@ - + - + @@ -43,27 +58,11 @@
    $/
    Additional Basic layoutsBasic layouts each $/ $/
    Additional Pro layoutsPro layouts each $/ $/
    -
    -
    +
    - - -
    -
    -

    Select desired plan:

    -
    - - - $/ -
    -
    - - - $/ -
    - +
  • -- cgit v1.2.3-70-g09d2 From d45c7f3c6e5a05a263f4a58dea83f2d578013f12 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 1 Feb 2015 18:49:29 -0500 Subject: save changes on profile --- views/partials/edit-profile.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views/partials') diff --git a/views/partials/edit-profile.ejs b/views/partials/edit-profile.ejs index 5775ca5..5720bc8 100644 --- a/views/partials/edit-profile.ejs +++ b/views/partials/edit-profile.ejs @@ -83,7 +83,7 @@
  • - +
  • There was a problem with your submission:
    -- cgit v1.2.3-70-g09d2 From 9e40939c50cf098e88f7d66f85bd925fcc9d01e4 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 1 Feb 2015 18:52:32 -0500 Subject: space for blabitybla text --- public/assets/javascripts/ui/site/EditSubscriptionModal.js | 8 +++++--- public/assets/stylesheets/app.css | 5 +++-- views/partials/edit-subscription.ejs | 7 ++++++- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 6e5dc9e..cd3d1bb 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -71,12 +71,11 @@ var EditSubscriptionModal = ModalView.extend({ this.$proLayoutTotal = this.$("[data-role=proLayoutTotal]") // menus.. main menu - this.$showLayoutsMenu = this.$("[data-role=showLayoutsMenu]") - this.$showPlanMenu = this.$("[data-role=showPlanMenu]") + this.$showEditMenu = this.$("[data-role=showEditMenu]") this.$cancelSubscription = this.$("[data-role=cancelSubscription]") // three submenus - this.$layoutsMenu = this.$("[data-role=layoutsMenu]") + this.$editMenu = this.$("[data-role=editMenu]") this.$planMenu = this.$("[data-role=planMenu]") this.$buyLayouts = this.$("[data-role=buyLayouts]") @@ -270,6 +269,9 @@ var EditSubscriptionModal = ModalView.extend({ this.didLoad(data) }.bind(this) }) + }.bind(this), + function(){ + this.show() }.bind(this)) }, diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index ffb133d..7c49ed1 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1069,17 +1069,18 @@ iframe.embed { form .paidPlan div { float: none; } form .paidPlan label { float: none; font-size: 2vw; margin: 0 10px; } .paidPlan .upgradeMenu div { padding: 5px 10px; } -.paidPlan .layoutsMenu { display: none } +.paidPlan .editMenu { display: none } .paidPlan .planMenu { display: none } .editing .section_break { display: none } .editing .paidPlan .currentPlanLevel { display: none } .editing .paidPlan .billingMenu { display: none } -.editing .paidPlan .layoutsMenu { display: block } +.editing .paidPlan .editMenu { display: block } .editing .paidPlan .planMenu { display: block } .editing .paidPlan input[type=number] { display: inline-block } .editing .paidPlan input[type=number]+span { display: none } +.editMenu .fineprint { font-size: 12px; width: auto; text-align: justify; } /* LAYOUTS MODAL */ .templates { diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 38c6dfc..f3c3589 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -61,7 +61,12 @@
    -
    +
    +
    + Your credit card will be charged the difference of XXXX for this month. + Your subscription will renew at XXXX at the start of your next billing cycle. + We thank you for your support! +
    -- cgit v1.2.3-70-g09d2 From 0cb3f8b480e46a3376b5accba18cde0c3cbdd13d Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 2 Feb 2015 10:53:28 -0500 Subject: bower moved lodash --- Gruntfile.js | 2 +- views/partials/scripts.ejs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'views/partials') diff --git a/Gruntfile.js b/Gruntfile.js index ed236c5..f7af106 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -9,7 +9,7 @@ module.exports = function(grunt) { js: { src: [ "public/assets/javascripts/vendor/bower_components/jquery/dist/jquery.min.js", - "public/assets/javascripts/vendor/bower_components/lodash/dist/lodash.min.js", + "public/assets/javascripts/vendor/bower_components/lodash/lodash.min.js", "public/assets/javascripts/vendor/bower_components/momentjs/min/moment.min.js", "public/assets/javascripts/vendor/bower_components/fiber/src/fiber.min.js", "public/assets/javascripts/vendor/bower_components/marked/lib/marked.js", diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 04bd945..a58eca1 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -2,7 +2,7 @@ [[ } else { ]] - + -- cgit v1.2.3-70-g09d2 From 673cd38ccb8a9c6ba7ec0a879fc96dcc580b046c Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 3 Feb 2015 14:46:16 -0500 Subject: enable hidpi canvas in main app --- Gruntfile.js | 1 + bower.json | 2 +- .../javascripts/rectangles/engine/map/draw.js | 2 +- public/assets/javascripts/ui/lib/LabColorPicker.js | 26 ++++++++++++---------- public/assets/javascripts/ui/reader/Tracker.js | 14 +++++++----- public/assets/test/surface.html | 2 +- views/controls/editor/color-control.ejs | 2 +- views/partials/scripts.ejs | 1 + 8 files changed, 29 insertions(+), 21 deletions(-) (limited to 'views/partials') diff --git a/Gruntfile.js b/Gruntfile.js index f7af106..70a8b13 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -13,6 +13,7 @@ module.exports = function(grunt) { "public/assets/javascripts/vendor/bower_components/momentjs/min/moment.min.js", "public/assets/javascripts/vendor/bower_components/fiber/src/fiber.min.js", "public/assets/javascripts/vendor/bower_components/marked/lib/marked.js", + "public/assets/javascripts/vendor/bower_components/hidpi-canvas/dist/hidpi-canvas.js", "public/assets/javascripts/vendor/tube.js", "public/assets/javascripts/vendor/loader.js", "public/assets/javascripts/vendor/polyfill.js", diff --git a/bower.json b/bower.json index c78310d..e3e83ca 100644 --- a/bower.json +++ b/bower.json @@ -10,6 +10,6 @@ "jquery-jsonview": "1.2.0", "prefixfree": "", "marked": "0.3.2", - "hidpi-canvas": "~1.0.9" + "hidpi-canvas": "git://github.com/julescarbon/hidpi-canvas-polyfill.git#master" } } diff --git a/public/assets/javascripts/rectangles/engine/map/draw.js b/public/assets/javascripts/rectangles/engine/map/draw.js index eceda3c..5a9b592 100644 --- a/public/assets/javascripts/rectangles/engine/map/draw.js +++ b/public/assets/javascripts/rectangles/engine/map/draw.js @@ -56,9 +56,9 @@ Map.Draw = function(map, opt){ } var canvas = document.createElement("canvas") - ctx = canvas.getContext('2d') canvas.width = thumbnail_width canvas.height = thumbnail_height + ctx = canvas.getContext('2d') draw.clear() 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/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/test/surface.html b/public/assets/test/surface.html index 02b473d..9e6abe8 100644 --- a/public/assets/test/surface.html +++ b/public/assets/test/surface.html @@ -2,7 +2,7 @@ - + diff --git a/views/controls/editor/color-control.ejs b/views/controls/editor/color-control.ejs index c035e24..bcc955d 100644 --- a/views/controls/editor/color-control.ejs +++ b/views/controls/editor/color-control.ejs @@ -1,4 +1,4 @@ -
    +

    Edit Room Colors

    diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index a58eca1..011644b 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -5,6 +5,7 @@ + -- cgit v1.2.3-70-g09d2 From e9aaaba09e7872fd6fd164f02ea6cc28251962b8 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 24 Mar 2015 13:25:04 -0400 Subject: copyright year --- views/partials/footer.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'views/partials') diff --git a/views/partials/footer.ejs b/views/partials/footer.ejs index 8a95fc4..52430f7 100644 --- a/views/partials/footer.ejs +++ b/views/partials/footer.ejs @@ -25,7 +25,7 @@ Privacy Contact

    - ©2014 Dot Dash 3, Inc. + © 2015 Dot Dash 3, Inc. Site by OKFocus
    -- cgit v1.2.3-70-g09d2 From 0a67e7f8ab74f82212a123dd6c30903124c1e8df Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 24 Mar 2015 17:08:47 -0400 Subject: sound interpolation --- .../assets/javascripts/mx/primitives/mx.soundcloud.js | 5 +++++ public/assets/javascripts/mx/primitives/mx.video.js | 2 +- public/assets/javascripts/mx/primitives/mx.vimeo.js | 2 +- public/assets/javascripts/mx/primitives/mx.youtube.js | 2 +- .../javascripts/rectangles/engine/scenery/_scenery.js | 1 + .../javascripts/rectangles/engine/scenery/sound.js | 17 +++++++++++++++++ .../rectangles/engine/scenery/types/audio.js | 4 ++++ views/partials/scripts.ejs | 1 + 8 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 public/assets/javascripts/rectangles/engine/scenery/sound.js (limited to 'views/partials') diff --git a/public/assets/javascripts/mx/primitives/mx.soundcloud.js b/public/assets/javascripts/mx/primitives/mx.soundcloud.js index 75286d9..fecb2f4 100644 --- a/public/assets/javascripts/mx/primitives/mx.soundcloud.js +++ b/public/assets/javascripts/mx/primitives/mx.soundcloud.js @@ -102,6 +102,11 @@ MX.Soundcloud = MX.Object3D.extend({ setLoop: function(state){ this.media.loop = state }, + + setVolume: function(n){ + if (this.muted || ! this.player) return + this.player.setVolume(floor( n * 100 )) + }, didPlay: function(){ this.paused = false diff --git a/public/assets/javascripts/mx/primitives/mx.video.js b/public/assets/javascripts/mx/primitives/mx.video.js index 9138cdd..43c392a 100644 --- a/public/assets/javascripts/mx/primitives/mx.video.js +++ b/public/assets/javascripts/mx/primitives/mx.video.js @@ -88,7 +88,7 @@ MX.Video = MX.Object3D.extend({ }, setVolume: function(n){ - if (this.muted) return + if (this.muted || ! this.player) return this.player.volume = n }, diff --git a/public/assets/javascripts/mx/primitives/mx.vimeo.js b/public/assets/javascripts/mx/primitives/mx.vimeo.js index bff781b..ccd0a13 100644 --- a/public/assets/javascripts/mx/primitives/mx.vimeo.js +++ b/public/assets/javascripts/mx/primitives/mx.vimeo.js @@ -132,7 +132,7 @@ MX.Vimeo = MX.Object3D.extend({ }, setVolume: function(n){ - if (this.muted) return + if (this.muted || ! this.player) return this.player.api('setVolume', n) }, diff --git a/public/assets/javascripts/mx/primitives/mx.youtube.js b/public/assets/javascripts/mx/primitives/mx.youtube.js index fad66dd..e4e73d6 100644 --- a/public/assets/javascripts/mx/primitives/mx.youtube.js +++ b/public/assets/javascripts/mx/primitives/mx.youtube.js @@ -175,7 +175,7 @@ MX.Youtube = MX.Object3D.extend({ }, setVolume: function(n){ - if (this.muted) return + if (this.muted || ! this.player || ! this.player.setVolume) return this.player.setVolume( floor(n * 100) ) }, diff --git a/public/assets/javascripts/rectangles/engine/scenery/_scenery.js b/public/assets/javascripts/rectangles/engine/scenery/_scenery.js index d52fe21..18d665f 100644 --- a/public/assets/javascripts/rectangles/engine/scenery/_scenery.js +++ b/public/assets/javascripts/rectangles/engine/scenery/_scenery.js @@ -11,6 +11,7 @@ var Scenery = new function(){ base.init = function(){ base.resize.init() + base.sound.init() } base.add = function(opt){ diff --git a/public/assets/javascripts/rectangles/engine/scenery/sound.js b/public/assets/javascripts/rectangles/engine/scenery/sound.js new file mode 100644 index 0000000..2f7f8de --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/scenery/sound.js @@ -0,0 +1,17 @@ + +Scenery.sound = {} +Scenery.sound.max_distance = 600 +Scenery.sound.init = function(){ + app.tube.on("move", Scenery.sound.move) +} +Scenery.sound.move = function(){ + var vals = Scenery.map(function(scenery){ + if ((scenery.type == "video" || scenery.type == "audio") && ! scenery.muted()) { + //get distance from A to B + var distance = dist(cam.x, cam.z, + scenery.mx.x, scenery.mx.z) + var volume = 1 - (clamp( distance, 0, Scenery.sound.max_distance ) / Scenery.sound.max_distance) + scenery.setVolume(volume) + } + }) +} diff --git a/public/assets/javascripts/rectangles/engine/scenery/types/audio.js b/public/assets/javascripts/rectangles/engine/scenery/types/audio.js index 82f984e..fdd221d 100644 --- a/public/assets/javascripts/rectangles/engine/scenery/types/audio.js +++ b/public/assets/javascripts/rectangles/engine/scenery/types/audio.js @@ -39,6 +39,10 @@ Scenery.types.audio = Scenery.types.base.extend(function(base){ this.dimensions.deserialize(data.dimensions) }, + setVolume: function(n){ + this.mx.setVolume(n) + }, + play: function(){ this.mx.play() }, diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 011644b..72aaa8c 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -65,6 +65,7 @@ + -- cgit v1.2.3-70-g09d2 From 39f1a7136567ae7e0afbf085732853cc86123393 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 1 Apr 2015 19:30:22 -0400 Subject: stub in 3d object ui --- .../javascripts/rectangles/engine/scenery/undo.js | 65 ++++++++++++++ .../rectangles/engine/sculpture/_sculpture.js | 94 +++++++++++++++++++++ .../rectangles/engine/sculpture/types/image.js | 98 ++++++++++++++++++++++ .../assets/javascripts/rectangles/models/floor.js | 8 +- views/controls/editor/sculpture.ejs | 42 ++++++++++ views/editor.ejs | 1 + views/partials/scripts.ejs | 3 + 7 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js create mode 100644 public/assets/javascripts/rectangles/engine/sculpture/types/image.js create mode 100644 views/controls/editor/sculpture.ejs (limited to 'views/partials') diff --git a/public/assets/javascripts/rectangles/engine/scenery/undo.js b/public/assets/javascripts/rectangles/engine/scenery/undo.js index 1232780..b976ea2 100644 --- a/public/assets/javascripts/rectangles/engine/scenery/undo.js +++ b/public/assets/javascripts/rectangles/engine/scenery/undo.js @@ -195,5 +195,70 @@ }, }, + // + { + type: "create-sculpture", + undo: function(state){ + Sculpture.remove(state.id) + Sculpture.resize.hide() + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + }, + redo: function(state){ + var scenery = Sculpture.deserialize([ state ]) + Sculpture.resize.show( sculpture ) + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + }, + }, + { + type: "update-sculpture", + undo: function(state){ + var sculpture = Sculpture.find(state.id) + + sculpture.deserialize(state) + + if (editor.permissions.resize) { + Sculpture.resize.show(sculpture) + } + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + }, + redo: function(state){ + var sculpture = Sculpture.find(state.id) + + sculpture.deserialize(state) + + if (editor.permissions.resize) { + Sculpture.resize.show(sculpture) + Sculpture.resize.move_dots() + Sculpture.resize.rotate_dots() + } + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + }, + }, + { + type: "destroy-sculpture", + undo: function(state){ + var sculpture = Sculpture.deserialize([ state ]) + Sculpture.resize.show( sculpture ) + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + }, + redo: function(state){ + Sculpture.resize.hide() + Sculpture.remove(state.id) + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + }, + }, + ]) })() diff --git a/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js b/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js new file mode 100644 index 0000000..eb64e92 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js @@ -0,0 +1,94 @@ + +var Sculpture = new function(){ + + var base = this; + + base.list = {} + base.nextMedia = null + + base.mouse = new mouse ({ use_offset: false, mousedownUsesCapture: true }) + + base.init = function(){ + } + + base.add = function(opt){ + var scene_media + switch (opt.media.type) { + case 'image': + scene_media = new Sculpture.types.image (opt) + break + } + base.list[scene_media.id] = scene_media + return scene_media + } + + base.addNextToWall = function(opt){ + opt.newMedia = true + opt.media = base.nextMedia + opt.index = opt.index || 0 + var scene_media = base.add(opt) + + // test if scenery was placed here + if (! scene_media) { + return null + } + else { + base.nextMedia = null + return scene_media + } + } + + base.find = function(id){ + return base.list[id] || null + } + + base.remove = function(id){ + var scene_media = base.list[id] + delete base.list[id] + scene_media && scene_media.destroy() + } + + base.removeAll = function(){ + base.forEach(function(scene_media){ + base.remove(scene_media.id) + }) + } + + base.uid = new UidGenerator(base.list) + + base.forEach = function(f){ + return base.values().forEach(f) + } + + base.map = function(f){ + return base.values().map(f) + } + + base.values = function(){ + return _.values(base.list) + } + + base.serialize = function(){ + var sculptures = base.map(function(sculpture){ + return sculpture.serialize() + }) + return sculptures + } + + base.deserialize = function(sculpture_data){ + var added = [] + sculpture_data.forEach(function(data){ + var scene_media = base.add({ + id: data.id, + data: data, + media: data.media, + }) + added.push(scene_media) + }) + return added + } + + return base +} + +Sculpture.types = {} diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/image.js b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js new file mode 100644 index 0000000..af538f7 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js @@ -0,0 +1,98 @@ +Scenery.types.base = Fiber.extend(function(base){ + + var exports = { + + init: function(opt){ + _.bindAll(this, 'enter', 'leave') + + this.id = opt.id || Scenery.uid("scenery") + this.move = new Scenery.move (this) + this.media = opt.media + this.naturalDimensions = new vec2(this.media.width, this.media.height) + + this.set_scale( opt.scale || this.media.scale || 1.0 ) + this.position = new vec2(0,0) + }, + + set_scale: function(scale){ + this.scale = scale || 1.0 + if (this.mx) { + this.mx.scale = this.mx.ops.scale = this.scale + } + this.dimensions = this.naturalDimensions.clone().mul(this.scale) + }, + + bind: function(){ + this.move.bind() +// $(this.mx.el).bind({ +// mouseenter: this.enter, +// mouseleave: this.leave, +// }) + }, + + unbind: function(){ + this.move.unbind() +// $(this.mx.el).unbind({ +// mouseenter: this.enter, +// mouseleave: this.leave, +// }) + }, + + remove: function(){ + if (this.removed) return + this.removed = true + + UndoStack.push({ + type: 'destroy-sculpture', + undo: this.serialize(), + redo: { id: this.id }, + }) + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + + Scenery.remove(this.id) + + Scenery.resize.hide() + if (app.controller.mediaEditor) { + app.controller.mediaEditor.tainted = false + app.controller.mediaEditor.hide() + } + if (app.controller.textEditor) { + app.controller.textEditor.tainted = false + app.controller.textEditor.hide() + } + }, + + destroy: function(){ + this.unbind() + scene.remove(this.mx) + this.mx.media = null + this.mx.ops = null + this.mx = null + this.move = null + this.media = null + this.dimensions = null + this.naturalDimensions = null + this.wall = null + this.bounds = null + this.center = null + }, + + serialize: function(){ + var data = { + id: this.id, + wall_id: this.wall && this.wall.id, + side: this.wall && this.wall.side, + dimensions: this.dimensions.serialize(), + position: app.position(this.mx), + scale: this.scale, + media: this.media, + } + return data + }, + } + + return exports + +}) diff --git a/public/assets/javascripts/rectangles/models/floor.js b/public/assets/javascripts/rectangles/models/floor.js index ac1f8c9..439c16a 100644 --- a/public/assets/javascripts/rectangles/models/floor.js +++ b/public/assets/javascripts/rectangles/models/floor.js @@ -68,8 +68,12 @@ } return } - - if (Scenery.nextWallpaper) { + + if (Scenery.nextMedia) { + e.preventDefault() + // + } + else if (Scenery.nextWallpaper) { var oldState = base.serialize() base.wallpaper(Scenery.nextWallpaper) // Scenery.nextWallpaper = null diff --git a/views/controls/editor/sculpture.ejs b/views/controls/editor/sculpture.ejs new file mode 100644 index 0000000..21e5039 --- /dev/null +++ b/views/controls/editor/sculpture.ejs @@ -0,0 +1,42 @@ +
    +

    3D Object

    + + + + +
    + +
    + +
    + +
    + +
    + + + +
    + +
    + + +
    + +
    + + +
    +
    + + +
    +
    + + +
    + + +
    diff --git a/views/editor.ejs b/views/editor.ejs index 74e4d6d..08959a0 100755 --- a/views/editor.ejs +++ b/views/editor.ejs @@ -16,6 +16,7 @@ [[ include controls/builder/info ]] [[ include controls/editor/media-drawer ]] [[ include controls/editor/media-editor ]] + [[ include controls/editor/sculpture ]] [[ include controls/editor/wallpaper ]] [[ include controls/editor/color-control ]] [[ include controls/editor/text-editor ]] diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 72aaa8c..6cc5315 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -73,6 +73,9 @@ + + + -- cgit v1.2.3-70-g09d2 From c6eea0f4887ba14e5a6ecfff8c9e8480ae6421c1 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Thu, 2 Apr 2015 17:05:31 -0400 Subject: placing objects on the floor --- .../rectangles/engine/sculpture/_sculpture.js | 24 +++-- .../rectangles/engine/sculpture/types/_object.js | 91 +++++++++++++++++ .../rectangles/engine/sculpture/types/image.js | 110 ++++++--------------- .../assets/javascripts/rectangles/models/floor.js | 7 +- .../assets/javascripts/rectangles/models/vec3.js | 9 ++ .../assets/javascripts/ui/editor/EditorSettings.js | 3 + server/lib/schemas/Project.js | 1 + views/partials/scripts.ejs | 1 + 8 files changed, 149 insertions(+), 97 deletions(-) create mode 100644 public/assets/javascripts/rectangles/engine/sculpture/types/_object.js (limited to 'views/partials') diff --git a/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js b/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js index eb64e92..c8c90d3 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js @@ -4,7 +4,6 @@ var Sculpture = new function(){ var base = this; base.list = {} - base.nextMedia = null base.mouse = new mouse ({ use_offset: false, mousedownUsesCapture: true }) @@ -12,29 +11,28 @@ var Sculpture = new function(){ } base.add = function(opt){ - var scene_media + var sculpture switch (opt.media.type) { case 'image': - scene_media = new Sculpture.types.image (opt) + sculpture = new Sculpture.types.image (opt) break } - base.list[scene_media.id] = scene_media - return scene_media + base.list[sculpture.id] = sculpture + return sculpture } - base.addNextToWall = function(opt){ + base.addNext = function(opt){ opt.newMedia = true - opt.media = base.nextMedia - opt.index = opt.index || 0 - var scene_media = base.add(opt) + opt.media = Scenery.nextMedia + var sculpture = base.add(opt) - // test if scenery was placed here - if (! scene_media) { + // test if sculpture was placed here + if (! sculpture) { return null } else { - base.nextMedia = null - return scene_media + Scenery.nextMedia = null + return sculpture } } diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js new file mode 100644 index 0000000..fa6b0b1 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js @@ -0,0 +1,91 @@ +Sculpture.types.base = Fiber.extend(function(base){ + + var exports = { + + init: function(opt){ + this.id = opt.id || Sculpture.uid("sculpture") + // this.move = new Sculpture.move (this) + this.media = opt.media + this.naturalDimensions = new vec2(this.media.width, this.media.height) + + this.set_scale( opt.scale || this.media.scale || 1.0 ) + this.position = new vec2(0,0) + }, + + set_scale: function(scale){ + this.scale = scale || 1.0 + if (this.mx) { + this.mx.scale = this.mx.ops.scale = this.scale + } + this.dimensions = this.naturalDimensions.clone().mul(this.scale) + }, + + place: function(opt){ + if (opt.data) { + this.deserialize(opt.data) + } + else { + this.mx.move(opt.position) + } + }, + + bind: function(){ + // this.move.bind() + }, + + unbind: function(){ + // this.move.unbind() + }, + + remove: function(){ + if (this.removed) return + this.removed = true + + UndoStack.push({ + type: 'destroy-sculpture', + undo: this.serialize(), + redo: { id: this.id }, + }) + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + + Sculpture.remove(this.id) + + // Sculpture.resize.hide() + if (app.controller.sculptureEditor) { + app.controller.sculptureEditor.tainted = false + app.controller.sculptureEditor.hide() + } + }, + + destroy: function(){ + this.unbind() + scene.remove(this.mx) + this.mx.media = null + this.mx.ops = null + this.mx = null + this.move = null + this.media = null + this.dimensions = null + this.naturalDimensions = null + this.wall = null + this.bounds = null + this.center = null + }, + + serialize: function(){ + var data = { + id: this.id, + dimensions: this.dimensions.serialize(), + position: app.position(this.mx), + scale: this.scale, + media: this.media, + } + return data + }, + } + + return exports + +}) diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/image.js b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js index af538f7..ae62133 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/types/image.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js @@ -1,98 +1,48 @@ -Scenery.types.base = Fiber.extend(function(base){ - var exports = { +Sculpture.types.image = Sculpture.types.base.extend(function(base){ + var exports = { + + type: 'image', + init: function(opt){ - _.bindAll(this, 'enter', 'leave') - this.id = opt.id || Scenery.uid("scenery") - this.move = new Scenery.move (this) - this.media = opt.media - this.naturalDimensions = new vec2(this.media.width, this.media.height) - - this.set_scale( opt.scale || this.media.scale || 1.0 ) - this.position = new vec2(0,0) - }, + opt.scale = opt.scale || (opt.data && opt.data.scale) || DEFAULT_PICTURE_WIDTH / max(DEFAULT_PICTURE_WIDTH, opt.media.width) - set_scale: function(scale){ - this.scale = scale || 1.0 - if (this.mx) { - this.mx.scale = this.mx.ops.scale = this.scale - } - this.dimensions = this.naturalDimensions.clone().mul(this.scale) - }, - - bind: function(){ - this.move.bind() -// $(this.mx.el).bind({ -// mouseenter: this.enter, -// mouseleave: this.leave, -// }) - }, - - unbind: function(){ - this.move.unbind() -// $(this.mx.el).unbind({ -// mouseenter: this.enter, -// mouseleave: this.leave, -// }) - }, - - remove: function(){ - if (this.removed) return - this.removed = true - - UndoStack.push({ - type: 'destroy-sculpture', - undo: this.serialize(), - redo: { id: this.id }, - }) + base.init.call(this, opt) - // TODO: watch individual scenery object here - Minotaur.watch( app.router.editorView.settings ) + this.build(opt) + this.bind() + this.place(opt) + }, - Scenery.remove(this.id) + build: function(opt){ + this.footprint = new MX.Object3D() + this.mx = new MX.Image({ + src: this.media.url, + scale: this.scale, + media: this.media, + backface: true, + }) - Scenery.resize.hide() - if (app.controller.mediaEditor) { - app.controller.mediaEditor.tainted = false - app.controller.mediaEditor.hide() - } - if (app.controller.textEditor) { - app.controller.textEditor.tainted = false - app.controller.textEditor.hide() - } - }, + opt.position.y = opt.position.y || this.scale * this.media.height/2, + opt.position.rotationY = opt.position.rotationY || scene.camera.rotationY, - destroy: function(){ - this.unbind() - scene.remove(this.mx) - this.mx.media = null - this.mx.ops = null - this.mx = null - this.move = null - this.media = null - this.dimensions = null - this.naturalDimensions = null - this.wall = null - this.bounds = null - this.center = null + scene.add( this.mx ) }, serialize: function(){ - var data = { - id: this.id, - wall_id: this.wall && this.wall.id, - side: this.wall && this.wall.side, - dimensions: this.dimensions.serialize(), - position: app.position(this.mx), - scale: this.scale, - media: this.media, - } + var data = base.serialize.call(this) return data }, + + deserialize: function(data){ + this.mx.move(data.position) + this.mx.ops.width = data.dimensions.a + this.mx.ops.height = data.dimensions.b + this.dimensions.deserialize(data.dimensions) + }, } return exports - }) diff --git a/public/assets/javascripts/rectangles/models/floor.js b/public/assets/javascripts/rectangles/models/floor.js index 7b020a9..530de2b 100644 --- a/public/assets/javascripts/rectangles/models/floor.js +++ b/public/assets/javascripts/rectangles/models/floor.js @@ -79,9 +79,8 @@ if (Scenery.nextMedia) { e.preventDefault() - var sculpture = Sculpture.addNextToWall({ - index: index, - position: pos, + var sculpture = Sculpture.addNext({ + position: { x: x, y: 0, z: z }, }) // scenery was not placed @@ -91,7 +90,7 @@ } app.controller.toolbar.resetPermissions() - Sculpture.resize.show(sculpture) + // Sculpture.resize.show(sculpture) Sculpture.hovering = true // app.controller.pick(sculpture) diff --git a/public/assets/javascripts/rectangles/models/vec3.js b/public/assets/javascripts/rectangles/models/vec3.js index c44dfe6..97329ed 100644 --- a/public/assets/javascripts/rectangles/models/vec3.js +++ b/public/assets/javascripts/rectangles/models/vec3.js @@ -32,3 +32,12 @@ vec3.prototype.apply_projection = function (m) { return this; } + +vec3.prototype.serialize = function(){ + return [ round(this.a), round(this.b), round(this.c) ] +} +vec3.prototype.deserialize = function(data){ + this.a = data[0] + this.b = data[1] + this.c = data[2] +} \ No newline at end of file diff --git a/public/assets/javascripts/ui/editor/EditorSettings.js b/public/assets/javascripts/ui/editor/EditorSettings.js index b319404..460863e 100644 --- a/public/assets/javascripts/ui/editor/EditorSettings.js +++ b/public/assets/javascripts/ui/editor/EditorSettings.js @@ -77,6 +77,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 +113,7 @@ var EditorSettings = FormView.extend({ clear: function(e){ e.preventDefault() Scenery.removeAll() + Sculpture.removeAll() }, destroy: function(){ @@ -191,6 +193,7 @@ var EditorSettings = FormView.extend({ 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/server/lib/schemas/Project.js b/server/lib/schemas/Project.js index a923d85..e9501fc 100644 --- a/server/lib/schemas/Project.js +++ b/server/lib/schemas/Project.js @@ -30,6 +30,7 @@ var ProjectSchema = new mongoose.Schema({ rooms: [mongoose.Schema.Types.Mixed], walls: [mongoose.Schema.Types.Mixed], media: [mongoose.Schema.Types.Mixed], + sculpture: [mongoose.Schema.Types.Mixed], colors: mongoose.Schema.Types.Mixed, startPosition: mongoose.Schema.Types.Mixed, lastPosition: mongoose.Schema.Types.Mixed, diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 6cc5315..ca6cc94 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -74,6 +74,7 @@ + -- cgit v1.2.3-70-g09d2 From 519ff21e00c5c48d06e1ddee0cdc1dc3d90a26f8 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 3 Apr 2015 18:40:04 -0400 Subject: pulling in move code / view code --- .../rectangles/engine/scenery/resize.js | 1 + .../rectangles/engine/sculpture/move.js | 158 ++++++++++++++++ .../rectangles/engine/sculpture/types/_object.js | 22 ++- .../rectangles/engine/sculpture/types/image.js | 18 -- public/assets/javascripts/ui/editor/EditorView.js | 10 +- .../javascripts/ui/editor/SculptureEditor.js | 200 +++++++++++++++++++++ views/partials/scripts.ejs | 2 + 7 files changed, 390 insertions(+), 21 deletions(-) create mode 100644 public/assets/javascripts/rectangles/engine/sculpture/move.js create mode 100644 public/assets/javascripts/ui/editor/SculptureEditor.js (limited to 'views/partials') diff --git a/public/assets/javascripts/rectangles/engine/scenery/resize.js b/public/assets/javascripts/rectangles/engine/scenery/resize.js index 73fd82a..a5e255a 100644 --- a/public/assets/javascripts/rectangles/engine/scenery/resize.js +++ b/public/assets/javascripts/rectangles/engine/scenery/resize.js @@ -49,6 +49,7 @@ Scenery.resize = new function(){ // rotate the dots as appropriate base.rotate_dots = function(){ + console.trace() rotationY = obj.wall.rotationY dots.forEach(function(dot){ dot.rotationY = rotationY diff --git a/public/assets/javascripts/rectangles/engine/sculpture/move.js b/public/assets/javascripts/rectangles/engine/sculpture/move.js new file mode 100644 index 0000000..b5a4b40 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/sculpture/move.js @@ -0,0 +1,158 @@ + +Sculpture.move = function(base){ + + var x, y, z, position, dimension, bounds + var dragging = false, moved = false + var oldState + + this.bind = function(){ + Sculpture.mouse.bind_el(base.mx.el) + Sculpture.mouse.on("down", down) + Sculpture.mouse.on("enter", switch_wall) + Sculpture.mouse.on("drag", drag) + Sculpture.mouse.on("up", up) + } + + this.unbind = function(){ + base.focused = false + Sculpture.mouse.unbind_el(base.mx.el) + Sculpture.mouse.off("down", down) + Sculpture.mouse.off("enter", switch_wall) + Sculpture.mouse.off("drag", drag) + Sculpture.mouse.off("up", up) + } + + function down (e, cursor){ + if (e.target != base.mx.el && (e.target != base.mx.overlay)) return; + if (editor.permissions.destroy) { + base.remove() + return + } + + // load the modal + app.controller.pick(base) + + if (! base.focused) { + e.clickAccepted = false + base.focused = true + return + } + if (! (editor.permissions.move || editor.permissions.resize) ) { + e.clickAccepted = false + return + } + dragging = true + moved = false + x = base.mx.x + y = base.mx.y + z = base.mx.z + + bounds = base.bounds + dimension = base.dimensions + position = base.wall.mxToPosition( base.mx, dimension ) + + oldState = base.serialize() + document.body.classList.add("dragging") + } + + function drag (e, cursor){ + if (! dragging) return + + moved = true + + var flipX = base.wall.side & (FRONT | RIGHT) + + var delta = cursor.delta() + delta.mul( cursor_amp ) // TODO: this should be proportional to your distance from the wall + if (flipX) { delta.a *= -1 } + delta.b *= -1 + + var new_bounds = base.wall.surface.translate( bounds, dimension, position, delta ) + if (new_bounds) bounds = new_bounds + if (flipX) { delta.a *= -1 } + + base.mx.y = position.b + delta.b + dimension.b / 2 + switch (base.wall.side) { + case FRONT: + case BACK: + base.mx.x = position.a + delta.a * cos(base.wall.rotationY) + dimension.a / 2 + break + case LEFT: + case RIGHT: + base.mx.z = position.a + delta.a * sin(base.wall.rotationY) + dimension.a / 2 + break + } + + if (editor.permissions.resize) { + Sculpture.resize.move_dots() + } + } + + function up (e, cursor){ + if (! dragging || ! oldState) return + + if (moved) { + UndoStack.push({ + type: 'update-sculpture', + undo: oldState, + redo: base.serialize(), + }) + + // TODO: watch individual sculpture object here + Minotaur.watch( app.router.editorView.settings ) + } + + dragging = moved = false + oldState = null + document.body.classList.remove("dragging") + } + + function switch_wall (e, target, cursor){ + if (! dragging) return + if (target.wall.id == base.wall.id) return + + var old_wall_side = base.wall.side + var wall_group = old_wall_side | target.wall.side + var new_bounds = target.wall.surface.bounds_at_index_with_dimensions(target.index || 0, dimension) + + if (! new_bounds) return + + base.wall = target.wall + base.bounds = bounds = new_bounds + + position.a = bounds.x.midpoint() - dimension.a / 2 + + if (old_wall_side !== target.wall.side && wall_group !== FRONT_BACK && wall_group !== LEFT_RIGHT) { + switch (old_wall_side) { + case FRONT: + position.a = bounds.x.a + dimension.a / 2 + break + case BACK: + position.a = bounds.x.b - dimension.a / 2 + break + case LEFT: + position.a = bounds.x.a + dimension.a / 2 + break + case RIGHT: + position.a = bounds.x.b - dimension.a / 2 + break + } + } + + var mx_delta = base.wall.positionToMx( position, dimension ) + base.mx.move(mx_delta) + + if (editor.permissions.resize) { + Sculpture.resize.rotate_dots() + Sculpture.resize.move_dots() + } + + cursor.x.a = cursor.x.b + //var delta = cursor.delta() + drag(e, cursor) + + } + + return this + +} \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js index fa6b0b1..6c93b41 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js @@ -8,8 +8,14 @@ Sculpture.types.base = Fiber.extend(function(base){ this.media = opt.media this.naturalDimensions = new vec2(this.media.width, this.media.height) + this.move = new Sculpture.move (this) + this.billboard = true + this.backface = true + this.set_scale( opt.scale || this.media.scale || 1.0 ) this.position = new vec2(0,0) + + this.isSculpture = true }, set_scale: function(scale){ @@ -30,11 +36,11 @@ Sculpture.types.base = Fiber.extend(function(base){ }, bind: function(){ - // this.move.bind() + this.move.bind() }, unbind: function(){ - // this.move.unbind() + this.move.unbind() }, remove: function(){ @@ -81,9 +87,21 @@ Sculpture.types.base = Fiber.extend(function(base){ position: app.position(this.mx), scale: this.scale, media: this.media, + billboard: this.billboard, + backface: this.backface, } return data }, + + deserialize: function(data){ + this.mx.move(data.position) + this.mx.ops.width = data.dimensions.a + this.mx.ops.height = data.dimensions.b + this.billboard = data.billboard + this.backface = data.backface + if (! this.backface) this.mx.el.classList.remove("backface-visible") + this.dimensions.deserialize(data.dimensions) + }, } return exports diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/image.js b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js index 9e8de58..3e5ab08 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/types/image.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js @@ -27,29 +27,11 @@ Sculpture.types.image = Sculpture.types.base.extend(function(base){ if (opt.position) { opt.position.y = opt.position.y || this.scale * this.media.height/2 + 3 opt.position.rotationY = opt.position.rotationY || scene.camera.rotationY - this.billboard = true - this.backface = true } scene.add( this.mx ) }, - serialize: function(){ - var data = base.serialize.call(this) - data.billboard = this.billboard - data.backface = this.backface - return data - }, - - deserialize: function(data){ - this.mx.move(data.position) - this.mx.ops.width = data.dimensions.a - this.mx.ops.height = data.dimensions.b - this.billboard = data.billboard - this.backface = data.backface - if (! this.backface) this.mx.el.classList.remove("backface-visible") - this.dimensions.deserialize(data.dimensions) - }, } return exports diff --git a/public/assets/javascripts/ui/editor/EditorView.js b/public/assets/javascripts/ui/editor/EditorView.js index 50d3650..e5e2ca0 100644 --- a/public/assets/javascripts/ui/editor/EditorView.js +++ b/public/assets/javascripts/ui/editor/EditorView.js @@ -17,6 +17,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 }) @@ -56,12 +57,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) } }, diff --git a/public/assets/javascripts/ui/editor/SculptureEditor.js b/public/assets/javascripts/ui/editor/SculptureEditor.js new file mode 100644 index 0000000..cce000e --- /dev/null +++ b/public/assets/javascripts/ui/editor/SculptureEditor.js @@ -0,0 +1,200 @@ + +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=loop]": "setLoop", + "change [name=mute]": "setMute", + "change [name=width]": 'changeWidth', + "change [name=height]": 'changeHeight', + "change [name=units]": 'changeUnits', + "click [data-role=destroy-media]": "destroy", + }, + + initialize: function(opt){ + this.parent = opt.parent + this.__super__.initialize.call(this) + + this.$name = this.$("[name=name]") + this.$description = this.$("[name=description]") + + // image fields + this.$width = this.$("[name=width]") + this.$height = this.$("[name=height]") + 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" ) + + 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 + }, + + 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.tainted = true + }, + changeWidth: function(e){ + e.stopPropagation() + this.sculpture.set_scale( this.$width.unitVal() / this.sculpture.naturalDimensions.a ) + this.setDimensions() + }, + changeHeight: function(e){ + e.stopPropagation() + this.sculpture.set_scale( this.$height.unitVal() / this.sculpture.naturalDimensions.b ) + this.setDimensions() + }, + 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/views/partials/scripts.ejs b/views/partials/scripts.ejs index ca6cc94..1eda8bd 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -74,6 +74,7 @@ + @@ -124,6 +125,7 @@ + -- cgit v1.2.3-70-g09d2 From 0b8b54e26aa7a40065a0be6f7708b7021e4fec13 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 20 Apr 2015 15:03:35 -0400 Subject: resize scenery --- Gruntfile.js | 1 + .../rectangles/engine/scenery/resize.js | 1 + .../rectangles/engine/sculpture/_sculpture.js | 4 + .../rectangles/engine/sculpture/move.js | 6 +- .../rectangles/engine/sculpture/resize.js | 207 +++++++++++++++++++++ .../rectangles/engine/sculpture/types/_object.js | 2 +- .../assets/javascripts/rectangles/models/floor.js | 2 +- public/assets/javascripts/ui/editor/EditorView.js | 1 + .../javascripts/ui/editor/SculptureEditor.js | 3 +- views/partials/scripts.ejs | 1 + 10 files changed, 221 insertions(+), 7 deletions(-) create mode 100644 public/assets/javascripts/rectangles/engine/sculpture/resize.js (limited to 'views/partials') diff --git a/Gruntfile.js b/Gruntfile.js index 026ec6f..789ce6f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -79,6 +79,7 @@ module.exports = function(grunt) { "public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js", "public/assets/javascripts/rectangles/engine/sculpture/move.js", + "public/assets/javascripts/rectangles/engine/sculpture/resize.js", "public/assets/javascripts/rectangles/engine/sculpture/types/_object.js", "public/assets/javascripts/rectangles/engine/sculpture/types/image.js", diff --git a/public/assets/javascripts/rectangles/engine/scenery/resize.js b/public/assets/javascripts/rectangles/engine/scenery/resize.js index 006ff2a..8dac140 100644 --- a/public/assets/javascripts/rectangles/engine/scenery/resize.js +++ b/public/assets/javascripts/rectangles/engine/scenery/resize.js @@ -8,6 +8,7 @@ Scenery.resize = new function(){ var dragging = false var naturalDimension, naturalDimensionCopy, dimension, position, scale var oldState + var rotationY var dots = [], dot, selected_dot diff --git a/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js b/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js index 1543def..888b925 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/_sculpture.js @@ -9,6 +9,7 @@ var Sculpture = new function(){ base.init = function(){ app.on("move", base.updateBillboards) + base.resize.init() } base.updateBillboards = function(){ @@ -17,6 +18,9 @@ var Sculpture = new function(){ sculpture.mx.rotationY = cam.rotationY } }) + if (Sculpture.resize.obj && Sculpture.resize.obj.billboard) { + Sculpture.resize.move_dots() + } } base.add = function(opt){ diff --git a/public/assets/javascripts/rectangles/engine/sculpture/move.js b/public/assets/javascripts/rectangles/engine/sculpture/move.js index 28d707e..f968bcf 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/move.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/move.js @@ -66,9 +66,9 @@ Sculpture.move = function(base){ base.mx.x = x + delta.a * cos(cam.rotationY) - delta.b * sin(cam.rotationY) base.mx.z = z + delta.a * sin(cam.rotationY) + delta.b * cos(cam.rotationY) -// if (editor.permissions.resize) { -// Sculpture.resize.move_dots() -// } + if (editor.permissions.resize) { + Sculpture.resize.move_dots() + } } function up (e, cursor){ diff --git a/public/assets/javascripts/rectangles/engine/sculpture/resize.js b/public/assets/javascripts/rectangles/engine/sculpture/resize.js new file mode 100644 index 0000000..53b8b2d --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/sculpture/resize.js @@ -0,0 +1,207 @@ +Sculpture.resize = new function(){ + + var base = this + + var obj + var x, y, z, bounds + var dragging = false + var naturalDimension, naturalDimensionCopy, dimension, position, scale + var oldState + var rotationY + + var dots = [], dot, selected_dot + + base.init = function(){ + base.build() + base.bind() + } + + // create 9 dots at the corners of the div + base.build = function(){ + [ TOP, + TOP_RIGHT, + RIGHT, + BOTTOM_RIGHT, + BOTTOM, + BOTTOM_LEFT, + LEFT, + TOP_LEFT ].forEach(base.build_dot) + } + + // generate a dot element + base.build_dot = function(side) { + var dot = new MX.Object3D('.dot') + dot.width = dot.height = dot_side * 2 + dot.scale = 0.5 + dot.side = side + $(dot.el).on({ + mouseenter: function(){ base.hovering = true }, + mouseleave: function(){ base.hovering = false }, + }) + dots.push(dot) + } + + base.add_dots = function(){ + dots.forEach(function(dot){ + scene.add(dot) + }) + } + + // move all the dots to the object's current position + base.move_dots = function(){ + rotationY = obj.mx.rotationY + + var x = obj.mx.x + sin(rotationY) * dot_distance_from_picture + var y = obj.mx.y + var z = obj.mx.z - cos(rotationY) * dot_distance_from_picture + + dots.forEach(function(dot){ + base.move_dot(dot, { x: x, y: y, z: z, rotationY: rotationY }) + }) + } + + // move a dot .. to the initial position of the image + base.move_dot = function(dot, pos){ + if (dot.side & TOP) { + pos.y += obj.dimensions.b / 2 + } + if (dot.side & BOTTOM) { + pos.y -= obj.dimensions.b / 2 + } + if (dot.side & LEFT) { + pos.x -= cos(rotationY) * (obj.dimensions.a) / 2 + pos.z -= sin(rotationY) * (obj.dimensions.a) / 2 + } + if (dot.side & RIGHT) { + pos.x += cos(rotationY) * (obj.dimensions.a) / 2 + pos.z += sin(rotationY) * (obj.dimensions.a) / 2 + } + dot.move(pos) + } + + // pick a new object to focus on and show the dots + base.show = function(new_object) { + // if (obj === new_object) return + if (! new_object) return + base.obj = obj = new_object + base.add_dots() + base.move_dots() + } + + // dismiss the dots on blur + var dotsHideTimeout; + base.defer_hide = function(){ + clearTimeout(dotsHideTimeout) + + dotsHideTimeout = setTimeout(function(){ + if (Scenery.hovering || Scenery.resize.hovering || Scenery.mouse.down) return + Scenery.resize.hide() + }, dot_hide_delay) + } + + base.hide = function () { + if (! obj) return + base.obj = obj = null + dots.forEach(function(dot){ + scene.remove(dot) + }) + } + + base.bind = function(){ + dots.forEach(function(dot){ + Sculpture.mouse.bind_el(dot.el) + }) + Sculpture.mouse.on("down", down) + Sculpture.mouse.on("drag", drag) + Sculpture.mouse.on("up", up) + } + + base.unbind = function(){ + dots.forEach(function(dot){ + Sculpture.mouse.unbind_el(dot.el) + }) + Sculpture.mouse.off("down", down) + Sculpture.mouse.off("drag", drag) + Sculpture.mouse.off("up", up) + } + + function down (e, cursor){ + var selection = dots.filter(function(dot){return e.target == dot.el}) + if (! selection.length) return + + selected_dot = selection[0] + dragging = true + + naturalDimension = obj.naturalDimensions + dimension = obj.dimensions + position = new vec3(obj.mx.x, obj.mx.y, obj.mx.z) + oldState = obj.serialize() + + if (obj.type == "text") { + naturalDimensionCopy = naturalDimension.clone() + positionCopy = position.clone() + } + + document.body.classList.add("dragging") + } + + function drag (e, cursor){ + if (! dragging) return + + var x_sign = selected_dot.side & LEFT ? -1 : selected_dot.side & RIGHT ? 1 : 0 + var y_sign = selected_dot.side & TOP ? -1 : selected_dot.side & BOTTOM ? 1 : 0 + var width = cursor.x.magnitude() + var height = cursor.y.magnitude() + var mag = cursor.magnitude() + + if (abs(width) > abs(height)) { + mag = x_sign * mag * sign(width) + } + else { + mag = y_sign * mag * sign(height) + } + + if (obj.type == "text") { + obj.mx.width = obj.media.width = naturalDimension.a = naturalDimensionCopy.a + (mag * 2) + obj.mx.height = obj.media.height = naturalDimension.b = naturalDimensionCopy.b + (mag * 2) + dimension.a = naturalDimension.a * obj.scale + dimension.b = naturalDimension.b * obj.scale + } + else { + obj.set_scale( ( dimension.a + mag ) / naturalDimension.a ) + } + + if (selected_dot.side & LEFT_RIGHT) { + obj.mx.x = position.a + cos(rotationY) * mag/2 * (x_sign) + obj.mx.z = position.c + sin(rotationY) * mag/2 * (x_sign) + } + if (selected_dot.side & TOP_BOTTOM) { + obj.mx.y = position.b - mag/2 * y_sign + } + + base.move_dots() + + app.controller.sculptureEditor.setDimensions() + } + + function up (e, cursor){ + if (! dragging) return + dragging = false + if (! editor.permissions.resize) { return } + + obj.scale = obj.mx.ops.scale = obj.mx.scale + obj.dimensions.assign(obj.naturalDimensions).mul(obj.scale) + + UndoStack.push({ + type: 'update-sculpture', + undo: oldState, + redo: obj.serialize(), + }) + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + + document.body.classList.remove("dragging") + selected_dot = null + } +} \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js index b903c5b..390c42e 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js @@ -80,7 +80,7 @@ Sculpture.types.base = Fiber.extend(function(base){ Sculpture.remove(this.id) - // Sculpture.resize.hide() + Sculpture.resize.hide() if (app.controller.sculptureEditor) { app.controller.sculptureEditor.tainted = false app.controller.sculptureEditor.hide() diff --git a/public/assets/javascripts/rectangles/models/floor.js b/public/assets/javascripts/rectangles/models/floor.js index 530de2b..799bdc7 100644 --- a/public/assets/javascripts/rectangles/models/floor.js +++ b/public/assets/javascripts/rectangles/models/floor.js @@ -90,7 +90,7 @@ } app.controller.toolbar.resetPermissions() - // Sculpture.resize.show(sculpture) + Sculpture.resize.show(sculpture) Sculpture.hovering = true // app.controller.pick(sculpture) diff --git a/public/assets/javascripts/ui/editor/EditorView.js b/public/assets/javascripts/ui/editor/EditorView.js index a7b4f20..a2d84a6 100644 --- a/public/assets/javascripts/ui/editor/EditorView.js +++ b/public/assets/javascripts/ui/editor/EditorView.js @@ -84,6 +84,7 @@ var EditorView = View.extend({ 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 index ff1e6b9..35abc00 100644 --- a/public/assets/javascripts/ui/editor/SculptureEditor.js +++ b/public/assets/javascripts/ui/editor/SculptureEditor.js @@ -67,7 +67,7 @@ var SculptureEditor = FormView.extend({ // app.controller.toolbar.resetMode() app.controller.toolbar.resetControls() - // Sculpture.resize.show(sculpture) + Sculpture.resize.show(sculpture) Sculpture.hovering = true var media = sculpture.media @@ -149,7 +149,6 @@ var SculptureEditor = FormView.extend({ this.tainted = true }, - setBillboard: function(){ var checked = this.$billboard.prop('checked') this.sculpture.setBillboard(checked) diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 1eda8bd..6dfe912 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -75,6 +75,7 @@ + -- cgit v1.2.3-70-g09d2 From b4ee999a47ae89c27b5cf4a86d81ded33c6c8f81 Mon Sep 17 00:00:00 2001 From: ryderr Date: Mon, 13 Jul 2015 17:55:25 -0400 Subject: sub rip --- public/assets/stylesheets/app.css | 149 +++++++++++++++++++++++++------------- views/about/brochure.ejs | 95 +++++++++++++++++++++++- views/partials/footer.ejs | 2 +- views/staff/_pagination.ejs | 2 +- 4 files changed, 190 insertions(+), 58 deletions(-) (limited to 'views/partials') diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index f4182d1..4bfa363 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -922,75 +922,120 @@ iframe.embed { width: 76vw; margin: 2vw 10vw; } -.planbox { - padding: 2vw; - border: 1px solid #ddd; - background: white; - border-radius: 25px; - font-size: 15px; - line-height: 23px; - text-align: center; -} -.planbox h3 { + +ul#plans { + margin: 0 auto; text-align: center; - margin-bottom: 10px; -} -.about_plan ul { - margin-bottom: 60px; + font-size: 14px; } -.planbox li { - list-style-type: none; - margin-bottom: 0; - font-size: 1.3vw; - padding: 0 1vw; + +ul#plans>li { + display: inline-block; + width: 300px; + vertical-align: top; + margin: 0 25px 25px 0; + position: relative; } -.paidPlan .planbox li { - padding: 0 5.6vw; + +ul#plans>li.most-popular:before { + content: 'Most Popular'; + display: block; + background: #F17E6F; + color: white; + font-size: 1em; + font-weight: 500; + letter-spacing: 1px; + text-transform: uppercase; + width: 100%; + position: absolute; + top: -31px; } -.about_custom.planbox li { - padding: 10px; - font-size: 17px; + +ul#plans .top { + background: #3A3A3A; + color: white; + padding: 30px 0; + height: 266px; } -.planbox.miscbox { - border: 0; - background: #f8f8f8; + +ul#plans h2 { + padding: 0; + font-size: 1.25em; + margin-bottom: 1.75em; + text-transform: uppercase; + letter-spacing: 3px; + font-weight: 500; } -.about_custom a { - border-bottom: 1px solid; + +ul#plans h3 { + margin: 0 0 20px; + font-weight: 200; } -/* Billing / Subscription Settings */ -.planList { - position: absolute; - left: 50%; - transform: translateX(-48%); +ul#plans h3 span.dollar { + font-size: 1.25em; + vertical-align: top; + position: relative; + top: -14px; } -.planList .about_custom { - width: 56vw; - margin: 1vw 4vw; + +ul#plans h3 span.price { + font-size: 5em; + font-weight: 100; } -.planList .planbox { - padding: 0; + +ul#plans h4 { + font-size: 0.85em; + color: #e6e6e6; + margin: 0 auto; + width: 50%; + font-weight: 500; + line-height: 30px; } -.planList .custombox { - margin: 2vw 4vw 4vw 4vw; + +ul#plans ul { + border-left: 1px solid #e5e5e5; + border-right: 1px solid #e5e5e5; } -.planList .miscbox { - line-height: 2.7vw; + +ul#plans ul li { + text-align: left; + border-bottom: 1px solid #e5e5e5; + padding: 5px 20px; + font-weight: 700; + list-style: none; + background: white; + color:#333; } -.mediaDrawer .planList h3 { - margin-top: 3px; - font-size: 21px; - font-weight: bold + +ul#plans .signup { + background: #3A3A3A; + padding: 25px 0; } -.freePlan { - text-align: left; + +.signup .button { + font-weight: bold; + padding: 16px 30px 14px; + -o-transition: background 0.2s ease-in-out; + -webkit-transition: background 0.2s ease-in-out; + transition: background 0.2s ease-in-out; + display: inline-block; + background: #F17E6F; + color: white; + text-decoration: none; + font-size: 1em; + padding: 4px 30px 3px; + border: none; + cursor: pointer; } -.planList .planbox li:first-child { - font-size: 1.9vw; - padding: 0; + + +.signup .button:hover { + color: white; + background: #ef6958; } + /* debug sync button */ .editSubscription .gear { position: absolute; diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs index 855f897..80cb154 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -11,11 +11,98 @@

    Subscriptions

    -
    - Want to get more out of VValls? Consider becoming a subscription user. -

    -
    + +
      + +
    • +
      +

      Medium

      +

      $10 / mo

      +

      Great for personal sites and small blogs.

      +
      +
        +
      • + 5 Source Accounts / Hashtags +
      • +
      • + 1 Embeddable Feed +
      • +
      • + Pulls In New Posts Every Hour +
      • +
      • + Moderation and Filtering Tools +
      • +
      • + Everything the Small Plan Contains +
      • +
      • + No Juicer Branding! +
      • +
      + +
    • +
    • +
      +

      Small

      +

      $0 / mo

      +

      Free forever.

      +
      +
        +
      • + 2 Source Accounts / Hashtags +
      • +
      • + 1 Embeddable Social Media Feed +
      • +
      • + Pulls In New Posts Every 24 Hours +
      • +
      • + All Templates and Custom Styling +
      • +
      • + HTTPS Secure Connection Support +
      • +
      • + Juicer Branding +
      • +
      + +
    • +
    + + + + [[ include _plans ]]
    diff --git a/views/partials/footer.ejs b/views/partials/footer.ejs index 52430f7..05bc128 100644 --- a/views/partials/footer.ejs +++ b/views/partials/footer.ejs @@ -2,7 +2,7 @@ [[ if (logged_in) { ]] - signed in as → + signed in as [[- user.displayName ]] [[ if (user.isStaff) { ]] Staff Area diff --git a/views/staff/_pagination.ejs b/views/staff/_pagination.ejs index 6c3bfb1..7d85c71 100644 --- a/views/staff/_pagination.ejs +++ b/views/staff/_pagination.ejs @@ -10,7 +10,7 @@ [[ if (pagination.next_page !== -1) { ]] Next page → [[ } else { ]] - → + -> [[ } ]]
    -- cgit v1.2.3-70-g09d2 From 44642b48203b3ee2fa9e281f31ed9fed3f60ee79 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 21 Jul 2015 13:23:22 -0400 Subject: find closest segment --- Gruntfile.js | 8 +- .../assets/javascripts/mx/primitives/mx.point.js | 17 + .../javascripts/mx/primitives/mx.polyline.js | 48 +++ .../rectangles/engine/map/tools/_base.js | 11 + .../rectangles/engine/map/tools/arrow.js | 46 +++ .../rectangles/engine/map/tools/ortho.js | 115 +++++++ .../rectangles/engine/map/tools/polyline.js | 69 ++++ .../rectangles/engine/map/tools/position.js | 17 + .../javascripts/rectangles/engine/map/ui/editor.js | 284 ++++++++++++++++ .../rectangles/engine/map/ui/minimap.js | 81 +++++ .../javascripts/rectangles/engine/map/ui/ortho.js | 105 ++++++ .../javascripts/rectangles/engine/map/ui_editor.js | 284 ---------------- .../rectangles/engine/map/ui_minimap.js | 81 ----- .../javascripts/rectangles/engine/map/ui_ortho.js | 105 ------ public/assets/test/ortho3.html | 362 ++------------------- views/partials/scripts.ejs | 4 +- 16 files changed, 824 insertions(+), 813 deletions(-) create mode 100644 public/assets/javascripts/mx/primitives/mx.point.js create mode 100644 public/assets/javascripts/mx/primitives/mx.polyline.js create mode 100644 public/assets/javascripts/rectangles/engine/map/tools/_base.js create mode 100644 public/assets/javascripts/rectangles/engine/map/tools/arrow.js create mode 100644 public/assets/javascripts/rectangles/engine/map/tools/ortho.js create mode 100644 public/assets/javascripts/rectangles/engine/map/tools/polyline.js create mode 100644 public/assets/javascripts/rectangles/engine/map/tools/position.js create mode 100644 public/assets/javascripts/rectangles/engine/map/ui/editor.js create mode 100644 public/assets/javascripts/rectangles/engine/map/ui/minimap.js create mode 100644 public/assets/javascripts/rectangles/engine/map/ui/ortho.js delete mode 100644 public/assets/javascripts/rectangles/engine/map/ui_editor.js delete mode 100644 public/assets/javascripts/rectangles/engine/map/ui_minimap.js delete mode 100644 public/assets/javascripts/rectangles/engine/map/ui_ortho.js (limited to 'views/partials') diff --git a/Gruntfile.js b/Gruntfile.js index a0f4d83..233c7ff 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -85,8 +85,8 @@ module.exports = function(grunt) { "public/assets/javascripts/rectangles/engine/sculpture/types/image.js", "public/assets/javascripts/rectangles/engine/map/_map.js", - "public/assets/javascripts/rectangles/engine/map/ui_editor.js", - "public/assets/javascripts/rectangles/engine/map/ui_minimap.js", + "public/assets/javascripts/rectangles/engine/map/ui/editor.js", + "public/assets/javascripts/rectangles/engine/map/ui/minimap.js", "public/assets/javascripts/rectangles/engine/map/draw.js", "public/assets/javascripts/ui/lib/View.js", @@ -228,8 +228,8 @@ module.exports = function(grunt) { "public/assets/javascripts/rectangles/engine/sculpture/types/image.js", "public/assets/javascripts/rectangles/engine/map/_map.js", - "public/assets/javascripts/rectangles/engine/map/ui_editor.js", - "public/assets/javascripts/rectangles/engine/map/ui_minimap.js", + "public/assets/javascripts/rectangles/engine/map/ui/editor.js", + "public/assets/javascripts/rectangles/engine/map/ui/minimap.js", "public/assets/javascripts/rectangles/engine/map/draw.js", "public/assets/javascripts/ui/lib/View.js", diff --git a/public/assets/javascripts/mx/primitives/mx.point.js b/public/assets/javascripts/mx/primitives/mx.point.js new file mode 100644 index 0000000..41a7732 --- /dev/null +++ b/public/assets/javascripts/mx/primitives/mx.point.js @@ -0,0 +1,17 @@ +MX.Point = MX.Object3D.extend({ + init: function(p){ + this.updateChildren = false + this.move({ + x: p.a, + y: 11, + z: p.b, + width: 20, + height: 20, + rotationX: PI/2, + }) + this.el.style.backgroundColor = 'rgb(' + [abs(floor(p.a*30)), 0, abs(floor(p.b*30))] + ')' + this.el.style.backfaceVisibility = "visible" + this.el.style.borderRadius = "50%" + scene.add(this) + } +}) diff --git a/public/assets/javascripts/mx/primitives/mx.polyline.js b/public/assets/javascripts/mx/primitives/mx.polyline.js new file mode 100644 index 0000000..555b3c6 --- /dev/null +++ b/public/assets/javascripts/mx/primitives/mx.polyline.js @@ -0,0 +1,48 @@ +MX.Polyline = MX.Object3D.extend({ + init: function(polyline){ + this.faces = [] + this.points = polyline.points + for (var i = 1; i < this.points.length; i++) { + var mx = new MX.Object3D() + var head = this.points[i-1] + var tail = this.points[i] + this.move_face(mx, head, tail) + this.faces.push(mx) + scene.add(mx) + } + }, + + rebuild: function(){ + for (var i = 1; i < this.points.length; i++) { + var mx = this.faces[i-1] + var head = this.points[i-1] + var tail = this.points[i] + this.move_face(mx, head, tail) + } + }, + + move_face: function (mx, head, tail){ + var mid_x = (head.a + tail.a) + var mid_z = (head.b + tail.b) + var len = head.distanceTo( tail ) + var angle = atan2( head.b - tail.b, head.a - tail.a ) + mx.move({ + x: mid_x / 2, + y: wall_height/2 + 1, + z: mid_z / 2, + width: ceil(len), + height: wall_height, + rotationY: angle + }) + var hue = abs(round( angle / PI * 90 + 300)) + mx.el.style.backgroundColor = 'hsl(' + [hue, "100%", "50%"] + ')' + }, + + destroy: function(){ + this.faces.forEach(function(mx){ + scene.remove(mx) + }) + this.faces = null + this.points = null + }, +}) diff --git a/public/assets/javascripts/rectangles/engine/map/tools/_base.js b/public/assets/javascripts/rectangles/engine/map/tools/_base.js new file mode 100644 index 0000000..17b247d --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/tools/_base.js @@ -0,0 +1,11 @@ +var MapTool = Fiber.extend(function(base){ + var exports = { + recenterCursor: true, + down: function(e, cursor){}, + move: function(e, cursor){}, + drag: function(e, cursor){}, + up: function(e, cursor, new_cursor){}, + cancel: function(){}, + } + return exports +}) \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/map/tools/arrow.js b/public/assets/javascripts/rectangles/engine/map/tools/arrow.js new file mode 100644 index 0000000..2a73954 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/tools/arrow.js @@ -0,0 +1,46 @@ +var ArrowTool = MapTool.extend(function(base){ + var exports = {} + + var selected_point = null, original_point = null, selected_shape = null + + exports.down = function(e, cursor){ + last_point.a = cursor.x.a + last_point.b = cursor.y.a + var p = shapes.findClosestPoint(last_point) + if (p) { + selected_shape = p.shape + selected_point = p.point + original_point = selected_point.clone() + } + else { + map.ui.set_drag_tool("position") + } + } + + exports.move = function(e, cursor){ + last_point.a = cursor.x.a + last_point.b = cursor.y.a + var p = shapes.findClosestPoint(last_point) + if (p) { + document.body.style.cursor = "pointer" + last_point.assign(p.point) + cursor.x.a = cursor.x.b = last_point.a + cursor.y.a = cursor.y.b = last_point.b + } + else { + document.body.style.cursor = "crosshair" + } + } + + exports.drag = function(e, cursor){ + selected_point.a = original_point.a + cursor.x.magnitude() + selected_point.b = original_point.b + cursor.y.magnitude() + selected_shape.rebuild() + } + + exports.up = function(e, cursor){ + selected_point = selected_shape = original_point = null + } + + return exports +}) \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/map/tools/ortho.js b/public/assets/javascripts/rectangles/engine/map/tools/ortho.js new file mode 100644 index 0000000..be3d707 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/tools/ortho.js @@ -0,0 +1,115 @@ +var OrthoPolylineTool = MapTool.extend(function (base) { + // this will work like normal polyline except all walls will be orthogonal + + var prev_point, horizontal = false, first_edge_is_horizontal = false + + var exports = {} + exports.down = function(e, cursor){ + // rightclick? + if (e.ctrlKey || e.which === 3) { + e.preventDefault() + e.stopPropagation() + if (map.ui.placing) { + // close polyline or cancel + map.ui.placing = false + if (line.points.length > 2) { + line.build() + } + else { + line.reset() + } + return + } + else { + map.ui.tools.position.rightclick(e, cursor) + } + return + } + + // compare to initial point + var p = last_point.clone() + if (map.ui.placing) { + if (line.lastPoint().eq(p)) { + return + } + else if (line.canCloseWith(p)) { + line.close() + line.build() + map.ui.placing = false + } + else { + line.add(p) + prev_point = p + horizontal = ! horizontal + } + } + else { + map.ui.placing = true + line = new Polyline () + line.add(p) + first_point = prev_point = p + horizontal = false + } + } + exports.move = function(e, cursor){ + last_point.a = cursor.x.a + last_point.b = cursor.y.a + if (map.ui.placing) { + if (line.points.length == 1) { + var x = abs(prev_point.a - last_point.a) + var y = abs(prev_point.b - last_point.b) + if (x > y) { + last_point.b = prev_point.b + first_edge_is_horizontal = horizontal = true + } + else { + last_point.a = prev_point.a + first_edge_is_horizontal = horizontal = false + } + } + else { + if (horizontal) { + last_point.b = prev_point.b + } + else { + last_point.a = prev_point.a + } + if (horizontal == first_edge_is_horizontal) { + // check if this point is within N pixels of the normal + // and lock it into place if so + if (horizontal && abs( first_point.a - last_point.a ) < 10/map.zoom) { + last_point.a = first_point.a + } + else if (! horizontal && abs( first_point.b - last_point.b ) < 10/map.zoom) { + last_point.b = first_point.b + } + } + } + + if (line.canCloseWith(last_point)) { + document.body.style.cursor = "pointer" + last_point.assign(first_point) + cursor.x.a = cursor.x.b = last_point.a + cursor.y.a = cursor.y.b = last_point.b + } + return + } + var end_point = shapes.findClosestEndPoint(last_point) + if (end_point) { + document.body.style.cursor = "pointer" + last_point.assign(end_point.point) + cursor.x.a = cursor.x.b = last_point.a + cursor.y.a = cursor.y.b = last_point.b + return + } + else { + document.body.style.cursor = "crosshair" + } + } + exports.cancel = function(){ + if (map.ui.placing) { line.reset() } + first_point = null + map.ui.placing = false + } + return exports +}) \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/map/tools/polyline.js b/public/assets/javascripts/rectangles/engine/map/tools/polyline.js new file mode 100644 index 0000000..559aea8 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/tools/polyline.js @@ -0,0 +1,69 @@ +var PolylineTool = MapTool.extend(function (base) { + var exports = {} + exports.down = function(e, cursor){ + + // rightclick? + if (e.ctrlKey || e.which === 3) { + e.preventDefault() + e.stopPropagation() + if (map.ui.placing) { + // close polyline or cancel + map.ui.placing = false + if (line.points.length > 2) { + line.build() + } + else { + line.reset() + } + return + } + map.ui.tools.position.rightclick(e, cursor) + return + } + + // compare to initial point + var p = last_point.clone() + if (map.ui.placing) { + if (line.canCloseWith(p)) { + line.close() + line.build() + map.ui.placing = false + } + else { + line.add(p) + } + } + else { + map.ui.placing = true + line = new Polyline () + line.add(p) + } + } + exports.move = function(e, cursor){ + last_point.a = cursor.x.a + last_point.b = cursor.y.a + if (map.ui.placing && line.canCloseWith(last_point)) { + document.body.style.cursor = "pointer" + last_point.assign(line.points[0]) + cursor.x.a = cursor.x.b = last_point.a + cursor.y.a = cursor.y.b = last_point.b + return + } + var end_point = shapes.findClosestEndPoint(last_point) + if (end_point) { + document.body.style.cursor = "pointer" + last_point.assign(end_point.point) + cursor.x.a = cursor.x.b = last_point.a + cursor.y.a = cursor.y.b = last_point.b + return + } + else { + document.body.style.cursor = "crosshair" + } + } + exports.cancel = function(){ + if (map.ui.placing) { line.reset() } + map.ui.placing = false + } + return exports +}) \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/map/tools/position.js b/public/assets/javascripts/rectangles/engine/map/tools/position.js new file mode 100644 index 0000000..a994f5a --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/tools/position.js @@ -0,0 +1,17 @@ +var PositionTool = MapTool.extend(function(base){ + var exports = { + recenterCursor: false, + drag: function(e, cursor){ + map.center.a = -cursor.x.magnitude() + map.center.b = cursor.y.magnitude() + }, + rightclick: function(e, cursor){ + cursor.quantize(1/map.zoom) + map.center.a = cursor.x.a + map.center.b = -cursor.y.a + cursor.x.b = cursor.x.a + cursor.y.b = cursor.y.a + } + } + return exports +}) \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/map/ui/editor.js b/public/assets/javascripts/rectangles/engine/map/ui/editor.js new file mode 100644 index 0000000..7308344 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/ui/editor.js @@ -0,0 +1,284 @@ + +Map.UI = Map.UI || {} +Map.UI.Editor = function(map){ + + var base = this + + base.creating = base.dragging = base.resizing = false + + base.mouse = new mouse({ + el: map.el, + down: down, + move: move, + drag: drag, + up: up, + rightclick: rightclick, + }) + + base.wheel = new wheel({ + el: map.el, + update: mousewheel, + }) + + base.permissions = new Permissions({ + create: true, + move: true, + resize: true, + destroy: false, + }) + + base.blur = function(){ + Rooms.forEach(function(r){ + return r.focused = false + }) + app.tube("builder-pick-nothing") + } + + // + + 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) + + if (e.ctrlKey || e.which === 3) { + if (Rooms.regions.length == 0) return + cursor.quantize(1/map.zoom) + map.center.a = cursor.x.a + map.center.b = -cursor.y.a + cursor.x.b = cursor.x.a + cursor.y.b = cursor.y.a + base.mouse.down = false + e.preventDefault() + e.stopPropagation() + return + } + + var intersects = Rooms.filter(function(r){ + return r.focused = r.rect.contains(cursor.x.a, cursor.y.a) + }) + + if (intersects.length && (base.permissions.destroy || e.altKey)) { + base.mouse.down = false + + room = intersects[0] + + UndoStack.push({ + type: "destroy-room", + undo: room.copy(), + redo: { id: room.id }, + }) + + Rooms.remove(room) + app.tube("builder-destroy-room", room) + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + return + } + else if (intersects.length) { + base.dragging = intersects[0] + 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 + } + + if (e.shiftKey && base.dragging) { + base.dragging.rect.quantize(10/map.zoom) + } + } + + 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) { + cursor.x.b = ((cursor.x.b/map.dimensions.a)+0.5) * map.dimensions.a / map.zoom + map.center.a + cursor.y.b = ((cursor.y.b/map.dimensions.b)-0.5) * map.dimensions.b / map.zoom - map.center.b + + if (base.resizing) { + var x_length = base.dragging.rect.x.length(), + y_length = base.dragging.rect.y.length() + + if (base.resizing & LEFT) { + base.dragging.rect.translation.a = clamp( cursor.x.magnitude(), x_length - side_max, x_length - side_min ) + } + if (base.resizing & RIGHT) { + base.dragging.rect.translation.a = clamp( cursor.x.magnitude(), side_min - x_length, side_max - x_length ) + } + if (base.resizing & FRONT) { + base.dragging.rect.translation.b = clamp( cursor.y.magnitude(), y_length - side_max, y_length - side_min ) + } + if (base.resizing & BACK) { + base.dragging.rect.translation.b = clamp( cursor.y.magnitude(), side_min - y_length, side_max - y_length ) + } + } + else if (base.dragging) { + base.dragging.rect.translation.a = cursor.x.magnitude() + base.dragging.rect.translation.b = cursor.y.magnitude() + } + } + + function up (e, cursor, new_cursor) { + new_cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom).add(map.center.a) + new_cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom).sub(map.center.b) + + if (base.creating) { + if (cursor.height() > side_min && cursor.width() > side_min) { + cursor.x.abs().quantize(1) + cursor.y.abs().quantize(1) + var room = Rooms.add_with_rect( cursor ) + + Rooms.rebuild() + + UndoStack.push({ + type: "create-room", + undo: { id: room.id }, + redo: room.copy() + }) + + Rooms.rebuild() + app.tube("builder-pick-room", room) + + // TODO: watch individual scenery object here + Minotaur.watch( app.controller.settings ) + } + } + 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() + }) + Rooms.rebuild() + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + } + + var intersects = Rooms.filter(function(r){ + return r.focused = r.rect.contains(cursor.x.a, cursor.y.a) + }) + if (! intersects.length) { + app.tube("builder-pick-nothing") + } + + base.creating = base.dragging = base.resizing = false + } + + var wheelState, wheelTimeout + + function mousewheel (e, deltaY, deltaX){ + var cursor = base.mouse.cursor + + var intersects = Rooms.filter(function(r){ + return r.focused // = r.rect.contains(cursor.x.a, cursor.y.a) + }) + + if (intersects.length && window.heightIsGlobal) { + var rooms = Rooms.values() + wheelState = wheelState || rooms[0].height + var height = clamp( ~~(rooms[0].height + deltaY * 2), height_min, height_max ) + rooms.forEach(function(room){ + room.height = height + }) + + app.tube("builder-pick-room", intersects[0]) + + clearTimeout(wheelTimeout) + wheelTimeout = setTimeout(function(){ + UndoStack.push({ + type: "update-rooms-height", + undo: wheelState, + redo: height + }) + Rooms.rebuild() + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + + wheelState = null + }, 250) + } + else if (intersects.length) { + wheelState = wheelState || intersects[0].copy() + + intersects[0].height = clamp( ~~(intersects[0].height + deltaY * 2), height_min, height_max ) + app.tube("builder-pick-room", intersects[0]) + + clearTimeout(wheelTimeout) + wheelTimeout = setTimeout(function(){ + UndoStack.push({ + type: "update-room", + undo: wheelState, + redo: intersects[0].copy() + }) + Rooms.rebuild() + + // TODO: watch individual scenery object here + Minotaur.watch( app.router.editorView.settings ) + + wheelState = null + }, 250) + } + else { + map.set_zoom(map.zoom_exponent + deltaY/20) + } + } + + function rightclick (e){ + } + +} diff --git a/public/assets/javascripts/rectangles/engine/map/ui/minimap.js b/public/assets/javascripts/rectangles/engine/map/ui/minimap.js new file mode 100644 index 0000000..0fdd336 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/ui/minimap.js @@ -0,0 +1,81 @@ + +Map.UI = Map.UI || {} + +Map.UI.Minimap = function(map){ + + var base = this + + base.creating = base.dragging = base.resizing = false + + base.mouse = new mouse({ + el: map.el, + down: down, + move: move, + drag: drag, + up: up, + rightclick: rightclick, + }) + + base.wheel = new wheel({ + el: map.el, + update: mousewheel, + }) + + var x, z + + // + + function down (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) + + x = scene.camera.x + z = scene.camera.z + + if (e.ctrlKey || e.which === 3) { + cursor.quantize(1/map.zoom) + map.center.a = cursor.x.a + map.center.b = -cursor.y.a + console.log(map.center+"") + cursor.x.b = cursor.x.a + cursor.y.b = cursor.y.a + base.mouse.down = false + e.preventDefault() + e.stopPropagation() + return + } + } + + 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) + } + + function drag (e, cursor) { + cursor.x.b = ((cursor.x.b/map.dimensions.a)+0.5) * map.dimensions.a / map.zoom + map.center.a + cursor.y.b = ((cursor.y.b/map.dimensions.b)-0.5) * map.dimensions.b / map.zoom - map.center.b + + scene.camera.x = x + cursor.x.magnitude() * map.zoom * 16 + scene.camera.z = z + cursor.y.magnitude() * map.zoom * 16 + Rooms.mover.room = null + + if (base.dragging) { + base.dragging.rect.translation.a = cursor.x.magnitude() + base.dragging.rect.translation.b = cursor.y.magnitude() + } + } + + function up (e, cursor, new_cursor) { + new_cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom).add(map.center.a) + new_cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom).sub(map.center.b) + + base.dragging = false + } + + function mousewheel (e, deltaY, deltaX){ + map.set_zoom(map.zoom_exponent - deltaY/20) + } + + function rightclick (e){ + } +} diff --git a/public/assets/javascripts/rectangles/engine/map/ui/ortho.js b/public/assets/javascripts/rectangles/engine/map/ui/ortho.js new file mode 100644 index 0000000..52f7339 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/ui/ortho.js @@ -0,0 +1,105 @@ +Map.UI = Map.UI || {} +Map.UI.Ortho = function(map){ + + var base = this + var last_event = null + + base.creating = base.dragging = base.resizing = false + + base.mouse = new mouse({ + el: map.el, + down: function(e, cursor){ + last_event = e + cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom) + cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom) + if (tool.recenterCursor) { + cursor.x.add(map.center.a) + cursor.y.sub(map.center.b) + base.tools[currentTool].down(e, cursor) + } + else { + base.tools[currentTool].down(e, cursor) + cursor.x.add(map.center.a) + cursor.y.sub(map.center.b) + } + }, + move: function(e, cursor){ + last_event = e + cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom) + cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom) + if (tool.recenterCursor) { + cursor.x.add(map.center.a) + cursor.y.sub(map.center.b) + base.tools[currentTool].move(e, cursor) + } + else { + base.tools[currentTool].move(e, cursor) + cursor.x.add(map.center.a) + cursor.y.sub(map.center.b) + } + }, + drag: function(e, cursor){ + last_event = e + cursor.x.b = ((cursor.x.b/map.dimensions.a)+0.5) * map.dimensions.a / map.zoom + cursor.y.b = ((cursor.y.b/map.dimensions.b)-0.5) * map.dimensions.b / map.zoom + if (tool.recenterCursor) { + cursor.x.b += map.center.a + cursor.y.b -= map.center.b + base.tools[currentTool].drag(e, cursor) + } + else { + base.tools[currentTool].drag(e, cursor) + cursor.x.b += map.center.a + cursor.y.b -= map.center.b + } + }, + up: function(e, cursor, new_cursor){ + last_event = e + new_cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom) + new_cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom) + if (tool.recenterCursor) { + new_cursor.x.add(map.center.a) + new_cursor.y.sub(map.center.b) + base.tools[currentTool].up(e, cursor, new_cursor) + } + else { + base.tools[currentTool].up(e, cursor, new_cursor) + new_cursor.x.add(map.center.a) + new_cursor.y.sub(map.center.b) + } + if (nextTool) { + console.log('found nextTool') + base.set_tool(nextTool) + nextTool = null + } + } + }) + + var currentTool = "polyline", nextTool, tool + base.add_tool = function(name, tool){ + base.tools[name] = tool + } + base.set_tool = function(s){ + console.log("set tool to", s) + base.tools[currentTool].cancel() + currentTool = s + tool = base.tools[currentTool] + } + base.set_drag_tool = function(s){ + console.log('set drag tool to', s) + nextTool = currentTool + currentTool = s + tool = base.tools[currentTool] + base.tools[currentTool].down(last_event, base.mouse.cursor) + } + base.tools = {} + + base.wheel = new wheel({ + el: map.el, + update: mousewheel, + }) + + function mousewheel (e, deltaY, deltaX){ + map.set_zoom(map.zoom_exponent - deltaY/20) + } +} diff --git a/public/assets/javascripts/rectangles/engine/map/ui_editor.js b/public/assets/javascripts/rectangles/engine/map/ui_editor.js deleted file mode 100644 index 7308344..0000000 --- a/public/assets/javascripts/rectangles/engine/map/ui_editor.js +++ /dev/null @@ -1,284 +0,0 @@ - -Map.UI = Map.UI || {} -Map.UI.Editor = function(map){ - - var base = this - - base.creating = base.dragging = base.resizing = false - - base.mouse = new mouse({ - el: map.el, - down: down, - move: move, - drag: drag, - up: up, - rightclick: rightclick, - }) - - base.wheel = new wheel({ - el: map.el, - update: mousewheel, - }) - - base.permissions = new Permissions({ - create: true, - move: true, - resize: true, - destroy: false, - }) - - base.blur = function(){ - Rooms.forEach(function(r){ - return r.focused = false - }) - app.tube("builder-pick-nothing") - } - - // - - 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) - - if (e.ctrlKey || e.which === 3) { - if (Rooms.regions.length == 0) return - cursor.quantize(1/map.zoom) - map.center.a = cursor.x.a - map.center.b = -cursor.y.a - cursor.x.b = cursor.x.a - cursor.y.b = cursor.y.a - base.mouse.down = false - e.preventDefault() - e.stopPropagation() - return - } - - var intersects = Rooms.filter(function(r){ - return r.focused = r.rect.contains(cursor.x.a, cursor.y.a) - }) - - if (intersects.length && (base.permissions.destroy || e.altKey)) { - base.mouse.down = false - - room = intersects[0] - - UndoStack.push({ - type: "destroy-room", - undo: room.copy(), - redo: { id: room.id }, - }) - - Rooms.remove(room) - app.tube("builder-destroy-room", room) - - // TODO: watch individual scenery object here - Minotaur.watch( app.router.editorView.settings ) - return - } - else if (intersects.length) { - base.dragging = intersects[0] - 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 - } - - if (e.shiftKey && base.dragging) { - base.dragging.rect.quantize(10/map.zoom) - } - } - - 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) { - cursor.x.b = ((cursor.x.b/map.dimensions.a)+0.5) * map.dimensions.a / map.zoom + map.center.a - cursor.y.b = ((cursor.y.b/map.dimensions.b)-0.5) * map.dimensions.b / map.zoom - map.center.b - - if (base.resizing) { - var x_length = base.dragging.rect.x.length(), - y_length = base.dragging.rect.y.length() - - if (base.resizing & LEFT) { - base.dragging.rect.translation.a = clamp( cursor.x.magnitude(), x_length - side_max, x_length - side_min ) - } - if (base.resizing & RIGHT) { - base.dragging.rect.translation.a = clamp( cursor.x.magnitude(), side_min - x_length, side_max - x_length ) - } - if (base.resizing & FRONT) { - base.dragging.rect.translation.b = clamp( cursor.y.magnitude(), y_length - side_max, y_length - side_min ) - } - if (base.resizing & BACK) { - base.dragging.rect.translation.b = clamp( cursor.y.magnitude(), side_min - y_length, side_max - y_length ) - } - } - else if (base.dragging) { - base.dragging.rect.translation.a = cursor.x.magnitude() - base.dragging.rect.translation.b = cursor.y.magnitude() - } - } - - function up (e, cursor, new_cursor) { - new_cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom).add(map.center.a) - new_cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom).sub(map.center.b) - - if (base.creating) { - if (cursor.height() > side_min && cursor.width() > side_min) { - cursor.x.abs().quantize(1) - cursor.y.abs().quantize(1) - var room = Rooms.add_with_rect( cursor ) - - Rooms.rebuild() - - UndoStack.push({ - type: "create-room", - undo: { id: room.id }, - redo: room.copy() - }) - - Rooms.rebuild() - app.tube("builder-pick-room", room) - - // TODO: watch individual scenery object here - Minotaur.watch( app.controller.settings ) - } - } - 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() - }) - Rooms.rebuild() - - // TODO: watch individual scenery object here - Minotaur.watch( app.router.editorView.settings ) - } - - var intersects = Rooms.filter(function(r){ - return r.focused = r.rect.contains(cursor.x.a, cursor.y.a) - }) - if (! intersects.length) { - app.tube("builder-pick-nothing") - } - - base.creating = base.dragging = base.resizing = false - } - - var wheelState, wheelTimeout - - function mousewheel (e, deltaY, deltaX){ - var cursor = base.mouse.cursor - - var intersects = Rooms.filter(function(r){ - return r.focused // = r.rect.contains(cursor.x.a, cursor.y.a) - }) - - if (intersects.length && window.heightIsGlobal) { - var rooms = Rooms.values() - wheelState = wheelState || rooms[0].height - var height = clamp( ~~(rooms[0].height + deltaY * 2), height_min, height_max ) - rooms.forEach(function(room){ - room.height = height - }) - - app.tube("builder-pick-room", intersects[0]) - - clearTimeout(wheelTimeout) - wheelTimeout = setTimeout(function(){ - UndoStack.push({ - type: "update-rooms-height", - undo: wheelState, - redo: height - }) - Rooms.rebuild() - - // TODO: watch individual scenery object here - Minotaur.watch( app.router.editorView.settings ) - - wheelState = null - }, 250) - } - else if (intersects.length) { - wheelState = wheelState || intersects[0].copy() - - intersects[0].height = clamp( ~~(intersects[0].height + deltaY * 2), height_min, height_max ) - app.tube("builder-pick-room", intersects[0]) - - clearTimeout(wheelTimeout) - wheelTimeout = setTimeout(function(){ - UndoStack.push({ - type: "update-room", - undo: wheelState, - redo: intersects[0].copy() - }) - Rooms.rebuild() - - // TODO: watch individual scenery object here - Minotaur.watch( app.router.editorView.settings ) - - wheelState = null - }, 250) - } - else { - map.set_zoom(map.zoom_exponent + deltaY/20) - } - } - - function rightclick (e){ - } - -} diff --git a/public/assets/javascripts/rectangles/engine/map/ui_minimap.js b/public/assets/javascripts/rectangles/engine/map/ui_minimap.js deleted file mode 100644 index 0fdd336..0000000 --- a/public/assets/javascripts/rectangles/engine/map/ui_minimap.js +++ /dev/null @@ -1,81 +0,0 @@ - -Map.UI = Map.UI || {} - -Map.UI.Minimap = function(map){ - - var base = this - - base.creating = base.dragging = base.resizing = false - - base.mouse = new mouse({ - el: map.el, - down: down, - move: move, - drag: drag, - up: up, - rightclick: rightclick, - }) - - base.wheel = new wheel({ - el: map.el, - update: mousewheel, - }) - - var x, z - - // - - function down (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) - - x = scene.camera.x - z = scene.camera.z - - if (e.ctrlKey || e.which === 3) { - cursor.quantize(1/map.zoom) - map.center.a = cursor.x.a - map.center.b = -cursor.y.a - console.log(map.center+"") - cursor.x.b = cursor.x.a - cursor.y.b = cursor.y.a - base.mouse.down = false - e.preventDefault() - e.stopPropagation() - return - } - } - - 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) - } - - function drag (e, cursor) { - cursor.x.b = ((cursor.x.b/map.dimensions.a)+0.5) * map.dimensions.a / map.zoom + map.center.a - cursor.y.b = ((cursor.y.b/map.dimensions.b)-0.5) * map.dimensions.b / map.zoom - map.center.b - - scene.camera.x = x + cursor.x.magnitude() * map.zoom * 16 - scene.camera.z = z + cursor.y.magnitude() * map.zoom * 16 - Rooms.mover.room = null - - if (base.dragging) { - base.dragging.rect.translation.a = cursor.x.magnitude() - base.dragging.rect.translation.b = cursor.y.magnitude() - } - } - - function up (e, cursor, new_cursor) { - new_cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom).add(map.center.a) - new_cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom).sub(map.center.b) - - base.dragging = false - } - - function mousewheel (e, deltaY, deltaX){ - map.set_zoom(map.zoom_exponent - deltaY/20) - } - - function rightclick (e){ - } -} diff --git a/public/assets/javascripts/rectangles/engine/map/ui_ortho.js b/public/assets/javascripts/rectangles/engine/map/ui_ortho.js deleted file mode 100644 index 52f7339..0000000 --- a/public/assets/javascripts/rectangles/engine/map/ui_ortho.js +++ /dev/null @@ -1,105 +0,0 @@ -Map.UI = Map.UI || {} -Map.UI.Ortho = function(map){ - - var base = this - var last_event = null - - base.creating = base.dragging = base.resizing = false - - base.mouse = new mouse({ - el: map.el, - down: function(e, cursor){ - last_event = e - cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom) - cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom) - if (tool.recenterCursor) { - cursor.x.add(map.center.a) - cursor.y.sub(map.center.b) - base.tools[currentTool].down(e, cursor) - } - else { - base.tools[currentTool].down(e, cursor) - cursor.x.add(map.center.a) - cursor.y.sub(map.center.b) - } - }, - move: function(e, cursor){ - last_event = e - cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom) - cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom) - if (tool.recenterCursor) { - cursor.x.add(map.center.a) - cursor.y.sub(map.center.b) - base.tools[currentTool].move(e, cursor) - } - else { - base.tools[currentTool].move(e, cursor) - cursor.x.add(map.center.a) - cursor.y.sub(map.center.b) - } - }, - drag: function(e, cursor){ - last_event = e - cursor.x.b = ((cursor.x.b/map.dimensions.a)+0.5) * map.dimensions.a / map.zoom - cursor.y.b = ((cursor.y.b/map.dimensions.b)-0.5) * map.dimensions.b / map.zoom - if (tool.recenterCursor) { - cursor.x.b += map.center.a - cursor.y.b -= map.center.b - base.tools[currentTool].drag(e, cursor) - } - else { - base.tools[currentTool].drag(e, cursor) - cursor.x.b += map.center.a - cursor.y.b -= map.center.b - } - }, - up: function(e, cursor, new_cursor){ - last_event = e - new_cursor.x.div(map.dimensions.a).add(0.5).mul(map.dimensions.a / map.zoom) - new_cursor.y.div(map.dimensions.b).sub(0.5).mul(map.dimensions.b / map.zoom) - if (tool.recenterCursor) { - new_cursor.x.add(map.center.a) - new_cursor.y.sub(map.center.b) - base.tools[currentTool].up(e, cursor, new_cursor) - } - else { - base.tools[currentTool].up(e, cursor, new_cursor) - new_cursor.x.add(map.center.a) - new_cursor.y.sub(map.center.b) - } - if (nextTool) { - console.log('found nextTool') - base.set_tool(nextTool) - nextTool = null - } - } - }) - - var currentTool = "polyline", nextTool, tool - base.add_tool = function(name, tool){ - base.tools[name] = tool - } - base.set_tool = function(s){ - console.log("set tool to", s) - base.tools[currentTool].cancel() - currentTool = s - tool = base.tools[currentTool] - } - base.set_drag_tool = function(s){ - console.log('set drag tool to', s) - nextTool = currentTool - currentTool = s - tool = base.tools[currentTool] - base.tools[currentTool].down(last_event, base.mouse.cursor) - } - base.tools = {} - - base.wheel = new wheel({ - el: map.el, - update: mousewheel, - }) - - function mousewheel (e, deltaY, deltaX){ - map.set_zoom(map.zoom_exponent - deltaY/20) - } -} diff --git a/public/assets/test/ortho3.html b/public/assets/test/ortho3.html index fa7e3c5..7e7e8ec 100644 --- a/public/assets/test/ortho3.html +++ b/public/assets/test/ortho3.html @@ -61,6 +61,8 @@ body { + + @@ -68,8 +70,13 @@ body { - + + + + + + - - + + -- cgit v1.2.3-70-g09d2 From 8d749201d661f62766b4e3a84735c3307ff7ab5e Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 11 Aug 2015 13:22:02 -0400 Subject: refactor environment loading --- public/assets/javascripts/app.js | 30 +----- public/assets/javascripts/rectangles/_env.js | 34 +++++- public/assets/javascripts/ui/_router.js | 11 ++ .../javascripts/ui/builder/BlueprintUpload.js | 120 --------------------- public/assets/test/ortho4.html | 9 +- views/modal.ejs | 3 +- views/partials/scripts.ejs | 17 ++- 7 files changed, 68 insertions(+), 156 deletions(-) delete mode 100644 public/assets/javascripts/ui/builder/BlueprintUpload.js (limited to 'views/partials') diff --git a/public/assets/javascripts/app.js b/public/assets/javascripts/app.js index 6ebcda5..3cafeca 100644 --- a/public/assets/javascripts/app.js +++ b/public/assets/javascripts/app.js @@ -21,40 +21,12 @@ app.init = function () { app.launch = function () { if ($.browser.msie || ! has3d()) { return app.fallback() } - scene = new MX.Scene().addTo('#scene') - scene.width = window.innerWidth - scene.height = window.innerHeight - scene.perspective = window.innerHeight - - window.onresize = function () { - scene.width = window.innerWidth - scene.height = window.innerHeight - scene.perspective = window.innerHeight - scene.update() - } - - cam = scene.camera - cam.y = viewHeight - - if (MX.Map) map = app.map = new MX.Map() - - if (is_mobile) { - app.movements = new MX.MobileMovements(cam, viewHeight) - } - else { - app.movements = new MX.Movements(cam, viewHeight) - } - app.movements.init() - var last_t = 0 function animate (t) { var dt = t - last_t last_t = t requestAnimationFrame(animate) - environment.update(t) - window.path && path.update(t) - app.movements.update(dt || 0) - scene.update() + environment.update(t, dt) } var loader = new Loader(function(){ diff --git a/public/assets/javascripts/rectangles/_env.js b/public/assets/javascripts/rectangles/_env.js index 14f73e3..b3c7d66 100644 --- a/public/assets/javascripts/rectangles/_env.js +++ b/public/assets/javascripts/rectangles/_env.js @@ -1,6 +1,22 @@ var environment = new function(){} environment.init = function(){ + scene = new MX.Scene().addTo('#scene') + scene.width = window.innerWidth + scene.height = window.innerHeight + scene.perspective = window.innerHeight + + cam = scene.camera + cam.y = viewHeight + + if (is_mobile) { + app.movements = new MX.MobileMovements(cam, viewHeight) + } + else { + app.movements = new MX.Movements(cam, viewHeight) + } + app.movements.init() + map = new Map () if (window.scene) { @@ -16,7 +32,14 @@ environment.init = function(){ scene.camera.radius = 20 } - + + window.onresize = function () { + scene.width = window.innerWidth + scene.height = window.innerHeight + scene.perspective = window.innerHeight + scene.update() + } + Rooms.init() Walls.init() Scenery.init() @@ -52,8 +75,13 @@ environment.init = function(){ } }) } -environment.update = function(t){ +environment.minimal = function(){ + environment.update = function(t){} +} +environment.update = function(t, dt){ + app.movements.update(dt || 0) + scene.update() map.update() - window.minimap && window.minimap.update && minimap.update() + window.minimap && minimap.update && minimap.update() z = false } diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js index 1bdce19..857377c 100644 --- a/public/assets/javascripts/ui/_router.js +++ b/public/assets/javascripts/ui/_router.js @@ -44,6 +44,8 @@ var SiteRouter = Router.extend({ "/project/:name": 'projectViewer', "/project/:name/edit": 'projectEditor', "/project/:name/view": 'projectViewer', + + "/test/blueprint": 'blueprintEditor', }, mobileRoutes: { @@ -157,6 +159,15 @@ var SiteRouter = Router.extend({ this.readerView = app.controller = new ReaderView() this.readerView.load(name) }, + + blueprintEditor: function(e){ + environment.init = environment.minimal + app.launch() + if (app.unsupported) return + + this.blueprintView = app.controller = new BlueprintView () + this.blueprintView.load() + }, signup: function(e){ e && e.preventDefault() diff --git a/public/assets/javascripts/ui/builder/BlueprintUpload.js b/public/assets/javascripts/ui/builder/BlueprintUpload.js deleted file mode 100644 index dbc6f12..0000000 --- a/public/assets/javascripts/ui/builder/BlueprintUpload.js +++ /dev/null @@ -1,120 +0,0 @@ - -var BlueprintUpload = UploadView.extend({ - el: ".blueprintUpload", - - mediaTag: "blueprint", - createAction: "/api/media/new", - uploadAction: "/api/media/upload", - listAction: "/api/media/user", - destroyAction: "/api/media/destroy", - - events: { - "mousedown": 'stopPropagation', - "change .url": "enterUrl", - "keydown .url": "enterSetUrl", - - "click .blueprint": "choose", - "change [name=blueprint-dimensions]": "changeDimensions", - "change [name=blueprint-units]": "changeUnits", - "click #saveBlueprint": "save", - }, - - initialize: function(opt){ - this.parent = opt.parent - this.__super__.initialize.call(this) - - this.$url = this.$(".url") - - this.$blueprintMap = this.$("#blueprintMap") - this.$blueprintDimensionsRapper = this.$("#blueprintDimensions") - this.$dimensions = this.$("[name=blueprint-dimensions]") - this.$units = this.$("[name=blueprint-units]") - this.$save = this.$("#saveBlueprint") - - this.map = new Map ({ type: ortho }) - - this.load() - }, - - loaded: false, - load: function(){ - $.get(this.listAction, { tag: this.mediaTag }, this.populate.bind(this)) - }, - - populate: function(data){ - this.loaded = true - if (data && data.length) { - data.forEach(this.append.bind(this)) - this.$(".txt").hide() - } - else { - this.$(".txt").show() - } - }, - - append: function(media){ - var $el = $("
    ") - $el.data("id", media._id) - $el.addClass("blueprint") - this.$blueprints.append($el) - }, - - pick: function(e){ - var $el = $(e.currentTarget) - // load map with it - }, - - destroy: function(_id, cb){ - $.ajax({ - type: "delete", - url: this.destroyAction, - data: { _id: _id, _csrf: $("[name=_csrf]").val() } - }).complete(cb || 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.append(media) - }, - changeDimensions: function(){ - }, - changeUnits: function(){ - }, - -}) diff --git a/public/assets/test/ortho4.html b/public/assets/test/ortho4.html index 12b6ab2..1c1adef 100644 --- a/public/assets/test/ortho4.html +++ b/public/assets/test/ortho4.html @@ -91,14 +91,16 @@ body {
    - - + + + + @@ -126,8 +128,10 @@ body { + + + + @@ -79,10 +81,20 @@ + + + + - + + + + + + + @@ -115,6 +127,9 @@ + + + -- cgit v1.2.3-70-g09d2 From 4024085b09261c23cd89227e340037e0238072c7 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 11 Aug 2015 14:15:31 -0400 Subject: uploader functioning --- .../javascripts/ui/blueprint/BlueprintEditor.js | 30 ++++++ .../javascripts/ui/blueprint/BlueprintScale.js | 0 .../javascripts/ui/blueprint/BlueprintUpload.js | 35 ++----- .../javascripts/ui/blueprint/BlueprintView.js | 3 +- public/assets/stylesheets/app.css | 2 +- views/controls/blueprint/editor.ejs | 104 +++++++++++++++++++++ views/controls/builder/blueprint.ejs | 92 ------------------ views/modal.ejs | 2 +- views/partials/scripts.ejs | 1 + 9 files changed, 149 insertions(+), 120 deletions(-) create mode 100644 public/assets/javascripts/ui/blueprint/BlueprintEditor.js delete mode 100644 public/assets/javascripts/ui/blueprint/BlueprintScale.js create mode 100644 views/controls/blueprint/editor.ejs delete mode 100644 views/controls/builder/blueprint.ejs (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/blueprint/BlueprintEditor.js b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js new file mode 100644 index 0000000..227c1c8 --- /dev/null +++ b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js @@ -0,0 +1,30 @@ + +var BlueprintEditor = ModalView.extend({ + el: ".blueprintEditor", + + events: { + "change [name=blueprint-dimensions]": "changeDimensions", + "change [name=blueprint-units]": "changeUnits", + "click #saveBlueprint": "save", + }, + + initialize: function(){ + this.$blueprintMap = this.$("#blueprintMap") + this.$blueprintDimensionsRapper = this.$("#blueprintDimensions") + this.$dimensions = this.$("[name=blueprint-dimensions]") + this.$units = this.$("[name=blueprint-units]") + this.$save = this.$("#saveBlueprint") + + this.map = new Map ({ type: 'ortho' }) + + this.$blueprintMap.append(this.map.el) + }, + + changeDimensions: function(){ + }, + changeUnits: function(){ + }, + save: function(){ + }, + +}) diff --git a/public/assets/javascripts/ui/blueprint/BlueprintScale.js b/public/assets/javascripts/ui/blueprint/BlueprintScale.js deleted file mode 100644 index e69de29..0000000 diff --git a/public/assets/javascripts/ui/blueprint/BlueprintUpload.js b/public/assets/javascripts/ui/blueprint/BlueprintUpload.js index fd3a659..9467715 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintUpload.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintUpload.js @@ -1,5 +1,5 @@ -var BlueprintUploadView = UploadView.extend({ +var BlueprintUpload = UploadView.extend({ el: ".blueprintUpload", mediaTag: "blueprint", @@ -14,9 +14,6 @@ var BlueprintUploadView = UploadView.extend({ "keydown .url": "enterSetUrl", "click .blueprint": "choose", - "change [name=blueprint-dimensions]": "changeDimensions", - "change [name=blueprint-units]": "changeUnits", - "click #saveBlueprint": "save", }, initialize: function(opt){ @@ -24,15 +21,8 @@ var BlueprintUploadView = UploadView.extend({ this.__super__.initialize.call(this) this.$url = this.$(".url") + this.$blueprints = this.$(".blueprints") - this.$blueprintMap = this.$("#blueprintMap") - this.$blueprintDimensionsRapper = this.$("#blueprintDimensions") - this.$dimensions = this.$("[name=blueprint-dimensions]") - this.$units = this.$("[name=blueprint-units]") - this.$save = this.$("#saveBlueprint") - - this.map = new Map ({ type: 'ortho' }) - this.load() }, @@ -52,13 +42,6 @@ var BlueprintUploadView = UploadView.extend({ } }, - append: function(media){ - var $el = $("
    ") - $el.data("id", media._id) - $el.addClass("blueprint") - this.$blueprints.append($el) - }, - pick: function(e){ var $el = $(e.currentTarget) // load map with it @@ -112,11 +95,13 @@ var BlueprintUploadView = UploadView.extend({ add: function(media){ this.append(media) }, - changeDimensions: function(){ - }, - changeUnits: function(){ - }, - save: function(){ - }, + append: function(media){ + var $el = $("") + $el.attr("src", media.url) + $el.data("id", media._id) + $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 index f7ee13e..40c61d7 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintView.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintView.js @@ -11,7 +11,8 @@ var BlueprintView = View.extend({ // this.settings = new BuilderSettings ({ parent: this }) // this.colorControl = new ColorControl ({ parent: this }) // this.cursor = new HelpCursor({ parent: this }) - this.blueprintUpload = new BlueprintUploadView ({ parent: this }) + this.blueprintUpload = new BlueprintUpload ({ parent: this }) + this.blueprintEditor = new BlueprintEditor ({ parent: this }) }, load: function(name){ diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index bb32500..0f89242 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1598,7 +1598,7 @@ form .paidPlan label { float: none; font-size: 16px; margin: 0 10px; } .mediaDrawer.alert, .mediaDrawer.confirm, .mediaDrawer.passwordForgot, .mediaDrawer.passwordReset, .mediaDrawer.usernameTaken, .mediaDrawer.layouts, .mediaDrawer.projects, .mediaDrawer.newProject, -.mediaDrawer.blueprintUpload { +.mediaDrawer.blueprintEditor { display:table; } .confirm button { diff --git a/views/controls/blueprint/editor.ejs b/views/controls/blueprint/editor.ejs new file mode 100644 index 0000000..6b80287 --- /dev/null +++ b/views/controls/blueprint/editor.ejs @@ -0,0 +1,104 @@ + + +
    +
    +
    + +
    + + + +
    + +
    + + + + +
    +
    + +
    + X +
    + +

    Upload your Blueprint

    + +
    + +
    +
    + + + +
    +
    + +
    +
    Your uploaded blueprints
    +
    +
    + + Please tell us the scale of your blueprint. + Click both corners of a wall, and then enter how long the wall is. + https://s3.amazonaws.com/luckyplop/fbf4295da80f1f66c5e4a248f2ea3e1ce7a22c3d.jpg + +
    +
    + +
    + + + + +
    + +
    +
    diff --git a/views/controls/builder/blueprint.ejs b/views/controls/builder/blueprint.ejs deleted file mode 100644 index e5f3257..0000000 --- a/views/controls/builder/blueprint.ejs +++ /dev/null @@ -1,92 +0,0 @@ - - -
    -
    -
    - -
    - - - -
    - -
    - - - - -
    - -
    - X -
    - -

    Upload A Room Image

    - -
    -
    -
    - - - -
    -
    - -
    - - Please tell us the scale of your map. - Click both corners of a wall, and then enter how long the wall is. - -
    -
    - -
    - - - - -
    - -
    -
    -
    \ No newline at end of file diff --git a/views/modal.ejs b/views/modal.ejs index 433861e..775ba88 100644 --- a/views/modal.ejs +++ b/views/modal.ejs @@ -10,7 +10,7 @@
    - [[ include controls/builder/blueprint ]] + [[ include controls/blueprint/editor ]] [[ include partials/confirm-modal ]] [[ include partials/sign-in ]] [[ include projects/layouts-modal ]] diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 64ac135..2a93e9b 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -128,6 +128,7 @@ + -- cgit v1.2.3-70-g09d2 From d84c89a8dd770ea174a7d2ac90927046a5f4b5f6 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 11 Aug 2015 16:50:31 -0400 Subject: blueprint upload styling --- .../javascripts/rectangles/engine/map/ui/ortho.js | 4 +- .../javascripts/ui/blueprint/BlueprintEditor.js | 30 ----- .../javascripts/ui/blueprint/BlueprintScaler.js | 43 ++++++++ .../javascripts/ui/blueprint/BlueprintUpload.js | 36 ++++-- .../javascripts/ui/blueprint/BlueprintView.js | 2 +- views/controls/blueprint/editor.ejs | 122 +++++++++++++++++---- views/partials/scripts.ejs | 2 +- 7 files changed, 178 insertions(+), 61 deletions(-) delete mode 100644 public/assets/javascripts/ui/blueprint/BlueprintEditor.js create mode 100644 public/assets/javascripts/ui/blueprint/BlueprintScaler.js (limited to 'views/partials') diff --git a/public/assets/javascripts/rectangles/engine/map/ui/ortho.js b/public/assets/javascripts/rectangles/engine/map/ui/ortho.js index 52f7339..5be7446 100644 --- a/public/assets/javascripts/rectangles/engine/map/ui/ortho.js +++ b/public/assets/javascripts/rectangles/engine/map/ui/ortho.js @@ -81,7 +81,9 @@ Map.UI.Ortho = function(map){ } base.set_tool = function(s){ console.log("set tool to", s) - base.tools[currentTool].cancel() + if (base.tools[currentTool]) { + base.tools[currentTool].cancel() + } currentTool = s tool = base.tools[currentTool] } diff --git a/public/assets/javascripts/ui/blueprint/BlueprintEditor.js b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js deleted file mode 100644 index 227c1c8..0000000 --- a/public/assets/javascripts/ui/blueprint/BlueprintEditor.js +++ /dev/null @@ -1,30 +0,0 @@ - -var BlueprintEditor = ModalView.extend({ - el: ".blueprintEditor", - - events: { - "change [name=blueprint-dimensions]": "changeDimensions", - "change [name=blueprint-units]": "changeUnits", - "click #saveBlueprint": "save", - }, - - initialize: function(){ - this.$blueprintMap = this.$("#blueprintMap") - this.$blueprintDimensionsRapper = this.$("#blueprintDimensions") - this.$dimensions = this.$("[name=blueprint-dimensions]") - this.$units = this.$("[name=blueprint-units]") - this.$save = this.$("#saveBlueprint") - - this.map = new Map ({ type: 'ortho' }) - - this.$blueprintMap.append(this.map.el) - }, - - changeDimensions: function(){ - }, - changeUnits: function(){ - }, - save: function(){ - }, - -}) diff --git a/public/assets/javascripts/ui/blueprint/BlueprintScaler.js b/public/assets/javascripts/ui/blueprint/BlueprintScaler.js new file mode 100644 index 0000000..e11b61e --- /dev/null +++ b/public/assets/javascripts/ui/blueprint/BlueprintScaler.js @@ -0,0 +1,43 @@ + +var BlueprintScaler = ModalView.extend({ + el: ".blueprintScaler", + + events: { + "change [name=blueprint-dimensions]": "changeDimensions", + "change [name=blueprint-units]": "changeUnits", + "click #saveBlueprint": "save", + }, + + initialize: function(){ + this.$blueprintMap = this.$("#blueprintMap") + this.$blueprintDimensionsRapper = this.$("#blueprintDimensions") + this.$dimensions = this.$("[name=blueprint-dimensions]") + this.$units = this.$("[name=blueprint-units]") + this.$save = this.$("#saveBlueprint") + + this.map = map = new Map ({ + type: "ortho", + el: this.$blueprintMap.get(0), + 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("position", new PositionTool) + map.ui.set_tool("position") + }, + + pick: function(){ + + }, + + changeDimensions: function(){ + }, + changeUnits: function(){ + }, + save: function(){ + }, + +}) diff --git a/public/assets/javascripts/ui/blueprint/BlueprintUpload.js b/public/assets/javascripts/ui/blueprint/BlueprintUpload.js index 9467715..deb1075 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintUpload.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintUpload.js @@ -13,7 +13,8 @@ var BlueprintUpload = UploadView.extend({ "change .url": "enterUrl", "keydown .url": "enterSetUrl", - "click .blueprint": "choose", + "click .blueprint": "pick", + "click .remove": "destroy", }, initialize: function(opt){ @@ -34,25 +35,33 @@ var BlueprintUpload = UploadView.extend({ populate: function(data){ this.loaded = true if (data && data.length) { + this.$blueprints.show() data.forEach(this.append.bind(this)) - this.$(".txt").hide() + this.show() } else { - this.$(".txt").show() + this.show() } }, pick: function(e){ var $el = $(e.currentTarget) - // load map with it + var media = $el.data("media") + this.hide() + this.parent.blueprintScaler.pick(media) }, - destroy: function(_id, cb){ + 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(cb || function(){}) + }).complete(function(){ + }) }, show: function(){ @@ -93,13 +102,24 @@ var BlueprintUpload = UploadView.extend({ }, add: function(media){ + this.$blueprints.show() this.append(media) + this.hide() + this.parent.blueprintScaler.pick(media) }, append: function(media){ - var $el = $("") - $el.attr("src", media.url) + var $el = $("") + var img = new Image () + img.src = media.url + var remove = document.createElement("span") + remove.className = "remove" + remove.innerHTML = "x" + $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 index 40c61d7..a803f12 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintView.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintView.js @@ -12,7 +12,7 @@ var BlueprintView = View.extend({ // this.colorControl = new ColorControl ({ parent: this }) // this.cursor = new HelpCursor({ parent: this }) this.blueprintUpload = new BlueprintUpload ({ parent: this }) - this.blueprintEditor = new BlueprintEditor ({ parent: this }) + this.blueprintScaler = new BlueprintScaler ({ parent: this }) }, load: function(name){ diff --git a/views/controls/blueprint/editor.ejs b/views/controls/blueprint/editor.ejs index 6b80287..aec5e25 100644 --- a/views/controls/blueprint/editor.ejs +++ b/views/controls/blueprint/editor.ejs @@ -33,13 +33,88 @@ body { .hud span.active { color: #000; } .blueprintUpload { - width: 240px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + width: 340px; + position: absolute; + top: 50%; left: 50%; + background: white; + padding: 10px; + border: 1px solid black; + box-shadow: -3px 3px #000; + -webkit-transform: translate3D(0%,-200%,0); + transform: translate3D(0%,-200%,0); + margin-left: -175px; + margin-top: -200px; + opacity: 0; +} +.blueprintUpload.active { + -webkit-transform: translate3D(0,0,0); + transform: translate3D(0,0,0); + opacity: 1; +} +.blueprintUpload .toolButton { + float: none; + width: 108px; + display: inline-block; +} +.blueprintUpload .url { + font-size: 15px; + border: 1px solid #888; + padding: 2px; + font-weight: 300; + position: relative; + top: 3px; + margin-right: 10px; + width: 190px; +} +.blueprintUpload p { + font-weight: 300; + font-size: 13px; +} +.blueprintUpload .blueprints { + display: none; +} +.blueprintUpload .blueprints h5 { + width: 250px; + margin: 10px auto; + padding-top: 9px; } .blueprints .blueprint { border: 1px solid black; - padding: 5px; + background: white; + padding: 0px; + position: relative; + display: inline-block; +} +.blueprints .blueprint img { height: 100px; max-width: 200px; + display: block; + cursor: pointer; +} +.blueprints .blueprint .remove { + box-shadow: 0 1px 2px #888; + cursor: pointer; + position: absolute; + color: red; + top: 7px; + right: 7px; + width: 20px; height: 20px; + text-align: center; + background: #fff; + border-radius: 50%; +} +.blueprints .blueprint .remove span { + position: relative; + top: -2px; +} +.blueprintUpload .wallpaperUpload .upload-icon { + margin: 0 4px; +} +.uploadNewBlueprint { + color: #333; + border-bottom: 1px solid; cursor: pointer; } @@ -63,42 +138,49 @@ body {
    - X
    -

    Upload your Blueprint

    -
    +

    Upload your Blueprint

    +

    + Upload an image which you will trace to make a floor plan. + Images should be at least 1000x1000. +

    +
    - +
    -
    Your uploaded blueprints
    - Please tell us the scale of your blueprint. - Click both corners of a wall, and then enter how long the wall is. - https://s3.amazonaws.com/luckyplop/fbf4295da80f1f66c5e4a248f2ea3e1ce7a22c3d.jpg +
    +
    + Please tell us the scale of your blueprint. + Click both corners of a wall, and then enter how long the wall is. +

    + Do you want to upload a blueprint? +
    -
    -
    +
    +
    -
    - - +
    + + - + +
    - +
    diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index 2a93e9b..136bd4d 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -128,7 +128,7 @@ - + -- cgit v1.2.3-70-g09d2 From 9ba29a587bf0722db82e5caf1b1cf4e5596003b6 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 12 Aug 2015 18:38:12 -0400 Subject: functioning blueprint scaler --- .../javascripts/rectangles/engine/map/draw.js | 2 +- .../rectangles/engine/map/tools/line.js | 49 ++++++++++++ .../assets/javascripts/rectangles/models/rect.js | 6 ++ .../javascripts/ui/blueprint/BlueprintScaler.js | 91 ++++++++++++++++++++-- .../javascripts/ui/blueprint/BlueprintView.js | 3 + server/lib/schemas/Layout.js | 1 + views/controls/blueprint/editor.ejs | 4 +- views/partials/scripts.ejs | 1 + 8 files changed, 148 insertions(+), 9 deletions(-) create mode 100644 public/assets/javascripts/rectangles/engine/map/tools/line.js (limited to 'views/partials') diff --git a/public/assets/javascripts/rectangles/engine/map/draw.js b/public/assets/javascripts/rectangles/engine/map/draw.js index 11ba3f8..cc2f4d8 100644 --- a/public/assets/javascripts/rectangles/engine/map/draw.js +++ b/public/assets/javascripts/rectangles/engine/map/draw.js @@ -198,7 +198,7 @@ Map.Draw = function(map, opt){ // - function line (x,y,a,b,translation){ + var line = draw.line = function (x,y,a,b,translation){ if (translation) { x += translation.a a += translation.a diff --git a/public/assets/javascripts/rectangles/engine/map/tools/line.js b/public/assets/javascripts/rectangles/engine/map/tools/line.js new file mode 100644 index 0000000..8f409a8 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/map/tools/line.js @@ -0,0 +1,49 @@ +var LineTool = MapTool.extend(function(base){ + var exports = {} + + var selected_point = null + + var line = exports.line = [] + + var can_drag, dragging + + exports.down = function(e, cursor){ + this.cursor = cursor + switch (line.length) { + case 0: + line[0] = cursor.x_component() + can_drag = true + break + case 1: + line[1] = cursor.x_component() + can_drag = false + break + case 2: + line[0] = cursor.x_component() + line.pop() + can_drag = true + break + } + } + + exports.move = function(e, cursor){ + this.cursor = cursor + } + + exports.drag = function(e, cursor){ + if (dragging) { + line[1].a = cursor.x.b + line[1].b = cursor.y.b + } + else if (can_drag && cursor.magnitude() > 10/map.zoom) { + line[1] = cursor.y_component() + dragging = true + } + } + + exports.up = function(e, cursor){ + can_drag = dragging = false + } + + return exports +}) \ No newline at end of file diff --git a/public/assets/javascripts/rectangles/models/rect.js b/public/assets/javascripts/rectangles/models/rect.js index c667cf5..92c8c9e 100644 --- a/public/assets/javascripts/rectangles/models/rect.js +++ b/public/assets/javascripts/rectangles/models/rect.js @@ -39,6 +39,12 @@ Rect.prototype.clone = function(){ return new Rect( this.x.clone(), this.y.clone() ) } + Rect.prototype.x_component = function(){ + return new vec2( this.x.a, this.y.a ) + } + Rect.prototype.y_component = function(){ + return new vec2( this.x.b, this.y.b ) + } Rect.prototype.assign = function(r) { this.x.assign(r.x) this.y.assign(r.y) diff --git a/public/assets/javascripts/ui/blueprint/BlueprintScaler.js b/public/assets/javascripts/ui/blueprint/BlueprintScaler.js index a81c89b..addf9a9 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintScaler.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintScaler.js @@ -1,10 +1,13 @@ -var BlueprintScaler = ModalView.extend({ +var BlueprintScaler = ModalFormView.extend({ el: ".blueprintScaler", + method: "/api/media/scale", + events: { "change [name=blueprint-dimensions]": "changeDimensions", "change [name=blueprint-units]": "changeUnits", + "click .uploadNewBlueprint": "showBlueprintUpload", "click #saveBlueprint": "save", }, @@ -12,6 +15,7 @@ var BlueprintScaler = ModalView.extend({ 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") @@ -24,23 +28,40 @@ var BlueprintScaler = ModalView.extend({ zoom_min: -6.2, zoom_max: 1, }) - map.ui.add_tool("arrow", new ArrowTool) - map.ui.add_tool("position", new PositionTool) - map.ui.set_tool("position") + this.lineTool = new LineTool + map.ui.add_tool("line", this.lineTool) + map.ui.set_tool("line") scene = scene || { camera: { x: 0, y: 0, z: 0 } } this.floorplan = new MX.Image () - this.animate() + this.animating = false + }, + + showBlueprintUpload: function(){ + this.parent.blueprintUpload.show() }, pick: function(media){ + this.media = media + + if (!! media.scale) { + this.parent.useFloorplan(media) + } + this.floorplan.load({ media: media, keepImage: true }) + + if (! this.animating) { + this.animating = true + this.animate() + } }, animate: function(t){ requestAnimationFrame(this.animate.bind(this)) + + if (! this.animating) return var dt = t - this.last_t this.last_t = t @@ -53,6 +74,27 @@ var BlueprintScaler = ModalView.extend({ this.map.draw.translate() this.floorplan.draw(this.map.draw.ctx, true) + + this.map.draw.ctx.strokeStyle = "#f00" + this.map.draw.ctx.lineWidth = 2/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.coords() @@ -62,10 +104,47 @@ var BlueprintScaler = ModalView.extend({ }, 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") + 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 }, - save: function(){ + + showErrors: function(){}, + + serialize: function(){ + var fd = new FormData() + fd.append( "_id", this.media._id) + fd.append( "units", this.$units.val() ) + fd.append( "scale", this.$dimensions.unitVal() / this.lineLength() ) + fd.append( "_csrf", $("[name=_csrf]").val()) + return fd + }, + + success: function(){ + this.animating = false + this.parent.useFloorplan(media) }, }) diff --git a/public/assets/javascripts/ui/blueprint/BlueprintView.js b/public/assets/javascripts/ui/blueprint/BlueprintView.js index a803f12..6b204e5 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintView.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintView.js @@ -33,6 +33,9 @@ var BlueprintView = View.extend({ hideExtras: function(){ }, + + useFloorplan: function(media){ + }, pickWall: function(wall, pos){ }, diff --git a/server/lib/schemas/Layout.js b/server/lib/schemas/Layout.js index cff1d78..e15e188 100644 --- a/server/lib/schemas/Layout.js +++ b/server/lib/schemas/Layout.js @@ -23,6 +23,7 @@ var LayoutSchema = new mongoose.Schema({ photo: { type: String, }, + media: mongoose.Schema.Types.Mixed, rooms: [mongoose.Schema.Types.Mixed], startPosition: mongoose.Schema.Types.Mixed, viewHeight: { type: Number }, diff --git a/views/controls/blueprint/editor.ejs b/views/controls/blueprint/editor.ejs index 308b4c8..3e0c097 100644 --- a/views/controls/blueprint/editor.ejs +++ b/views/controls/blueprint/editor.ejs @@ -99,8 +99,8 @@ body {

    - - + + - -
    - - -
    +
    +
    + + + +
    + +
    +
    -
    -
    - +
    diff --git a/views/modal.ejs b/views/modal.ejs index 775ba88..dfc5573 100644 --- a/views/modal.ejs +++ b/views/modal.ejs @@ -10,7 +10,6 @@
    - [[ include controls/blueprint/editor ]] [[ include partials/confirm-modal ]] [[ include partials/sign-in ]] [[ include projects/layouts-modal ]] diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index a0222b5..e0024a4 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -102,6 +102,7 @@ + -- cgit v1.2.3-70-g09d2 From 599b43df07f092b35d25e7adac11db3c3b3d9c76 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 17 Aug 2015 12:23:39 -0400 Subject: BlueprintEditor --- public/assets/javascripts/ui/_router.js | 7 +- .../javascripts/ui/blueprint/BlueprintEditor.js | 155 +++++++++++++++++++++ .../javascripts/ui/blueprint/BlueprintView.js | 18 +-- server/index.js | 3 + server/lib/views/index.js | 4 + views/blueprint.ejs | 1 + views/controls/blueprint/editor.ejs | 53 ------- views/controls/blueprint/scaler.ejs | 48 +++++++ views/partials/scripts.ejs | 1 + 9 files changed, 227 insertions(+), 63 deletions(-) create mode 100644 public/assets/javascripts/ui/blueprint/BlueprintEditor.js create mode 100644 views/controls/blueprint/scaler.ejs (limited to 'views/partials') diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js index 857377c..177e86f 100644 --- a/public/assets/javascripts/ui/_router.js +++ b/public/assets/javascripts/ui/_router.js @@ -38,6 +38,9 @@ var SiteRouter = Router.extend({ "/layout": 'layoutPicker', "/layout/:name": 'layoutEditor', + "/blueprint": 'blueprintEditor', + "/blueprint/:name": 'blueprintEditor', + "/project": 'projectPicker', "/project/new": 'newProject', "/project/new/:layout": 'projectNewWithLayout', @@ -160,13 +163,13 @@ var SiteRouter = Router.extend({ this.readerView.load(name) }, - blueprintEditor: function(e){ + blueprintEditor: function(e, name){ environment.init = environment.minimal app.launch() if (app.unsupported) return this.blueprintView = app.controller = new BlueprintView () - this.blueprintView.load() + this.blueprintView.load(name) }, signup: function(e){ diff --git a/public/assets/javascripts/ui/blueprint/BlueprintEditor.js b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js new file mode 100644 index 0000000..c781495 --- /dev/null +++ b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js @@ -0,0 +1,155 @@ + +var wall_height = 180 +var shapes = new ShapeList +var last_point = new vec2 (0,0) + +var BlueprintEditor = View.extend(AnimatedView.prototype).extend({ + + initialize: function(opt){ + this.parent = opt.parent + + 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.placing = false + +/* + $(window).resize(function(){ + scene.width = window.innerWidth/2 + scene.height = window.innerHeight + map.canvas.width = map.dimensions.a = window.innerWidth/2 + map.canvas.height = map.dimensions.b = window.innerHeight/2 + }) +*/ + + var PerspectiveToolbar = new Toolbar (".persp-hud") + PerspectiveToolbar.add("orbit-mode", function(){ + controls.toggle(true) + movements.lock() + }) + PerspectiveToolbar.add("keyboard-mode", function(){ + controls.toggle(false) + movements.unlock() + movements.gravity(true) + cam.rotationX = 0 + cam.rotationY = -cam.rotationY + cam.x = 0 + cam.y = viewHeight + 100 + cam.z = 0 + }) + + var OrthographicToolbar = new Toolbar (".ortho-hud") + OrthographicToolbar.add("arrow-mode", function(){ + map.ui.set_tool("arrow") + }) + OrthographicToolbar.add("polyline-mode", function(){ + map.ui.set_tool("polyline") + }) + OrthographicToolbar.add("ortho-polyline-mode", function(){ + map.ui.set_tool("ortho-polyline") + }) + OrthographicToolbar.add("eraser-mode", function(){ + map.ui.set_tool("eraser") + }) + OrthographicToolbar.pick("ortho-polyline-mode") + }, + + animate: function(t, dt){ + map.update(t) + + movements.update(dt) + controls.update() + scene.update() + + map.draw.ctx.save() + map.draw.translate() + + floorplan.draw(map.draw.ctx, true) + + map.draw.coords() + + if (shapes.workline) { + shapes.workline.draw(map.draw.ctx) + if (map.ui.placing && last_point) { + shapes.workline.draw_line( map.draw.ctx, last_point ) + } + } + + shapes.forEach(function(shape){ + shape.draw(map.draw.ctx) + }) + + map.draw.ctx.strokeStyle = "#f00"; + map.draw.x_at(0,0) + map.draw.mouse(map.ui.mouse.cursor) + map.draw.camera(scene.camera) + + map.draw.ctx.restore() + }, + +}) + +function build () { + scene = new MX.Scene().addTo("#perspective") + scene.camera.radius = 20 + + viewHeight = 100 + + scene.width = window.innerWidth/2 + scene.height = window.innerHeight + scene.perspective = window.innerHeight + + cam = scene.camera + movements = new MX.Movements(cam, viewHeight) + movements.init() + movements.lock() + movements.velocity(8) + app.on("move", function(pos){ + cam.x = pos.x + cam.y = pos.y + cam.z = pos.z + }) + + floorplan = new MX.Image({ + src: "https://s3.amazonaws.com/luckyplop/fbf4295da80f1f66c5e4a248f2ea3e1ce7a22c3d.jpg", + keepImage: true, + rotationX: -PI/2, + rotationY: PI, + }) + scene.add(floorplan) + + // recenter perspective view by rightclicking map + 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() + + animate(0) +} diff --git a/public/assets/javascripts/ui/blueprint/BlueprintView.js b/public/assets/javascripts/ui/blueprint/BlueprintView.js index 6b204e5..0a06fda 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintView.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintView.js @@ -1,7 +1,9 @@ var BlueprintView = View.extend({ el: "#blueprintView", - + + action: "/api/layout/", + events: { }, @@ -16,14 +18,14 @@ var BlueprintView = View.extend({ }, load: function(name){ -// if (! name || name == "new") { + if (! name || name == "new") { // this.ready({ isNew: true, _id: "new", name: "" }) -// return -// } -// -// name = sanitize(name) -// -// $.get(this.action + name, this.ready.bind(this)) + return + } + + name = sanitize(name) + + $.get(this.action + name, this.ready.bind(this)) }, ready: function(data){ diff --git a/server/index.js b/server/index.js index 0028888..078db8e 100644 --- a/server/index.js +++ b/server/index.js @@ -127,6 +127,9 @@ site.route = function () { app.get('/layout', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.modal) app.get('/layout/:name', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.builder) + app.get('/blueprint', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.blueprint) + app.get('/blueprint/:name', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.blueprint) + app.get('/join/:nonce', middleware.ensureAuthenticated, api.collaborator.join) app.get('/api/collaborator/:slug/index', middleware.ensureAuthenticated, middleware.ensureProject, api.collaborator.index) app.post('/api/collaborator/:slug/create', middleware.ensureAuthenticated, middleware.ensureProject, api.collaborator.create) diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 5241ddb..523f628 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -84,6 +84,10 @@ var views = module.exports = { res.render('builder') }, + blueprint: function (req, res) { + res.render('blueprint') + }, + modal: function (req, res) { res.render('modal'); }, diff --git a/views/blueprint.ejs b/views/blueprint.ejs index 371d66f..7e13318 100644 --- a/views/blueprint.ejs +++ b/views/blueprint.ejs @@ -16,6 +16,7 @@ [[ include controls/builder/toolbar ]] [[ include controls/builder/settings ]] [[ include controls/blueprint/editor ]] + [[ include controls/blueprint/scaler ]]
    diff --git a/views/controls/blueprint/editor.ejs b/views/controls/blueprint/editor.ejs index e18f501..5334f85 100644 --- a/views/controls/blueprint/editor.ejs +++ b/views/controls/blueprint/editor.ejs @@ -1,8 +1,4 @@