3 Commits

Author SHA1 Message Date
Lukas F. Hartmann
386d784952 touch: fix vector transforming (points of arrows, scribbles) 2020-12-18 18:11:33 +01:00
Lukas F. Hartmann
352b01569f touch: fix media upload on iDevice 2020-12-18 17:36:44 +01:00
Lukas F. Hartmann
82515e3a8e touch (tablet): fix deselect when tapping space; add edit text button 2020-12-18 17:07:32 +01:00
39 changed files with 16471 additions and 8521 deletions

3
.gitignore vendored
View File

@@ -5,5 +5,4 @@ public/stylesheets/*.css
database.sqlite database.sqlite
*.swp *.swp
*~ *~
storage/
.DS_Store

View File

@@ -1,44 +0,0 @@
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

View File

@@ -1 +0,0 @@
nodejs 10.23.1

29
.vscode/launch.json vendored
View File

@@ -1,29 +0,0 @@
{
"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"
}
}
]
}

View File

@@ -1,8 +0,0 @@
# Changelog
## [X.X.X] - 2021-03-23
### Changes
- Replaced phantomjs with puppeteer #169
- Create Hungarian language pack #174

View File

@@ -21,20 +21,6 @@ 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

View File

@@ -1,15 +1,13 @@
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()
}); })

View File

@@ -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) after cloning the repository: To install all node dependencies, run (do this once):
npm install npm install
@@ -45,52 +45,6 @@ To install all node dependencies, run (do this once) after cloning the repositor
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
@@ -107,34 +61,18 @@ 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`
- adapt your `docker-compose.yml` if needed. - configure `volumes` section inside `docker-compose.yml`
- start the container with `docker-compose up` - point to `database.sqlite` on the host system
(use `-d` for background process and `--build` for rebuilding the image) - `touch database.sqlite` if it not exists
- 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

View File

@@ -7,15 +7,8 @@
"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/database.sqlite", "storage_local_db": "./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",
@@ -25,7 +18,7 @@
"redis_mock": true, "redis_mock": true,
"redis_host": "localhost", "redis_host": "localhost",
"export_api_secret": "very_secret_export_password", "phantom_api_secret": "very_secret_phantom_password",
"mail_provider": "smtp", "mail_provider": "smtp",
"mail_smtp_host": "your.smtp.host", "mail_smtp_host": "your.smtp.host",
@@ -33,6 +26,5 @@
"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": {}
} }

View File

@@ -1,4 +1,5 @@
version: "2.0" version: "2.0"
services: services:
spacedeck: spacedeck:
build: . build: .
@@ -6,5 +7,6 @@ services:
ports: ports:
- "9666:9666" - "9666:9666"
volumes: volumes:
- ./storage:/app/storage - /absolute/path/to/storage:/app/storage
- ./database:/app/database - /absolute/path/to/database.sqlite:/app/database.sqlite

View File

@@ -12,7 +12,7 @@ server {
listen 80; listen 80;
listen [::]:80; listen [::]:80;
server_name spacedeck.domain.de servername spacedeck.domain.de
return 301 https://$server_name$request_uri; return 301 https://$server_name$request_uri;
} }

View File

@@ -50,8 +50,6 @@ 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) {
@@ -60,40 +58,6 @@ 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";
@@ -171,7 +135,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(getConversionProgress(""+data)+"%"); progressCallback(data);
} }
}); });

View File

@@ -1,58 +0,0 @@
'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();
}
})();
}
};

70
helpers/phantom.js Normal file
View File

@@ -0,0 +1,70 @@
'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
});
}
};

View File

@@ -320,6 +320,5 @@
"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"
} }

View File

@@ -1,328 +0,0 @@
{
"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"
}

View File

@@ -173,7 +173,7 @@
"tool_bullets": "Bullets", "tool_bullets": "Bullets",
"tool_numbers": "Nombres", "tool_numbers": "Nombres",
"color_fill": "Fill", "color_fill": "Fill",
"tool_font": "Poliça", "tool_font": "Font",
"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 tipe que siá 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 que siá tipe 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 lescòla e a luniversitat pels mai rics, experiéncia daprendissatge connectat.", "landing_example": "Lo monde utiliza Spacedeck per organizar lors idèas, en equipa per veire totes los projèctes en una ulhada, a lescòla e a luniversitat pels mai rics, experiéncia daprendissatge 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 quan creats.", "access_anonymous_edit_blocking": "Los convidats pòdon pas modificar los elements quan 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 daqueste Espaci apareisseràn aquí.", "access_no_members": "Los membres daqueste Espacii apreissarà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 dutilizar.", "landing_features_title": "Un jòc d'enfants dutilizar.",
@@ -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 coma PDF", "download_space_as_pdf": "Telecargar espaci 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": "Se qualquun mai presenta aqueste espaci, los demai membres seguiràn automaticament la presentacion. Basculatz labonament a la presentacion amb aqueste boton.", "follow_present_help": "follow_present_help",
"export": "exportar", "export": "exportar",
"media": "Mèdia" "media": "Media"
} }

View File

@@ -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 => {
if (user) { req.user = user;
req.user = user; next();
next(); }).error(err => {
} else { res.status(403).json({
res.status(403).json({ "error": "invalid_api-token"
error: "invalid_api-token", });
}); next();
}
}); });
return; return;
@@ -26,29 +26,28 @@ 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 }
db.User.findOne({ where: { _id: session.user_id } }).then((user) => { else db.User.findOne({where: {_id: session.user_id}})
.then(user => {
if (!user) { if (!user) {
var domain = var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : req.headers.hostname;
process.env.NODE_ENV == "production" res.clearCookie('sdsession', { domain: domain });
? 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;
@@ -56,11 +55,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();
} }
}; }

View File

@@ -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('export_api_secret')) { if (req.query['api_token'] && req.query['api_token'] == config.get('phantom_api_secret')) {
finalizeReq(space, "viewer"); finalizeReq(space, "viewer");
return; return;
} }

View File

@@ -6,28 +6,24 @@ function sequel_log(a,b,c) {
} }
const Sequelize = require('sequelize'); const Sequelize = require('sequelize');
const sequelize = new Sequelize( const sequelize = new Sequelize('database', 'username', 'password', {
config.get('storage_database'), host: 'localhost',
config.get('storage_username'), dialect: 'sqlite',
config.get('storage_password'),
{ pool: {
host: config.get('storage_host'), max: 5,
dialect: config.get('storage_dialect'), min: 0,
pool: { acquire: 30000,
max: 5, idle: 10000
min: 0, },
acquire: 30000,
idle: 10000 // SQLite only
}, storage: config.get('storage_local_db'),
logging: config.has('db_logs_disabled') ? false : sequel_log, logging: sequel_log,
// http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
operatorsAliases: false, // http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
// SQLite only operatorsAliases: false
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;

7528
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,9 +3,7 @@
"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"
@@ -24,35 +22,33 @@
"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": "^4.0.2", "mock-aws-s3": "^2.6.0",
"moment": "^2.19.3", "moment": "^2.19.3",
"morgan": "^1.9.1", "morgan": "^1.9.1",
"nodemailer": "^6.6.0", "node-phantom-simple": "2.2.4",
"puppeteer": "8.0.0", "node-server-screenshot": "^0.2.1",
"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": "^2.3.3", "sanitize-html": "^1.11.1",
"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.2.0", "sqlite3": "^4.0.0",
"umzug": "^2.1.0", "umzug": "^2.1.0",
"underscore": "^1.13.1", "underscore": "1.8.3",
"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": {},

View File

@@ -8,8 +8,6 @@ var SpacedeckSections = {
data: { data: {
MAX_COLUMNS: 20, MAX_COLUMNS: 20,
isShift: false,
redo_stack: [], redo_stack: [],
undo_stack: [], undo_stack: [],
@@ -64,15 +62,15 @@ var SpacedeckSections = {
active_style: { active_style: {
border_radius: 0, border_radius: 0,
stroke: 2, stroke: 0,
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: ENV.options.default_stroke_color ? ENV.options.default_stroke_color : "#000000", stroke_color: "#000000",
fill_color: ENV.options.default_fill_color ? ENV.options.default_fill_color : "#000000", fill_color: "#00000000",
text_color: ENV.options.default_text_color ? ENV.options.default_text_color : "#000000", text_color: "#000000",
background_color: "#ffffff", background_color: "#ffffff",
padding: 0, padding: 0,
@@ -111,7 +109,7 @@ var SpacedeckSections = {
color_picker_hue: 127, color_picker_hue: 127,
color_picker_opacity: 255, color_picker_opacity: 255,
swatches: ENV.options.swatches ? ENV.options.swatches : [ 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"},
@@ -135,7 +133,18 @@ 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: [
@@ -208,9 +217,7 @@ 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));
@@ -1360,7 +1367,7 @@ var SpacedeckSections = {
}, },
reset_stroke: function() { reset_stroke: function() {
this.active_style.stroke = 2; this.active_style.stroke = 0;
this.active_style.border_radius = 0; this.active_style.border_radius = 0;
this.active_style.stroke_style = "solid"; this.active_style.stroke_style = "solid";
}, },
@@ -1718,7 +1725,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: this.active_style.stroke, stroke: 0,
fill_color: this.active_style.fill_color, fill_color: this.active_style.fill_color,
shape: shape_type, shape: shape_type,
valign: "middle", valign: "middle",
@@ -2296,19 +2303,17 @@ 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(!this.isShift) { if (parsed.length==1) {
if (parsed.length==1) { var w = parsed[i].w;
var w = parsed[i].w; var h = parsed[i].h;
var h = parsed[i].h; var point = this.find_place_for_item(w,h);
var point = this.find_place_for_item(w,h); parsed[i].x = point.x;
parsed[i].x = point.x; parsed[i].y = point.y;
parsed[i].y = point.y; parsed[i].z = point.z;
parsed[i].z = point.z; } else {
} else { parsed[i].x = parsed[i].x+50;
parsed[i].x = parsed[i].x+100; parsed[i].y = parsed[i].y+50;
parsed[i].y = parsed[i].y+100; parsed[i].y = parsed[i].z+z;
parsed[i].y = parsed[i].z+z;
}
} }
this.clone_artifact(parsed[i], 0,0, function(a) { this.clone_artifact(parsed[i], 0,0, function(a) {
this.multi_select([a]); this.multi_select([a]);

View File

@@ -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) { load_space: function(space_id, on_success, on_error, space_auth) {
this.folder_spaces_filter=""; this.folder_spaces_filter="";
this.folder_spaces_search=""; this.folder_spaces_search="";
@@ -308,8 +308,7 @@ var SpacedeckSpaces = {
userReady(); userReady();
} }
if (!this.user.nickname && space_auth) { if (!this.user && space_auth) {
this.guest_nickname = get_query_param("nickname") || this.guest_nickname;
if (this.guest_nickname) { if (this.guest_nickname) {
userReady(); userReady();
} else { } else {

View File

@@ -23,9 +23,6 @@ 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

View File

@@ -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 exporter = require('../../helpers/exporter'); var phantom = require('../../helpers/phantom');
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 }});
exporter.takeScreenshot(req.space, "png", function(local_path) { phantom.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");
exporter.takeScreenshot(req.space, "pdf", function(local_path) { phantom.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

View File

@@ -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 exporter = require('../../helpers/exporter'); var phantom = require('../../helpers/phantom');
var async = require('async'); var async = require('async');
var fs = require('fs'); var fs = require('fs');

View File

@@ -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 exporter = require('../../helpers/exporter'); var phantom = require('../../helpers/phantom');
var payloadConverter = require('../../helpers/artifact_converter'); var payloadConverter = require('../../helpers/artifact_converter');
var slug = require('slug'); var slug = require('slug');

View File

@@ -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,39 +19,40 @@ 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 {
(async () => { phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) {
let browser; return browser.createPage(function (err, page) {
let page; page.set('settings.resourceTimeout',timeout);
try { page.set('settings.javascriptEnabled',false);
browser = await puppeteer.launch(
{
headless: true,
args: ['--disable-dev-shm-usage', '--no-sandbox']
}
);
page = await browser.newPage();
page.setDefaultTimeout(timeout); return page.open(url, function(err, status) {
await page.setJavaScriptEnabled(false); console.log("[webgrabber] status: "+status);
await page.goto(url, {waitUntil: 'networkidle2'}); page.render(export_path, function() {
await page.emulateMedia('screen'); on_success_called = true;
await page.screenshot({path: export_path, printBackground: true}); on_success(export_path);
browser.exit();
await browser.close(); });
on_success(export_path); });
} catch (error) { });
console.error(error); }, {
console.log("[webgrabber] puppeteer abnormal exit for url "+url); onExit: on_exit
on_error(); });
}
})();
} }
}); });
} }

View File

@@ -78,22 +78,6 @@ 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");
}); });
@@ -103,7 +87,7 @@ router.get('/en', (req, res) => {
}); });
router.get('/account', (req, res) => { router.get('/account', (req, res) => {
res.render('spacedeck', { config:config }); res.render('spacedeck');
}); });
router.get('/login', (req, res) => { router.get('/login', (req, res) => {

View File

@@ -33,7 +33,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: ["de", "en", "es", "fr", "hu", "oc"], locales: ["en", "de", "fr", "oc", "es"],
defaultLocale: "en", defaultLocale: "en",
cookieName: "spacedeck_locale", cookieName: "spacedeck_locale",
devMode: (app.get('env') == 'development') devMode: (app.get('env') == 'development')

View File

@@ -11,12 +11,10 @@
max-height: 100%; max-height: 100%;
} }
&.hide-text .text { &.hide-text .text { opacity: 0 }
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 {
@@ -28,9 +26,7 @@
} }
} }
&.artifact-text.text-blank &.artifact-text.text-blank [contentEditable=true]:not(.text-editing) p:first-child::after {
[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;
} }
@@ -83,6 +79,7 @@
// padding-right: 20px; margin-right: -20px; // padding-right: 20px; margin-right: -20px;
//> * {pointer-events: auto; } //> * {pointer-events: auto; }
} }
&:not(.artifact-text) { &:not(.artifact-text) {
@@ -145,9 +142,7 @@
li { li {
margin-top: 0; margin-top: 0;
margin-bottom: 0.5em; margin-bottom: 0.5em;
&:last-child { &:last-child {margin-bottom: 0em !important; }
margin-bottom: 0em !important;
}
} }
h1 { h1 {
@@ -184,14 +179,10 @@
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 { &:last-child {margin-bottom: 0em !important; }
margin-bottom: 0em !important;
}
} }
a { a {pointer-events: none; }
pointer-events: none;
}
ol { ol {
padding: 0; padding: 0;
@@ -256,7 +247,7 @@
} }
.oembed, .oembed,
div[class*="oembed-"] { div[class*='oembed-'] {
height: 100%; height: 100%;
.play { .play {
position: absolute; position: absolute;
@@ -299,9 +290,7 @@
} }
} }
.title { .title {font-size: 20px; }
font-size: 20px;
}
.image { .image {
height: auto; height: auto;
top: 0; top: 0;
@@ -330,11 +319,10 @@
} }
} }
.video { .video {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-size: cover; background-size: cover;
background-color: black;
&.playing { &.playing {
video { video {
@@ -359,7 +347,6 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
left: 0;
} }
.tl-controls { .tl-controls {
@@ -372,8 +359,10 @@
.btn { .btn {
margin-top: 20px; margin-top: 20px;
} }
} }
} }
// FIXME: fix later // FIXME: fix later
@@ -392,8 +381,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%;
@@ -402,7 +391,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;
@@ -438,11 +427,12 @@
.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;
@@ -464,41 +454,19 @@
height: 100%; height: 100%;
} }
&.bold { &.bold { font-weight: bold;}
font-weight: bold; &.italic { font-style: italic;}
} &.underline { text-decoration: underline;}
&.italic { &.strike { text-decoration: line-through;}
font-style: italic;
}
&.underline {
text-decoration: underline;
}
&.strike {
text-decoration: line-through;
}
&.align-top .text-cell { &.align-top .text-cell {vertical-align: top;}
vertical-align: top; &.align-middle .text-cell {vertical-align: middle;}
} &.align-bottom .text-cell {vertical-align: bottom;}
&.align-middle .text-cell {
vertical-align: middle;
}
&.align-bottom .text-cell {
vertical-align: bottom;
}
&.align-left { &.align-left { text-align: left; }
text-align: left; &.align-center { text-align: center; }
} &.align-right { text-align: right; }
&.align-center { &.align-justify { text-align: justify; }
text-align: center;
}
&.align-right {
text-align: right;
}
&.align-justify {
text-align: justify;
}
audio { audio {
width: 100%; width: 100%;
@@ -513,14 +481,10 @@
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 { &:after {display: none; }
display: none; .shape {display: none; }
}
.shape {
display: none;
}
.zone { .zone {
height: 100%; height: 100%;
} }
@@ -532,31 +496,32 @@ body.present-mode {
.artifact-zone { .artifact-zone {
display: none; display: none;
} }
.artifact { .artifact {
cursor: default !important; cursor: default !important;
.text a { .text a { pointer-events: auto !important; }
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;
} }
} }
@@ -570,27 +535,24 @@ 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, .mouse-scribble, .tool-scribble, .tool-line, .tool-arrow {
.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:after, .artifact:before {
.artifact:before {
display: none !important; display: none !important;
} }
} }
@@ -604,27 +566,21 @@ body:not(.present-mode) {
} }
.artifact.state-idle { .artifact.state-idle {
.progress, .progress, .progress-text {
.progress-text {
display: none; display: none;
} }
} }
.artifact.state-processing, .artifact.state-processing, .artifact.state-uploading {
.artifact.state-uploading {
.progress { .progress {
height: 100%; height: 100%;
padding: 4px; padding: 10px;
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;
@@ -637,48 +593,43 @@ body:not(.present-mode) {
color: #888; color: #888;
font-size: 10px; font-size: 10px;
} }
video, video, audio, .tl-controls, .timeline {
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 { &.state-loading { background-color: rgba(40,140,215,0.05);}
background-color: rgba(40, 140, 215, 0.05); &.state-processing { background-color: rgba(107,195,111,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;
} }

View File

@@ -3,17 +3,12 @@
@import "unicode"; @import "unicode";
@-webkit-keyframes appear { @-webkit-keyframes appear {
0% { 0% { opacity: 0;}
opacity: 0; 30% { 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;
@@ -31,9 +26,7 @@
#user-root { #user-root {
margin-left: 5px !important; margin-left: 5px !important;
padding: 0px !important; padding: 0px !important;
.btn { .btn {margin-right: 10px; }
margin-right: 10px;
}
} }
#sidebar.folder-sidebar { #sidebar.folder-sidebar {
@@ -77,9 +70,7 @@
li { li {
display: inline-block; display: inline-block;
line-height: 44px; line-height: 44px;
&.active span { &.active span {color: $light; }
color: $light;
}
span { span {
color: $medium; color: $medium;
display: inline-block; display: inline-block;
@@ -91,6 +82,8 @@
} }
} }
#folder { #folder {
position: absolute; position: absolute;
height: 100%; height: 100%;
@@ -144,7 +137,7 @@
z-index: initial; z-index: initial;
} }
.folder .icon { .folder .icon {
color: $yellow; color: $yellow;
opacity: 1; opacity: 1;
} }
@@ -157,7 +150,7 @@
width: 100%; width: 100%;
} }
> .icon { > .icon {
margin-left: -15px; margin-left: -15px
} }
} }
@@ -183,30 +176,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 {
@@ -219,22 +212,15 @@
margin: auto; margin: auto;
} }
#folder-grid .item { #folder-grid .item {
float: left; float: left;
width: 100%; width: 100%;
@media screen and (min-width: 640px) { @media screen and (min-width: 640px) {width: 50%; }
width: 50%; @media screen and (min-width: 800px) {width: 33.333333%; }
} @media screen and (min-width: 1000px) {width: 25%; }
@media screen and (min-width: 800px) { @media screen and (min-width: 1200px) {width: 20%; }
width: 33.333333%;
}
@media screen and (min-width: 1000px) {
width: 25%;
}
@media screen and (min-width: 1200px) {
width: 20%;
}
} }
.compact-hidden { .compact-hidden {
@@ -270,8 +256,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;
@@ -279,38 +265,36 @@
cursor: pointer; cursor: pointer;
.folder-drop { .folder-drop {display:none; }
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 {
@@ -324,7 +308,7 @@
&.dropping { &.dropping {
.folder-drop { .folder-drop {
display: block; display:block;
} }
} }
@@ -365,13 +349,7 @@
background-color: $darker; background-color: $darker;
position: absolute; position: absolute;
bottom: 2px; bottom: 2px;
-webkit-mask-image: -webkit-gradient( -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.1)));
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;
} }
@@ -382,7 +360,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);
} }
} }
@@ -406,7 +384,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*/
@@ -414,11 +392,9 @@
} }
background-color: white; background-color: white;
border-radius: $radius * 2; border-radius: $radius*2;
&:active { &:active { opacity: 0.95 !important; }
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;
@@ -430,7 +406,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 {
@@ -444,9 +420,8 @@
overflow: hidden; overflow: hidden;
background-color: transparent; background-color: transparent;
background-size: cover; border-top-left-radius: $radius*2;
border-top-left-radius: $radius * 2; border-top-right-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;
@@ -456,7 +431,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%;
@@ -464,8 +439,8 @@
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;
@@ -489,8 +464,8 @@
} }
.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;
@@ -518,8 +493,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;
@@ -534,7 +509,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;

View File

@@ -2,8 +2,9 @@
<div class="footer"> <div class="footer">
<p> <p>
<div class="col-xs-6"> <div class="col-xs-6">
Spacedeck is Free and Open Source Software. The developers are not affiliated with this website.<br> &copy; 2020 <a href="https://mntre.com">MNT Research GmbH</a>, Fehlerstr. 8, 12161 Berlin, Germany<br>
&copy; 20112020 <a href="https://github.com/mntmn/spacedeck-open">Spacedeck Open Developers</a><br> &copy; 20112020 Spacedeck GmbH (in liquidation)<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>

View File

@@ -3,12 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Spacedeck Open</title> <title>Spacedeck Open</title>
<meta name="title" content="Spacedeck Open"> <meta name="description" content="">
<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" />
@@ -29,5 +24,6 @@
<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>

View File

@@ -111,9 +111,6 @@
<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>

View File

@@ -156,13 +156,8 @@
<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="spinner"></div>
<div class="progress-container"> <div class="progress" v-bind:style="{width: a.view.progress+'%'}">{{a.description}}</div>
<h3>
{{a.description}}
</h3>
</div>
</div>
</div> </div>
<!-- audio --> <!-- audio -->

View File

@@ -17,8 +17,7 @@
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>
@@ -74,17 +73,15 @@
<script type="text/javascript"> <script type="text/javascript">
window.locales = {}; window.locales = {};
window.locales.de = {};
window.locales.en = {}; window.locales.en = {};
window.locales.es = {}; window.locales.de = {};
window.locales.fr = {}; window.locales.fr = {};
window.locales.hu = {};
window.locales.oc = {}; window.locales.oc = {};
window.locales.de.translation = <%- include("./../locales/de.js") %>; window.locales.es = {};
window.locales.en.translation = <%- include("./../locales/en.js") %>; window.locales.en.translation = <%- include("./../locales/en.js") %>;
window.locales.es.translation = <%- include("./../locales/es.js") %>; window.locales.de.translation = <%- include("./../locales/de.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>