mirror of
https://github.com/spacedeck/spacedeck-open.git
synced 2026-01-30 23:05:25 +01:00
Compare commits
79 Commits
remove-cdn
...
chargebee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfad9269ff | ||
|
|
0a1bd2a107 | ||
|
|
6ef1f8fba6 | ||
|
|
a1fb09709a | ||
|
|
3dd0fce139 | ||
|
|
50e421d64d | ||
|
|
c88433fcff | ||
|
|
ff403a9c23 | ||
|
|
79384a2fb2 | ||
|
|
7fba188661 | ||
|
|
1242cb84ee | ||
|
|
8cc027ed95 | ||
|
|
aa3deb9d72 | ||
|
|
0cb5ecb08c | ||
|
|
364578b0aa | ||
|
|
08b9bb4118 | ||
|
|
63d70c498a | ||
|
|
38fffa5644 | ||
|
|
b626a21b83 | ||
|
|
6cdb804a8b | ||
|
|
89d5a7fd9f | ||
|
|
8ea0fd190f | ||
|
|
9018a233a1 | ||
|
|
d196af739c | ||
|
|
0c877bc20b | ||
|
|
803aad6219 | ||
|
|
79cd848cbb | ||
|
|
6bd7130597 | ||
|
|
5c753cb82a | ||
|
|
7a42865c84 | ||
|
|
ea40f1cc7a | ||
|
|
26329b000b | ||
|
|
7c8ef82bd1 | ||
|
|
20bbb5aa08 | ||
|
|
176b383cbd | ||
|
|
0e2c6401e0 | ||
|
|
28c31e9331 | ||
|
|
56988fc1c4 | ||
|
|
f23b44e6c2 | ||
|
|
927b0ddac1 | ||
|
|
1cd69e6538 | ||
|
|
ec797709fd | ||
|
|
8d73918d0d | ||
|
|
7e5b988606 | ||
|
|
35c747eabb | ||
|
|
fab692787c | ||
|
|
c1a3700bae | ||
|
|
c64c41f624 | ||
|
|
3fd00bf755 | ||
|
|
e135976299 | ||
|
|
170ed5471d | ||
|
|
1b05aaeaf8 | ||
|
|
a7704875c5 | ||
|
|
60667187f3 | ||
|
|
058c414ae3 | ||
|
|
ba72cf7dc8 | ||
|
|
3d391c571c | ||
|
|
96e9b82fbb | ||
|
|
5a9a79addb | ||
|
|
fbf18839f9 | ||
|
|
65476a0d09 | ||
|
|
18d09b49be | ||
|
|
b2cf8cf336 | ||
|
|
e04eedb2c4 | ||
|
|
4df480c8c5 | ||
|
|
a184225c8b | ||
|
|
72221fcf0b | ||
|
|
531ad2f833 | ||
|
|
ba10889ef8 | ||
|
|
16e926b76a | ||
|
|
0e97945b95 | ||
|
|
581ee8eb04 | ||
|
|
c1e29fb7e2 | ||
|
|
447076845c | ||
|
|
a051fc4e6f | ||
|
|
5a7839ceaa | ||
|
|
26f4da68ea | ||
|
|
c9b6e7c2c8 | ||
|
|
0fdeef12ed |
20
.github/ISSUE_TEMPLATE.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
|
||||||
|
## Actual Behavior
|
||||||
|
|
||||||
|
|
||||||
|
## Possible Solution
|
||||||
|
|
||||||
|
|
||||||
|
## Steps to Reproduce the Problem
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
## Specifications
|
||||||
|
|
||||||
|
- OS Platform and Distribution (e.g., Linux Ubuntu 16.04):
|
||||||
|
- Node version:
|
||||||
|
- Database engine (e.g., SQLite):
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,4 +5,5 @@ public/stylesheets/*.css
|
|||||||
database.sqlite
|
database.sqlite
|
||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
|
storage/
|
||||||
|
.DS_Store
|
||||||
44
.gitlab-ci.yml
Normal file
44
.gitlab-ci.yml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
variables:
|
||||||
|
CONTAINER_IMAGE: git.universe.io:4567/$CI_PROJECT_PATH
|
||||||
|
DOCKER_HOST: tcp://docker:2376
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- deploy_dev
|
||||||
|
- deploy
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
image: docker:stable
|
||||||
|
services:
|
||||||
|
- docker:19.03.12-dind
|
||||||
|
variables:
|
||||||
|
DOCKER_TLS_CERTDIR: "/certs"
|
||||||
|
script:
|
||||||
|
- docker image build -t $CONTAINER_IMAGE:$CI_BUILD_REF -t $CONTAINER_IMAGE:latest .
|
||||||
|
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN git.universe.io:4567
|
||||||
|
- docker image push $CONTAINER_IMAGE:latest
|
||||||
|
- docker image push $CONTAINER_IMAGE:$CI_BUILD_REF
|
||||||
|
only:
|
||||||
|
- mnt
|
||||||
|
- custom/freiwerkb
|
||||||
|
deploy_dev:
|
||||||
|
stage: deploy
|
||||||
|
image: alpine
|
||||||
|
script:
|
||||||
|
- apk add --update curl
|
||||||
|
- curl -XPOST $WWW_WEBHOOK
|
||||||
|
only:
|
||||||
|
- mnt
|
||||||
|
- custom/freiwerkb
|
||||||
|
deploy:
|
||||||
|
when: manual
|
||||||
|
stage: deploy
|
||||||
|
image: alpine
|
||||||
|
script:
|
||||||
|
- apk add --update curl
|
||||||
|
- |
|
||||||
|
curl -XPOST -K - <<URL
|
||||||
|
$WWW_WEBHOOKS
|
||||||
|
URL
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- custom/freiwerkb
|
||||||
1
.tool-versions
Normal file
1
.tool-versions
Normal file
@@ -0,0 +1 @@
|
|||||||
|
nodejs 10.23.1
|
||||||
29
.vscode/launch.json
vendored
Normal file
29
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch debug",
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/nodemon/bin/nodemon.js",
|
||||||
|
"skipFiles": ["<node_internals>/**"],
|
||||||
|
"program": "${workspaceFolder}/spacedeck.js",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"env": {
|
||||||
|
"NODE_APP_INSTANCE" :"dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch ldap",
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/nodemon/bin/nodemon.js",
|
||||||
|
"skipFiles": ["<node_internals>/**"],
|
||||||
|
"program": "${workspaceFolder}/spacedeck.js",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"env": {
|
||||||
|
"NODE_APP_INSTANCE" :"ldap"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
8
CHANGELOG.md
Normal file
8
CHANGELOG.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [X.X.X] - 2021-03-23
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Replaced phantomjs with puppeteer #169
|
||||||
|
- Create Hungarian language pack #174
|
||||||
14
Dockerfile
14
Dockerfile
@@ -21,6 +21,20 @@ RUN cd audiowaveform/build/ && cmake -D ENABLE_TESTS=0 -D BUILD_STATIC=1 ..
|
|||||||
RUN cd audiowaveform/build/ && make
|
RUN cd audiowaveform/build/ && make
|
||||||
RUN cd audiowaveform/build/ && make install
|
RUN cd audiowaveform/build/ && make install
|
||||||
|
|
||||||
|
# install chromium
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
chromium \
|
||||||
|
nss \
|
||||||
|
freetype \
|
||||||
|
freetype-dev \
|
||||||
|
harfbuzz \
|
||||||
|
ca-certificates \
|
||||||
|
ttf-freefont
|
||||||
|
|
||||||
|
# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
|
||||||
|
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
|
||||||
|
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
|
||||||
|
|
||||||
# install other requirements
|
# install other requirements
|
||||||
|
|
||||||
RUN apk add graphicsmagick ffmpeg ffmpeg-dev ghostscript
|
RUN apk add graphicsmagick ffmpeg ffmpeg-dev ghostscript
|
||||||
|
|||||||
10
Gulpfile.js
10
Gulpfile.js
@@ -1,13 +1,15 @@
|
|||||||
const gulp = require('gulp')
|
const gulp = require('gulp');
|
||||||
const sass = require('gulp-sass')
|
const sass = require('gulp-sass');
|
||||||
const concat = require('gulp-concat')
|
const concat = require('gulp-concat');
|
||||||
|
const cleanCSS = require('gulp-clean-css');
|
||||||
|
|
||||||
gulp.task('styles', function(done) {
|
gulp.task('styles', function(done) {
|
||||||
gulp.src('styles/**/*.scss')
|
gulp.src('styles/**/*.scss')
|
||||||
.pipe(sass({
|
.pipe(sass({
|
||||||
errLogToConsole: true
|
errLogToConsole: true
|
||||||
}))
|
}))
|
||||||
|
.pipe(cleanCSS())
|
||||||
.pipe(gulp.dest('./public/stylesheets/'))
|
.pipe(gulp.dest('./public/stylesheets/'))
|
||||||
.pipe(concat('style.css'))
|
.pipe(concat('style.css'))
|
||||||
done()
|
done()
|
||||||
})
|
});
|
||||||
84
README.md
84
README.md
@@ -12,7 +12,7 @@ We appreciate filed issues, pull requests and general discussion.
|
|||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
- Create virtual whiteboards called *Spaces* with virtually unlimited size
|
- Create virtual whiteboards called _Spaces_ with virtually unlimited size
|
||||||
- Drag & drop images, videos and audio from your computer or the web
|
- Drag & drop images, videos and audio from your computer or the web
|
||||||
- Write and format text with full control over fonts, colors and style
|
- Write and format text with full control over fonts, colors and style
|
||||||
- Draw, annotate and highlight with included graphical shapes
|
- Draw, annotate and highlight with included graphical shapes
|
||||||
@@ -37,7 +37,7 @@ Spacedeck requires:
|
|||||||
|
|
||||||
To run Spacedeck, you only need Node.JS 10.x.
|
To run Spacedeck, you only need Node.JS 10.x.
|
||||||
|
|
||||||
To install all node dependencies, run (do this once):
|
To install all node dependencies, run (do this once) after cloning the repository:
|
||||||
|
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
@@ -45,6 +45,52 @@ To install all node dependencies, run (do this once):
|
|||||||
|
|
||||||
See [config/default.json](config/default.json). Set `storage_local_path` for a local sqlite database or `storage_region`, `storage_bucket`, `storage_cdn` and `storage_endpoint` for AWS S3. `mail_provider` may be one of `console` or `smtp`. Also, omit a trailing `/` for the `endpoint`.
|
See [config/default.json](config/default.json). Set `storage_local_path` for a local sqlite database or `storage_region`, `storage_bucket`, `storage_cdn` and `storage_endpoint` for AWS S3. `mail_provider` may be one of `console` or `smtp`. Also, omit a trailing `/` for the `endpoint`.
|
||||||
|
|
||||||
|
## Disable DB logs
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"db_logs_disabled": true
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configure color swatches
|
||||||
|
|
||||||
|
Add a custom array of swatches to your config/default.json.
|
||||||
|
|
||||||
|
**You should include the swatch transparent (rgba(0,0,0,0)) so users can remove the color applied.**
|
||||||
|
|
||||||
|
## Configure default colors
|
||||||
|
|
||||||
|
You can define text, stroke and fill color in your config/default.json.
|
||||||
|
|
||||||
|
**You also should include the default colors in your custom swatches palette.**
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"spacedeck": {
|
||||||
|
"default_text_color": "#E11F26",
|
||||||
|
"default_stroke_color": "#9E0F13",
|
||||||
|
"default_fill_color": "#64BCCA",
|
||||||
|
"swatches": [
|
||||||
|
{"id":8, "hex":"#000000"},
|
||||||
|
{"id":30, "hex":"rgba(0,0,0,0)"},
|
||||||
|
{"id":31, "hex": "#E11F26"},
|
||||||
|
{"id":32, "hex": "#9E0F13"},
|
||||||
|
{"id":33, "hex": "#64BCCA"},
|
||||||
|
{"id":34, "hex": "#40808A"},
|
||||||
|
{"id":35, "hex": "#036492"},
|
||||||
|
{"id":36, "hex": "#005179"},
|
||||||
|
{"id":37, "hex": "#84427E"},
|
||||||
|
{"id":38, "hex": "#6C3468"},
|
||||||
|
{"id":39, "hex": "#F79B84"},
|
||||||
|
{"id":40, "hex": "#B57362"},
|
||||||
|
{"id":41, "hex": "#E7D45A"},
|
||||||
|
{"id":42, "hex": "#ACA044"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
# Run (web server)
|
# Run (web server)
|
||||||
|
|
||||||
node spacedeck.js
|
node spacedeck.js
|
||||||
@@ -61,18 +107,34 @@ For advanced media conversion:
|
|||||||
|
|
||||||
# Data Storage
|
# Data Storage
|
||||||
|
|
||||||
By default, media files are uploaded to the ```storage``` folder.
|
By default, media files are uploaded to the `storage` folder.
|
||||||
The database is stored in ```database.sqlite``` by default.
|
The database is stored in `database.sqlite` by default.
|
||||||
|
|
||||||
|
# Other databases (Not officially supported)
|
||||||
|
|
||||||
|
## Postgres
|
||||||
|
|
||||||
|
Add the [pg](https://www.npmjs.com/package/pg) module and change the config/default.json to
|
||||||
|
|
||||||
|
```
|
||||||
|
"storage_dialect": "postgres",
|
||||||
|
```
|
||||||
|
|
||||||
|
Adapt the other values as needed
|
||||||
|
|
||||||
|
```
|
||||||
|
"storage_host": "localhost",
|
||||||
|
"storage_database": "spacedeck",
|
||||||
|
"storage_username": "username",
|
||||||
|
"storage_password": "password",
|
||||||
|
```
|
||||||
|
|
||||||
# Run with Docker
|
# Run with Docker
|
||||||
|
|
||||||
- configure `config/default.json`
|
- configure `config/default.json`
|
||||||
- configure `volumes` section inside `docker-compose.yml`
|
- adapt your `docker-compose.yml` if needed.
|
||||||
- point to `database.sqlite` on the host system
|
- start the container with `docker-compose up`
|
||||||
- `touch database.sqlite` if it not exists
|
(use `-d` for background process and `--build` for rebuilding the image)
|
||||||
- point to `storage/` on the host system
|
|
||||||
- `mkdir storage/` if it not exists
|
|
||||||
- start the container with `sudo docker-compose up -f docker-compose.yml -d --build`
|
|
||||||
|
|
||||||
# Hacking
|
# Hacking
|
||||||
|
|
||||||
@@ -89,7 +151,7 @@ Spacedeck Open source code is released under the GNU Affero General Public Licen
|
|||||||
Spacedeck Open - Web-based Collaborative Whiteboard For Rich Media
|
Spacedeck Open - Web-based Collaborative Whiteboard For Rich Media
|
||||||
Copyright (C) 2011-2018 Lukas F. Hartmann, Martin Güther
|
Copyright (C) 2011-2018 Lukas F. Hartmann, Martin Güther
|
||||||
Icons and original CSS design copyright by Thomas Helbig
|
Icons and original CSS design copyright by Thomas Helbig
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Affero General Public License as
|
it under the terms of the GNU Affero General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of the
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
|||||||
@@ -7,8 +7,15 @@
|
|||||||
"endpoint": "http://localhost:9666",
|
"endpoint": "http://localhost:9666",
|
||||||
"invite_code": "top-sekrit",
|
"invite_code": "top-sekrit",
|
||||||
|
|
||||||
|
"storage_dialect": "sqlite",
|
||||||
|
|
||||||
|
"storage_host": "localhost",
|
||||||
|
"storage_database": "spacedeck",
|
||||||
|
"storage_username": "username",
|
||||||
|
"storage_password": "password",
|
||||||
|
|
||||||
"storage_local_path": "./storage",
|
"storage_local_path": "./storage",
|
||||||
"storage_local_db": "./database.sqlite",
|
"storage_local_db": "./database/database.sqlite",
|
||||||
"storage_region": "eu-central-1",
|
"storage_region": "eu-central-1",
|
||||||
"storage_endpoint": "http://localhost:4572",
|
"storage_endpoint": "http://localhost:4572",
|
||||||
"storage_bucket": "my_spacedeck_bucket",
|
"storage_bucket": "my_spacedeck_bucket",
|
||||||
@@ -18,7 +25,7 @@
|
|||||||
"redis_mock": true,
|
"redis_mock": true,
|
||||||
"redis_host": "localhost",
|
"redis_host": "localhost",
|
||||||
|
|
||||||
"phantom_api_secret": "very_secret_phantom_password",
|
"export_api_secret": "very_secret_export_password",
|
||||||
|
|
||||||
"mail_provider": "smtp",
|
"mail_provider": "smtp",
|
||||||
"mail_smtp_host": "your.smtp.host",
|
"mail_smtp_host": "your.smtp.host",
|
||||||
@@ -26,5 +33,6 @@
|
|||||||
"mail_smtp_secure": true,
|
"mail_smtp_secure": true,
|
||||||
"mail_smtp_require_tls": true,
|
"mail_smtp_require_tls": true,
|
||||||
"mail_smtp_user": "your.smtp.user",
|
"mail_smtp_user": "your.smtp.user",
|
||||||
"mail_smtp_pass": "your.secret.smtp.password"
|
"mail_smtp_pass": "your.secret.smtp.password",
|
||||||
|
"spacedeck": {}
|
||||||
}
|
}
|
||||||
|
|||||||
0
database/.gitkeep
Normal file
0
database/.gitkeep
Normal file
@@ -1,5 +1,4 @@
|
|||||||
version: "2.0"
|
version: "2.0"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
spacedeck:
|
spacedeck:
|
||||||
build: .
|
build: .
|
||||||
@@ -7,6 +6,5 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "9666:9666"
|
- "9666:9666"
|
||||||
volumes:
|
volumes:
|
||||||
- /absolute/path/to/storage:/app/storage
|
- ./storage:/app/storage
|
||||||
- /absolute/path/to/database.sqlite:/app/database.sqlite
|
- ./database:/app/database
|
||||||
|
|
||||||
|
|||||||
53
docs/nginx_setup.md
Normal file
53
docs/nginx_setup.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Nginx as reverse proxy
|
||||||
|
|
||||||
|
Below theres an example of how the site configuration for nginx as a reverse proxy can look like:
|
||||||
|
|
||||||
|
```
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
server_name spacedeck.domain.de
|
||||||
|
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
ssl on;
|
||||||
|
|
||||||
|
server_name spacedeck.domain.de;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/spacedeck.domain.de.cer;
|
||||||
|
ssl_certificate_key /etc/ssl/spacedeck.domain.de.key;
|
||||||
|
|
||||||
|
include ssl_params;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
client_max_body_size 50m;
|
||||||
|
|
||||||
|
add_header Content-Security-Policy "default-src https: wss:; script-src https: 'unsafe-inline' 'unsafe-eval'; style-src https: 'unsafe-inline'";
|
||||||
|
add_header X-XSS-Protection "1; mode=block;";
|
||||||
|
add_header Referrer-Policy "no-referrer";
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:9666;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /socket {
|
||||||
|
proxy_pass http://127.0.0.1:9666;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -50,6 +50,8 @@ const convertableAudioTypes = [
|
|||||||
"audio/x-hx-aac-adts",
|
"audio/x-hx-aac-adts",
|
||||||
"audio/aac"];
|
"audio/aac"];
|
||||||
|
|
||||||
|
// ffmpeg progress
|
||||||
|
var duration = 0, time = 0, progress = 0;
|
||||||
|
|
||||||
function getDuration(localFilePath, callback){
|
function getDuration(localFilePath, callback){
|
||||||
exec.execFile("ffprobe", ["-show_format", "-of", "json", localFilePath], function(error, stdout, stderr) {
|
exec.execFile("ffprobe", ["-show_format", "-of", "json", localFilePath], function(error, stdout, stderr) {
|
||||||
@@ -58,6 +60,40 @@ function getDuration(localFilePath, callback){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getConversionProgress(content){
|
||||||
|
// get duration of source
|
||||||
|
var matches = (content) ? content.match(/Duration: (.*?), start:/) : [];
|
||||||
|
if( matches && matches.length>0 ){
|
||||||
|
var rawDuration = matches[1];
|
||||||
|
// convert rawDuration from 00:00:00.00 to seconds.
|
||||||
|
var ar = rawDuration.split(":").reverse();
|
||||||
|
duration = parseFloat(ar[0]);
|
||||||
|
if (ar[1]) duration += parseInt(ar[1]) * 60;
|
||||||
|
if (ar[2]) duration += parseInt(ar[2]) * 60 * 60;
|
||||||
|
}
|
||||||
|
// get the time
|
||||||
|
matches = content.match(/time=(.*?) bitrate/g);
|
||||||
|
if( matches && matches.length>0 ){
|
||||||
|
var rawTime = matches.pop();
|
||||||
|
// needed if there is more than one match
|
||||||
|
if (Array.isArray(rawTime)){
|
||||||
|
rawTime = rawTime.pop().replace('time=','').replace(' bitrate','');
|
||||||
|
} else {
|
||||||
|
rawTime = rawTime.replace('time=','').replace(' bitrate','');
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert rawTime from 00:00:00.00 to seconds.
|
||||||
|
ar = rawTime.split(":").reverse();
|
||||||
|
time = parseFloat(ar[0]);
|
||||||
|
if (ar[1]) time += parseInt(ar[1]) * 60;
|
||||||
|
if (ar[2]) time += parseInt(ar[2]) * 60 * 60;
|
||||||
|
|
||||||
|
//calculate the progress
|
||||||
|
progress = Math.round((time/duration) * 100);
|
||||||
|
}
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
function createWaveform(fileName, localFilePath, callback){
|
function createWaveform(fileName, localFilePath, callback){
|
||||||
var filePathImage = localFilePath + "-" + (new Date().getTime()) + ".png";
|
var filePathImage = localFilePath + "-" + (new Date().getTime()) + ".png";
|
||||||
|
|
||||||
@@ -135,7 +171,7 @@ function convertVideo(fileName, filePath, codec, callback, progressCallback) {
|
|||||||
ff.stderr.on('data', function (data) {
|
ff.stderr.on('data', function (data) {
|
||||||
console.log('[ffmpeg-video] stderr: ' + data);
|
console.log('[ffmpeg-video] stderr: ' + data);
|
||||||
if (progressCallback) {
|
if (progressCallback) {
|
||||||
progressCallback(data);
|
progressCallback(getConversionProgress(""+data)+"%");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
58
helpers/exporter.js
Normal file
58
helpers/exporter.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const db = require('../models/db');
|
||||||
|
const config = require('config');
|
||||||
|
const puppeteer = require('puppeteer');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// type = "pdf" or "png"
|
||||||
|
takeScreenshot: function(space,type,on_success,on_error) {
|
||||||
|
var spaceId = space._id;
|
||||||
|
var space_url = config.get("endpoint")+"/api/spaces/"+spaceId+"/html";
|
||||||
|
|
||||||
|
var export_path = os.tmpdir()+"/"+spaceId+"."+type;
|
||||||
|
|
||||||
|
var timeout = 5000;
|
||||||
|
if (type=="pdf") timeout = 30000;
|
||||||
|
|
||||||
|
space_url += "?api_token="+config.get("export_api_secret");
|
||||||
|
|
||||||
|
console.log("[space-screenshot] url: "+space_url);
|
||||||
|
console.log("[space-screenshot] export_path: "+export_path);
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
try {
|
||||||
|
browser = await puppeteer.launch(
|
||||||
|
{
|
||||||
|
headless: true,
|
||||||
|
args: ['--disable-dev-shm-usage', '--no-sandbox']
|
||||||
|
}
|
||||||
|
);
|
||||||
|
page = await browser.newPage();
|
||||||
|
|
||||||
|
page.setDefaultTimeout(timeout);
|
||||||
|
await page.setJavaScriptEnabled(false);
|
||||||
|
await page.goto(space_url, {waitUntil: 'networkidle2'});
|
||||||
|
await page.emulateMediaType('screen');
|
||||||
|
|
||||||
|
if (type=="pdf") {
|
||||||
|
let margin = 2;
|
||||||
|
await page.pdf({path: export_path, printBackground: true, width: space.width+margin+'px', height: space.height+margin+'px' });
|
||||||
|
}else{
|
||||||
|
await page.screenshot({path: export_path, printBackground: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
await browser.close();
|
||||||
|
on_success(export_path);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
console.error("[space-screenshot] puppeteer abnormal exit for url "+space_url);
|
||||||
|
on_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const db = require('../models/db');
|
|
||||||
const config = require('config');
|
|
||||||
const phantom = require('node-phantom-simple');
|
|
||||||
const os = require('os');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// type = "pdf" or "png"
|
|
||||||
takeScreenshot: function(space,type,on_success,on_error) {
|
|
||||||
var spaceId = space._id;
|
|
||||||
var space_url = config.get("endpoint")+"/api/spaces/"+spaceId+"/html";
|
|
||||||
|
|
||||||
var export_path = os.tmpdir()+"/"+spaceId+"."+type;
|
|
||||||
|
|
||||||
var timeout = 5000;
|
|
||||||
if (type=="pdf") timeout = 30000;
|
|
||||||
|
|
||||||
space_url += "?api_token="+config.get("phantom_api_secret");
|
|
||||||
|
|
||||||
console.log("[space-screenshot] url: "+space_url);
|
|
||||||
console.log("[space-screenshot] export_path: "+export_path);
|
|
||||||
|
|
||||||
var on_success_called = false;
|
|
||||||
|
|
||||||
var on_exit = function(exit_code) {
|
|
||||||
if (exit_code>0) {
|
|
||||||
console.error("phantom abnormal exit for url "+space_url);
|
|
||||||
if (!on_success_called && on_error) {
|
|
||||||
on_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
} else {
|
|
||||||
return browser.createPage(function (err, page) {
|
|
||||||
console.log("page created, opening ",space_url);
|
|
||||||
|
|
||||||
if (type=="pdf") {
|
|
||||||
var psz = {
|
|
||||||
width: space.width+"px",
|
|
||||||
height: space.height+"px"
|
|
||||||
};
|
|
||||||
page.set('paperSize', psz);
|
|
||||||
}
|
|
||||||
|
|
||||||
page.set('settings.resourceTimeout',timeout);
|
|
||||||
page.set('settings.javascriptEnabled',false);
|
|
||||||
|
|
||||||
return page.open(space_url, function (err,status) {
|
|
||||||
page.render(export_path, function() {
|
|
||||||
on_success_called = true;
|
|
||||||
if (on_success) {
|
|
||||||
on_success(export_path);
|
|
||||||
}
|
|
||||||
page.close();
|
|
||||||
browser.exit();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}, {
|
|
||||||
onExit: on_exit
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -103,7 +103,7 @@ function render_space_as_html(space, artifacts) {
|
|||||||
walk(dom("#space")[0],0);
|
walk(dom("#space")[0],0);
|
||||||
//console.log("compiled template: \n"+compiled_js);
|
//console.log("compiled template: \n"+compiled_js);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------
|
// --------
|
||||||
var mouse_state = "idle";
|
var mouse_state = "idle";
|
||||||
var active_tool = "pointer";
|
var active_tool = "pointer";
|
||||||
@@ -136,14 +136,13 @@ function render_space_as_html(space, artifacts) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("error rendering space "+space._id+" as html: "+e);
|
console.error("error rendering space "+space._id+" as html: "+e);
|
||||||
}
|
}
|
||||||
|
|
||||||
var style="html, body, #space { overflow: visible !important; }\n";
|
var style="html, body, #space { overflow: visible !important; }\n";
|
||||||
style+=".wrapper { border: none !important; }\n";
|
style+=".wrapper { border: none !important; }\n";
|
||||||
|
|
||||||
h='<html>\n<head>\n<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,700,600,800,300|Montserrat:400,700|EB+Garamond|Vollkorn|Fire+Sans|Lato|Roboto|Source+Code+Pro|Ubuntu|Raleway|Playfair+Display|Crimson+Text" rel="stylesheet" type="text/css">\n<link type="text/css" rel="stylesheet" href="https://fast.fonts.net/cssapi/ee1a3484-4d98-4f9f-9f55-020a7b37f3c5.css"/>\n<link rel="stylesheet" href="/stylesheets/style.css"><style>'+style+'</style>\n</head>\n<body id="main">\n'+h+"\n</html>\n";
|
h='<html>\n<head>\n<link rel="stylesheet" href="/stylesheets/style.css"><style>'+style+'</style>\n</head>\n<body id="main">\n'+h+"\n</html>\n";
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.render_space_as_html = render_space_as_html;
|
exports.render_space_as_html = render_space_as_html;
|
||||||
|
|
||||||
|
|||||||
@@ -320,5 +320,6 @@
|
|||||||
"follow_present": "Folgen",
|
"follow_present": "Folgen",
|
||||||
"mute_present": "Entfolgen",
|
"mute_present": "Entfolgen",
|
||||||
"follow_present_help": "Wenn jemand den Space präsentiert, folgen die anderen Mitglieder automatisch der Präsentation. Mit diesem Knopf lässt sich das an- oder ausschalten.",
|
"follow_present_help": "Wenn jemand den Space präsentiert, folgen die anderen Mitglieder automatisch der Präsentation. Mit diesem Knopf lässt sich das an- oder ausschalten.",
|
||||||
"media": "Media"
|
"media": "Media",
|
||||||
}
|
"tool_edit_text": "Text bearbeiten"
|
||||||
|
}
|
||||||
@@ -322,6 +322,7 @@
|
|||||||
"follow_present": "Follow",
|
"follow_present": "Follow",
|
||||||
"mute_present": "Unfollow",
|
"mute_present": "Unfollow",
|
||||||
"follow_present_help": "If someone else is presenting this Space, the other members automatically follow the presentation. Switch following on or off with this button.",
|
"follow_present_help": "If someone else is presenting this Space, the other members automatically follow the presentation. Switch following on or off with this button.",
|
||||||
"export": "export",
|
"export": "Export",
|
||||||
"media": "Media"
|
"media": "Media",
|
||||||
}
|
"tool_edit_text": "Edit Text"
|
||||||
|
}
|
||||||
|
|||||||
328
locales/hu.js
Normal file
328
locales/hu.js
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
{
|
||||||
|
"ok": "Rendben",
|
||||||
|
"cancel": "Mégse",
|
||||||
|
"close": "Bezárás",
|
||||||
|
"open": "Megnyitás",
|
||||||
|
"folder": "Mappa",
|
||||||
|
"save": "Mentés",
|
||||||
|
"saved": "Mentve",
|
||||||
|
"created": "létrehozva",
|
||||||
|
"duplicate": "Másolás",
|
||||||
|
"delete": "Törlés",
|
||||||
|
"remove": "Eltávolítás",
|
||||||
|
"set": "készlet",
|
||||||
|
"reset": "alaphelyzet",
|
||||||
|
"thanks": "Köszönöm",
|
||||||
|
"share": "Megosztás",
|
||||||
|
"signup": "Feliratkozás",
|
||||||
|
"login": "Bejelentkezés",
|
||||||
|
"logout": "Kijelentkezés",
|
||||||
|
"email": "E-mail-cím",
|
||||||
|
"password": "Jelszó",
|
||||||
|
"width": "Szélesség",
|
||||||
|
"height": "Magasság",
|
||||||
|
"nick": "Név",
|
||||||
|
"role": "Szerepkör",
|
||||||
|
"members": "Tagok",
|
||||||
|
"actions": "Műveletek",
|
||||||
|
"or": "vagy",
|
||||||
|
"you": "Ön",
|
||||||
|
"via": "ezen keresztül:",
|
||||||
|
"by": "szerző:",
|
||||||
|
"zero": "Nulla",
|
||||||
|
"page": "Oldal:",
|
||||||
|
"new": "Új",
|
||||||
|
"copy": "Másolás",
|
||||||
|
"home": "Kezdőoldal",
|
||||||
|
"owner": "Tulajdonos",
|
||||||
|
"space": "Hely",
|
||||||
|
"second": "másodperc",
|
||||||
|
"not_found": "Nem található.",
|
||||||
|
"untitled_space": "Névtelen hely",
|
||||||
|
"untitled_folder": "Névtelen mappa",
|
||||||
|
"untitled": "névtelen",
|
||||||
|
"sure": "Biztos vagy benne?",
|
||||||
|
"specify": "Kérjük, részletezze",
|
||||||
|
"confirm": "Erősítse meg a műveletet",
|
||||||
|
"error_unknown_email": "Ez az e-mail/jelszó kombináció ismeretlen.",
|
||||||
|
"error_password_confirmation": "A megadott jelszavak nem egyeznek.",
|
||||||
|
"error_domain_blocked": "Tartománya letiltva.",
|
||||||
|
"error_user_email_already_used": "Ez az e-mail cím már használatban van.",
|
||||||
|
"support": "Spacedeck támogatás",
|
||||||
|
"offline": "Kapcsolat nélküli üzemmód. Kattintson további információkért.",
|
||||||
|
"error": "Sajnálom, de valami rosszul ment. Kérjük, lépjen kapcsolatba a support@spacedeck.com-al",
|
||||||
|
"welcome": "Üdvözöljük",
|
||||||
|
"claim": "A digitális rajztáblája.",
|
||||||
|
"trynow": "Próbálja most.",
|
||||||
|
"about": "Rólunk",
|
||||||
|
"terms": "Feltételek",
|
||||||
|
"contact": "Kapcsolat",
|
||||||
|
"privacy": "Adatvédelem",
|
||||||
|
"business_adress": "Üzleti cím",
|
||||||
|
"post_adress": "Posta cím",
|
||||||
|
"phone": "Telefon",
|
||||||
|
"ceo": "Ügyvezető igazgató",
|
||||||
|
"name": "Név",
|
||||||
|
"confirm_subject": "Spacedeck e-mail megerősítés",
|
||||||
|
"confirm_body": "Köszönjük, hogy feliratkozott a Spacedeck-re.\nKérjük, hogy kattintson az alábbi linkre az e-mail cím megerősítéséhez.\n",
|
||||||
|
"confirm_action": "Erősítse meg most",
|
||||||
|
"team_invite_membership_subject": "Csapat meghívó %-s számára",
|
||||||
|
"team_invite_membership_body": "Meghívták a(z) %s oldalra a Spacedeck-en. Kattintson a következő hivatkozásra a meghívás elfogadásához.",
|
||||||
|
"team_invite_user_body": "Meghívták a(z)%s oldalra a Spacedeck-en.\nAz ideiglenes jelszó \"%s\".\n Kérjük, kattintson a következő hivatkozásra a meghívás elfogadásához.",
|
||||||
|
"team_invite_admin_body": "%s meghívást kapott a csapatodba: %s. Az ideiglenes jelszó \"%s\".",
|
||||||
|
"team_invite_membership_acction": "Elfogad",
|
||||||
|
"team_new_member_subject": "A(z) %s új csapattagja feliratkozott",
|
||||||
|
"team_new_member_body": "%s most csatlakozott a(z) %s csoporthoz a Spacedeck-en.",
|
||||||
|
"space_invite_membership_subject": "%s meghívott %s helyre",
|
||||||
|
"space_invite_membership_body": "%s meghívta, hogy csatlakozzon a(z) %s helyre a Spacedecken. Kattintson a következő linkre a meghívás elfogadásához.",
|
||||||
|
"space_invite_membership_action": "Elfogad",
|
||||||
|
"folder_invite_membership_subject": "Hely",
|
||||||
|
"folder_invite_membership_body": "Meghívták a Spacedeck csoportjába. Kérjük, hogy kattintson a következő linkre a meghívás elfogadásához.",
|
||||||
|
"folder_invite_membership_acction": "Elfogad",
|
||||||
|
"login_google": "Bejelentkezés a Google-al",
|
||||||
|
"save_changes": "Változtatások mentése",
|
||||||
|
"upgrade": "Frissítés",
|
||||||
|
"upgrade_now": "Frissítés most",
|
||||||
|
"create_space": "Hely létrehozása",
|
||||||
|
"create_folder": "Mappa létrehozása",
|
||||||
|
"email_unconfirmed": "E-mail nincs megerősítve",
|
||||||
|
"confirmation_sent": "E-mail elküldve",
|
||||||
|
"folder_filter": "Szűrő",
|
||||||
|
"sort_by": "Rendezés",
|
||||||
|
"last_modified": "Utoljára módosítva",
|
||||||
|
"last_opened": "Utoljára nyitva",
|
||||||
|
"title": "Cím",
|
||||||
|
"edit_team": "Csapat szerkesztése",
|
||||||
|
"edit_account": "Fiók szerkesztése",
|
||||||
|
"log_out": "Kijelentkezés",
|
||||||
|
"no_spaces_yet": "Isten hozta! Itt létrehozhat helyeket és mappákat a bal felső sarokban található gombokkal.",
|
||||||
|
"new_folder_title": "Új cím a mappához",
|
||||||
|
"folder_settings": "Mappa beállításai",
|
||||||
|
"upload_cover_image": "Borító kép feltöltése",
|
||||||
|
"spacedeck_pro_ad_folders": "A Spacedeck Pro segítségével korlátlan mennyiségű helyet foglalhat el a mappákban és kezelheti az egyes mappák hozzáférési vezérléseit. Szeretne többet megtudni a Pro funkcióiról?",
|
||||||
|
"spacedeck_pro_ad_versions": "A Spacedeck Pro segítségével korlátlan verziókat menthet az egyes helyekről, hogy nyomon kövesse az előrehaladást vagy biztonságban tartsa a pillanatképeket. Szeretne többet megtudni a Pro funkcióiról?",
|
||||||
|
"spacedeck_pro_ad_pdf": "A Spacedeck Pro segítségével a helyeket éles PDF-fájlokként exportálhatja archiváláshoz, postázáshoz vagy nyomtatáshoz. Szeretne többet megtudni a Pro funkcióiról?",
|
||||||
|
"spacedeck_pro_ad_zip": "A Spacedeck Pro segítségével exportálhatja a hely tartalmát ZIP-csomagként. Szeretne többet megtudni a Pro funkcióiról?",
|
||||||
|
"spacedeck_pro_ad_colors": "A Spacedeck Pro segítségével professzionális színválasztóval keverheti össze saját színeit.",
|
||||||
|
"profile_caption": "Profil",
|
||||||
|
"upload_avatar": "Avatar feltöltése",
|
||||||
|
"uploading_avatar": "Avatar feltöltése…",
|
||||||
|
"avatar_dimensions": "Ajánlott méretek: 200 × 200 képpont.",
|
||||||
|
"profile_name": "Név",
|
||||||
|
"profile_email": "E-mail cím",
|
||||||
|
"send_again": "Küldje újra",
|
||||||
|
"confirmation_sent_long": "E-mail megerősítő hivatkozáds elküldve.Kérjük, ellenőrizze a beérkező leveleket.",
|
||||||
|
"confirmation_sent_another": "Egy másik megerősítő link elküldve.",
|
||||||
|
"confirmation_sent_dialog_text": "E-mailt küldtünk Önnek, amelyben elmagyaráztuk, hogyan erősítse meg e-mail címét.",
|
||||||
|
"payment_caption": "Fizetés",
|
||||||
|
"language_caption": "Nyelv",
|
||||||
|
"notifications_caption": "Értesítések",
|
||||||
|
"notifications_option_chat": "E-mailben értesítsen az új megjegyzésekről",
|
||||||
|
"notifications_option_spaces": "Küldjön napi összefoglalót arról, hogy mi történt a helyeim és mappáim között",
|
||||||
|
"password_caption": "Jelszó",
|
||||||
|
"current_password": "Jelenlegi jelszó",
|
||||||
|
"new_password": "Új jelszó",
|
||||||
|
"verify_password": "Jelszó megerősítése",
|
||||||
|
"change_password": "Jelszó módosítása",
|
||||||
|
"reset_password": "Jelszó visszaállítása",
|
||||||
|
"terminate_caption": "Fiók törlése",
|
||||||
|
"terminate_warning": "Ha törli a fiókját, akkor az összes hely, mappa és üzenet, beleértve az Ön összes tartalmát és a helyeiben létrehozott más embereket megsemmisül.",
|
||||||
|
"terminate_warning2": "Ezt nem lehet visszavonni.",
|
||||||
|
"terminate_reason": "Üzenet",
|
||||||
|
"terminate_reason_caption": "Segítsen nekünk a fejlesztésben, ha megosztja a lemondás okait.",
|
||||||
|
"terminate_terminate": "Leállít",
|
||||||
|
"space_blank1": "Üdvözöljük egy friss, új helyen!",
|
||||||
|
"space_blank2": "Húzza ide a fájlokat, hivatkozások beillesztése",
|
||||||
|
"space_blank3": "vagy használja az alábbi eszközöket",
|
||||||
|
"space_blank4": "hogy ezt a helyet tartalommal töltse meg.",
|
||||||
|
"draft": "Piszkozat",
|
||||||
|
"publish": "Közzététel",
|
||||||
|
"published": "Közzétett",
|
||||||
|
"save_version": "Verzió mentése",
|
||||||
|
"version_saved": "Verzió mentve",
|
||||||
|
"post": "Üzenet küldése",
|
||||||
|
"chat_invite_cta1": "Az együttműködés szórakoztató!",
|
||||||
|
"chat_invite_cta2": "Miért ne",
|
||||||
|
"chat_invite_cta3": "hívjon meg néhány embert",
|
||||||
|
"chat_invite_cta4": "Önnel dolgozni?",
|
||||||
|
"chat_message_placeholder": "Írja meg az üzenetét…",
|
||||||
|
"view": "Nézet",
|
||||||
|
"edit": "Szerkesztés",
|
||||||
|
"present": "Jelen van",
|
||||||
|
"chat": "Csevegés",
|
||||||
|
"meta": "Meta",
|
||||||
|
"tool_search": "Keresés",
|
||||||
|
"tool_upload": "Feltöltés",
|
||||||
|
"tool_text": "Szöveg",
|
||||||
|
"tool_shape": "Forma",
|
||||||
|
"tool_zones": "Zónák",
|
||||||
|
"tool_canvas": "Vászon",
|
||||||
|
"search_media": "Keresés a médiában…",
|
||||||
|
"type_here": "Írja ide",
|
||||||
|
"text_formats": "Formátumok",
|
||||||
|
"format_p": "Bekezdés",
|
||||||
|
"format_bullets": "Listajeles lista",
|
||||||
|
"format_numbers": "Számozott lista",
|
||||||
|
"format_h1": "1. címsor",
|
||||||
|
"format_h2": "2. címsor",
|
||||||
|
"format_h3": "3. címsor",
|
||||||
|
"font_size": "Betűméret",
|
||||||
|
"line_height": "Sormagasság",
|
||||||
|
"tool_align": "Igazítás",
|
||||||
|
"tool_styles": "Stílusok",
|
||||||
|
"tool_bullets": "Felsorolás",
|
||||||
|
"tool_numbers": "Számok",
|
||||||
|
"tool_font": "Betűtípus",
|
||||||
|
"color_fill": "Kitöltés",
|
||||||
|
"color_stroke": "Vonás",
|
||||||
|
"color_text": "Szöveg",
|
||||||
|
"tool_type": "Típus",
|
||||||
|
"tool_box": "Doboz",
|
||||||
|
"tool_link": "Hivatkozás",
|
||||||
|
"tool_layout": "Elrendezés",
|
||||||
|
"tool_options": "Lehetőségek",
|
||||||
|
"tool_stroke": "Vonás ",
|
||||||
|
"tool_delete": "Törlés",
|
||||||
|
"tool_lock": "Lezár",
|
||||||
|
"tool_copy": "Másol",
|
||||||
|
"stack": "Halom",
|
||||||
|
"tool_circle": "Kör",
|
||||||
|
"tool_hexagon": "Hatszög",
|
||||||
|
"tool_square": "Négyzet",
|
||||||
|
"tool_diamond": "Gyémánt",
|
||||||
|
"tool_bubble": "Buborék",
|
||||||
|
"tool_cloud": "Felhő",
|
||||||
|
"tool_burst": "Sorozatfelvétel",
|
||||||
|
"tool_star": "Csillag",
|
||||||
|
"tool_heart": "Szív",
|
||||||
|
"tool_scribble": "Irkál",
|
||||||
|
"tool_line": "Vonal",
|
||||||
|
"tool_arrow": "Nyíl",
|
||||||
|
"search_media_placeholder": "Keresés az internetes médiában…",
|
||||||
|
"add_zone": "Új zóna",
|
||||||
|
"palette": "Paletta",
|
||||||
|
"picker": "Választó",
|
||||||
|
"background_image_caption": "Kép",
|
||||||
|
"background_color_caption": "Szín",
|
||||||
|
"upload_background_caption": "Kattintson egy háttérkép feltöltéséhez",
|
||||||
|
"upload_background": "Háttér feltöltése",
|
||||||
|
"access_caption": "Hozzáférés",
|
||||||
|
"versions_caption": "Verziók",
|
||||||
|
"info_caption": "Információ",
|
||||||
|
"mode_private": "Magán: Csak a tagok tekinthetik meg és szerkeszthetik",
|
||||||
|
"mode_public": "Nyilvános: A hivatkozás birtokában bárki megtekintheti",
|
||||||
|
"invite_collaborators": "Hívjon meg együttműködőket",
|
||||||
|
"revoke_access": "Hozzáférés visszavonása",
|
||||||
|
"invite": "Meghívók küldése",
|
||||||
|
"invitee_email_address": "Az új tag e-mail címe",
|
||||||
|
"optional_message": "Választható üzenet",
|
||||||
|
"role_viewer": "Néző",
|
||||||
|
"role_editor": "Szerkesztő",
|
||||||
|
"role_admin": "Adminisztrátor",
|
||||||
|
"new_space_title": "Új cím a helynek",
|
||||||
|
"team": "Csoport",
|
||||||
|
"search": "Keresés",
|
||||||
|
"search_no_results": "keresés_nincsenek_eredmények",
|
||||||
|
"search_clear": "keresés_törlés",
|
||||||
|
"rename": "Átnevezés",
|
||||||
|
"mobile": "mobil",
|
||||||
|
"image": "kép",
|
||||||
|
"tool_filter": "szűrő",
|
||||||
|
"canel": "mégse",
|
||||||
|
"invite_membership_action": "meghívni_tagságot",
|
||||||
|
"viewer": "néző",
|
||||||
|
"editor": "szerkesztő",
|
||||||
|
"admin": "adminisztrátor ",
|
||||||
|
"logging_in": "bejelentkezés",
|
||||||
|
"password_confirmation": "Jelszó megerősítése",
|
||||||
|
"confirm_again": "E-mailt küldtünk Önnek, amelyben elmagyaráztuk, hogyan erősítse meg e-mail címét.",
|
||||||
|
"confirmed": "Fiókját sikeresen megerősítettük. Köszönjük.",
|
||||||
|
"signing_up": "Feliratkozás",
|
||||||
|
"password_check_inbox": "Kérjük, ellenőrizze a beérkező leveleket",
|
||||||
|
"new_space": "Új hely",
|
||||||
|
"tool_more": "Több",
|
||||||
|
"what_is_your_name": "Üdvözöljük a %s oldalon! Kérjük, hogy válasszon egy felhasználónevet.",
|
||||||
|
"lang": "hu",
|
||||||
|
"landing_title": "Rajztáblája az interneten.",
|
||||||
|
"landing_claim": "A Spacedeck segítségével könnyedén kombinálhat mindenféle típusú médiát a virtuális rajztáblákon: szöveges jegyzeteket, fotókat, internetes linkeket, sőt videókat és hangfelvételeket.",
|
||||||
|
"landing_example": "Az emberek a Spacedeck segítségével szervezik ötleteiket, csoportokban, hogy egy pillantással teljes projekteket láthassanak vagy iskolákban és egyetemeken gazdagabb, összekapcsolt tanulási tapasztalatokkal.",
|
||||||
|
"spaces": "Saját helyek",
|
||||||
|
"access_editor_link": "Azonnali hivatkozás szerkesztése",
|
||||||
|
"access_editor_link_desc": "Adja meg ezt a hivatkozást mindenkinek, akinek képesnek kell lennie a hely azonnali szerkesztésére, nincs szükség fiókra:",
|
||||||
|
"access_editor_link_desc_slug": "Ez a hivatkozás tartalmazza a hely nevét is.",
|
||||||
|
"access_anonymous_edit_blocking": "Névtelen szerkesztők csak a saját tételeiket változtathatják meg",
|
||||||
|
"access_current_members": "Current Members",
|
||||||
|
"access_new_members": "Új tagok meghívása",
|
||||||
|
"access_no_members": "A Hely tagjai itt jelennek meg.",
|
||||||
|
"comments": "hozzászólások",
|
||||||
|
"landing_customers": "Ezrek bíznak benne.",
|
||||||
|
"landing_features_title": "Gyerekjáték használni.",
|
||||||
|
"landing_features_text": "Az új Spacedeck 5 korszerű, gyönyörű felhasználói felülettel rendelkezik, amely minden eddiginél könnyebbé és szórakoztatóbbá teszi munkáját - miközben még erőteljesebb funkciókat kínál:",
|
||||||
|
"landing_features_1": "<b>Fogd és vidd</b> képeket, videókat és hangokat a számítógépről vagy az internetről",
|
||||||
|
"landing_features_2": "<b>Szöveg írása és formázása</b> de a betűtípusok, a színek és a stílus teljes ellenőrzésével",
|
||||||
|
"landing_features_3": "<b>Rajzoljon, kommentáljon és jelöljön ki</b> a mellékelt grafikus alakzatokkal",
|
||||||
|
"landing_features_4": "</b>Kapcsolja tábláját <b>nagyító prezentációvá</b>",
|
||||||
|
"landing_features_5": "<b>Együttműködés és csevegés</b> valós időben csoport társaival, diákjaival vagy barátaival. ",
|
||||||
|
"landing_features_6": "<b>Helyek megosztása</b> az interneten vagy e-mailben",
|
||||||
|
"landing_features_7": "<b>Exportálja munkáját</b> nyomtatható PDF vagy ZIP formátumban",
|
||||||
|
"landing_pricing": "Hihetetlenül megfizethető.",
|
||||||
|
"landing_pricing_lite": "Ingyenes/személyes használat",
|
||||||
|
"landing_pricing_lite_text": "Az alap, átfogó verzió a képek gyűjtésére és a jegyzetek vezetésére.",
|
||||||
|
"landing_pricing_pro_features_list": "<ul><li>Korlátlan helyek</li><li>Mappa struktúrák</li><li>PDF és ZIP exportálás</li><li>Nincs vízjel</li><li>Egyéni hátterek</li><li>Tevékenység előzmények</li><li>20 GB tárhely</li><ul>",
|
||||||
|
"landing_pricing_pro": "€4,90/Felhasználó/hónap. <br><small>or 49,90/Felhasználó /év</small>",
|
||||||
|
"landing_pricing_pro_text": "Turbófeltöltve minden elvárt erővel.",
|
||||||
|
"landing_pricing_pro_features": "Turbófeltöltve minden elvárt erővel.",
|
||||||
|
"welcome_subject": "Üdvözöljük a Spacedeck-en",
|
||||||
|
"welcome_body": "Üdvözlet!\nKöszönjük, hogy feliratkozott a Spacedeck webhelyre.<br>Reméljük, hogy élvezni fogja a Helyek szolgáltatásban való munkát.<br>Ne feledje, hogy fiókjában korlátlan számú munkatárs található. Nyugodtan ossza meg helyeit barátaival és kollégáival a világ minden tájáról.",
|
||||||
|
"invite_emails": "E-mail címek (vesszővel elválasztva)",
|
||||||
|
"history_recently_updated": "Mostanában frissítve",
|
||||||
|
"history_recently_empty": "Még nem történt semmi.",
|
||||||
|
"parent_folder": "szülő_mappa",
|
||||||
|
"created_by": "Készítette",
|
||||||
|
"last_updated": "Utolsó frissítés",
|
||||||
|
"feedback_sent": "Köszönjük a visszajelzését!",
|
||||||
|
"role_member": "Tag",
|
||||||
|
"team_invite_membership_action": "Meghívás elfogadása",
|
||||||
|
"space_message_subject": "Új üzenet a következő helyen % s",
|
||||||
|
"space_message_body": "%s ezt írta %s-ban: \n",
|
||||||
|
"pro_ad_history_headline": "A Spacedeck Pro verzióra való frissítéskor itt láthatja az összes (megosztott) hely legújabb frissítésének előzményeit.",
|
||||||
|
"password_reset_subject": "Spacedeck jelszavának visszaállítása",
|
||||||
|
"password_reset_body": "Ön kérte a Spacedeck jelszavának visszaállítását.\n Kérjük, hogy kattintson a következő hivatkozásra az új jelszó beállításához.",
|
||||||
|
"password_reset_action": "Visszaállítás most",
|
||||||
|
"was_offline": "A Spacedeck-hez való kapcsolat megszakadt. Ha nem mentett munkája van, kérjük, tartsa nyitva ezt a böngészőfület a kapcsolat helyreállításáig, majd érintse meg újra a nem mentett objektumokat.",
|
||||||
|
"subscription_failed_user_subject": "Probléma a Spacedeck fizetésével",
|
||||||
|
"subscription_failed_user_body": "Sajnos nem tudtuk feldolgozni a fizetési módját. A fiók beállításokban könnyedén létrehozhat egy új fizetési módot, beleértve a PayPalt is.",
|
||||||
|
"subscription_failed_team_subject": "Probléma a Spacedeck fizetésével",
|
||||||
|
"subscription_failed_team_body": "Sajnos nem tudtuk feldolgozni a fizetési módját a Team-fiókjához. Kérjük, javítsa ki fizetési módját a lehető leghamarabb.",
|
||||||
|
"team_name": "Csoport név",
|
||||||
|
"subdomain": "altartomány",
|
||||||
|
"team_adresses": "E-mail címek",
|
||||||
|
"add": "Hozzáadás",
|
||||||
|
"invited": "meghívott",
|
||||||
|
"duplicate_destination": "Melyik mappába kívánja másolni ezt a helyet?",
|
||||||
|
"duplicate_confirm": "A(z)% s másolat% s-ra?",
|
||||||
|
"duplicate_success": "% s másolva lett% s-ra.",
|
||||||
|
"goto_space": "Lépjen a(z)% s helyre",
|
||||||
|
"goto_folder": "Lépjen a(z)% s mappába",
|
||||||
|
"stay_here": "Maradjon itt",
|
||||||
|
"sharing": "Megosztás",
|
||||||
|
"list": "Lista exportálása",
|
||||||
|
"link": "Hivatkozás",
|
||||||
|
"download_space": "Hely letöltése ",
|
||||||
|
"download_as_pdf": "Hely letöltése PDF formátumban",
|
||||||
|
"type": "Típus",
|
||||||
|
"download": "Letöltés",
|
||||||
|
"Previous Zone": "Előző zóna",
|
||||||
|
"Next Zone": "Következő zóna",
|
||||||
|
"promote": "Népszerűsít",
|
||||||
|
"demote": "Lefokoz",
|
||||||
|
"more": "Több",
|
||||||
|
"lock": "Lezár",
|
||||||
|
"unlock": "Felold",
|
||||||
|
"follow_present": "Követ",
|
||||||
|
"mute_present": "Követés megszüntetése",
|
||||||
|
"follow_present_help": "Ha valaki más mutatja be ezt a helyet, a többi tag automatikusan követi az előadást. Ezzel a gombbal kapcsolhatja be vagy ki a követést.",
|
||||||
|
"export": "Exportál",
|
||||||
|
"media": "Média",
|
||||||
|
"tool_edit_text": "Szöveg szerkesztése"
|
||||||
|
}
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
"tool_bullets": "Bullets",
|
"tool_bullets": "Bullets",
|
||||||
"tool_numbers": "Nombres",
|
"tool_numbers": "Nombres",
|
||||||
"color_fill": "Fill",
|
"color_fill": "Fill",
|
||||||
"tool_font": "Font",
|
"tool_font": "Poliça",
|
||||||
"color_stroke": "Traçat",
|
"color_stroke": "Traçat",
|
||||||
"color_text": "Tèxte",
|
"color_text": "Tèxte",
|
||||||
"tool_type": "Tipe",
|
"tool_type": "Tipe",
|
||||||
@@ -244,7 +244,7 @@
|
|||||||
"what_is_your_name": "La benvenguda a %s ! Mercés de causir un escais-nom.",
|
"what_is_your_name": "La benvenguda a %s ! Mercés de causir un escais-nom.",
|
||||||
"lang": "en",
|
"lang": "en",
|
||||||
"landing_title": "Vòstre tablèu blanc sul Web.",
|
"landing_title": "Vòstre tablèu blanc sul Web.",
|
||||||
"landing_claim": "Spacedeck vos permet de facilament combinar quin que siá tipe de mèdias sus un tablèu virtual : tèxte, nòtas, ligams web, amai vidèos e enregistraments àudio. ",
|
"landing_claim": "Spacedeck vos permet de facilament combinar quin tipe que siá de mèdias sus un tablèu virtual : tèxte, nòtas, ligams web, amai vidèos e enregistraments àudio. ",
|
||||||
"landing_example": "Lo monde utiliza Spacedeck per organizar lors idèas, en equipa per veire totes los projèctes en una ulhada, a l’escòla e a l’universitat pels mai rics, experiéncia d’aprendissatge connectat.",
|
"landing_example": "Lo monde utiliza Spacedeck per organizar lors idèas, en equipa per veire totes los projèctes en una ulhada, a l’escòla e a l’universitat pels mai rics, experiéncia d’aprendissatge connectat.",
|
||||||
"spaces": "Mos espacis",
|
"spaces": "Mos espacis",
|
||||||
"access_editor_link": "Ligam de modificacion dirècta",
|
"access_editor_link": "Ligam de modificacion dirècta",
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
"access_anonymous_edit_blocking": "Los convidats pòdon pas modificar los elements qu’an creats.",
|
"access_anonymous_edit_blocking": "Los convidats pòdon pas modificar los elements qu’an creats.",
|
||||||
"access_current_members": "Membres actuals",
|
"access_current_members": "Membres actuals",
|
||||||
"access_new_members": "Convidar de novèls membres",
|
"access_new_members": "Convidar de novèls membres",
|
||||||
"access_no_members": "Los membres d’aqueste Espacii apreissaràn aquí.",
|
"access_no_members": "Los membres d’aqueste Espaci apareisseràn aquí.",
|
||||||
"comments": "comentaris",
|
"comments": "comentaris",
|
||||||
"landing_customers": "La fisança de milièr de personas.",
|
"landing_customers": "La fisança de milièr de personas.",
|
||||||
"landing_features_title": "Un jòc d'enfants d’utilizar.",
|
"landing_features_title": "Un jòc d'enfants d’utilizar.",
|
||||||
@@ -309,7 +309,7 @@
|
|||||||
"list": "lista",
|
"list": "lista",
|
||||||
"link": "Ligam",
|
"link": "Ligam",
|
||||||
"download_space": "Telecargar espaci",
|
"download_space": "Telecargar espaci",
|
||||||
"download_space_as_pdf": "Telecargar espaci PDF",
|
"download_space_as_pdf": "Telecargar espaci coma PDF",
|
||||||
"type": "Tipe",
|
"type": "Tipe",
|
||||||
"download": "Telecargar",
|
"download": "Telecargar",
|
||||||
"Previous Zone": "Zòna precedenta",
|
"Previous Zone": "Zòna precedenta",
|
||||||
@@ -321,7 +321,7 @@
|
|||||||
"unlock": "Desverrolhar",
|
"unlock": "Desverrolhar",
|
||||||
"follow_present": "Seguir",
|
"follow_present": "Seguir",
|
||||||
"mute_present": "Quitar de seguir",
|
"mute_present": "Quitar de seguir",
|
||||||
"follow_present_help": "follow_present_help",
|
"follow_present_help": "Se qualqu’un mai presenta aqueste espaci, los demai membres seguiràn automaticament la presentacion. Basculatz l’abonament a la presentacion amb aqueste boton.",
|
||||||
"export": "exportar",
|
"export": "exportar",
|
||||||
"media": "Media"
|
"media": "Mèdia"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const db = require('../models/db');
|
const db = require("../models/db");
|
||||||
var config = require('config');
|
var config = require("config");
|
||||||
|
|
||||||
module.exports = (req, res, next) => {
|
module.exports = (req, res, next) => {
|
||||||
|
|
||||||
// authentication via API token
|
// authentication via API token
|
||||||
const api_token = req.headers["x-spacedeck-api-token"];
|
const api_token = req.headers["x-spacedeck-api-token"];
|
||||||
|
|
||||||
if (api_token && api_token.length>7) {
|
if (api_token && api_token.length > 7) {
|
||||||
db.User.findOne({where: {api_token: api_token}}).then(user => {
|
db.User.findOne({ where: { api_token: api_token } }).then((user) => {
|
||||||
req.user = user;
|
if (user) {
|
||||||
next();
|
req.user = user;
|
||||||
}).error(err => {
|
next();
|
||||||
res.status(403).json({
|
} else {
|
||||||
"error": "invalid_api-token"
|
res.status(403).json({
|
||||||
});
|
error: "invalid_api-token",
|
||||||
next();
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -26,28 +26,29 @@ module.exports = (req, res, next) => {
|
|||||||
const token = req.cookies["sdsession"];
|
const token = req.cookies["sdsession"];
|
||||||
|
|
||||||
if (token && token != "null" && token != null) {
|
if (token && token != "null" && token != null) {
|
||||||
db.Session.findOne({where: {token: token}})
|
db.Session.findOne({ where: { token: token } })
|
||||||
.then(session => {
|
.then((session) => {
|
||||||
if (!session) {
|
if (!session) {
|
||||||
// session not found
|
// session not found
|
||||||
next();
|
next();
|
||||||
}
|
} else
|
||||||
else db.User.findOne({where: {_id: session.user_id}})
|
db.User.findOne({ where: { _id: session.user_id } }).then((user) => {
|
||||||
.then(user => {
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : req.headers.hostname;
|
var domain =
|
||||||
res.clearCookie('sdsession', { domain: domain });
|
process.env.NODE_ENV == "production"
|
||||||
|
? new URL(config.get("endpoint")).hostname
|
||||||
|
: req.headers.hostname;
|
||||||
|
res.clearCookie("sdsession", { domain: domain });
|
||||||
|
|
||||||
if (req.accepts("text/html")) {
|
if (req.accepts("text/html")) {
|
||||||
res.send("Please clear your cookies and try again.");
|
res.send("Please clear your cookies and try again.");
|
||||||
} else if (req.accepts('application/json')) {
|
} else if (req.accepts("application/json")) {
|
||||||
res.status(403).json({
|
res.status(403).json({
|
||||||
"error": "token_not_found"
|
error: "token_not_found",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.send("Please clear your cookies and try again.");
|
res.send("Please clear your cookies and try again.");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
req["token"] = token;
|
req["token"] = token;
|
||||||
req["user"] = user;
|
req["user"] = user;
|
||||||
@@ -55,11 +56,11 @@ module.exports = (req, res, next) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.error(err => {
|
.error((err) => {
|
||||||
console.error("Session resolve error",err);
|
console.error("Session resolve error", err);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ module.exports = (req, res, next) => {
|
|||||||
// space is private
|
// space is private
|
||||||
|
|
||||||
// special permission for screenshot/pdf export from backend
|
// special permission for screenshot/pdf export from backend
|
||||||
if (req.query['api_token'] && req.query['api_token'] == config.get('phantom_api_secret')) {
|
if (req.query['api_token'] && req.query['api_token'] == config.get('export_api_secret')) {
|
||||||
finalizeReq(space, "viewer");
|
finalizeReq(space, "viewer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
40
models/db.js
40
models/db.js
@@ -6,24 +6,28 @@ function sequel_log(a,b,c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Sequelize = require('sequelize');
|
const Sequelize = require('sequelize');
|
||||||
const sequelize = new Sequelize('database', 'username', 'password', {
|
const sequelize = new Sequelize(
|
||||||
host: 'localhost',
|
config.get('storage_database'),
|
||||||
dialect: 'sqlite',
|
config.get('storage_username'),
|
||||||
|
config.get('storage_password'),
|
||||||
pool: {
|
{
|
||||||
max: 5,
|
host: config.get('storage_host'),
|
||||||
min: 0,
|
dialect: config.get('storage_dialect'),
|
||||||
acquire: 30000,
|
pool: {
|
||||||
idle: 10000
|
max: 5,
|
||||||
},
|
min: 0,
|
||||||
|
acquire: 30000,
|
||||||
// SQLite only
|
idle: 10000
|
||||||
storage: config.get('storage_local_db'),
|
},
|
||||||
logging: sequel_log,
|
logging: config.has('db_logs_disabled') ? false : sequel_log,
|
||||||
|
// http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
|
||||||
// http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
|
operatorsAliases: false,
|
||||||
operatorsAliases: false
|
// SQLite only
|
||||||
});
|
storage: config.get('storage_local_db')
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// https://github.com/sequelize/sequelize/issues/8019#issuecomment-384316346
|
||||||
|
Sequelize.postgres.DECIMAL.parse = function (value) { return parseFloat(value); };
|
||||||
|
|
||||||
var User;
|
var User;
|
||||||
var Session;
|
var Session;
|
||||||
|
|||||||
7541
package-lock.json
generated
Normal file
7541
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@@ -3,7 +3,9 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node spacedeck.js"
|
"start": "node spacedeck.js",
|
||||||
|
"dev": "nodemon spacedeck.js",
|
||||||
|
"styles": "gulp styles"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
@@ -13,6 +15,7 @@
|
|||||||
"async": "2.3.0",
|
"async": "2.3.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
|
"chargebee": "2.6.5",
|
||||||
"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",
|
||||||
@@ -22,33 +25,35 @@
|
|||||||
"file-type": "^7.6.0",
|
"file-type": "^7.6.0",
|
||||||
"glob": "7.1.1",
|
"glob": "7.1.1",
|
||||||
"gm": "^1.23.1",
|
"gm": "^1.23.1",
|
||||||
"gulp": "^4.0.2",
|
|
||||||
"gulp-concat": "^2.6.1",
|
|
||||||
"gulp-sass": "^4.0.2",
|
|
||||||
"helmet": "^3.5.0",
|
"helmet": "^3.5.0",
|
||||||
"i18n-2": "0.6.3",
|
"i18n-2": "0.6.3",
|
||||||
"log-timestamp": "latest",
|
"log-timestamp": "latest",
|
||||||
"mock-aws-s3": "^2.6.0",
|
"mock-aws-s3": "^4.0.2",
|
||||||
"moment": "^2.19.3",
|
"moment": "^2.19.3",
|
||||||
"morgan": "^1.9.1",
|
"morgan": "^1.9.1",
|
||||||
"node-phantom-simple": "2.2.4",
|
"nodemailer": "^6.6.0",
|
||||||
"node-server-screenshot": "^0.2.1",
|
"puppeteer": "8.0.0",
|
||||||
"nodemailer": "^4.6.7",
|
|
||||||
"phantomjs-prebuilt": "^2.1.16",
|
|
||||||
"read-chunk": "^2.1.0",
|
"read-chunk": "^2.1.0",
|
||||||
"request": "^2.88.0",
|
"request": "^2.88.0",
|
||||||
"sanitize-html": "^1.11.1",
|
"sanitize-html": "^2.3.3",
|
||||||
"sequelize": "^4.37.6",
|
"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": "^1.1.0",
|
"slug": "^1.1.0",
|
||||||
"sqlite3": "^4.0.0",
|
"sqlite3": "^4.2.0",
|
||||||
"umzug": "^2.1.0",
|
"umzug": "^2.1.0",
|
||||||
"underscore": "1.8.3",
|
"underscore": "^1.13.1",
|
||||||
"uuid": "^3.2.1",
|
"uuid": "^3.2.1",
|
||||||
"validator": "7.0.0",
|
"validator": "7.0.0",
|
||||||
"ws": "3.3.1"
|
"ws": "3.3.1"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"gulp-clean-css": "^4.3.0",
|
||||||
|
"gulp-concat": "^2.6.1",
|
||||||
|
"gulp-sass": "^4.0.2",
|
||||||
|
"nodemon": "^2.0.6"
|
||||||
|
},
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"description": "",
|
"description": "",
|
||||||
"directories": {},
|
"directories": {},
|
||||||
|
|||||||
@@ -52,9 +52,18 @@ function setup_directives() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var play_func = function() {
|
var play_func = function() {
|
||||||
video.play();
|
var playPromise = video.play();
|
||||||
player_state = "playing";
|
if (playPromise !== undefined) {
|
||||||
update_view();
|
playPromise.then(_ => {
|
||||||
|
// Automatic playback started!
|
||||||
|
player_state = "playing";
|
||||||
|
update_view();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
// Auto-play was prevented
|
||||||
|
// Show paused UI.
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pause_func = function() {
|
var pause_func = function() {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ var SpacedeckSections = {
|
|||||||
data: {
|
data: {
|
||||||
MAX_COLUMNS: 20,
|
MAX_COLUMNS: 20,
|
||||||
|
|
||||||
|
isShift: false,
|
||||||
|
|
||||||
redo_stack: [],
|
redo_stack: [],
|
||||||
undo_stack: [],
|
undo_stack: [],
|
||||||
|
|
||||||
@@ -62,15 +64,15 @@ var SpacedeckSections = {
|
|||||||
|
|
||||||
active_style: {
|
active_style: {
|
||||||
border_radius: 0,
|
border_radius: 0,
|
||||||
stroke: 0,
|
stroke: 2,
|
||||||
font_family: "Inter",
|
font_family: "Inter",
|
||||||
font_size: 36,
|
font_size: 36,
|
||||||
line_height: 1.5,
|
line_height: 1.5,
|
||||||
letter_spacing: 0,
|
letter_spacing: 0,
|
||||||
|
|
||||||
stroke_color: "#000000",
|
stroke_color: ENV.options.default_stroke_color ? ENV.options.default_stroke_color : "#000000",
|
||||||
fill_color: "#00000000",
|
fill_color: ENV.options.default_fill_color ? ENV.options.default_fill_color : "#000000",
|
||||||
text_color: "#000000",
|
text_color: ENV.options.default_text_color ? ENV.options.default_text_color : "#000000",
|
||||||
background_color: "#ffffff",
|
background_color: "#ffffff",
|
||||||
|
|
||||||
padding: 0,
|
padding: 0,
|
||||||
@@ -109,7 +111,7 @@ var SpacedeckSections = {
|
|||||||
color_picker_hue: 127,
|
color_picker_hue: 127,
|
||||||
color_picker_opacity: 255,
|
color_picker_opacity: 255,
|
||||||
|
|
||||||
swatches: [
|
swatches: ENV.options.swatches ? ENV.options.swatches : [
|
||||||
{id:1, hex:"#ff00ff"},
|
{id:1, hex:"#ff00ff"},
|
||||||
{id:2, hex:"#ffff00"},
|
{id:2, hex:"#ffff00"},
|
||||||
{id:3, hex:"#00ffff"},
|
{id:3, hex:"#00ffff"},
|
||||||
@@ -133,18 +135,7 @@ var SpacedeckSections = {
|
|||||||
{id:26, hex:"#d55c4b"},
|
{id:26, hex:"#d55c4b"},
|
||||||
{id:27, hex:"#6f4021"},
|
{id:27, hex:"#6f4021"},
|
||||||
{id:29, hex:"#95a5a6"},
|
{id:29, hex:"#95a5a6"},
|
||||||
{id:30, hex:"rgba(0,0,0,0)"},
|
{id:30, hex:"rgba(0,0,0,0)"}
|
||||||
],
|
|
||||||
|
|
||||||
swatches_text: [
|
|
||||||
{id:1, hex:"#9b59b6"},
|
|
||||||
{id:2, hex:"#3498db"},
|
|
||||||
{id:3, hex:"#2ecc71"},
|
|
||||||
{id:4, hex:"#f1c40f"},
|
|
||||||
{id:5, hex:"#e67e22"},
|
|
||||||
{id:6, hex:"#d55c4b"},
|
|
||||||
{id:8, hex:"#ffffff"},
|
|
||||||
{id:10, hex:"#252525"},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
fonts: [
|
fonts: [
|
||||||
@@ -182,7 +173,8 @@ var SpacedeckSections = {
|
|||||||
toolbar_props_in: false,
|
toolbar_props_in: false,
|
||||||
toolbar_artifacts_x: "-1000px",
|
toolbar_artifacts_x: "-1000px",
|
||||||
toolbar_artifacts_y: "-1000px",
|
toolbar_artifacts_y: "-1000px",
|
||||||
toolbar_artifacts_in: true
|
toolbar_artifacts_in: true,
|
||||||
|
toolbar_lock_in: false
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -216,7 +208,9 @@ var SpacedeckSections = {
|
|||||||
Mousetrap.bind('shift+left', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(-10,0,evt);}) }.bind(this));
|
Mousetrap.bind('shift+left', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(-10,0,evt);}) }.bind(this));
|
||||||
Mousetrap.bind('shift+right', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(10,0,evt);}) }.bind(this));
|
Mousetrap.bind('shift+right', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(10,0,evt);}) }.bind(this));
|
||||||
Mousetrap.bind('space', function(evt) { this.activate_pan_tool(evt); }.bind(this));
|
Mousetrap.bind('space', function(evt) { this.activate_pan_tool(evt); }.bind(this));
|
||||||
|
Mousetrap.bind(['shift'], function(evt) { this.isShift = true; }.bind(this), 'keydown');
|
||||||
|
Mousetrap.bind(['shift'], function(evt) { this.isShift = false; }.bind(this), 'keyup');
|
||||||
|
Mousetrap.bind('shift+up', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(0,-10,evt);}) }.bind(this));
|
||||||
$(document).bind("beforecopy", this.handle_onbeforecopy.bind(this));
|
$(document).bind("beforecopy", this.handle_onbeforecopy.bind(this));
|
||||||
$(window).bind("beforeunload", this.handle_onunload.bind(this));
|
$(window).bind("beforeunload", this.handle_onunload.bind(this));
|
||||||
$(window).bind("resize", this.handle_window_resize.bind(this));
|
$(window).bind("resize", this.handle_window_resize.bind(this));
|
||||||
@@ -848,7 +842,7 @@ var SpacedeckSections = {
|
|||||||
if (!a) return false;
|
if (!a) return false;
|
||||||
if (!this.active_space) return false;
|
if (!this.active_space) return false;
|
||||||
|
|
||||||
if (this.active_space_role=="viewer" || (a.locked && this.active_space_role!="admin")) {
|
if (this.active_space_role=="viewer" || (a.locked && this.active_space_role=="viewer")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1018,8 +1012,7 @@ var SpacedeckSections = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
update_selection_metrics: function(arts) {
|
update_selection_metrics: function(arts, temporary) {
|
||||||
|
|
||||||
if (this.active_tool == "scribble") {
|
if (this.active_tool == "scribble") {
|
||||||
this.selection_metrics.count = 1;
|
this.selection_metrics.count = 1;
|
||||||
return;
|
return;
|
||||||
@@ -1052,8 +1045,6 @@ var SpacedeckSections = {
|
|||||||
// FIXME make sure that menus fit in window
|
// FIXME make sure that menus fit in window
|
||||||
this.toolbar_props_x = pp.x+"px";
|
this.toolbar_props_x = pp.x+"px";
|
||||||
this.toolbar_props_y = pp.y+"px";
|
this.toolbar_props_y = pp.y+"px";
|
||||||
|
|
||||||
//this.hide_toolbar_artifacts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selection_metrics.x1 = sr.x1;
|
this.selection_metrics.x1 = sr.x1;
|
||||||
@@ -1068,24 +1059,26 @@ var SpacedeckSections = {
|
|||||||
|
|
||||||
if (!arts) arts = this.selected_artifacts();
|
if (!arts) arts = this.selected_artifacts();
|
||||||
|
|
||||||
this.first_selected_artifact = arts[0];
|
if (!temporary) {
|
||||||
this.selection_metrics.count=arts.length;
|
this.first_selected_artifact = arts[0];
|
||||||
this.selection_metrics.scribble_selection = false;
|
this.selection_metrics.count=arts.length;
|
||||||
if (arts.length == 1 && arts[0].mime == "x-spacedeck/vector") {
|
this.selection_metrics.scribble_selection = false;
|
||||||
if (arts[0].shape == "scribble") {
|
if (arts.length == 1 && arts[0].mime == "x-spacedeck/vector") {
|
||||||
this.selection_metrics.scribble_selection = true;
|
if (arts[0].shape == "scribble") {
|
||||||
|
this.selection_metrics.scribble_selection = true;
|
||||||
|
}
|
||||||
|
this.selection_metrics.vector_points = arts[0].control_points;
|
||||||
|
this.selection_metrics.vector_selection = true;
|
||||||
|
} else {
|
||||||
|
this.selection_metrics.vector_points = [{},{}];
|
||||||
|
this.selection_metrics.vector_selection = false;
|
||||||
|
}
|
||||||
|
this.selection_metrics.has_link=false;
|
||||||
|
this.insert_link_url="";
|
||||||
|
if (arts.length == 1 && arts[0].meta && arts[0].meta.link_uri && arts[0].meta.link_uri.length>0) {
|
||||||
|
this.selection_metrics.has_link=true;
|
||||||
|
this.insert_link_url = arts[0].meta.link_uri;
|
||||||
}
|
}
|
||||||
this.selection_metrics.vector_points = arts[0].control_points;
|
|
||||||
this.selection_metrics.vector_selection = true;
|
|
||||||
} else {
|
|
||||||
this.selection_metrics.vector_points = [{},{}];
|
|
||||||
this.selection_metrics.vector_selection = false;
|
|
||||||
}
|
|
||||||
this.selection_metrics.has_link=false;
|
|
||||||
this.insert_link_url="";
|
|
||||||
if (arts.length == 1 && arts[0].meta && arts[0].meta.link_uri && arts[0].meta.link_uri.length>0) {
|
|
||||||
this.selection_metrics.has_link=true;
|
|
||||||
this.insert_link_url = arts[0].meta.link_uri;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1367,7 +1360,7 @@ var SpacedeckSections = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset_stroke: function() {
|
reset_stroke: function() {
|
||||||
this.active_style.stroke = 0;
|
this.active_style.stroke = 2;
|
||||||
this.active_style.border_radius = 0;
|
this.active_style.border_radius = 0;
|
||||||
this.active_style.stroke_style = "solid";
|
this.active_style.stroke_style = "solid";
|
||||||
},
|
},
|
||||||
@@ -1435,13 +1428,13 @@ var SpacedeckSections = {
|
|||||||
this.color_picker_rgb = rgb_to_hex(rgba.r,rgba.g,rgba.b);
|
this.color_picker_rgb = rgb_to_hex(rgba.r,rgba.g,rgba.b);
|
||||||
},
|
},
|
||||||
|
|
||||||
update_selected_artifacts: function(change_func, override_locked) {
|
update_selected_artifacts: function(change_func, override_locked, temporary) {
|
||||||
var artifacts = this.selected_artifacts(!override_locked);
|
var artifacts = this.selected_artifacts(!override_locked);
|
||||||
|
|
||||||
if (!artifacts.length) return;
|
if (!artifacts.length) return;
|
||||||
|
|
||||||
this.update_artifacts(artifacts, change_func);
|
this.update_artifacts(artifacts, change_func);
|
||||||
this.update_selection_metrics();
|
this.update_selection_metrics(null, temporary||false);
|
||||||
},
|
},
|
||||||
|
|
||||||
nudge_selected_artifacts: function(dx, dy, event) {
|
nudge_selected_artifacts: function(dx, dy, event) {
|
||||||
@@ -1725,7 +1718,7 @@ var SpacedeckSections = {
|
|||||||
h: h,
|
h: h,
|
||||||
stroke_color: this.active_style.stroke_color,
|
stroke_color: this.active_style.stroke_color,
|
||||||
text_color: this.active_style.text_color,
|
text_color: this.active_style.text_color,
|
||||||
stroke: 0,
|
stroke: this.active_style.stroke,
|
||||||
fill_color: this.active_style.fill_color,
|
fill_color: this.active_style.fill_color,
|
||||||
shape: shape_type,
|
shape: shape_type,
|
||||||
valign: "middle",
|
valign: "middle",
|
||||||
@@ -1922,10 +1915,7 @@ var SpacedeckSections = {
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
delayed_edit_artifact: function(evt) {
|
delayed_edit_artifact: function() {
|
||||||
evt.stopPropagation();
|
|
||||||
evt.preventDefault();
|
|
||||||
|
|
||||||
var a = this.selected_artifacts()[0];
|
var a = this.selected_artifacts()[0];
|
||||||
|
|
||||||
var el = $("#ios-focuser-"+a._id);
|
var el = $("#ios-focuser-"+a._id);
|
||||||
@@ -2086,8 +2076,6 @@ 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);
|
||||||
|
|
||||||
@@ -2308,17 +2296,19 @@ var SpacedeckSections = {
|
|||||||
for (var i=0; i<parsed.length; i++) {
|
for (var i=0; i<parsed.length; i++) {
|
||||||
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(!this.isShift) {
|
||||||
var w = parsed[i].w;
|
if (parsed.length==1) {
|
||||||
var h = parsed[i].h;
|
var w = parsed[i].w;
|
||||||
var point = this.find_place_for_item(w,h);
|
var h = parsed[i].h;
|
||||||
parsed[i].x = point.x;
|
var point = this.find_place_for_item(w,h);
|
||||||
parsed[i].y = point.y;
|
parsed[i].x = point.x;
|
||||||
parsed[i].z = point.z;
|
parsed[i].y = point.y;
|
||||||
} else {
|
parsed[i].z = point.z;
|
||||||
parsed[i].x = parsed[i].x+50;
|
} else {
|
||||||
parsed[i].y = parsed[i].y+50;
|
parsed[i].x = parsed[i].x+100;
|
||||||
parsed[i].y = parsed[i].z+z;
|
parsed[i].y = parsed[i].y+100;
|
||||||
|
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]);
|
||||||
@@ -2526,11 +2516,18 @@ var SpacedeckSections = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
show_toolbar_props: function() {
|
show_toolbar_props: function() {
|
||||||
if (this.selection_metrics.count==0) return;
|
if (this.selection_metrics.count==0) {
|
||||||
|
this.toolbar_lock_in = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
arts = this.selected_artifacts();
|
arts = this.selected_artifacts();
|
||||||
|
// check if selected artifacts are all from the same user
|
||||||
|
let same_user = true;
|
||||||
for (var i=0;i<arts.length; i++) {
|
for (var i=0;i<arts.length; i++) {
|
||||||
if (arts[i].mime=="x-spacedeck/zone") return;
|
if (arts[i].mime=="x-spacedeck/zone") return;
|
||||||
|
if (arts[i].user_id!==this.user._id) same_user = false;
|
||||||
}
|
}
|
||||||
|
this.toolbar_lock_in = same_user;
|
||||||
this.toolbar_props_in = true;
|
this.toolbar_props_in = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ var SpacedeckSpaces = {
|
|||||||
}.bind(this), {value: dft || "Guest "+parseInt(10000*Math.random()), ok: __("ok"), cancel: __("cancel")});
|
}.bind(this), {value: dft || "Guest "+parseInt(10000*Math.random()), ok: __("ok"), cancel: __("cancel")});
|
||||||
},
|
},
|
||||||
|
|
||||||
load_space: function(space_id, on_success, on_error, space_auth) {
|
load_space: function(space_id, on_success, on_error) {
|
||||||
this.folder_spaces_filter="";
|
this.folder_spaces_filter="";
|
||||||
this.folder_spaces_search="";
|
this.folder_spaces_search="";
|
||||||
|
|
||||||
@@ -308,7 +308,8 @@ var SpacedeckSpaces = {
|
|||||||
userReady();
|
userReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.user && space_auth) {
|
if (!this.user.nickname && space_auth) {
|
||||||
|
this.guest_nickname = get_query_param("nickname") || this.guest_nickname;
|
||||||
if (this.guest_nickname) {
|
if (this.guest_nickname) {
|
||||||
userReady();
|
userReady();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -130,9 +130,27 @@ SpacedeckUsers = {
|
|||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
create_user(name, email, password, password_confirmation, invite_code, function(session) {
|
create_user(name, email, password, password_confirmation, invite_code, function(res) {
|
||||||
this.creating_user = false;
|
this.creating_user = false;
|
||||||
this.login_submit(email, password, null, on_success);
|
|
||||||
|
if (res.chargebee_checkout) {
|
||||||
|
var chargebeeInstance = Chargebee.init({
|
||||||
|
site: "spacedeck-test",
|
||||||
|
enableRedirectMode: true,
|
||||||
|
enableFriendbuyTracking: false
|
||||||
|
});
|
||||||
|
|
||||||
|
chargebeeInstance.openCheckout({
|
||||||
|
hostedPage: function() {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
resolve(res.chargebee_checkout);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// user created, login
|
||||||
|
this.login_submit(email, password, null, on_success);
|
||||||
|
}
|
||||||
}.bind(this), function(req) {
|
}.bind(this), function(req) {
|
||||||
this.creating_user = false;
|
this.creating_user = false;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
function setup_whiteboard_directives() {
|
function setup_whiteboard_directives() {
|
||||||
var mode_touch = false;
|
var mode_touch = false;
|
||||||
|
|
||||||
if ('ontouchstart' in window) {
|
if ('ontouchstart' in window) {
|
||||||
mode_touch = true;
|
mode_touch = true;
|
||||||
var edown = "touchstart";
|
var edown = "touchstart";
|
||||||
@@ -38,7 +38,7 @@ function setup_whiteboard_directives() {
|
|||||||
$(el).bind("mousedown", this.handle_mouse_down_space.bind(this));
|
$(el).bind("mousedown", this.handle_mouse_down_space.bind(this));
|
||||||
$(el).bind("mousemove", this.handle_mouse_move.bind(this));
|
$(el).bind("mousemove", this.handle_mouse_move.bind(this));
|
||||||
$(el).bind("mouseup", this.handle_mouse_up_space.bind(this));
|
$(el).bind("mouseup", this.handle_mouse_up_space.bind(this));
|
||||||
|
|
||||||
$(el).bind("wheel", this.handle_wheel_space.bind(this));
|
$(el).bind("wheel", this.handle_wheel_space.bind(this));
|
||||||
|
|
||||||
$(document.body).bind("mouseleave", this.handle_mouse_leave.bind(this));
|
$(document.body).bind("mouseleave", this.handle_mouse_leave.bind(this));
|
||||||
@@ -99,7 +99,7 @@ function setup_whiteboard_directives() {
|
|||||||
this.handle_mouse_down_space(evt);
|
this.handle_mouse_down_space(evt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($scope.active_tool == "note") {
|
if ($scope.active_tool == "note") {
|
||||||
this.handle_mouse_down_space(evt, true);
|
this.handle_mouse_down_space(evt, true);
|
||||||
return;
|
return;
|
||||||
@@ -154,7 +154,7 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
var a = $scope.find_artifact_by_id(evt.currentTarget.id.replace("artifact-",""));
|
var a = $scope.find_artifact_by_id(evt.currentTarget.id.replace("artifact-",""));
|
||||||
if (!a) return;
|
if (!a) return;
|
||||||
|
|
||||||
if (a.payload_uri) {
|
if (a.payload_uri) {
|
||||||
$scope.download_selected_artifacts();
|
$scope.download_selected_artifacts();
|
||||||
}
|
}
|
||||||
@@ -200,10 +200,10 @@ function setup_whiteboard_directives() {
|
|||||||
var $scope = this.vm.$root;
|
var $scope = this.vm.$root;
|
||||||
|
|
||||||
if (!evt.ctrlKey && !evt.shiftKey) return;
|
if (!evt.ctrlKey && !evt.shiftKey) return;
|
||||||
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
|
|
||||||
var amount = 1;
|
var amount = 1;
|
||||||
var dy = evt.originalEvent.deltaY;
|
var dy = evt.originalEvent.deltaY;
|
||||||
if (dy>0) {
|
if (dy>0) {
|
||||||
@@ -222,7 +222,7 @@ function setup_whiteboard_directives() {
|
|||||||
if (!force && evt.which != 2) {
|
if (!force && evt.which != 2) {
|
||||||
if (evt.target != evt.currentTarget && !_.include(["wrapper"],evt.target.className)) return;
|
if (evt.target != evt.currentTarget && !_.include(["wrapper"],evt.target.className)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var $scope = this.vm.$root;
|
var $scope = this.vm.$root;
|
||||||
|
|
||||||
$scope.opened_dialog="none";
|
$scope.opened_dialog="none";
|
||||||
@@ -234,7 +234,7 @@ function setup_whiteboard_directives() {
|
|||||||
if ((mode_touch && $scope.active_tool=="pointer") || evt.which == 2 || evt.buttons == 4) {
|
if ((mode_touch && $scope.active_tool=="pointer") || evt.which == 2 || evt.buttons == 4) {
|
||||||
$scope.active_tool = "pan";
|
$scope.active_tool = "pan";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($scope.active_tool=="note") {
|
if ($scope.active_tool=="note") {
|
||||||
this.deselect();
|
this.deselect();
|
||||||
this.mouse_state = "transform";
|
this.mouse_state = "transform";
|
||||||
@@ -285,6 +285,7 @@ function setup_whiteboard_directives() {
|
|||||||
$scope.start_adding_placeholder(evt);
|
$scope.start_adding_placeholder(evt);
|
||||||
return;
|
return;
|
||||||
} else if ($scope.active_tool=="pan") {
|
} else if ($scope.active_tool=="pan") {
|
||||||
|
this.deselect();
|
||||||
this.start_pan(evt);
|
this.start_pan(evt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -305,7 +306,7 @@ function setup_whiteboard_directives() {
|
|||||||
this.old_panx = el.scrollLeft;
|
this.old_panx = el.scrollLeft;
|
||||||
this.old_pany = el.scrollTop;
|
this.old_pany = el.scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cursor = this.cursor_point_to_space(evt);
|
var cursor = this.cursor_point_to_space(evt);
|
||||||
$scope.mouse_ox = cursor.x;
|
$scope.mouse_ox = cursor.x;
|
||||||
$scope.mouse_oy = cursor.y;
|
$scope.mouse_oy = cursor.y;
|
||||||
@@ -314,7 +315,7 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
deselect: function() {
|
deselect: function() {
|
||||||
var $scope = this.vm.$root;
|
var $scope = this.vm.$root;
|
||||||
|
|
||||||
$scope.deselect();
|
$scope.deselect();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -342,7 +343,7 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
rects_intersecting: function(r1,r2) {
|
rects_intersecting: function(r1,r2) {
|
||||||
if (!r1 || !r2) return false;
|
if (!r1 || !r2) return false;
|
||||||
|
|
||||||
if ( (r1.x+r1.w < r2.x)
|
if ( (r1.x+r1.w < r2.x)
|
||||||
|| (r1.x > r2.x+r2.w)
|
|| (r1.x > r2.x+r2.w)
|
||||||
|| (r1.y+r1.h < r2.y)
|
|| (r1.y+r1.h < r2.y)
|
||||||
@@ -352,7 +353,7 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
artifacts_in_rect: function(rect) {
|
artifacts_in_rect: function(rect) {
|
||||||
if (!rect) return [];
|
if (!rect) return [];
|
||||||
|
|
||||||
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) {
|
||||||
@@ -688,7 +689,7 @@ function setup_whiteboard_directives() {
|
|||||||
var $scope = this.vm.$root;
|
var $scope = this.vm.$root;
|
||||||
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
|
||||||
if (this.mouse_state == "lasso") {
|
if (this.mouse_state == "lasso") {
|
||||||
var lasso_rect = this.abs_rect(this.lasso);
|
var lasso_rect = this.abs_rect(this.lasso);
|
||||||
|
|
||||||
@@ -696,7 +697,7 @@ function setup_whiteboard_directives() {
|
|||||||
var arts = this.artifacts_in_rect(lasso_rect);
|
var arts = this.artifacts_in_rect(lasso_rect);
|
||||||
this.multi_select(arts);
|
this.multi_select(arts);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (this._no_artifact_toolbar_this_round) {
|
if (this._no_artifact_toolbar_this_round) {
|
||||||
this._no_artifact_toolbar_this_round = false;
|
this._no_artifact_toolbar_this_round = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -708,7 +709,7 @@ function setup_whiteboard_directives() {
|
|||||||
}
|
}
|
||||||
else if (_.include(["transform","move","vector_transform","scribble"],this.mouse_state)) {
|
else if (_.include(["transform","move","vector_transform","scribble"],this.mouse_state)) {
|
||||||
var ars = $scope.selected_artifacts();
|
var ars = $scope.selected_artifacts();
|
||||||
|
|
||||||
for (var i=0; i<ars.length; i++) {
|
for (var i=0; i<ars.length; i++) {
|
||||||
|
|
||||||
if (_.include(["text","placeholder"],$scope.artifact_major_type(ars[i]))) {
|
if (_.include(["text","placeholder"],$scope.artifact_major_type(ars[i]))) {
|
||||||
@@ -723,6 +724,9 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
//save_artifact(ars[i], null, $scope.display_saving_error);
|
//save_artifact(ars[i], null, $scope.display_saving_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update vector handles
|
||||||
|
$scope.update_selection_metrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mouse_state == "text_editor") {
|
if (this.mouse_state == "text_editor") {
|
||||||
@@ -794,7 +798,7 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
$scope.websocket_send(cursor_msg);
|
$scope.websocket_send(cursor_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// side effects ftw!
|
// side effects ftw!
|
||||||
$scope.snap_ruler_x = -1000;
|
$scope.snap_ruler_x = -1000;
|
||||||
$scope.snap_ruler_y = -1000;
|
$scope.snap_ruler_y = -1000;
|
||||||
@@ -818,7 +822,7 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
if (this.mouse_state == "move") {
|
if (this.mouse_state == "move") {
|
||||||
$scope.hide_toolbar_props();
|
$scope.hide_toolbar_props();
|
||||||
|
|
||||||
var snap_dx = 0;
|
var snap_dx = 0;
|
||||||
var snap_dy = 0;
|
var snap_dy = 0;
|
||||||
|
|
||||||
@@ -878,7 +882,7 @@ function setup_whiteboard_directives() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$scope.hide_toolbar_props();
|
$scope.hide_toolbar_props();
|
||||||
|
|
||||||
var ew = (edges.x2-edges.x1);
|
var ew = (edges.x2-edges.x1);
|
||||||
var eh = (edges.y2-edges.y1);
|
var eh = (edges.y2-edges.y1);
|
||||||
|
|
||||||
@@ -924,7 +928,7 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
} else if (this.mouse_state == "vector_transform") {
|
} else if (this.mouse_state == "vector_transform") {
|
||||||
$scope.hide_toolbar_props();
|
$scope.hide_toolbar_props();
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
$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);
|
||||||
@@ -941,18 +945,14 @@ function setup_whiteboard_directives() {
|
|||||||
|
|
||||||
// special case for arrow's 3rd point
|
// special case for arrow's 3rd point
|
||||||
if (a.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].dy += dy/2; */
|
|
||||||
|
|
||||||
control_points[2].dx = (control_points[0].dx+control_points[1].dx)/2;
|
control_points[2].dx = (control_points[0].dx+control_points[1].dx)/2;
|
||||||
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, old_a);
|
return _this.normalize_control_points(control_points, old_a);
|
||||||
});
|
}, false, true); // override_locked: false, temporary: true
|
||||||
|
|
||||||
} else if (this.mouse_state == "scribble") {
|
} else if (this.mouse_state == "scribble") {
|
||||||
|
|
||||||
$scope.update_selected_artifacts(function(a) {
|
$scope.update_selected_artifacts(function(a) {
|
||||||
var old_a = a;
|
var old_a = a;
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ function vec2_angle(v) {
|
|||||||
function render_vector_drawing(a, padding) {
|
function render_vector_drawing(a, padding) {
|
||||||
var shape = a.shape || "";
|
var shape = a.shape || "";
|
||||||
var path = [];
|
var path = [];
|
||||||
|
if(typeof a.control_points == 'string'){
|
||||||
|
a.control_points = JSON.parse(a.control_points);
|
||||||
|
}
|
||||||
var p = a.control_points[0];
|
var p = a.control_points[0];
|
||||||
|
|
||||||
if (!p) return "";
|
if (!p) return "";
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@ const db = require('../../models/db');
|
|||||||
var mailer = require('../../helpers/mailer');
|
var mailer = require('../../helpers/mailer');
|
||||||
var uploader = require('../../helpers/uploader');
|
var uploader = require('../../helpers/uploader');
|
||||||
var space_render = require('../../helpers/space-render');
|
var space_render = require('../../helpers/space-render');
|
||||||
var phantom = require('../../helpers/phantom');
|
var exporter = require('../../helpers/exporter');
|
||||||
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var moment = require('moment');
|
var moment = require('moment');
|
||||||
@@ -51,7 +51,7 @@ router.get('/png', function(req, res, next) {
|
|||||||
if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) {
|
if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) {
|
||||||
db.Space.update({ thumbnail_updated_at: triggered }, {where : {"_id": req.space._id }});
|
db.Space.update({ thumbnail_updated_at: triggered }, {where : {"_id": req.space._id }});
|
||||||
|
|
||||||
phantom.takeScreenshot(req.space, "png", function(local_path) {
|
exporter.takeScreenshot(req.space, "png", function(local_path) {
|
||||||
var localResizedFilePath = local_path + ".thumb.jpg";
|
var localResizedFilePath = local_path + ".thumb.jpg";
|
||||||
gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) {
|
gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) {
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ function make_export_filename(space, extension) {
|
|||||||
router.get('/pdf', function(req, res, next) {
|
router.get('/pdf', function(req, res, next) {
|
||||||
var s3_filename = make_export_filename(req.space, "pdf");
|
var s3_filename = make_export_filename(req.space, "pdf");
|
||||||
|
|
||||||
phantom.takeScreenshot(req.space, "pdf", function(local_path) {
|
exporter.takeScreenshot(req.space, "pdf", function(local_path) {
|
||||||
uploader.uploadFile(s3_filename, "application/pdf", local_path, function(err, url) {
|
uploader.uploadFile(s3_filename, "application/pdf", local_path, function(err, url) {
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
url: url
|
url: url
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ var redis = require('../../helpers/redis');
|
|||||||
var mailer = require('../../helpers/mailer');
|
var mailer = require('../../helpers/mailer');
|
||||||
var uploader = require('../../helpers/uploader');
|
var uploader = require('../../helpers/uploader');
|
||||||
var space_render = require('../../helpers/space-render');
|
var space_render = require('../../helpers/space-render');
|
||||||
var phantom = require('../../helpers/phantom');
|
var exporter = require('../../helpers/exporter');
|
||||||
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ var redis = require('../../helpers/redis');
|
|||||||
var mailer = require('../../helpers/mailer');
|
var mailer = require('../../helpers/mailer');
|
||||||
var uploader = require('../../helpers/uploader');
|
var uploader = require('../../helpers/uploader');
|
||||||
var space_render = require('../../helpers/space-render');
|
var space_render = require('../../helpers/space-render');
|
||||||
var phantom = require('../../helpers/phantom');
|
var exporter = require('../../helpers/exporter');
|
||||||
var payloadConverter = require('../../helpers/artifact_converter');
|
var payloadConverter = require('../../helpers/artifact_converter');
|
||||||
|
|
||||||
var slug = require('slug');
|
var slug = require('slug');
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ var express = require('express');
|
|||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
var glob = require('glob');
|
var glob = require('glob');
|
||||||
|
|
||||||
|
var chargebee = require('chargebee');
|
||||||
|
|
||||||
router.get('/current', function(req, res, next) {
|
router.get('/current', function(req, res, next) {
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
var u = _.clone(req.user.dataValues);
|
var u = _.clone(req.user.dataValues);
|
||||||
@@ -39,6 +41,88 @@ router.get('/current', function(req, res, next) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function createChargebeeCheckout(req, res, plan_id, email, name, company) {
|
||||||
|
var nameParts = name.split(" ");
|
||||||
|
var firstName = nameParts.shift();
|
||||||
|
var lastName = nameParts.join(" ");
|
||||||
|
|
||||||
|
chargebee.hosted_page.checkout_new({
|
||||||
|
subscription: {
|
||||||
|
plan_id: plan_id
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
first_name: firstName,
|
||||||
|
last_name: lastName,
|
||||||
|
email: email,
|
||||||
|
company: company,
|
||||||
|
}
|
||||||
|
}).request(function(error,result) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
res.status(400).json({"error":error+""});
|
||||||
|
} else {
|
||||||
|
res.status(200).json({"chargebee_checkout":result.hosted_page});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function createUser(req, res, email, nickname, password) {
|
||||||
|
bcrypt.genSalt(10, function(err, salt) {
|
||||||
|
bcrypt.hash(password, salt, function(err, hash) {
|
||||||
|
crypto.randomBytes(16, function(ex, buf) {
|
||||||
|
var token = buf.toString('hex');
|
||||||
|
|
||||||
|
var u = {
|
||||||
|
_id: uuidv4(),
|
||||||
|
email: email,
|
||||||
|
account_type: "email",
|
||||||
|
nickname: nickname,
|
||||||
|
password_hash: hash,
|
||||||
|
prefs_language: req.i18n.locale,
|
||||||
|
confirmation_token: token
|
||||||
|
};
|
||||||
|
|
||||||
|
db.User.create(u)
|
||||||
|
.error(err => {
|
||||||
|
res.sendStatus(400);
|
||||||
|
})
|
||||||
|
.then(u => {
|
||||||
|
var homeFolder = {
|
||||||
|
_id: uuidv4(),
|
||||||
|
name: req.i18n.__("home"),
|
||||||
|
space_type: "folder",
|
||||||
|
creator_id: u._id
|
||||||
|
};
|
||||||
|
db.Space.create(homeFolder)
|
||||||
|
.error(err => {
|
||||||
|
res.sendStatus(400);
|
||||||
|
})
|
||||||
|
.then(homeFolder => {
|
||||||
|
u.home_folder_id = homeFolder._id;
|
||||||
|
u.save()
|
||||||
|
.then(() => {
|
||||||
|
// home folder created,
|
||||||
|
// auto accept pending invites
|
||||||
|
db.Membership.update({
|
||||||
|
"state": "active"
|
||||||
|
}, {
|
||||||
|
where: {
|
||||||
|
"email_invited": u.email,
|
||||||
|
"state": "pending"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res.status(201).json({});
|
||||||
|
})
|
||||||
|
.error(err => {
|
||||||
|
res.status(400).json(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// create user
|
// create user
|
||||||
router.post('/', function(req, res) {
|
router.post('/', function(req, res) {
|
||||||
if (!req.body["email"] || !req.body["password"]) {
|
if (!req.body["email"] || !req.body["password"]) {
|
||||||
@@ -51,6 +135,7 @@ router.post('/', function(req, res) {
|
|||||||
var password = req.body["password"];
|
var password = req.body["password"];
|
||||||
var password_confirmation = req.body["password_confirmation"];
|
var password_confirmation = req.body["password_confirmation"];
|
||||||
var invite_code = req.body["invite_code"];
|
var invite_code = req.body["invite_code"];
|
||||||
|
var company = req.body["company"] || "";
|
||||||
|
|
||||||
if (password_confirmation != password) {
|
if (password_confirmation != password) {
|
||||||
res.status(400).json({"error":"password_confirmation"});
|
res.status(400).json({"error":"password_confirmation"});
|
||||||
@@ -67,67 +152,17 @@ router.post('/', function(req, res) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var createUser = function() {
|
|
||||||
bcrypt.genSalt(10, function(err, salt) {
|
|
||||||
bcrypt.hash(password, salt, function(err, hash) {
|
|
||||||
crypto.randomBytes(16, function(ex, buf) {
|
|
||||||
var token = buf.toString('hex');
|
|
||||||
|
|
||||||
var u = {
|
|
||||||
_id: uuidv4(),
|
|
||||||
email: email,
|
|
||||||
account_type: "email",
|
|
||||||
nickname: nickname,
|
|
||||||
password_hash: hash,
|
|
||||||
prefs_language: req.i18n.locale,
|
|
||||||
confirmation_token: token
|
|
||||||
};
|
|
||||||
|
|
||||||
db.User.create(u)
|
|
||||||
.error(err => {
|
|
||||||
res.sendStatus(400);
|
|
||||||
})
|
|
||||||
.then(u => {
|
|
||||||
var homeFolder = {
|
|
||||||
_id: uuidv4(),
|
|
||||||
name: req.i18n.__("home"),
|
|
||||||
space_type: "folder",
|
|
||||||
creator_id: u._id
|
|
||||||
};
|
|
||||||
db.Space.create(homeFolder)
|
|
||||||
.error(err => {
|
|
||||||
res.sendStatus(400);
|
|
||||||
})
|
|
||||||
.then(homeFolder => {
|
|
||||||
u.home_folder_id = homeFolder._id;
|
|
||||||
u.save()
|
|
||||||
.then(() => {
|
|
||||||
// home folder created,
|
|
||||||
// auto accept pending invites
|
|
||||||
db.Membership.update({
|
|
||||||
"state": "active"
|
|
||||||
}, {
|
|
||||||
where: {
|
|
||||||
"email_invited": u.email,
|
|
||||||
"state": "pending"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
res.status(201).json({});
|
|
||||||
})
|
|
||||||
.error(err => {
|
|
||||||
res.status(400).json(err);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
db.User.findAll({where: {email: email}})
|
db.User.findAll({where: {email: email}})
|
||||||
.then(users => {
|
.then(users => {
|
||||||
if (users.length == 0) {
|
if (users.length == 0) {
|
||||||
createUser();
|
if (config.get('chargebee_integration')) {
|
||||||
|
// sign up via paid plan trial
|
||||||
|
createChargebeeCheckout(req, res, config.get('chargebee_default_plan_id'), email, nickname, company);
|
||||||
|
// TODO: createUser after chargebee checkout
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createUser(req, res, email, nickname, password);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(400).json({"error":"user_email_already_used"});
|
res.status(400).json({"error":"user_email_already_used"});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const puppeteer = require('puppeteer');
|
||||||
|
|
||||||
var config = require('config');
|
var config = require('config');
|
||||||
require('../../models/db');
|
require('../../models/db');
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var phantom = require('node-phantom-simple');
|
|
||||||
var md5 = require('md5');
|
var md5 = require('md5');
|
||||||
|
|
||||||
var express = require('express');
|
var express = require('express');
|
||||||
@@ -19,40 +19,39 @@ function website_to_png(url,on_success,on_error) {
|
|||||||
console.log("[webgrabber] url: "+url);
|
console.log("[webgrabber] url: "+url);
|
||||||
console.log("[webgrabber] export_path: "+export_path);
|
console.log("[webgrabber] export_path: "+export_path);
|
||||||
|
|
||||||
var on_success_called = false;
|
|
||||||
|
|
||||||
var on_exit = function(exit_code) {
|
|
||||||
if (exit_code>0) {
|
|
||||||
console.log("[phantom-webgrabber] abnormal exit for url "+url);
|
|
||||||
if (!on_success_called && on_error) {
|
|
||||||
on_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fs.stat(export_path, function(err, stat) {
|
fs.stat(export_path, function(err, stat) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
// file exists
|
// file exists
|
||||||
console.log("[webgrabber] serving cached snapshot of url: "+url);
|
console.log("[webgrabber] serving cached snapshot of url: "+url);
|
||||||
on_success(export_path);
|
on_success(export_path);
|
||||||
} else {
|
} else {
|
||||||
phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) {
|
(async () => {
|
||||||
return browser.createPage(function (err, page) {
|
let browser;
|
||||||
page.set('settings.resourceTimeout',timeout);
|
let page;
|
||||||
page.set('settings.javascriptEnabled',false);
|
try {
|
||||||
|
browser = await puppeteer.launch(
|
||||||
return page.open(url, function(err, status) {
|
{
|
||||||
console.log("[webgrabber] status: "+status);
|
headless: true,
|
||||||
page.render(export_path, function() {
|
args: ['--disable-dev-shm-usage', '--no-sandbox']
|
||||||
on_success_called = true;
|
}
|
||||||
on_success(export_path);
|
);
|
||||||
browser.exit();
|
page = await browser.newPage();
|
||||||
});
|
|
||||||
});
|
page.setDefaultTimeout(timeout);
|
||||||
});
|
await page.setJavaScriptEnabled(false);
|
||||||
}, {
|
await page.goto(url, {waitUntil: 'networkidle2'});
|
||||||
onExit: on_exit
|
await page.emulateMedia('screen');
|
||||||
});
|
await page.screenshot({path: export_path, printBackground: true});
|
||||||
|
|
||||||
|
await browser.close();
|
||||||
|
on_success(export_path);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
console.log("[webgrabber] puppeteer abnormal exit for url "+url);
|
||||||
|
on_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,22 @@ router.get('/oc', (req, res) => {
|
|||||||
res.redirect("/t/oc");
|
res.redirect("/t/oc");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/es/*', (req, res) => {
|
||||||
|
res.redirect("/t/es");
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/es', (req, res) => {
|
||||||
|
res.redirect("/t/es");
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/hu/*', (req, res) => {
|
||||||
|
res.redirect("/t/hu");
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/hu', (req, res) => {
|
||||||
|
res.redirect("/t/hu");
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/en/*', (req, res) => {
|
router.get('/en/*', (req, res) => {
|
||||||
res.redirect("/t/en");
|
res.redirect("/t/en");
|
||||||
});
|
});
|
||||||
@@ -87,7 +103,7 @@ router.get('/en', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/account', (req, res) => {
|
router.get('/account', (req, res) => {
|
||||||
res.render('spacedeck');
|
res.render('spacedeck', { config:config });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/login', (req, res) => {
|
router.get('/login', (req, res) => {
|
||||||
|
|||||||
12
spacedeck.js
12
spacedeck.js
@@ -23,6 +23,8 @@ const express = require('express');
|
|||||||
const app = express();
|
const app = express();
|
||||||
const serveStatic = require('serve-static');
|
const serveStatic = require('serve-static');
|
||||||
|
|
||||||
|
const chargebee = require('chargebee');
|
||||||
|
|
||||||
const isProduction = app.get('env') === 'production';
|
const isProduction = app.get('env') === 'production';
|
||||||
|
|
||||||
// workaround for libssl_conf.so error triggered by phantomjs
|
// workaround for libssl_conf.so error triggered by phantomjs
|
||||||
@@ -33,7 +35,7 @@ console.log("Booting Spacedeck Open… (environment: " + app.get('env') + ")");
|
|||||||
app.use(logger(isProduction ? 'combined' : 'dev'));
|
app.use(logger(isProduction ? 'combined' : 'dev'));
|
||||||
|
|
||||||
i18n.expressBind(app, {
|
i18n.expressBind(app, {
|
||||||
locales: ["en", "de", "fr", "oc", "es"],
|
locales: ["de", "en", "es", "fr", "hu", "oc"],
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
cookieName: "spacedeck_locale",
|
cookieName: "spacedeck_locale",
|
||||||
devMode: (app.get('env') == 'development')
|
devMode: (app.get('env') == 'development')
|
||||||
@@ -110,6 +112,14 @@ if (app.get('env') == 'development') {
|
|||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
||||||
|
|
||||||
|
// ChargeBee Integration (Optional)
|
||||||
|
if (config.get('chargebee_integration')) {
|
||||||
|
chargebee.configure({
|
||||||
|
site: config.get('chargebee_site'),
|
||||||
|
api_key: config.get('chargebee_api_key')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// CONNECT TO DATABASE
|
// CONNECT TO DATABASE
|
||||||
db.init();
|
db.init();
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,12 @@
|
|||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.hide-text .text { opacity: 0 }
|
&.hide-text .text {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
&.locked.selected {
|
&.locked.selected {
|
||||||
box-shadow: 0px 0px 0px 3px rgba(0,0,0,0.5) !important;
|
box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.5) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder {
|
.placeholder {
|
||||||
@@ -26,7 +28,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.artifact-text.text-blank [contentEditable=true]:not(.text-editing) p:first-child::after {
|
&.artifact-text.text-blank
|
||||||
|
[contentEditable="true"]:not(.text-editing)
|
||||||
|
p:first-child::after {
|
||||||
content: "Double click to edit";
|
content: "Double click to edit";
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
}
|
}
|
||||||
@@ -79,7 +83,6 @@
|
|||||||
// padding-right: 20px; margin-right: -20px;
|
// padding-right: 20px; margin-right: -20px;
|
||||||
|
|
||||||
//> * {pointer-events: auto; }
|
//> * {pointer-events: auto; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.artifact-text) {
|
&:not(.artifact-text) {
|
||||||
@@ -142,7 +145,9 @@
|
|||||||
li {
|
li {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
&:last-child {margin-bottom: 0em !important; }
|
&:last-child {
|
||||||
|
margin-bottom: 0em !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -179,10 +184,14 @@
|
|||||||
p {
|
p {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0.5em; // compatibility to old system
|
margin-bottom: 0.5em; // compatibility to old system
|
||||||
&:last-child {margin-bottom: 0em !important; }
|
&:last-child {
|
||||||
|
margin-bottom: 0em !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {pointer-events: none; }
|
a {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
ol {
|
ol {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -247,7 +256,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.oembed,
|
.oembed,
|
||||||
div[class*='oembed-'] {
|
div[class*="oembed-"] {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
.play {
|
.play {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -290,7 +299,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {font-size: 20px; }
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
.image {
|
.image {
|
||||||
height: auto;
|
height: auto;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -319,10 +330,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.video {
|
.video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
background-color: black;
|
||||||
|
|
||||||
|
&.playing {
|
||||||
|
video {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -340,21 +358,22 @@
|
|||||||
video {
|
video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-controls {
|
.tl-controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
top: 10px;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: fix later
|
// FIXME: fix later
|
||||||
@@ -373,8 +392,8 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
.timeline {
|
.timeline {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left:0;
|
left: 0;
|
||||||
top:0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
bottom: 54px;
|
bottom: 54px;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
@@ -383,7 +402,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.tl-current-time {
|
.tl-current-time {
|
||||||
height:100%;
|
height: 100%;
|
||||||
background: white;
|
background: white;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
border-right: 1px solid #888;
|
border-right: 1px solid #888;
|
||||||
@@ -419,12 +438,11 @@
|
|||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tl-title {
|
.tl-title {
|
||||||
margin-left:10px;
|
margin-left: 10px;
|
||||||
max-width: 55%;
|
max-width: 55%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -446,19 +464,41 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bold { font-weight: bold;}
|
&.bold {
|
||||||
&.italic { font-style: italic;}
|
font-weight: bold;
|
||||||
&.underline { text-decoration: underline;}
|
}
|
||||||
&.strike { text-decoration: line-through;}
|
&.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
&.underline {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
&.strike {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
&.align-top .text-cell {vertical-align: top;}
|
&.align-top .text-cell {
|
||||||
&.align-middle .text-cell {vertical-align: middle;}
|
vertical-align: top;
|
||||||
&.align-bottom .text-cell {vertical-align: bottom;}
|
}
|
||||||
|
&.align-middle .text-cell {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
&.align-bottom .text-cell {
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
&.align-left { text-align: left; }
|
&.align-left {
|
||||||
&.align-center { text-align: center; }
|
text-align: left;
|
||||||
&.align-right { text-align: right; }
|
}
|
||||||
&.align-justify { text-align: justify; }
|
&.align-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
&.align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
&.align-justify {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
audio {
|
audio {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -473,10 +513,14 @@
|
|||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
|
|
||||||
&.artifact-zone {
|
&.artifact-zone {
|
||||||
background-color: rgba(0,0,0,0.05);
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
&:after {display: none; }
|
&:after {
|
||||||
.shape {display: none; }
|
display: none;
|
||||||
|
}
|
||||||
|
.shape {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.zone {
|
.zone {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
@@ -488,32 +532,31 @@ body.present-mode {
|
|||||||
.artifact-zone {
|
.artifact-zone {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.artifact {
|
.artifact {
|
||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
.text a { pointer-events: auto !important; }
|
.text a {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body:not(.present-mode) {
|
body:not(.present-mode) {
|
||||||
|
|
||||||
#space {
|
#space {
|
||||||
|
|
||||||
.Medium {
|
.Medium {
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.artifact {
|
.artifact {
|
||||||
|
|
||||||
&.selected.text-editing,
|
&.selected.text-editing,
|
||||||
&.text-editing {
|
&.text-editing {
|
||||||
cursor: text;
|
cursor: text;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
border: 1px solid rgba(255,255,255,0.25);
|
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||||
}
|
}
|
||||||
&:after {
|
&:after {
|
||||||
border: 1px dotted rgba(40,140,215,0.5);
|
border: 1px dotted rgba(40, 140, 215, 0.5);
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,24 +570,27 @@ body:not(.present-mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not(.artifact-vector):after {
|
&:not(.artifact-vector):after {
|
||||||
border: 1px solid rgba(40,140,215,1);
|
border: 1px solid rgba(40, 140, 215, 1);
|
||||||
// overlay color removed for now (messes with colors)
|
// overlay color removed for now (messes with colors)
|
||||||
//background-color: rgba(40,140,215,0.35);
|
//background-color: rgba(40,140,215,0.35);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mouse-scribble, .tool-scribble, .tool-line, .tool-arrow {
|
.mouse-scribble,
|
||||||
|
.tool-scribble,
|
||||||
|
.tool-line,
|
||||||
|
.tool-arrow {
|
||||||
cursor: crosshair !important;
|
cursor: crosshair !important;
|
||||||
|
|
||||||
.artifact {
|
.artifact {
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.artifact:after, .artifact:before {
|
.artifact:after,
|
||||||
|
.artifact:before {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -558,21 +604,27 @@ body:not(.present-mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.artifact.state-idle {
|
.artifact.state-idle {
|
||||||
.progress, .progress-text {
|
.progress,
|
||||||
|
.progress-text {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.artifact.state-processing, .artifact.state-uploading {
|
.artifact.state-processing,
|
||||||
|
.artifact.state-uploading {
|
||||||
.progress {
|
.progress {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 10px;
|
padding: 4px;
|
||||||
|
|
||||||
background-color: $blue;
|
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
.progress-container {
|
||||||
|
background: $white;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
.progress-text {
|
.progress-text {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
@@ -585,43 +637,48 @@ body:not(.present-mode) {
|
|||||||
color: #888;
|
color: #888;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
video, audio, .tl-controls, .timeline {
|
video,
|
||||||
|
audio,
|
||||||
|
.tl-controls,
|
||||||
|
.timeline {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.state-processing .spinner {
|
.state-processing .spinner {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background-image: url('/images/hourglass.gif');
|
background-image: url("/images/hourglass.gif");
|
||||||
}
|
}
|
||||||
|
|
||||||
.state-uploading .spinner {
|
.state-uploading .spinner {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
background-image: url('/images/hourglass.gif');
|
background-image: url("/images/hourglass.gif");
|
||||||
}
|
}
|
||||||
|
|
||||||
.state-idle .spinner {
|
.state-idle .spinner {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.artifact.image {
|
.artifact.image {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
&.state-loading { background-color: rgba(40,140,215,0.05);}
|
&.state-loading {
|
||||||
&.state-processing { background-color: rgba(107,195,111,0.05);}
|
background-color: rgba(40, 140, 215, 0.05);
|
||||||
|
}
|
||||||
|
&.state-processing {
|
||||||
|
background-color: rgba(107, 195, 111, 0.05);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
height:44px;
|
height: 44px;
|
||||||
width:44px;
|
width: 44px;
|
||||||
position:absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -22px;
|
margin: -22px;
|
||||||
border-radius:100%;
|
border-radius: 100%;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,17 @@
|
|||||||
@import "unicode";
|
@import "unicode";
|
||||||
|
|
||||||
@-webkit-keyframes appear {
|
@-webkit-keyframes appear {
|
||||||
0% { opacity: 0;}
|
0% {
|
||||||
30% { opacity: 0;}
|
opacity: 0;
|
||||||
100% { opacity: 1; }
|
}
|
||||||
|
30% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
background-color: $blue;
|
background-color: $blue;
|
||||||
font-family: $main-font;
|
font-family: $main-font;
|
||||||
@@ -26,7 +31,9 @@
|
|||||||
#user-root {
|
#user-root {
|
||||||
margin-left: 5px !important;
|
margin-left: 5px !important;
|
||||||
padding: 0px !important;
|
padding: 0px !important;
|
||||||
.btn {margin-right: 10px; }
|
.btn {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar.folder-sidebar {
|
#sidebar.folder-sidebar {
|
||||||
@@ -70,7 +77,9 @@
|
|||||||
li {
|
li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
line-height: 44px;
|
line-height: 44px;
|
||||||
&.active span {color: $light; }
|
&.active span {
|
||||||
|
color: $light;
|
||||||
|
}
|
||||||
span {
|
span {
|
||||||
color: $medium;
|
color: $medium;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -82,8 +91,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#folder {
|
#folder {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -137,7 +144,7 @@
|
|||||||
z-index: initial;
|
z-index: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.folder .icon {
|
.folder .icon {
|
||||||
color: $yellow;
|
color: $yellow;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@@ -150,7 +157,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
> .icon {
|
> .icon {
|
||||||
margin-left: -15px
|
margin-left: -15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,30 +183,30 @@
|
|||||||
// margin-top: -18px;
|
// margin-top: -18px;
|
||||||
margin-right: -60px;
|
margin-right: -60px;
|
||||||
// margin-bottom: -18px;
|
// margin-bottom: -18px;
|
||||||
@include transition( all 0.125s ease-in-out);
|
@include transition(all 0.125s ease-in-out);
|
||||||
.icon {
|
.icon {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@include scale(0,0);
|
@include scale(0, 0);
|
||||||
@include transition( all 0.125s ease-in-out);
|
@include transition(all 0.125s ease-in-out);
|
||||||
@include opacity(0.25);
|
@include opacity(0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
margin-right: -12px;
|
margin-right: -12px;
|
||||||
.icon {
|
.icon {
|
||||||
@include scale(1,1);
|
@include scale(1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#folder-header {
|
#folder-header {
|
||||||
background-color: rgba(41,41,41,0.95);
|
background-color: rgba(41, 41, 41, 0.95);
|
||||||
background-color: rgba(245,245,245,0.95);
|
background-color: rgba(245, 245, 245, 0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
#folder-wrapper {
|
#folder-wrapper {
|
||||||
@@ -212,15 +219,22 @@
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#folder-grid .item {
|
#folder-grid .item {
|
||||||
float: left;
|
float: left;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@media screen and (min-width: 640px) {width: 50%; }
|
@media screen and (min-width: 640px) {
|
||||||
@media screen and (min-width: 800px) {width: 33.333333%; }
|
width: 50%;
|
||||||
@media screen and (min-width: 1000px) {width: 25%; }
|
}
|
||||||
@media screen and (min-width: 1200px) {width: 20%; }
|
@media screen and (min-width: 800px) {
|
||||||
|
width: 33.333333%;
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 1000px) {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 1200px) {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.compact-hidden {
|
.compact-hidden {
|
||||||
@@ -256,8 +270,8 @@
|
|||||||
.item {
|
.item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-right: $folder-gutter*2;
|
padding-right: $folder-gutter * 2;
|
||||||
padding-bottom: $folder-gutter*2;
|
padding-bottom: $folder-gutter * 2;
|
||||||
margin-bottom: $folder-gutter;
|
margin-bottom: $folder-gutter;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -265,36 +279,38 @@
|
|||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.folder-drop {display:none; }
|
.folder-drop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
&.appear > a,
|
&.appear > a,
|
||||||
&.creating > a {
|
&.creating > a {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
-webkit-animation: appear 0.25s ease-out 0.05s;
|
-webkit-animation: appear 0.25s ease-out 0.05s;
|
||||||
-moz-animation: appear 0.25s ease-out 0.05s;
|
-moz-animation: appear 0.25s ease-out 0.05s;
|
||||||
-ms-animation: appear 0.25s ease-out 0.05s;
|
-ms-animation: appear 0.25s ease-out 0.05s;
|
||||||
-o-animation: appear 0.25s ease-out 0.05s;
|
-o-animation: appear 0.25s ease-out 0.05s;
|
||||||
animation: appear 0.25s ease-out 0.05s;
|
animation: appear 0.25s ease-out 0.05s;
|
||||||
|
|
||||||
-webkit-animation-fill-mode: forwards;
|
-webkit-animation-fill-mode: forwards;
|
||||||
-moz-animation-fill-mode: forwards;
|
-moz-animation-fill-mode: forwards;
|
||||||
-ms-animation-fill-mode: forwards;
|
-ms-animation-fill-mode: forwards;
|
||||||
-o-animation-fill-mode: forwards;
|
-o-animation-fill-mode: forwards;
|
||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.deleting > a {
|
&.deleting > a {
|
||||||
-webkit-animation: disappear 0.25s ease-out 0.05s;
|
-webkit-animation: disappear 0.25s ease-out 0.05s;
|
||||||
-moz-animation: disappear 0.25s ease-out 0.05s;
|
-moz-animation: disappear 0.25s ease-out 0.05s;
|
||||||
-ms-animation: disappear 0.25s ease-out 0.05s;
|
-ms-animation: disappear 0.25s ease-out 0.05s;
|
||||||
-o-animation: disappear 0.25s ease-out 0.05s;
|
-o-animation: disappear 0.25s ease-out 0.05s;
|
||||||
animation: disappear 0.25s ease-out 0.05s;
|
animation: disappear 0.25s ease-out 0.05s;
|
||||||
|
|
||||||
-webkit-animation-fill-mode: forwards;
|
-webkit-animation-fill-mode: forwards;
|
||||||
-moz-animation-fill-mode: forwards;
|
-moz-animation-fill-mode: forwards;
|
||||||
-ms-animation-fill-mode: forwards;
|
-ms-animation-fill-mode: forwards;
|
||||||
-o-animation-fill-mode: forwards;
|
-o-animation-fill-mode: forwards;
|
||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.tag-important > a {
|
&.tag-important > a {
|
||||||
@@ -308,7 +324,7 @@
|
|||||||
|
|
||||||
&.dropping {
|
&.dropping {
|
||||||
.folder-drop {
|
.folder-drop {
|
||||||
display:block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +365,13 @@
|
|||||||
background-color: $darker;
|
background-color: $darker;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
-webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.1)));
|
-webkit-mask-image: -webkit-gradient(
|
||||||
|
linear,
|
||||||
|
left top,
|
||||||
|
left bottom,
|
||||||
|
from(rgba(0, 0, 0, 0)),
|
||||||
|
to(rgba(0, 0, 0, 0.1))
|
||||||
|
);
|
||||||
background-color: black;
|
background-color: black;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -360,7 +382,7 @@
|
|||||||
.fav-toggle {
|
.fav-toggle {
|
||||||
margin-right: -12px;
|
margin-right: -12px;
|
||||||
.icon {
|
.icon {
|
||||||
@include scale(1,1);
|
@include scale(1, 1);
|
||||||
@include opacity(1);
|
@include opacity(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,7 +406,7 @@
|
|||||||
|
|
||||||
> a {
|
> a {
|
||||||
/* aspect ratio without spacer image */
|
/* aspect ratio without spacer image */
|
||||||
&:before{
|
&:before {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
padding-top: 100%; /* initial ratio of 1:1*/
|
padding-top: 100%; /* initial ratio of 1:1*/
|
||||||
@@ -392,9 +414,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-radius: $radius*2;
|
border-radius: $radius * 2;
|
||||||
|
|
||||||
&:active { opacity: 0.95 !important; }
|
&:active {
|
||||||
|
opacity: 0.95 !important;
|
||||||
|
}
|
||||||
|
|
||||||
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15);
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
@@ -406,7 +430,7 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
display: block;
|
display: block;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-radius: $radius*2;
|
border-radius: $radius * 2;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.item-thumbnail {
|
.item-thumbnail {
|
||||||
@@ -420,8 +444,9 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-top-left-radius: $radius*2;
|
background-size: cover;
|
||||||
border-top-right-radius: $radius*2;
|
border-top-left-radius: $radius * 2;
|
||||||
|
border-top-right-radius: $radius * 2;
|
||||||
|
|
||||||
border-bottom-left-radius: 10px;
|
border-bottom-left-radius: 10px;
|
||||||
border-bottom-right-radius: 10px;
|
border-bottom-right-radius: 10px;
|
||||||
@@ -431,7 +456,7 @@
|
|||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
display: block;
|
display: block;
|
||||||
border-top: 1px solid rgba(0,0,0,0.05);
|
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
background-color: white;
|
background-color: white;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -439,15 +464,15 @@
|
|||||||
left: 0px;
|
left: 0px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-bottom-left-radius: $radius*2;
|
border-bottom-left-radius: $radius * 2;
|
||||||
border-bottom-right-radius: $radius*2;
|
border-bottom-right-radius: $radius * 2;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
color: $dark;
|
color: $dark;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbnail-loading {
|
.thumbnail-loading {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
@@ -464,11 +489,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item-meta {
|
.item-meta {
|
||||||
border-top: 2px solid rgba(0,0,0,0.025);
|
border-top: 2px solid rgba(0, 0, 0, 0.025);
|
||||||
border-radius: 2*$radius;
|
border-radius: 2 * $radius;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
|
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
color: $medium;
|
color: $medium;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -493,8 +518,8 @@
|
|||||||
left: 0px;
|
left: 0px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom-left-radius: $radius*2;
|
border-bottom-left-radius: $radius * 2;
|
||||||
border-bottom-right-radius: $radius*2;
|
border-bottom-right-radius: $radius * 2;
|
||||||
//white-space: nowrap;
|
//white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -509,7 +534,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: $folder-gutter*2;
|
right: $folder-gutter * 2;
|
||||||
color: $medium;
|
color: $medium;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-family: $main-font;
|
font-family: $main-font;
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
<div class="footer">
|
<div class="footer">
|
||||||
<p>
|
<p>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
© 2020 <a href="https://mntre.com">MNT Research GmbH</a>, Fehlerstr. 8, 12161 Berlin, Germany<br>
|
Spacedeck is Free and Open Source Software. The developers are not affiliated with this website.<br>
|
||||||
© 2011–2020 Spacedeck GmbH (in liquidation)<br>
|
© 2011–2020 <a href="https://github.com/mntmn/spacedeck-open">Spacedeck Open Developers</a><br>
|
||||||
Source Code: <a href="https://github.com/mntmn/spacedeck-open">https://github.com/mntmn/spacedeck-open</a>
|
|
||||||
<br>
|
<br>
|
||||||
Font: <a href="https://rsms.me/inter/">Inter by rsms</a>
|
Font: <a href="https://rsms.me/inter/">Inter by rsms</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Spacedeck Open</title>
|
<title>Spacedeck Open</title>
|
||||||
<meta name="description" content="">
|
<meta name="title" content="Spacedeck Open">
|
||||||
|
<meta name="description" content="Whenever you need to lay out pictures, text notes, video and audio clips on a blank canvas, Spacedeck can help you."/>
|
||||||
|
<meta name="keywords" content="spacedeck, collaboration, teams, collages, moodboards, teaching, shared whiteboards, design thinking"/>
|
||||||
|
<meta name="author" content="MNT Research GmbH"/>
|
||||||
|
<meta name="copyright" content="MNT Research GmbH"/>
|
||||||
|
<meta name="robots" content="index,follow"/>
|
||||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
@@ -24,6 +29,5 @@
|
|||||||
<a class="btn btn-md btn-dark btn-round" href="/spaces"><%=__("spaces")%></a>
|
<a class="btn btn-md btn-dark btn-round" href="/spaces"><%=__("spaces")%></a>
|
||||||
<a class="btn btn-md btn-dark btn-round" href="/logout"><%=__("logout")%></a>
|
<a class="btn btn-md btn-dark btn-round" href="/logout"><%=__("logout")%></a>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -110,7 +110,10 @@
|
|||||||
</label>
|
</label>
|
||||||
<label class="radio" v-bind:class="{checked: user.prefs_language=='es'}" v-on:click="save_user_language('es')">
|
<label class="radio" v-bind:class="{checked: user.prefs_language=='es'}" v-on:click="save_user_language('es')">
|
||||||
<input type="radio" id="user-preferences_language" name="language" value="es"><span>Español</span>
|
<input type="radio" id="user-preferences_language" name="language" value="es"><span>Español</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="radio" v-bind:class="{checked: user.prefs_language=='hu'}" v-on:click="save_user_language('hu')">
|
||||||
|
<input type="radio" id="user-preferences_language" name="language" value="hu"><span>Magyar</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -85,13 +85,13 @@
|
|||||||
v-bind:class="{text-editing:(editing_artifact_id==a._id && (a.view.major_type=='text' || a.view.major_type=='shape'))}"
|
v-bind:class="{text-editing:(editing_artifact_id==a._id && (a.view.major_type=='text' || a.view.major_type=='shape'))}"
|
||||||
id="artifact-{{a._id}}">
|
id="artifact-{{a._id}}">
|
||||||
|
|
||||||
|
|
||||||
<div v-if="a.view && a.view.major_type" style="height:100%; width:100%" v-bind:title="(a.editor_name || (a.user && a.user.nickname) || '')">
|
<div v-if="a.view && a.view.major_type" style="height:100%; width:100%" v-bind:title="(a.editor_name || (a.user && a.user.nickname) || '')">
|
||||||
<span v-if="a.locked && is_selected(a)" class="link-wrapper">
|
<span v-if="a.locked && is_selected(a)" class="link-wrapper">
|
||||||
<span class="btn btn-sm btn-icon btn-round btn-primary">
|
<span class="btn btn-sm btn-icon btn-round btn-primary">
|
||||||
<span class="icon icon-lock-closed"></span>
|
<span class="icon icon-lock-closed"></span>
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- text -->
|
<!-- text -->
|
||||||
<div v-if="a.view.major_type == 'text'" class="text" v-bind:style="a.view.inner_style">
|
<div v-if="a.view.major_type == 'text'" class="text" v-bind:style="a.view.inner_style">
|
||||||
<div class="text-table">
|
<div class="text-table">
|
||||||
@@ -151,30 +151,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- video -->
|
<!-- video -->
|
||||||
<div v-if="a.view.major_type == 'video'" v-videoplayer="a" class="video" v-bind:style="a.view.inner_style">
|
<div v-if="a.view.major_type == 'video'" class="video">
|
||||||
<video preload="metadata" v-bind:poster="a.view.thumbnail_uri">
|
<video preload="metadata" controls="auto" v-bind:poster="a.view.thumbnail_uri">
|
||||||
<source v-for="rep in a.view.payload_alternatives" v-bind:src="rep.payload_uri" v-bind:type="rep.mime" />
|
<source v-for="rep in a.view.payload_alternatives" v-bind:src="rep.payload_uri" v-bind:type="rep.mime" />
|
||||||
<source v-if="a.view.payload_uri && a.view.mime" v-bind:src="a.view.payload_uri" v-bind:type="a.view.mime" />
|
<source v-if="a.view.payload_uri && a.view.mime" v-bind:src="a.view.payload_uri" v-bind:type="a.view.mime" />
|
||||||
</video>
|
</video>
|
||||||
|
<div class="progress" v-bind:style="{width: a.description}">
|
||||||
<div class="tl-controls">
|
<div class="progress-container">
|
||||||
<div class="btn btn-md btn-toggle btn-round" v-bind:class="{alt:a.player_view.state=='playing'}">
|
<h3>
|
||||||
<span class="btn-option play">
|
{{a.description}}
|
||||||
<span class="icon icon-controls-play"></span>
|
</h3>
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="btn-option pause">
|
|
||||||
<span class="icon icon-controls-pause"></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="btn btn-md btn-round btn-icon stop" v-show="a.player_view.state=='playing' || a.player_view.state=='paused'">
|
|
||||||
<span class="icon icon-controls-stop"></span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner"></div>
|
|
||||||
<div class="progress" v-bind:style="{width: a.view.progress+'%'}">{{a.description}}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- audio -->
|
<!-- audio -->
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="dialog-section">
|
<div class="dialog-section">
|
||||||
<label class="btn btn-xxl btn-transparent btn-icon">
|
<label class="btn btn-xxl btn-transparent btn-icon">
|
||||||
<span class="icon icon-picture-upload"></span>
|
<span class="icon icon-picture-upload"></span>
|
||||||
<input type="file" accept="*/*" multiple v-on:change="handle_image_file_upload($event)" id="image_file_upload">
|
<input type="file" multiple v-on:change="handle_image_file_upload($event)" id="image_file_upload">
|
||||||
</label>
|
</label>
|
||||||
<p>Click to Upload<br/> or drag file(s) anywhere.</p>
|
<p>Click to Upload<br/> or drag file(s) anywhere.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
|
|
||||||
<button class="btn btn-divider"></button>
|
<button class="btn btn-divider"></button>
|
||||||
|
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-on:click="lock_selected_artifacts()" v-if="active_space_role=='admin'" title="<%=__("lock")%>">
|
<button class="btn btn-transparent btn-icon-labeled" v-on:click="lock_selected_artifacts()" v-if="active_space_role=='admin' || toolbar_lock_in" title="<%=__("lock")%>">
|
||||||
<span class="icon icon-lock-closed"></span>
|
<span class="icon icon-lock-closed"></span>
|
||||||
<span class="icon-label"><%=__("lock")%></span>
|
<span class="icon-label"><%=__("lock")%></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-on:click="unlock_selected_artifacts()" v-if="active_space_role=='admin'" title="<%=__("unlock")%>">
|
<button class="btn btn-transparent btn-icon-labeled" v-on:click="unlock_selected_artifacts()" v-if="active_space_role=='admin' || toolbar_lock_in" title="<%=__("unlock")%>">
|
||||||
<span class="icon icon-lock-open"></span>
|
<span class="icon icon-lock-open"></span>
|
||||||
<span class="icon-label"><%=__("unlock")%></span>
|
<span class="icon-label"><%=__("unlock")%></span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<div class="toolbar toolbar-elements" v-bind:class="{in:toolbar_artifacts_in,out:!toolbar_artifacts_in}" v-show="!is_active_space_role('viewer') && active_space_loaded">
|
<div class="toolbar toolbar-elements" v-bind:class="{in:toolbar_artifacts_in,out:!toolbar_artifacts_in}" v-show="!is_active_space_role('viewer') && active_space_loaded">
|
||||||
|
|
||||||
<div class="btn-group light vertical">
|
<div class="btn-group light vertical">
|
||||||
|
|
||||||
<a class="btn btn-icon btn-transparent"
|
<a class="btn btn-icon btn-transparent"
|
||||||
title="<%=__("home")%>" href="/spaces"
|
title="<%=__("home")%>" href="/spaces"
|
||||||
v-if="(!active_space.parent_space_id && !guest_nickname && !embedded)">
|
v-if="(!active_space.parent_space_id && !guest_nickname && !embedded)">
|
||||||
<span class="icon icon-folder"></span>
|
<span class="icon icon-folder"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="btn btn-icon btn-dark"
|
<a class="btn btn-icon btn-dark"
|
||||||
title="Parent Folder"
|
title="Parent Folder"
|
||||||
href="/folders/{{active_space.parent_space_id}}"
|
href="/folders/{{active_space.parent_space_id}}"
|
||||||
v-if="(active_space.parent_space_id && !guest_nickname && !embedded)">
|
v-if="(active_space.parent_space_id && !guest_nickname && !embedded)">
|
||||||
|
|
||||||
<span class="icon icon-sd6 icon-svg"></span>
|
<span class="icon icon-sd6 icon-svg"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@@ -35,15 +35,16 @@
|
|||||||
<span class="icon icon-tool-scribble"></span>
|
<span class="icon icon-tool-scribble"></span>
|
||||||
<span class="icon-label"><%=__("tool_scribble")%></span>
|
<span class="icon-label"><%=__("tool_scribble")%></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-icon-labeled btn-transparent" v-on:click="start_drawing_arrow()" v-bind:class="{active:active_tool=='arrow'}" title="<%=__("tool_arrow")%>">
|
<button class="btn btn-icon-labeled btn-transparent" v-on:click="start_drawing_arrow()" v-bind:class="{active:active_tool=='arrow'}" title="<%=__("tool_arrow")%>">
|
||||||
<span class="icon icon-tool-arrow"></span>
|
<span class="icon icon-tool-arrow"></span>
|
||||||
<span class="icon-label"><%=__("tool_arrow")%></span>
|
<span class="icon-label"><%=__("tool_arrow")%></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="dropdown bottom light center">
|
<div class="dropdown bottom light center">
|
||||||
<div class="btn-collapse in">
|
<div class="btn-collapse in">
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-on:click="handle_insert_image_url()" v-on:touchstart="handle_insert_image_url()" title="<%=__("media")%>">
|
<input type="file" multiple v-on:change="handle_image_file_upload($event)" id="image_file_upload" class="btn btn-transparent btn-icon-labeled" style="position: absolute; z-index: 1; opacity: 0;">
|
||||||
|
<button class="btn btn-transparent btn-icon-labeled" title="<%=__("media")%>">
|
||||||
<span class="icon icon-upload"></span>
|
<span class="icon icon-upload"></span>
|
||||||
<span class="icon-label" ><%=__("media")%></span>
|
<span class="icon-label" ><%=__("media")%></span>
|
||||||
</button>
|
</button>
|
||||||
@@ -59,19 +60,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dropdown top left light">
|
|
||||||
<div class="btn-collapse">
|
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='image'}" v-on:click="open_dialog('image')" title="<%=__("image")%>">
|
|
||||||
<span class="icon icon-picture"></span>
|
|
||||||
<span class="icon-label"><%=__("image")%></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="dialog">
|
|
||||||
<%- include("./image.html") %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="dropdown top left light" v-bind:class="{open:opened_dialog=='zones'}">
|
<div class="dropdown top left light" v-bind:class="{open:opened_dialog=='zones'}">
|
||||||
<div class="btn-collapse in">
|
<div class="btn-collapse in">
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='zones'}" v-on:click="open_dialog('zones')" title="<%=__("tool_zones")%>">
|
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='zones'}" v-on:click="open_dialog('zones')" title="<%=__("tool_zones")%>">
|
||||||
@@ -84,7 +72,7 @@
|
|||||||
<%- include("./zones.html") %>
|
<%- include("./zones.html") %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-divider" v-show="logged_in"></button>
|
<button class="btn btn-divider" v-show="logged_in"></button>
|
||||||
|
|
||||||
<div class="dropdown top left center" v-show="logged_in" v-bind:class="{open:opened_dialog=='background'}">
|
<div class="dropdown top left center" v-show="logged_in" v-bind:class="{open:opened_dialog=='background'}">
|
||||||
@@ -107,8 +95,8 @@
|
|||||||
<span class="icon icon-share"></span>
|
<span class="icon icon-share"></span>
|
||||||
<span class="icon-label"><%= __('share') %></span>
|
<span class="icon-label"><%= __('share') %></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<li v-on:click="edit_space_title()" v-if="logged_in">
|
<li v-on:click="edit_space_title()" v-if="logged_in">
|
||||||
<span>
|
<span>
|
||||||
<span class="icon icon-sm icon-tag"></span>
|
<span class="icon icon-sm icon-tag"></span>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
<button class="btn btn-divider"></button>
|
<button class="btn btn-divider"></button>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='text-styles'}">
|
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='text-styles'}">
|
||||||
<div class="btn-collapse in">
|
<div class="btn-collapse in">
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-styles')" v-bind:class="{open : opened_dialog=='text-styles'}" title="<%=__("tool_styles")%>">
|
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-styles')" v-bind:class="{open : opened_dialog=='text-styles'}" title="<%=__("tool_styles")%>">
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
<%- include("./text-styles.html") %>
|
<%- include("./text-styles.html") %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='type-align'}">
|
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='type-align'}">
|
||||||
<div class="btn-collapse" v-bind:class="{in:selection_metrics.contains_text}">
|
<div class="btn-collapse" v-bind:class="{in:selection_metrics.contains_text}">
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('type-align')" v-bind:class="{open : opened_dialog=='type-align'}" title="<%=__("tool_align")%>">
|
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('type-align')" v-bind:class="{open : opened_dialog=='type-align'}" title="<%=__("tool_align")%>">
|
||||||
@@ -80,9 +80,9 @@
|
|||||||
<%- include("./layout.html") %>
|
<%- include("./layout.html") %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='text-settings'}">
|
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='text-settings'}">
|
||||||
|
|
||||||
<div class="btn-collapse in">
|
<div class="btn-collapse in">
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-settings')" v-bind:class="{open : opened_dialog=='text-settings'}" title="<%=__("tool_font")%>">
|
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-settings')" v-bind:class="{open : opened_dialog=='text-settings'}" title="<%=__("tool_font")%>">
|
||||||
<span class="icon icon-text-typeface"></span>
|
<span class="icon icon-text-typeface"></span>
|
||||||
@@ -97,6 +97,17 @@
|
|||||||
|
|
||||||
<button class="btn btn-divider"></button>
|
<button class="btn btn-divider"></button>
|
||||||
|
|
||||||
|
<div class="dropdown bottom light center">
|
||||||
|
<div class="btn-collapse" v-bind:class="{in:selection_metrics.contains_text}">
|
||||||
|
<button
|
||||||
|
class="btn btn-icon-labeled btn-transparent"
|
||||||
|
v-on:click="delayed_edit_artifact()">
|
||||||
|
<span class="icon icon-pencil"></span>
|
||||||
|
<span class="icon-label"><%=__("tool_edit_text")%></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='object-options'}">
|
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='object-options'}">
|
||||||
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('object-options')" v-bind:class="{open : opened_dialog=='object-options'}">
|
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('object-options')" v-bind:class="{open : opened_dialog=='object-options'}">
|
||||||
<span class="icon icon-cogwheel"></span>
|
<span class="icon icon-cogwheel"></span>
|
||||||
@@ -107,6 +118,6 @@
|
|||||||
<%- include("./object-options.html") %>
|
<%- include("./object-options.html") %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,21 +7,18 @@
|
|||||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
|
|
||||||
<link href="/images/favicon.png" rel="icon" type="image/x-icon" />
|
<link href="/images/favicon.png" rel="icon" type="image/x-icon" />
|
||||||
<link href='https://fonts.googleapis.com/css?family=Inter' rel='stylesheet' type='text/css'>
|
|
||||||
<link rel="stylesheet" href="/stylesheets/style.css">
|
<link rel="stylesheet" href="/stylesheets/style.css">
|
||||||
|
|
||||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
//window.browser_lang = '< %= locale %>';
|
|
||||||
var ENV = {
|
var ENV = {
|
||||||
name: 'development',
|
name: 'development',
|
||||||
webHost: location.host,
|
webHost: location.host,
|
||||||
webEndpoint: location.origin,
|
webEndpoint: location.origin,
|
||||||
apiEndpoint: location.origin,
|
apiEndpoint: location.origin,
|
||||||
websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:")
|
websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:"),
|
||||||
|
options: <%- config && config.spacedeck ? JSON.stringify(config.spacedeck) : "{}" %>
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -59,6 +56,9 @@
|
|||||||
<script src="/javascripts/spacedeck_whiteboard.js"></script>
|
<script src="/javascripts/spacedeck_whiteboard.js"></script>
|
||||||
<script src="/javascripts/spacedeck_directives.js"></script>
|
<script src="/javascripts/spacedeck_directives.js"></script>
|
||||||
<script src="/javascripts/spacedeck_vue.js"></script>
|
<script src="/javascripts/spacedeck_vue.js"></script>
|
||||||
|
|
||||||
|
<!-- TODO: only include based on config -->
|
||||||
|
<script src="https://js.chargebee.com/v2/chargebee.js"></script>
|
||||||
|
|
||||||
<script>if (window.module) module = window.module;</script>
|
<script>if (window.module) module = window.module;</script>
|
||||||
</head>
|
</head>
|
||||||
@@ -77,15 +77,17 @@
|
|||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.locales = {};
|
window.locales = {};
|
||||||
window.locales.en = {};
|
|
||||||
window.locales.de = {};
|
window.locales.de = {};
|
||||||
window.locales.fr = {};
|
window.locales.en = {};
|
||||||
window.locales.oc = {};
|
|
||||||
window.locales.es = {};
|
window.locales.es = {};
|
||||||
window.locales.en.translation = <%- include("./../locales/en.js") %>;
|
window.locales.fr = {};
|
||||||
|
window.locales.hu = {};
|
||||||
|
window.locales.oc = {};
|
||||||
window.locales.de.translation = <%- include("./../locales/de.js") %>;
|
window.locales.de.translation = <%- include("./../locales/de.js") %>;
|
||||||
|
window.locales.en.translation = <%- include("./../locales/en.js") %>;
|
||||||
|
window.locales.es.translation = <%- include("./../locales/es.js") %>;
|
||||||
window.locales.fr.translation = <%- include("./../locales/fr.js") %>;
|
window.locales.fr.translation = <%- include("./../locales/fr.js") %>;
|
||||||
|
window.locales.hu.translation = <%- include("./../locales/hu.js") %>;
|
||||||
window.locales.oc.translation = <%- include("./../locales/oc.js") %>;
|
window.locales.oc.translation = <%- include("./../locales/oc.js") %>;
|
||||||
window.locales.es.translation = <%- include("./../locales/es.js") %>;
|
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user