Unverified Commit ebac854d authored by mntmn's avatar mntmn Committed by GitHub
Browse files

Port Backend to SQLite/Sequelize (removes MongoDB), Support Electron (#14)

* The MongoDB/Mongoose data storage is removed in favor of Sequelize. This abstracts over SQLite or RDBMs like PostgreSQL and MSSQL. The default is SQLite, which significantly simplifies deployments in end-user environments.

* As Spacedeck now has no more mandatory server dependencies, we can wrap it in Electron and ship it as a desktop application.

* Removes docker-compose.yml

* First version of import UI
parent 8e0bc69a
Showing with 713 additions and 1096 deletions
+713 -1096
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports.artifactSchema = Schema({
mime: String,
thumbnail_uri: String,
space_id: Schema.Types.ObjectId,
user_id: {type: Schema.Types.ObjectId, ref: 'User' },
last_update_user_id: {type: Schema.Types.ObjectId, ref: 'User' },
editor_name: String,
last_update_editor_name: String,
description: String,
state: {type: String, default: "idle"},
meta: {
linked_to: [String],
title: String,
tags: [String],
search_text: String,
link_uri: String,
play_from: Number,
play_to: Number,
},
board: {
x: {type: Number, default: 0.0},
y: {type: Number, default: 0.0},
z: {type: Number, default: 0.0},
r: {type: Number, default: 0.0},
w: {type: Number, default: 100},
h: {type: Number, default: 100},
},
control_points: [{
dx: Number, dy: Number
}],
group:{type: String, default: ""},
locked: {type: Boolean, default: false},
payload_uri: String,
payload_thumbnail_web_uri: String,
payload_thumbnail_medium_uri: String,
payload_thumbnail_big_uri: String,
payload_size: Number, // file size in bytes
style: {
fill_color: {type: String, default: "transparent"},
stroke_color:{type: String, default: "#000000"},
text_color: String,
stroke: {type: Number, default: 0.0},
stroke_style: {type: String, default: "solid"},
alpha: {type: Number, default: 1.0},
order: {type: Number, default: 0},
crop: {
x: Number,
y: Number,
w: Number,
h: Number
},
shape: String,
shape_svg: String,
padding_left: Number,
padding_right: Number,
padding_top: Number,
padding_bottom: Number,
margin_left: Number,
margin_right: Number,
margin_top: Number,
margin_bottom: Number,
border_radius: Number,
align: {type: String, default: "left"},
valign: {type: String, default: "top"},
brightness: Number,
contrast: Number,
saturation: Number,
blur: Number,
hue: Number,
opacity: Number
},
payload_alternatives: [{
mime: String,
payload_uri: String,
payload_thumbnail_web_uri: String,
payload_thumbnail_medium_uri: String,
payload_thumbnail_big_uri: String,
payload_size: Number
}],
created_at: {type: Date, default: Date.now},
created_from_ip: {type: String},
updated_at: {type: Date, default: Date.now}
});
//'use strict';
//var mongoose = require('mongoose');
//const sqlite3 = require('sqlite3').verbose();
function sequel_log(a,b,c) {
console.log(a);
}
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'sqlite',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
// SQLite only
storage: 'database.sqlite',
logging: sequel_log,
// http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
operatorsAliases: false
});
var User;
var Session;
var Space;
var Membership;
var Artifact;
var Message;
var Action;
module.exports = {
User: sequelize.define('user', {
_id: {type: Sequelize.STRING, primaryKey: true},
email: Sequelize.STRING,
password_hash: Sequelize.STRING,
nickname: Sequelize.STRING,
avatar_original_uri: Sequelize.STRING,
avatar_thumb_uri: Sequelize.STRING,
confirmation_token: Sequelize.STRING,
password_reset_token: Sequelize.STRING,
home_folder_id: Sequelize.STRING,
prefs_language: Sequelize.STRING,
prefs_email_notifications: Sequelize.STRING,
prefs_email_digest: Sequelize.STRING,
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
}),
Session: sequelize.define('session', {
token: {type: Sequelize.STRING, primaryKey: true},
user_id: Sequelize.STRING,
expires: Sequelize.DATE,
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
device: Sequelize.STRING,
ip: Sequelize.STRING
}),
Space: sequelize.define('space', {
_id: {type: Sequelize.STRING, primaryKey: true},
name: {type: Sequelize.STRING, default: "New Space"},
space_type: {type: Sequelize.STRING, defaultValue: "space"},
creator_id: Sequelize.STRING,
parent_space_id: Sequelize.STRING,
access_mode: {type: Sequelize.STRING, default: "private"}, // "public" || "private"
password: Sequelize.STRING,
edit_hash: Sequelize.STRING,
edit_slug: Sequelize.STRING,
editors_locking: Sequelize.BOOLEAN,
thumbnail_uri: Sequelize.STRING,
width: Sequelize.INTEGER,
height: Sequelize.INTEGER,
background_color: Sequelize.STRING,
background_uri: Sequelize.STRING,
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
thumbnail_url: Sequelize.STRING,
thumbnail_updated_at: {type: Sequelize.DATE}
}),
Membership: sequelize.define('membership', {
_id: {type: Sequelize.STRING, primaryKey: true},
space_id: Sequelize.STRING,
user_id: Sequelize.STRING,
role: Sequelize.STRING,
code: Sequelize.STRING,
state: {type: Sequelize.STRING, defaultValue: "pending"},
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
}),
Message: sequelize.define('message', {
_id: {type: Sequelize.STRING, primaryKey: true},
space_id: Sequelize.STRING,
user_id: Sequelize.STRING,
editor_name: Sequelize.STRING,
message: Sequelize.TEXT,
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
}),
Artifact: sequelize.define('artifact', {
_id: {type: Sequelize.STRING, primaryKey: true},
space_id: Sequelize.STRING,
user_id: Sequelize.STRING,
mime: Sequelize.STRING,
thumbnail_uri: Sequelize.STRING,
last_update_user_id: Sequelize.STRING,
editor_name: Sequelize.STRING,
last_update_editor_name: Sequelize.STRING,
description: Sequelize.TEXT,
state: {type: Sequelize.STRING, default: "idle"},
//linked_to: Sequelize.STRING,
title: Sequelize.STRING,
tags: Sequelize.TEXT,
search_text: Sequelize.STRING,
link_uri: Sequelize.STRING,
play_from: Sequelize.DECIMAL,
play_to: Sequelize.DECIMAL,
x: {type: Sequelize.DECIMAL, default: 0.0},
y: {type: Sequelize.DECIMAL, default: 0.0},
z: {type: Sequelize.DECIMAL, default: 0.0},
r: {type: Sequelize.DECIMAL, default: 0.0},
w: {type: Sequelize.DECIMAL, default: 100},
h: {type: Sequelize.DECIMAL, default: 100},
//control_points: [{
// dx: Number, dy: Number
//}],
control_points: Sequelize.TEXT,
group: Sequelize.STRING,
locked: {type: Sequelize.BOOLEAN, default: false},
payload_uri: Sequelize.STRING,
payload_thumbnail_web_uri: Sequelize.STRING,
payload_thumbnail_medium_uri: Sequelize.STRING,
payload_thumbnail_big_uri: Sequelize.STRING,
payload_size: Sequelize.INTEGER, // file size in bytes
fill_color: {type: Sequelize.STRING, default: "transparent"},
stroke_color: {type: Sequelize.STRING, default: "#000000"},
text_color: Sequelize.STRING,
stroke: {type: Sequelize.DECIMAL, default: 0.0},
stroke_style: {type: Sequelize.STRING, default: "solid"},
alpha: {type: Sequelize.DECIMAL, default: 1.0},
order: {type: Sequelize.INTEGER, default: 0},
crop_x: Sequelize.INTEGER,
crop_y: Sequelize.INTEGER,
crop_w: Sequelize.INTEGER,
crop_h: Sequelize.INTEGER,
shape: Sequelize.STRING,
shape_svg: Sequelize.STRING,
padding_left: Sequelize.INTEGER,
padding_right: Sequelize.INTEGER,
padding_top: Sequelize.INTEGER,
padding_bottom: Sequelize.INTEGER,
margin_left: Sequelize.INTEGER,
margin_right: Sequelize.INTEGER,
margin_top: Sequelize.INTEGER,
margin_bottom: Sequelize.INTEGER,
border_radius: Sequelize.INTEGER,
align: {type: Sequelize.STRING, default: "left"},
valign: {type: Sequelize.STRING, default: "top"},
brightness: Sequelize.DECIMAL,
contrast: Sequelize.DECIMAL,
saturation: Sequelize.DECIMAL,
blur: Sequelize.DECIMAL,
hue: Sequelize.DECIMAL,
opacity: Sequelize.DECIMAL,
payload_alternatives: Sequelize.TEXT,
/*payload_alternatives: [{
mime: String,
payload_uri: String,
payload_thumbnail_web_uri: String,
payload_thumbnail_medium_uri: String,
payload_thumbnail_big_uri: String,
payload_size: Number
}],*/
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
}),
init: function() {
User = this.User;
Session = this.Session;
Space = this.Space;
Artifact = this.Artifact;
Message = this.Message;
Membership = this.Membership;
Space.belongsTo(User, {
foreignKey: {
name: 'creator_id'
},
as: 'creator'
});
Membership.belongsTo(User, {
foreignKey: {
name: 'user_id'
},
as: 'user'
});
Membership.belongsTo(Space, {
foreignKey: {
name: 'space_id'
},
as: 'space'
});
Artifact.belongsTo(User, {
foreignKey: {
name: 'user_id'
},
as: 'user'
});
Artifact.belongsTo(Space, {
foreignKey: {
name: 'space_id'
},
as: 'space'
});
Message.belongsTo(User, {
foreignKey: {
name: 'user_id'
},
as: 'user'
});
Message.belongsTo(Space, {
foreignKey: {
name: 'space_id'
},
as: 'space'
});
sequelize.sync();
},
getUserRoleInSpace: (originalSpace, user, cb) => {
originalSpace.path = [];
console.log("getUserRoleInSpace",originalSpace._id,user._id,user.home_folder_id);
if (originalSpace._id == user.home_folder_id || (originalSpace.creator_id && originalSpace.creator_id == user._id)) {
cb("admin");
} else {
var findMembershipsForSpace = function(space, allMemberships, prevRole) {
Membership.findAll({ where: {
"space": space._id
}}).then(function(parentMemberships) {
var currentMemberships = parentMemberships.concat(allMemberships);
if (space.parent_space_id) {
Space.findOne({ where: {
"_id": space.parent_space_id
}}, function(err, parentSpace) {
findMembershipsForSpace(parentSpace, currentMemberships, prevRole);
});
} else {
// reached the top
var role = prevRole;
space.memberships = currentMemberships;
if (role == "none") {
if (originalSpace.access_mode == "public") {
role = "viewer";
}
}
currentMemberships.forEach(function(m, i) {
if (m.user_id && m.user_id == user._id) {
role = m.role;
}
});
cb(role);
}
});
};
findMembershipsForSpace(originalSpace, [], "none");
}
},
spaceToObject: (space) => {
// FIXME TODO
return space;
},
findUserBySessionToken: (token, cb) => {
Session.findOne({where: {token: token}})
.then(session => {
if (!session) cb(null, null)
else User.findOne({where: {_id: session.user_id}})
.then(user => {
cb(null, user)
})
})
},
unpackArtifact: (a) => {
if (a.tags) {
a.tags = JSON.parse(a.tags);
}
if (a.control_points) {
a.control_points = JSON.parse(a.control_points);
}
if (a.payload_alternatives) {
a.payload_alternatives = JSON.parse(a.payload_alternatives);
}
return a;
},
packArtifact: (a) => {
if (a.tags) {
a.tags = JSON.stringify(a.tags);
}
if (a.control_points) {
a.control_points = JSON.stringify(a.control_points);
}
if (a.payload_alternatives) {
a.payload_alternatives = JSON.stringify(a.payload_alternatives);
}
return a;
}
}
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports.domainSchema = mongoose.Schema({
domain: String,
edu: Boolean,
created_at: {
type: Date,
default: Date.now
},
updated_at: {
type: Date,
default: Date.now
}
});
module.exports.domainSchema.index({
domain: 1
});
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports.membershipSchema = mongoose.Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
space: {
type: Schema.Types.ObjectId,
ref: 'Space'
},
team: {
type: Schema.Types.ObjectId,
ref: 'Team'
},
role: {
type: String,
default: "viewer"
},
state: {
type: String,
default: "active"
},
email_invited: String,
code: String,
created_at: {
type: Date,
default: Date.now
},
updated_at: {
type: Date,
default: Date.now
}
});
module.exports.membershipSchema.index({
user: 1,
space: 1,
team: 1,
code: 1
});
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports.messageSchema = mongoose.Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
editor_name: String,
space: {
type: Schema.Types.ObjectId,
ref: 'Space'
},
message: String,
created_from_ip: {type: String},
created_at: {
type: Date,
default: Date.now
},
updated_at: {
type: Date,
default: Date.now
}
});
module.exports.messageSchema.index({
space: 1,
user: 1
});
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
Plan = mongoose.model('Plan', {
key: String,
description: String,
limit_folders: {
type: Number,
default: 200
},
limit_spaces: {
type: Number,
default: 500
},
limit_storage_bytes: {
type: Number,
default: 10737418240
},
plan_type: {
type: String,
default: "org"
},
price: Number,
public: Boolean,
recurring: {
type: String,
default: "month"
},
title: String,
trial_days: Number,
voucher_code: String,
created_at: {
type: Date,
default: Date.now
},
updated_at: {
type: Date,
default: Date.now
}
});
exports.planModel = Plan;
\ No newline at end of file
//'use strict';
var mongoose = require('mongoose');
User = mongoose.model('User', require('./user').userSchema);
Action = mongoose.model('Action', require('./action').actionSchema);
Space = mongoose.model('Space', require('./space').spaceSchema);
Artifact = mongoose.model('Artifact', require('./artifact').artifactSchema);
Team = mongoose.model('Team', require('./team').teamSchema);
Message = mongoose.model('Message', require('./message').messageSchema);
Membership = mongoose.model('Membership', require('./membership').membershipSchema);
Domain = mongoose.model('Domain', require('./domain').domainSchema);
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var async = require('async');
var _ = require("underscore");
var crypto = require('crypto');
module.exports.spaceSchema = Schema({
name: {type: String, default: "New Space"},
space_type: {type: String, default: "space"},
creator : { type: Schema.Types.ObjectId, ref: 'User' },
parent_space_id: Schema.Types.ObjectId,
access_mode: {type: String, default: "private"}, // "public" || "private"
password: String,
edit_hash: String,
edit_slug: String,
editors_locking: Boolean,
thumbnail_uri: String,
stats: {
num_children: Number,
total_spaces: Number,
total_folders: Number,
storage_bytes: Number,
},
advanced: {
type: {
width: Number,
height: Number,
margin: Number,
background_color: String,
background_uri: String,
background_repeat: Boolean,
grid_size: Number,
grid_divisions: Number,
gutter: Number,
columns: Number,
column_max_width: Number,
columns_responsive: Number,
row_max_height: Number,
padding_horz: Number,
padding_vert: Number
},
default: {
width: 200,
height: 400,
margin: 0,
background_color: "rgba(255,255,255,1)"
}
},
blocked_at: {type: Date, default: Date.now},
created_at: {type: Date, default: Date.now},
updated_at: {type: Date, default: Date.now},
thumbnail_updated_at: {type: Date},
thumbnail_url: String
});
module.exports.spaceSchema.index({ creator: 1, parent_space_id: 1, created_at: 1, updated_at: 1, edit_hash: 1});
module.exports.spaceSchema.statics.allForUser = function (user, callback) {
return this.find({user_id: user_id}, callback);
};
module.exports.spaceSchema.statics.getMemberships = function (err, callback) {
callback(null, {});
};
var getRecursiveSubspacesForSpace = (parentSpace, cb) => {
if (parentSpace.space_type == "folder") {
Space.find({
"parent_space_id": parentSpace._id
}).exec((err, subspaces) => {
async.map(subspaces, (space, innerCb) => {
getRecursiveSubspacesForSpace(space, (err, spaces) => {
innerCb(err, spaces);
});
}, (err, subspaces) => {
var flattenSubspaces = _.flatten(subspaces);
flattenSubspaces.push(parentSpace);
cb(null, flattenSubspaces);
});
});
} else {
cb(null, [parentSpace]);
}
};
module.exports.spaceSchema.statics.getRecursiveSubspacesForSpace = getRecursiveSubspacesForSpace;
var roleMapping = {
"none": 0,
"viewer": 1,
"editor": 2,
"admin": 3
}
module.exports.spaceSchema.statics.roleInSpace = (originalSpace, user, cb) => {
if (user.home_folder_id.toString() === originalSpace._id.toString()) {
cb(null, "admin");
return;
}
if (originalSpace.creator) {
if (originalSpace.creator._id.toString() === user._id.toString()) {
cb(null, "admin");
return;
}
}
var findMembershipsForSpace = function(space, allMemberships, prevRole) {
Membership.find({
"space": space._id
}, (err, parentMemberships) => {
var currentMemberships = parentMemberships.concat(allMemberships);
if (space.parent_space_id) {
Space.findOne({
"_id": space.parent_space_id
}, function(err, parentSpace) {
var role = prevRole;
if(role == "none"){
if(originalSpace.access_mode == "public") {
role = "viewer";
}
}
findMembershipsForSpace(parentSpace, currentMemberships, role);
});
} else {
// reached the top
var role = prevRole;
space.memberships = currentMemberships;
currentMemberships.forEach(function(m, i) {
if (m.user && m.user.equals(user._id)) {
if (m.role != null) {
if (roleMapping[m.role] > roleMapping[role]) {
role = m.role;
}
}
}
});
cb(err, role);
}
});
};
findMembershipsForSpace(originalSpace, [], "none");
}
module.exports.spaceSchema.statics.recursiveDelete = (space, cb) => {
space.remove(function(err) {
Action.remove({
space: space
}, function(err) {
if (err)
console.error("removed actions for space: ", err);
});
Membership.remove({
space: space
}, function(err) {
if (err)
console.error("removed memberships for space: ", err);
});
if (space.space_type === "folder") {
Space
.find({
parent_space_id: space._id
})
.exec(function(err, spaces) {
async.eachLimit(spaces, 10, function(subSpace, innerCb) {
module.exports.spaceSchema.statics.recursiveDelete(subSpace, function(err) {
innerCb(err);
});
}, function(err) {
cb(err);
});
});
} else {
Artifact.find({
space_id: space._id
}, function(err, artifacts) {
if (err) cb(err);
else {
async.eachLimit(artifacts, 20, function(a, innerCb) {
a.remove(function(err) {
innerCb(null, a);
});
}, function(err) {
cb(err);
});
}
});
}
});
};
var duplicateRecursiveSpace = (space, user, depth, cb, newParentSpace) => {
var newSpace = new Space(space);
newSpace._id = mongoose.Types.ObjectId();
if (newParentSpace) {
newSpace.parent_space_id = newParentSpace._id;
} else {
newSpace.name = newSpace.name + " (b)";
}
newSpace.creator = user;
newSpace.created_at = new Date();
newSpace.updated_at = new Date();
if (newSpace.space_type === "space") {
newSpace.edit_hash = crypto.randomBytes(64).toString('hex').substring(0, 7);
}
newSpace.save(function(err) {
if (newSpace.space_type === "folder" && depth < 10) {
Space
.find({
parent_space_id: space._id
})
.exec(function(err, spaces) {
async.eachLimit(spaces, 10, function(subSpace, innerCb) {
duplicateRecursiveSpace(subSpace, user, ++depth, function(err, newSubSpace) {
innerCb(err, newSubSpace);
}, newSpace);
}, function(err, allNewSubspaces) {
cb(err, newSpace);
});
});
} else {
Artifact.find({
space_id: space._id
}, function(err, artifacts) {
if (err) innerCb(err);
else {
async.eachLimit(artifacts, 20, function(a, innerCb) {
var newArtifact = new Artifact(a);
newArtifact._id = mongoose.Types.ObjectId();
newArtifact.space_id = newSpace._id;
newArtifact.created_at = new Date();
newArtifact.updated_at = new Date();
newArtifact.save(function(err) {
innerCb(null, newArtifact);
});
}, function(err, allNewArtifacts) {
cb(err, newSpace);
});
}
});
}
});
};
module.exports.spaceSchema.statics.duplicateSpace = duplicateRecursiveSpace;
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports.teamSchema = mongoose.Schema({
name: String,
subdomain: String,
creator: {
type: Schema.Types.ObjectId,
ref: 'User'
},
admins: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
invitation_codes: [String],
avatar_thumb_uri: String,
avatar_uri: String,
payment_type: {
type: String,
default: "auto"
},
payment_plan_key: String,
payment_subscription_id: String,
blocked_at: {
type: Date
},
upgraded_at: {
type: Date
},
created_at: {
type: Date,
default: Date.now
},
updated_at: {
type: Date,
default: Date.now
}
});
module.exports.teamSchema.index({
creator: 1
});
module.exports.teamSchema.statics.getTeamForHost = (host, cb) => {
if (host != "127.0.0.1:9666") { //phantomjs check
let subDomainParts = host.split('.');
if (subDomainParts.length > 2) {
const subdomain = subDomainParts[0];
if (subdomain != "www") {
Team.findOne({
subdomain: subdomain
}).exec((err, team) => {
cb(err, team, subdomain)
});
} else {
cb(null, null)
}
} else {
cb(null, null);
}
} else {
cb(null, null);
}
}
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports.userSchema = mongoose.Schema({
email: String,
password_hash: String,
nickname: String,
account_type: {type: String, default: "email"},
created_at: {type: Date, default: Date.now},
updated_at: {type: Date, default: Date.now},
avatar_original_uri: String,
avatar_thumb_uri: String,
src: String,
confirmation_token: String,
confirmed_at: Date,
password_reset_token: String,
home_folder_id: Schema.Types.ObjectId,
team : { type: Schema.Types.ObjectId, ref: 'Team' },
preferences: {
language: String,
email_notifications: {type: Boolean, default: true},
daily_digest_last_send: Date,
daily_digest: {type: Boolean, default: true}
},
sessions: [
{
token: String,
expires: Date,
device: String,
ip: String,
created_at: Date
}
],
payment_info: String,
payment_plan_key: {type: String, default: "free"},
payment_customer_id: String,
payment_subscription_id: String,
payment_notification_state: Number
});
module.exports.userSchema.index({
email: 1,
"sessions.token": 1,
team: 1,
created_at: 1,
home_folder_id: 1
});
module.exports.userSchema.statics.findBySessionToken = function (token, cb) {
return this.findOne({ "sessions.token": token}, cb);
};
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "nodemon -e .js,.html bin/www", "start": "electron ."
"test": "mocha"
}, },
"engines": { "engines": {
"node": ">=7.8.0" "node": ">=7.8.0"
...@@ -12,76 +11,42 @@ ...@@ -12,76 +11,42 @@
"dependencies": { "dependencies": {
"archiver": "1.3.0", "archiver": "1.3.0",
"async": "2.3.0", "async": "2.3.0",
"aws-sdk": "2.39.0",
"basic-auth": "1.1.0", "basic-auth": "1.1.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "~1.17.1", "body-parser": "~1.17.1",
"cheerio": "0.22.0", "cheerio": "0.22.0",
"config": "1.25.1", "config": "1.25.1",
"cookie-parser": "~1.4.3", "cookie-parser": "~1.4.3",
"csurf": "1.9.0", "electron": "^1.8.4",
"debug": "~2.6.3",
"execSync": "latest", "execSync": "latest",
"express": "~4.13.0", "express": "~4.13.0",
"extract-zip": "^1.6.6", "file-type": "^7.6.0",
"glob": "7.1.1", "glob": "7.1.1",
"gm": "1.23.0", "gm": "1.23.0",
"googleapis": "18.0.0",
"gulp": "^3.9.1",
"gulp-concat": "2.6.0",
"gulp-express": "0.3.0",
"gulp-nodemon": "*",
"gulp-sass": "^2.0.3",
"gulp-uglify": "^1.5.1",
"gulp-util": "^3.0.6",
"helmet": "^3.5.0", "helmet": "^3.5.0",
"i18n-2": "0.6.3", "i18n-2": "0.6.3",
"ioredis": "2.5.0",
"lodash": "^4.3.0",
"log-timestamp": "latest", "log-timestamp": "latest",
"md5": "2.2.1", "morgan": "1.8.1",
"mock-aws-s3": "^2.6.0", "mock-aws-s3": "^2.6.0",
"moment": "^2.19.3", "moment": "^2.19.3",
"mongoose": "4.9.3",
"morgan": "1.8.1",
"node-phantom-simple": "2.2.4", "node-phantom-simple": "2.2.4",
"node-sass-middleware": "0.11.0",
"pdfkit": "0.8.0",
"phantomjs-prebuilt": "2.1.14", "phantomjs-prebuilt": "2.1.14",
"pm2": "latest", "read-chunk": "^2.1.0",
"qr-image": "3.2.0",
"raven": "1.2.0",
"request": "2.81.0", "request": "2.81.0",
"sanitize-html": "^1.11.1", "sanitize-html": "^1.11.1",
"sequelize": "^4.37.6",
"serve-favicon": "~2.4.2", "serve-favicon": "~2.4.2",
"serve-static": "^1.13.1", "serve-static": "^1.13.1",
"slug": "0.9.1", "slug": "0.9.1",
"sqlite3": "^4.0.0",
"swig": "1.4.2", "swig": "1.4.2",
"underscore": "1.8.3", "underscore": "1.8.3",
"uuid": "^3.2.1",
"validator": "7.0.0", "validator": "7.0.0",
"weak": "1.0.1",
"ws": "2.2.3" "ws": "2.2.3"
}, },
"devDependencies": { "main": "app.js",
"express": "^4.13.3",
"gulp": "^3.9.1",
"gulp-clean": "^0.3.2",
"gulp-concat": "^2.6.0",
"gulp-express": "^0.3.0",
"gulp-fingerprint": "^0.3.2",
"gulp-nodemon": "^2.0.4",
"gulp-rev": "^7.1.2",
"gulp-rev-all": "^0.9.7",
"gulp-rev-replace": "^0.4.3",
"gulp-sass": "^3.1.0",
"gulp-uglify": "^2.1.2",
"nodemon": "1.11.0",
"should": "^11.2.1",
"supertest": "^3.0.0",
"winston": "^2.3.1"
},
"description": "", "description": "",
"main": "Gulpfile.js",
"directories": {}, "directories": {},
"repository": { "repository": {
"type": "git", "type": "git",
......
...@@ -133,7 +133,15 @@ function load_spaces(id, is_home, on_success, on_error) { ...@@ -133,7 +133,15 @@ function load_spaces(id, is_home, on_success, on_error) {
}, on_error); }, on_error);
} }
function load_writable_folders( on_success, on_error) { function load_importables(user, on_success, on_error) {
load_resource("get", "/users/"+user._id+"/importables", null, on_success, on_error);
}
function import_zip(user, filename, on_success, on_error) {
load_resource("get", "/users/"+user._id+"/import?zip="+filename, null, on_success, on_error);
}
function load_writable_folders(on_success, on_error) {
load_resource("get", "/spaces?writablefolders=true", null, on_success, on_error); load_resource("get", "/spaces?writablefolders=true", null, on_success, on_error);
} }
......
...@@ -8,24 +8,29 @@ SpacedeckAccount = { ...@@ -8,24 +8,29 @@ SpacedeckAccount = {
account_confirmed_sent: false, account_confirmed_sent: false,
account_tab: 'invoices', account_tab: 'invoices',
password_change_error: null, password_change_error: null,
feedback_text: "" feedback_text: "",
importables: [], // spacedeck.com zip import files
}, },
methods: { methods: {
show_account: function(user) { show_account: function() {
this.activate_dropdown('account'); this.activate_dropdown('account');
this.load_subscription(); },
this.load_billing();
start_zip_import: function(f) {
if (confirm("Your archive will be imported in the background. This can take a few minutes. You can continue using Spacedeck in the meantime.")) {
import_zip(this.user, f);
}
}, },
account_save_user_digest: function(val) { account_save_user_digest: function(val) {
this.user.preferences.daily_digest = val; this.user.prefs_email_digest = val;
this.save_user(function(){ this.save_user(function() {
}); });
}, },
account_save_user_notifications: function(val) { account_save_user_notifications: function(val) {
this.user.preferences.email_notifications = val; this.user.prefs_email_notifications = val;
this.save_user(function(){ this.save_user(function() {
}); });
}, },
...@@ -36,13 +41,11 @@ SpacedeckAccount = { ...@@ -36,13 +41,11 @@ SpacedeckAccount = {
save_user_language: function(lang) { save_user_language: function(lang) {
localStorage.lang = lang; localStorage.lang = lang;
if (this.user.preferences) { this.user.prefs_language = lang;
this.user.preferences.language = lang; this.save_user(function() {
this.save_user(function() { window._spacedeck_location_change = true;
window._spacedeck_location_change = true; location.href="/spaces";
location.href="/spaces"; }.bind(this));
}.bind(this));
}
}, },
save_user: function(on_success) { save_user: function(on_success) {
......
This diff is collapsed.
...@@ -170,7 +170,6 @@ var SpacedeckRoutes = { ...@@ -170,7 +170,6 @@ var SpacedeckRoutes = {
location.href = "/"; location.href = "/";
} else { } else {
this.active_view = "account"; this.active_view = "account";
this.load_subscription();
} }
}.bind(this) }.bind(this)
} }
......
...@@ -369,8 +369,8 @@ var SpacedeckSections = { ...@@ -369,8 +369,8 @@ var SpacedeckSections = {
// canvas // canvas
this.$watch('active_style.background_color', function (value, mutation) { this.$watch('active_style.background_color', function (value, mutation) {
if (this.active_style.background_color != this.active_space.advanced.background_color) { if (this.active_style.background_color != this.active_space.background_color) {
this.$set("active_space.advanced.background_color",this.active_style.background_color); this.$set("active_space.background_color",this.active_style.background_color);
this.throttled_save_active_space(); this.throttled_save_active_space();
} }
...@@ -448,7 +448,7 @@ var SpacedeckSections = { ...@@ -448,7 +448,7 @@ var SpacedeckSections = {
for (var i=0; i<props.length; i++) { for (var i=0; i<props.length; i++) {
var prop = props[i]; var prop = props[i];
this.active_style[prop]=a.style[prop]; this.active_style[prop]=a[prop];
} }
// defaults // defaults
...@@ -457,10 +457,10 @@ var SpacedeckSections = { ...@@ -457,10 +457,10 @@ var SpacedeckSections = {
this.active_style.line_height = this.default_style.line_height; this.active_style.line_height = this.default_style.line_height;
this.active_style.letter_spacing = this.default_style.letter_spacing; this.active_style.letter_spacing = this.default_style.letter_spacing;
this.active_style.padding_top = a.style.padding_top || 0; this.active_style.padding_top = a.padding_top || 0;
this.active_style.padding_bottom = a.style.padding_bottom || 0; this.active_style.padding_bottom = a.padding_bottom || 0;
this.active_style.padding_left = a.style.padding_left || 0; this.active_style.padding_left = a.padding_left || 0;
this.active_style.padding_right = a.style.padding_right || 0; this.active_style.padding_right = a.padding_right || 0;
if (this.active_style.padding_top == this.active_style.padding_bottom) { if (this.active_style.padding_top == this.active_style.padding_bottom) {
this.active_style.padding_vert = this.active_style.padding_top; this.active_style.padding_vert = this.active_style.padding_top;
...@@ -476,10 +476,10 @@ var SpacedeckSections = { ...@@ -476,10 +476,10 @@ var SpacedeckSections = {
this.active_style.padding = this.active_style.padding_top; this.active_style.padding = this.active_style.padding_top;
} }
this.active_style.margin_top = a.style.margin_top || 0; this.active_style.margin_top = a.margin_top || 0;
this.active_style.margin_bottom = a.style.margin_bottom || 0; this.active_style.margin_bottom = a.margin_bottom || 0;
this.active_style.margin_left = a.style.margin_left || 0; this.active_style.margin_left = a.margin_left || 0;
this.active_style.margin_right = a.style.margin_right || 0; this.active_style.margin_right = a.margin_right || 0;
if (this.active_style.margin_top == this.active_style.margin_bottom) { if (this.active_style.margin_top == this.active_style.margin_bottom) {
this.active_style.margin_vert = this.active_style.margin_top; this.active_style.margin_vert = this.active_style.margin_top;
...@@ -758,8 +758,8 @@ var SpacedeckSections = { ...@@ -758,8 +758,8 @@ var SpacedeckSections = {
}, },
resize_minimap: function() { resize_minimap: function() {
if (!this.active_space || !this.active_space.advanced) return; if (!this.active_space) return;
this.minimap_scale = this.active_space.advanced.width/100.0; this.minimap_scale = this.active_space.width/100.0;
}, },
handle_minimap_mouseup: function(evt) { handle_minimap_mouseup: function(evt) {
...@@ -921,7 +921,7 @@ var SpacedeckSections = { ...@@ -921,7 +921,7 @@ var SpacedeckSections = {
discover_zones: function() { discover_zones: function() {
this.zones = _.sortBy(_.filter(this.active_space_artifacts, function(a) { return (a.mime=="x-spacedeck/zone") }), this.zones = _.sortBy(_.filter(this.active_space_artifacts, function(a) { return (a.mime=="x-spacedeck/zone") }),
function(z){return z.style.order}); function(z){return z.order});
}, },
artifact_plaintext: function(a) { artifact_plaintext: function(a) {
...@@ -1015,10 +1015,10 @@ var SpacedeckSections = { ...@@ -1015,10 +1015,10 @@ var SpacedeckSections = {
arts = _.filter(arts); // remove any nulls arts = _.filter(arts); // remove any nulls
return { return {
x1: parseInt(_.min(arts.map(function(a){return ((!a.board || !a.board.x)?0:a.board.x)}))), x1: parseInt(_.min(arts.map(function(a){return ((!a || !a.x)?0:a.x)}))),
y1: parseInt(_.min(arts.map(function(a){return ((!a.board || !a.board.y)?0:a.board.y)}))), y1: parseInt(_.min(arts.map(function(a){return ((!a || !a.y)?0:a.y)}))),
x2: parseInt(_.max(arts.map(function(a){return (!a.board?0:a.board.x+a.board.w)}))), x2: parseInt(_.max(arts.map(function(a){return (!a?0:a.x+a.w)}))),
y2: parseInt(_.max(arts.map(function(a){return (!a.board?0:a.board.y+a.board.h)}))) y2: parseInt(_.max(arts.map(function(a){return (!a?0:a.y+a.h)})))
}; };
}, },
...@@ -1076,7 +1076,7 @@ var SpacedeckSections = { ...@@ -1076,7 +1076,7 @@ var SpacedeckSections = {
this.selection_metrics.count=arts.length; this.selection_metrics.count=arts.length;
this.selection_metrics.scribble_selection = false; this.selection_metrics.scribble_selection = false;
if (arts.length == 1 && arts[0].mime == "x-spacedeck/vector") { if (arts.length == 1 && arts[0].mime == "x-spacedeck/vector") {
if (arts[0].style.shape == "scribble") { if (arts[0].shape == "scribble") {
this.selection_metrics.scribble_selection = true; this.selection_metrics.scribble_selection = true;
} }
this.selection_metrics.vector_points = arts[0].control_points; this.selection_metrics.vector_points = arts[0].control_points;
...@@ -1112,8 +1112,8 @@ var SpacedeckSections = { ...@@ -1112,8 +1112,8 @@ var SpacedeckSections = {
fixup_space_size: function() { fixup_space_size: function() {
if (!this.active_space) return; if (!this.active_space) return;
this.active_space.advanced.width =Math.max(this.active_space.advanced.width, window.innerWidth); this.active_space.width =Math.max(this.active_space.width, window.innerWidth);
this.active_space.advanced.height=Math.max(this.active_space.advanced.height, window.innerHeight); this.active_space.height=Math.max(this.active_space.height, window.innerHeight);
}, },
end_transaction: function() { end_transaction: function() {
...@@ -1125,13 +1125,13 @@ var SpacedeckSections = { ...@@ -1125,13 +1125,13 @@ var SpacedeckSections = {
var er = this.enclosing_rect(this.active_space_artifacts); var er = this.enclosing_rect(this.active_space_artifacts);
if (!er) return; if (!er) return;
this.active_space.advanced.width =Math.max(er.x2+100, window.innerWidth); this.active_space.width =Math.max(er.x2+100, window.innerWidth);
this.active_space.advanced.height=Math.max(er.y2+100, window.innerHeight); this.active_space.height=Math.max(er.y2+100, window.innerHeight);
if (this._last_bounds_width != this.active_space.advanced.width || if (this._last_bounds_width != this.active_space.width ||
this._last_bounds_height != this.active_space.advanced.height) { this._last_bounds_height != this.active_space.height) {
this._last_bounds_width = this.active_space.advanced.width; this._last_bounds_width = this.active_space.width;
this._last_bounds_height = this.active_space.advanced.height; this._last_bounds_height = this.active_space.height;
save_space(this.active_space); save_space(this.active_space);
} }
...@@ -1214,7 +1214,7 @@ var SpacedeckSections = { ...@@ -1214,7 +1214,7 @@ var SpacedeckSections = {
// this is a bit hacky, but might be the smartest place to do it // this is a bit hacky, but might be the smartest place to do it
if (a.view && a.view.vector_svg) { if (a.view && a.view.vector_svg) {
a.style.shape_svg = a.view.vector_svg; a.shape_svg = a.view.vector_svg;
} }
window.artifact_save_queue[a._id] = a; window.artifact_save_queue[a._id] = a;
...@@ -1329,7 +1329,7 @@ var SpacedeckSections = { ...@@ -1329,7 +1329,7 @@ var SpacedeckSections = {
this.update_selected_artifacts(function(a) { this.update_selected_artifacts(function(a) {
var c = {}; var c = {};
if (c[prop] != val) { if (a[prop] != val) {
//console.log("set_artifact_prop: ",c,val); //console.log("set_artifact_prop: ",c,val);
c[prop]=val; c[prop]=val;
return c; return c;
...@@ -1343,11 +1343,11 @@ var SpacedeckSections = { ...@@ -1343,11 +1343,11 @@ var SpacedeckSections = {
this.begin_transaction(); this.begin_transaction();
this.update_selected_artifacts(function(a) { this.update_selected_artifacts(function(a) {
var c = {style: a.style||{}}; var c = {};
if (c.style[prop] != val) { if (a[prop] != val) {
//console.log("set_artifact_style_prop: ",c,val); //console.log("set_artifact_style_prop: ",c,val);
c.style[prop]=val; c[prop]=val;
return c; return c;
} }
...@@ -1419,7 +1419,7 @@ var SpacedeckSections = { ...@@ -1419,7 +1419,7 @@ var SpacedeckSections = {
if (this.selected_artifacts().length!=1 && this.opened_dialog!="background") return; if (this.selected_artifacts().length!=1 && this.opened_dialog!="background") return;
if (this.opened_dialog=="background") { if (this.opened_dialog=="background") {
this.active_style[this.color_picker_target] = this.active_space.advanced.background_color; this.active_style[this.color_picker_target] = this.active_space.background_color;
} else { } else {
if (!this.active_style[this.color_picker_target]) { if (!this.active_style[this.color_picker_target]) {
this.active_style[this.color_picker_target] = this.default_style[this.color_picker_target]; this.active_style[this.color_picker_target] = this.default_style[this.color_picker_target];
...@@ -1478,10 +1478,8 @@ var SpacedeckSections = { ...@@ -1478,10 +1478,8 @@ var SpacedeckSections = {
this.update_selected_artifacts(function(a) { this.update_selected_artifacts(function(a) {
return { return {
board: _.extend(a.board, { x: a.x+dx,
x: a.board.x+dx, y: a.y+dy
y: a.board.y+dy
})
}; };
}); });
}, },
...@@ -1489,7 +1487,7 @@ var SpacedeckSections = { ...@@ -1489,7 +1487,7 @@ var SpacedeckSections = {
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
highest_z: function() { highest_z: function() {
var z = _.max(this.active_space_artifacts.map(function(a){return a.board.z||0})); var z = _.max(this.active_space_artifacts.map(function(a){return a.z||0}));
if (z<0) z=0; if (z<0) z=0;
if (z>999) z=999; if (z>999) z=999;
return z; return z;
...@@ -1574,20 +1572,18 @@ var SpacedeckSections = { ...@@ -1574,20 +1572,18 @@ var SpacedeckSections = {
payload_thumbnail_web_uri: url || null, payload_thumbnail_web_uri: url || null,
space_id: space._id, space_id: space._id,
style: { order: this.active_space_artifacts.length+1,
order: this.active_space_artifacts.length+1, valign: "middle",
valign: "middle", align: "center"
align: "center" //fill_color: "#f8f8f8"
//fill_color: "#f8f8f8"
}
}; };
if (mimes[item_type] == "text/html") { if (mimes[item_type] == "text/html") {
new_item.style.padding_left = 10; new_item.padding_left = 10;
new_item.style.padding_top = 10; new_item.padding_top = 10;
new_item.style.padding_right = 10; new_item.padding_right = 10;
new_item.style.padding_bottom = 10; new_item.padding_bottom = 10;
new_item.style.fill_color = "rgba(255,255,255,1)"; new_item.fill_color = "rgba(255,255,255,1)";
new_item.description = "<p>Text</p>"; new_item.description = "<p>Text</p>";
} }
...@@ -1600,13 +1596,11 @@ var SpacedeckSections = { ...@@ -1600,13 +1596,11 @@ var SpacedeckSections = {
z = point.z; z = point.z;
} }
new_item.board = { new_item.x = parseInt(point.x);
x: parseInt(point.x), new_item.y = parseInt(point.y);
y: parseInt(point.y), new_item.z = z;
w: w, new_item.w = w;
h: h, new_item.h = h;
z: z
};
if (this.guest_nickname) { if (this.guest_nickname) {
new_item.editor_name = this.guest_nickname; new_item.editor_name = this.guest_nickname;
...@@ -1665,7 +1659,7 @@ var SpacedeckSections = { ...@@ -1665,7 +1659,7 @@ var SpacedeckSections = {
for (var i=0; i<new_zones.length; i++) { for (var i=0; i<new_zones.length; i++) {
if (new_zones[i]) { if (new_zones[i]) {
if (!new_zones[i].style) new_zones[i].style = {}; if (!new_zones[i].style) new_zones[i].style = {};
new_zones[i].style.order = i; new_zones[i].order = i;
save_artifact(new_zones[i]); save_artifact(new_zones[i]);
} }
} }
...@@ -1679,7 +1673,7 @@ var SpacedeckSections = { ...@@ -1679,7 +1673,7 @@ var SpacedeckSections = {
for (var i=0; i<new_zones.length; i++) { for (var i=0; i<new_zones.length; i++) {
if (new_zones[i]) { if (new_zones[i]) {
if (!new_zones[i].style) new_zones[i].style = {}; if (!new_zones[i].style) new_zones[i].style = {};
new_zones[i].style.order = i; new_zones[i].order = i;
save_artifact(new_zones[i]); save_artifact(new_zones[i]);
} }
} }
...@@ -1695,17 +1689,13 @@ var SpacedeckSections = { ...@@ -1695,17 +1689,13 @@ var SpacedeckSections = {
space_id: this.active_space._id, space_id: this.active_space._id,
mime: "x-spacedeck/zone", mime: "x-spacedeck/zone",
description: "Zone "+(this.zones.length+1), description: "Zone "+(this.zones.length+1),
board: { x: point.x,
x: point.x, y: point.y,
y: point.y, w: w,
w: w, h: h,
h: h, z: 0,
z: 0 valign: "middle",
}, align: "center"
style: {
valign: "middle",
align: "center"
}
}; };
if (this.guest_nickname) { if (this.guest_nickname) {
...@@ -1735,22 +1725,18 @@ var SpacedeckSections = { ...@@ -1735,22 +1725,18 @@ var SpacedeckSections = {
space_id: this.active_space._id, space_id: this.active_space._id,
mime: "x-spacedeck/shape", mime: "x-spacedeck/shape",
description: "Text", description: "Text",
board: { x: point.x,
x: point.x, y: point.y,
y: point.y, z: point.z,
z: point.z, w: w,
w: w, h: h,
h: h stroke_color: "#ffffff",
}, text_color: "#ffffff",
style: { stroke: 0,
stroke_color: "#ffffff", fill_color: "#000000",
text_color: "#ffffff", shape: shape_type,
stroke: 0, valign: "middle",
fill_color: "#000000", align: "center"
shape: shape_type,
valign: "middle",
align: "center"
}
}; };
if (this.guest_nickname) { if (this.guest_nickname) {
...@@ -1829,17 +1815,13 @@ var SpacedeckSections = { ...@@ -1829,17 +1815,13 @@ var SpacedeckSections = {
state: "uploading", state: "uploading",
payload_thumbnail_medium_uri: null, payload_thumbnail_medium_uri: null,
payload_thumbnail_web_uri: null, payload_thumbnail_web_uri: null,
board: { x: point.x,
x: point.x, y: point.y,
y: point.y, w: w,
w: w, h: h,
h: h, z: point.z,
z: point.z order: this.active_space_artifacts.length+1,
}, fill_color: fill
style: {
order: this.active_space_artifacts.length+1,
fill_color: fill
}
} }
this.update_board_artifact_viewmodel(a); this.update_board_artifact_viewmodel(a);
...@@ -1864,7 +1846,11 @@ var SpacedeckSections = { ...@@ -1864,7 +1846,11 @@ var SpacedeckSections = {
a.payload_thumbnail_big_uri = updated_a.payload_thumbnail_big_uri; a.payload_thumbnail_big_uri = updated_a.payload_thumbnail_big_uri;
a.payload_alternatives = updated_a.payload_alternatives; a.payload_alternatives = updated_a.payload_alternatives;
a.mime = updated_a.mime; a.mime = updated_a.mime;
a.board = updated_a.board; a.x = updated_a.x;
a.y = updated_a.y;
a.w = updated_a.w;
a.h = updated_a.h;
a.z = updated_a.z;
a.state = updated_a.state; a.state = updated_a.state;
this.update_board_artifact_viewmodel(a); this.update_board_artifact_viewmodel(a);
...@@ -2002,26 +1988,26 @@ var SpacedeckSections = { ...@@ -2002,26 +1988,26 @@ var SpacedeckSections = {
clear_formatting_walk: function(el,cmd,arg1,arg2) { clear_formatting_walk: function(el,cmd,arg1,arg2) {
if (el && el.style) { if (el && el.style) {
if (cmd == "preciseFontSize") { if (cmd == "preciseFontSize") {
el.style.fontSize = null; el.fontSize = null;
} else if (cmd == "letterSpacing") { } else if (cmd == "letterSpacing") {
el.style.letterSpacing = null; el.letterSpacing = null;
} else if (cmd == "lineHeight") { } else if (cmd == "lineHeight") {
el.style.lineHeight = null; el.lineHeight = null;
} else if (cmd == "fontName") { } else if (cmd == "fontName") {
el.style.fontFamily = null; el.fontFamily = null;
} else if (cmd == "fontWeight") { } else if (cmd == "fontWeight") {
el.style.fontWeight = null; el.fontWeight = null;
el.style.fontStyle = null; el.fontStyle = null;
} else if (cmd == "bold") { } else if (cmd == "bold") {
el.style.fontWeight = null; el.fontWeight = null;
} else if (cmd == "italic") { } else if (cmd == "italic") {
el.style.fontStyle = null; el.fontStyle = null;
} else if (cmd == "underline") { } else if (cmd == "underline") {
el.style.textDecoration = null; el.textDecoration = null;
} else if (cmd == "strikeThrough") { } else if (cmd == "strikeThrough") {
el.style.textDecoration = null; el.textDecoration = null;
} else if (cmd == "forecolor") { } else if (cmd == "forecolor") {
el.style.color = null; el.color = null;
} }
} }
...@@ -2108,6 +2094,9 @@ var SpacedeckSections = { ...@@ -2108,6 +2094,9 @@ var SpacedeckSections = {
if (a.description!=dom.innerHTML) { if (a.description!=dom.innerHTML) {
a.description = dom.innerHTML; a.description = dom.innerHTML;
console.log("new DOM:",dom.innerHTML);
this.update_board_artifact_viewmodel(a); this.update_board_artifact_viewmodel(a);
this.queue_artifact_for_save(a); this.queue_artifact_for_save(a);
...@@ -2141,10 +2130,7 @@ var SpacedeckSections = { ...@@ -2141,10 +2130,7 @@ var SpacedeckSections = {
remove_link_from_selected_artifacts: function() { remove_link_from_selected_artifacts: function() {
this.update_selected_artifacts(function(a) { this.update_selected_artifacts(function(a) {
var meta = a.meta || {}; return {link_uri: ""};
delete meta.link_uri;
return {meta: meta};
}); });
}, },
...@@ -2160,9 +2146,7 @@ var SpacedeckSections = { ...@@ -2160,9 +2146,7 @@ var SpacedeckSections = {
var insert_link_url = prompt("URL:",def); var insert_link_url = prompt("URL:",def);
this.update_selected_artifacts(function(a) { this.update_selected_artifacts(function(a) {
var meta = a.meta || {}; var update = {link_uri: insert_link_url};
meta.link_uri = insert_link_url;
var update = {meta: meta};
if (a.payload_uri && a.payload_uri.match("webgrabber")) { if (a.payload_uri && a.payload_uri.match("webgrabber")) {
var enc_uri = encodeURIComponent(btoa(insert_link_url)); var enc_uri = encodeURIComponent(btoa(insert_link_url));
...@@ -2185,11 +2169,10 @@ var SpacedeckSections = { ...@@ -2185,11 +2169,10 @@ var SpacedeckSections = {
delete copy["$index"]; delete copy["$index"];
delete copy["_id"]; delete copy["_id"];
if (dx) copy.board.x += dx; if (dx) copy.x += dx;
if (dy) copy.board.y += dy; if (dy) copy.y += dy;
if (!copy.style) copy.style = {}; copy.order = this.active_space_artifacts.length+1;
copy.style.order = this.active_space_artifacts.length+1;
if (this.guest_nickname) { if (this.guest_nickname) {
copy.editor_name = this.guest_nickname; copy.editor_name = this.guest_nickname;
...@@ -2334,16 +2317,16 @@ var SpacedeckSections = { ...@@ -2334,16 +2317,16 @@ var SpacedeckSections = {
if (parsed[i].mime) { if (parsed[i].mime) {
var z = this.highest_z()+1; var z = this.highest_z()+1;
if (parsed.length==1) { if (parsed.length==1) {
var w = parsed[i].board.w; var w = parsed[i].w;
var h = parsed[i].board.h; var h = parsed[i].h;
var point = this.find_place_for_item(w,h); var point = this.find_place_for_item(w,h);
parsed[i].board.x = point.x; parsed[i].x = point.x;
parsed[i].board.y = point.y; parsed[i].y = point.y;
parsed[i].board.z = point.z; parsed[i].z = point.z;
} else { } else {
parsed[i].board.x = parsed[i].board.x+50; parsed[i].x = parsed[i].x+50;
parsed[i].board.y = parsed[i].board.y+50; parsed[i].y = parsed[i].y+50;
parsed[i].board.y = parsed[i].board.z+z; parsed[i].y = parsed[i].z+z;
} }
this.clone_artifact(parsed[i], 0,0, function(a) { this.clone_artifact(parsed[i], 0,0, function(a) {
this.multi_select([a]); this.multi_select([a]);
...@@ -2373,13 +2356,11 @@ var SpacedeckSections = { ...@@ -2373,13 +2356,11 @@ var SpacedeckSections = {
var h = 300; var h = 300;
var point = this.find_place_for_item(w,h); var point = this.find_place_for_item(w,h);
new_item.board = { new_item.x = point.x;
x: point.x, new_item.y = point.y;
y: point.y, new_item.w = w;
w: w, new_item.h = h;
h: h, new_item.z = point.z;
z: point.z
};
if (this.guest_nickname) { if (this.guest_nickname) {
new_item.editor_name = this.guest_nickname; new_item.editor_name = this.guest_nickname;
...@@ -2402,16 +2383,12 @@ var SpacedeckSections = { ...@@ -2402,16 +2383,12 @@ var SpacedeckSections = {
mime: "image/png", mime: "image/png",
description: url, description: url,
state: "uploading", state: "uploading",
board: { x: point.x,
x: point.x, y: point.y,
y: point.y, w: 200,
w: 200, h: 200,
h: 200, z: z,
z: z order: this.active_space_artifacts.length
},
style: {
order: this.active_space_artifacts.length
}
} }
var metadata = parse_link(url) var metadata = parse_link(url)
...@@ -2473,16 +2450,12 @@ var SpacedeckSections = { ...@@ -2473,16 +2450,12 @@ var SpacedeckSections = {
payload_thumbnail_medium_uri: metadata.thumbnail_url, payload_thumbnail_medium_uri: metadata.thumbnail_url,
payload_thumbnail_web_uri: metadata.thumbnail_url, payload_thumbnail_web_uri: metadata.thumbnail_url,
state: "idle", state: "idle",
meta: { title: metadata.title,
title: metadata.title, link_uri: metadata.url || url,
link_uri: metadata.url || url x: point.x - w/2,
}, y: point.y - h/2,
board: { w: w,
x: point.x - w/2, h: h
y: point.y - h/2,
w: w,
h: h
}
}); });
if (this.guest_nickname) { if (this.guest_nickname) {
...@@ -2591,7 +2564,7 @@ var SpacedeckSections = { ...@@ -2591,7 +2564,7 @@ var SpacedeckSections = {
}, },
remove_section_background: function() { remove_section_background: function() {
this.active_space.advanced.background_uri = null; this.active_space.background_uri = null;
save_space(this.active_space); save_space(this.active_space);
}, },
...@@ -2652,8 +2625,8 @@ var SpacedeckSections = { ...@@ -2652,8 +2625,8 @@ var SpacedeckSections = {
this.bounds_zoom = this.viewport_zoom; this.bounds_zoom = this.viewport_zoom;
var eff_w = this.active_space.advanced.width*this.viewport_zoom; var eff_w = this.active_space.width*this.viewport_zoom;
var eff_h = this.active_space.advanced.height*this.viewport_zoom; var eff_h = this.active_space.height*this.viewport_zoom;
if (window.innerWidth>eff_w) { if (window.innerWidth>eff_w) {
// horizontal centering // horizontal centering
...@@ -2846,8 +2819,8 @@ var SpacedeckSections = { ...@@ -2846,8 +2819,8 @@ var SpacedeckSections = {
var el = $("#space")[0]; var el = $("#space")[0];
var eff_w = this.active_space.advanced.width*this.viewport_zoom; var eff_w = this.active_space.width*this.viewport_zoom;
var eff_h = this.active_space.advanced.height*this.viewport_zoom; var eff_h = this.active_space.height*this.viewport_zoom;
var sx = el.scrollLeft; var sx = el.scrollLeft;
var sy = el.scrollTop; var sy = el.scrollTop;
...@@ -2980,9 +2953,9 @@ var SpacedeckSections = { ...@@ -2980,9 +2953,9 @@ var SpacedeckSections = {
var w = 300; var w = 300;
var h = 200; var h = 200;
if (parsed.board && parsed.board.w && parsed.board.h) { if (parsed.board && parsed.w && parsed.h) {
w = parsed.board.w; w = parsed.w;
h = parsed.board.h; h = parsed.h;
} }
var point = this.cursor_point_to_space(evt); var point = this.cursor_point_to_space(evt);
......
...@@ -283,9 +283,9 @@ var SpacedeckSpaces = { ...@@ -283,9 +283,9 @@ var SpacedeckSpaces = {
this.discover_zones(); this.discover_zones();
window.setTimeout(function() { //window.setTimeout(function() {
this.zoom_to_fit(); // this.zoom_to_fit();
}.bind(this),10); //}.bind(this),10);
if (on_success) { if (on_success) {
on_success(); on_success();
...@@ -636,17 +636,14 @@ var SpacedeckSpaces = { ...@@ -636,17 +636,14 @@ var SpacedeckSpaces = {
download_space: function() { download_space: function() {
smoke.quiz(__("download_space"), function(e, test) { smoke.quiz(__("download_space"), function(e, test) {
if (e == "PDF"){ if (e == "PDF") {
this.download_space_as_pdf(this.active_space); this.download_space_as_pdf(this.active_space);
}else if (e == "ZIP"){ } else if (e == "ZIP") {
this.download_space_as_zip(this.active_space); this.download_space_as_zip(this.active_space);
}else if (e == "TXT"){
this.download_space_as_list(this.active_space);
} }
}.bind(this), { }.bind(this), {
button_1: "PDF", button_1: "PDF",
button_2: "ZIP", button_2: "ZIP",
button_3: "TXT",
button_cancel:__("cancel") button_cancel:__("cancel")
}); });
......
...@@ -15,7 +15,8 @@ SpacedeckUsers = { ...@@ -15,7 +15,8 @@ SpacedeckUsers = {
account_remove_error: null, account_remove_error: null,
loading_user: false, loading_user: false,
password_reset_confirm_error: "", password_reset_confirm_error: "",
password_reset_error: "" password_reset_error: "",
}, },
methods:{ methods:{
load_user: function(on_success, on_error) { load_user: function(on_success, on_error) {
...@@ -29,6 +30,12 @@ SpacedeckUsers = { ...@@ -29,6 +30,12 @@ SpacedeckUsers = {
if (on_success) { if (on_success) {
on_success(user); on_success(user);
} }
// see spacedeck_account.js
load_importables(this.user, function(files) {
this.importables = files;
}.bind(this));
}.bind(this), function() { }.bind(this), function() {
// error // error
this.loading_user = false; this.loading_user = false;
...@@ -40,18 +47,6 @@ SpacedeckUsers = { ...@@ -40,18 +47,6 @@ SpacedeckUsers = {
}.bind(this)); }.bind(this));
}, },
login_google: function(evt) {
this.loading_user = true;
create_oauthtoken(function(data){
this.loading_user = false;
location.href = data.url;
}, function(xhr){
this.loading_user = false;
alert("could not get oauth token");
});
},
finalize_login: function(session_token, on_success) { finalize_login: function(session_token, on_success) {
if(!window.socket_auth || window.socket_auth == '' || window.socket_auth == 'null') { if(!window.socket_auth || window.socket_auth == '' || window.socket_auth == 'null') {
window.socket_auth = session_token; window.socket_auth = session_token;
...@@ -169,7 +164,6 @@ SpacedeckUsers = { ...@@ -169,7 +164,6 @@ SpacedeckUsers = {
}, },
password_reset_submit: function(evt, email) { password_reset_submit: function(evt, email) {
if (evt) { if (evt) {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
...@@ -203,7 +197,6 @@ SpacedeckUsers = { ...@@ -203,7 +197,6 @@ SpacedeckUsers = {
}, },
password_reset_confirm: function(evt, password, password_confirmation) { password_reset_confirm: function(evt, password, password_confirmation) {
if (evt) { if (evt) {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
......
...@@ -158,7 +158,7 @@ function boot_spacedeck() { ...@@ -158,7 +158,7 @@ function boot_spacedeck() {
}); });
} }
$(document).ready(function(){ document.addEventListener("DOMContentLoaded",function() {
window.smoke = smoke; window.smoke = smoke;
window.alert = smoke.alert; window.alert = smoke.alert;
......
...@@ -331,7 +331,7 @@ function setup_whiteboard_directives() { ...@@ -331,7 +331,7 @@ function setup_whiteboard_directives() {
var $scope = this.vm.$root; var $scope = this.vm.$root;
return _.filter($scope.active_space_artifacts, function(a) { return _.filter($scope.active_space_artifacts, function(a) {
return this.rects_intersecting(a.board, rect); return this.rects_intersecting(a, rect);
}.bind(this)); }.bind(this));
}, },
...@@ -439,15 +439,15 @@ function setup_whiteboard_directives() { ...@@ -439,15 +439,15 @@ function setup_whiteboard_directives() {
dists = $scope.unselected_artifacts().map(function(a){ dists = $scope.unselected_artifacts().map(function(a){
var r = this.rect_to_points(a.board); var r = this.rect_to_points(a);
var xd1 = Math.abs(r[0].x-x); var xd1 = Math.abs(r[0].x-x);
var xd2 = Math.abs(r[1].x-x); var xd2 = Math.abs(r[1].x-x);
var xd3 = Math.abs(r[0].x+a.board.w/2 - x); var xd3 = Math.abs(r[0].x+a.w/2 - x);
var yd1 = Math.abs(r[0].y-y); var yd1 = Math.abs(r[0].y-y);
var yd2 = Math.abs(r[2].y-y); var yd2 = Math.abs(r[2].y-y);
var yd3 = Math.abs(r[0].y+a.board.h/2 - y); var yd3 = Math.abs(r[0].y+a.h/2 - y);
if (!snap_middle) { if (!snap_middle) {
if (xd2<xd1) { if (xd2<xd1) {
...@@ -469,10 +469,10 @@ function setup_whiteboard_directives() { ...@@ -469,10 +469,10 @@ function setup_whiteboard_directives() {
if (snap_middle) { if (snap_middle) {
var xd = xd3; var xd = xd3;
var sx = r[0].x+a.board.w/2; var sx = r[0].x+a.w/2;
var yd = yd3; var yd = yd3;
var sy = r[0].y+a.board.h/2; var sy = r[0].y+a.h/2;
} }
return [[xd,sx],[yd,sy]]; return [[xd,sx],[yd,sy]];
...@@ -531,18 +531,14 @@ function setup_whiteboard_directives() { ...@@ -531,18 +531,14 @@ function setup_whiteboard_directives() {
mime: "x-spacedeck/vector", mime: "x-spacedeck/vector",
description: "", description: "",
control_points: [{dx:0,dy:0}], control_points: [{dx:0,dy:0}],
board: { x: point.x,
x: point.x, y: point.y,
y: point.y, z: z,
z: z, w: 64,
w: 64, h: 64,
h: 64 stroke_color: "#000000",
}, stroke: 2,
style: { shape: "scribble"
stroke_color: "#000000",
stroke: 2,
shape: "scribble"
}
}; };
$scope.save_artifact(a, function(saved_a) { $scope.save_artifact(a, function(saved_a) {
...@@ -572,18 +568,14 @@ function setup_whiteboard_directives() { ...@@ -572,18 +568,14 @@ function setup_whiteboard_directives() {
mime: "x-spacedeck/vector", mime: "x-spacedeck/vector",
description: "", description: "",
control_points: [{dx:0,dy:0},{dx:0,dy:0},{dx:0,dy:0}], control_points: [{dx:0,dy:0},{dx:0,dy:0},{dx:0,dy:0}],
board: { x: point.x,
x: point.x, y: point.y,
y: point.y, z: z,
z: z, w: 64,
w: 64, h: 64,
h: 64 stroke_color: "#000000",
}, stroke: 2,
style: { shape: "arrow"
stroke_color: "#000000",
stroke: 2,
shape: "arrow"
}
}; };
$scope.save_artifact(a, function(saved_a) { $scope.save_artifact(a, function(saved_a) {
...@@ -612,18 +604,14 @@ function setup_whiteboard_directives() { ...@@ -612,18 +604,14 @@ function setup_whiteboard_directives() {
mime: "x-spacedeck/vector", mime: "x-spacedeck/vector",
description: "", description: "",
control_points: [{dx:0,dy:0},{dx:0,dy:0}], control_points: [{dx:0,dy:0},{dx:0,dy:0}],
board: { x: point.x,
x: point.x, y: point.y,
y: point.y, z: z,
z: z, w: 64,
w: 64, h: 64,
h: 64 stroke_color: "#000000",
}, stroke: 2,
style: { shape: "line"
stroke_color: "#000000",
stroke: 2,
shape: "line"
}
}; };
$scope.save_artifact(a, function(saved_a) { $scope.save_artifact(a, function(saved_a) {
...@@ -675,11 +663,11 @@ function setup_whiteboard_directives() { ...@@ -675,11 +663,11 @@ function setup_whiteboard_directives() {
if (_.include(["text","placeholder"],$scope.artifact_major_type(ars[i]))) { if (_.include(["text","placeholder"],$scope.artifact_major_type(ars[i]))) {
// some types of artifact need a minimum size // some types of artifact need a minimum size
if (ars[i].board.w<10) { if (ars[i].w<10) {
ars[i].board.w = 10; ars[i].w = 10;
} }
if (ars[i].board.h<10) { if (ars[i].h<10) {
ars[i].board.h = 10; ars[i].h = 10;
} }
} }
...@@ -827,10 +815,8 @@ function setup_whiteboard_directives() { ...@@ -827,10 +815,8 @@ function setup_whiteboard_directives() {
if (old_a) { if (old_a) {
return { return {
board: _.extend(a.board, { x: old_a.x + dx - snap_dx,
x: old_a.board.x + dx - snap_dx, y: old_a.y + dy - snap_dy
y: old_a.board.y + dy - snap_dy
})
}; };
} else { } else {
// deleted? // deleted?
...@@ -865,26 +851,24 @@ function setup_whiteboard_directives() { ...@@ -865,26 +851,24 @@ function setup_whiteboard_directives() {
var scale_x = lead_x ? (moved_x)/lead_x : 1; var scale_x = lead_x ? (moved_x)/lead_x : 1;
var scale_y = lead_y ? (moved_y)/lead_y : 1; var scale_y = lead_y ? (moved_y)/lead_y : 1;
if ($scope.transform_lock) scale_y = scale_x; if (!$scope.transform_lock) scale_y = scale_x;
$scope.update_selected_artifacts(function(a) { $scope.update_selected_artifacts(function(a) {
var old_a = $scope.find_artifact_before_transaction(a); var old_a = $scope.find_artifact_before_transaction(a);
var x1 = origin_x + ((old_a.board.x - origin_x) * scale_x); var x1 = origin_x + ((old_a.x - origin_x) * scale_x);
var y1 = origin_y + ((old_a.board.y - origin_y) * scale_y); var y1 = origin_y + ((old_a.y - origin_y) * scale_y);
var x2 = origin_x + (((old_a.board.x + old_a.board.w) - origin_x) * scale_x); var x2 = origin_x + (((old_a.x + old_a.w) - origin_x) * scale_x);
var y2 = origin_y + (((old_a.board.y + old_a.board.h) - origin_y) * scale_y); var y2 = origin_y + (((old_a.y + old_a.h) - origin_y) * scale_y);
if (x1>x2) { var t = x1; x1 = x2; x2 = t; } if (x1>x2) { var t = x1; x1 = x2; x2 = t; }
if (y1>y2) { var t = y1; y1 = y2; y2 = t; } if (y1>y2) { var t = y1; y1 = y2; y2 = t; }
return { return {
board: _.extend(a.board, { x: x1,
x: x1, y: y1,
y: y1, w: x2 - x1,
w: x2 - x1, h: y2 - y1
h: y2 - y1
})
}; };
}.bind(this)); }.bind(this));
...@@ -902,18 +886,17 @@ function setup_whiteboard_directives() { ...@@ -902,18 +886,17 @@ function setup_whiteboard_directives() {
var old_a = $scope.find_artifact_before_transaction(a); var old_a = $scope.find_artifact_before_transaction(a);
var control_points = _.cloneDeep(old_a.control_points); var control_points = _.cloneDeep(old_a.control_points);
var board = _.clone(old_a.board);
var cp = control_points[$scope.selected_control_point_idx]; var cp = control_points[$scope.selected_control_point_idx];
var snapped = _this.snap_point(board.x+cp.dx+dx, board.y+cp.dy+dy); var snapped = _this.snap_point(old_a.x+cp.dx+dx, old_a.y+cp.dy+dy);
dx = snapped.snapx[1]-(board.x+cp.dx); dx = snapped.snapx[1]-(old_a.x+cp.dx);
dy = snapped.snapy[1]-(board.y+cp.dy); dy = snapped.snapy[1]-(old_a.y+cp.dy);
cp.dx += dx; cp.dx += dx;
cp.dy += dy; cp.dy += dy;
// special case for arrow's 3rd point // special case for arrow's 3rd point
if (a.style.shape == "arrow" && $scope.selected_control_point_idx!=2) { if (a.shape == "arrow" && $scope.selected_control_point_idx!=2) {
/*control_points[2].dx += dx/2; /*control_points[2].dx += dx/2;
control_points[2].dy += dy/2; */ control_points[2].dy += dy/2; */
...@@ -921,7 +904,7 @@ function setup_whiteboard_directives() { ...@@ -921,7 +904,7 @@ function setup_whiteboard_directives() {
control_points[2].dy = (control_points[0].dy+control_points[1].dy)/2; control_points[2].dy = (control_points[0].dy+control_points[1].dy)/2;
} }
return _this.normalize_control_points(control_points, board); return _this.normalize_control_points(control_points, old_a);
}); });
} else if (this.mouse_state == "scribble") { } else if (this.mouse_state == "scribble") {
...@@ -930,16 +913,14 @@ function setup_whiteboard_directives() { ...@@ -930,16 +913,14 @@ function setup_whiteboard_directives() {
var old_a = a; var old_a = a;
var control_points = _.cloneDeep(old_a.control_points); var control_points = _.cloneDeep(old_a.control_points);
var board = _.clone(old_a.board);
var offset = this.offset_point_in_wrapper({x:cursor.x,y:cursor.y}); var offset = this.offset_point_in_wrapper({x:cursor.x,y:cursor.y});
control_points.push({ control_points.push({
dx: offset.x-board.x, dx: offset.x-old_a.x,
dy: offset.y-board.y dy: offset.y-old_a.y
}); });
return this.normalize_control_points(simplify_scribble_points(control_points), board); return this.normalize_control_points(simplify_scribble_points(control_points), old_a);
}.bind(this)); }.bind(this));
var arts = $scope.selected_artifacts(); var arts = $scope.selected_artifacts();
...@@ -959,7 +940,7 @@ function setup_whiteboard_directives() { ...@@ -959,7 +940,7 @@ function setup_whiteboard_directives() {
} }
}, },
normalize_control_points: function(control_points, board) { normalize_control_points: function(control_points, artifact) {
var x1 = _.min(control_points,"dx").dx; var x1 = _.min(control_points,"dx").dx;
var y1 = _.min(control_points,"dy").dy; var y1 = _.min(control_points,"dy").dy;
var x2 = _.max(control_points,"dx").dx; var x2 = _.max(control_points,"dx").dx;
...@@ -981,19 +962,15 @@ function setup_whiteboard_directives() { ...@@ -981,19 +962,15 @@ function setup_whiteboard_directives() {
var bshiftx = 0; var bshiftx = 0;
var bshifty = 0; var bshifty = 0;
if (board.w < 0) bshiftx = -board.w; if (artifact.w < 0) bshiftx = -artifact.w;
if (board.h < 0) bshifty = -board.h; if (artifact.h < 0) bshifty = -artifact.h;
var shifted_board = { return {
x: board.x + bshiftx - shiftx, x: artifact.x + bshiftx - shiftx,
y: board.y + bshifty - shifty, y: artifact.y + bshifty - shifty,
w: w, w: w,
h: h, h: h,
z: board.z z: artifact.z,
};
return {
board: shifted_board,
control_points: shifted_cps control_points: shifted_cps
}; };
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment