Merge pull request #51 from FloChehab/style/setup_prettier
Features: auto-formating and CI to ckeck formating and docker build
This commit is contained in:
commit
69d7ebbe34
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.js,*.css,*.html}]
|
||||
indent_size = 4
|
18
.github/workflows/build-docker.yml
vendored
Normal file
18
.github/workflows/build-docker.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
# This workflow will do clean build of the docker image
|
||||
|
||||
name: Docker Image CI (also tests build)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build the Docker image
|
||||
run: docker build . --file Dockerfile --tag rofl256/whiteboard:$(date +%s)
|
21
.github/workflows/linting-code.yml
vendored
Normal file
21
.github/workflows/linting-code.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# This workflow will do a clean install of node dependencies and check the code style
|
||||
|
||||
name: Linting code CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
- run: npm ci
|
||||
- run: npm run style
|
3
.prettierrc.json
Normal file
3
.prettierrc.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"printWidth": 100
|
||||
}
|
151
README.md
151
README.md
@ -1,27 +1,33 @@
|
||||
# whiteboard
|
||||
|
||||
This is a lightweight NodeJS collaborative Whiteboard/Sketchboard witch can easily be customized...
|
||||
|
||||
![start](./doc/start.png)
|
||||
|
||||
## Demowhiteboard ##
|
||||
## Demowhiteboard
|
||||
|
||||
[HERE](https://cloud13.de/testwhiteboard/) (Reset every night)
|
||||
|
||||
## Some Features
|
||||
* Shows remote user cursors while drawing
|
||||
* Undo / Redo function for each user
|
||||
* Drag+Drop / Copy+Paste Images or PDFs from PC and Browsers
|
||||
* Resize, Move & Draw Images to Canvas or Background
|
||||
* Write text
|
||||
* Save Whiteboard to Image and JSON
|
||||
* Draw angle lines by pressing "shift" while drawing (with line tool)
|
||||
* Draw square by pressing "shift" while drawing (with rectangle tool)
|
||||
* Indicator that shows the smallest screen participating
|
||||
* Keybindings for ALL the functions
|
||||
* Working on PC, Tablet & Mobile
|
||||
|
||||
- Shows remote user cursors while drawing
|
||||
- Undo / Redo function for each user
|
||||
- Drag+Drop / Copy+Paste Images or PDFs from PC and Browsers
|
||||
- Resize, Move & Draw Images to Canvas or Background
|
||||
- Write text
|
||||
- Save Whiteboard to Image and JSON
|
||||
- Draw angle lines by pressing "shift" while drawing (with line tool)
|
||||
- Draw square by pressing "shift" while drawing (with rectangle tool)
|
||||
- Indicator that shows the smallest screen participating
|
||||
- Keybindings for ALL the functions
|
||||
- Working on PC, Tablet & Mobile
|
||||
|
||||
## Install the App
|
||||
|
||||
You can run this app with and without docker
|
||||
|
||||
### Without Docker
|
||||
|
||||
1. install the latest NodeJs
|
||||
2. Clone the app
|
||||
3. Run `npm ci` inside the folder
|
||||
@ -29,6 +35,7 @@ You can run this app with and without docker
|
||||
5. Surf to http://YOURIP:8080
|
||||
|
||||
### With Docker
|
||||
|
||||
1. `docker run -d -p 8080:8080 rofl256/whiteboard`
|
||||
2. Surf to http://YOURIP:8080
|
||||
|
||||
@ -37,63 +44,66 @@ You can run this app with and without docker
|
||||
After you have installed the app, run `npm run start:dev` to start the backend and a frontend development server. The website will be accessible on http://locahost:8080.
|
||||
|
||||
## Default keyboard shortcuts
|
||||
|
||||
Use keyboard shortcuts to become more productive while using Whiteboard.
|
||||
|
||||
They are especially useful if you work with interactive displays such as XP-Pen Artist, Huion Kamvas and Wacom Cintiq. These devices have quick buttons (6-8 buttons and scrolling). By default, the buttons on these displays are mapped to standard Photoshop keyboard shortcuts. Keys can be configured to function effectively in other software.
|
||||
|
||||
The following are predefined shortcuts that you can override in the file [./src/js/keybinds.js](./src/js/keybinds.js)
|
||||
|
||||
Result | Windows and Linux | macOS
|
||||
------ | -------------------- | -------
|
||||
Clear the whiteboard | Ctrl + Shift + Z | Command + Shift + Z
|
||||
Undo your last step | Ctrl + Z | Command + Z
|
||||
Redo your last undo | Ctrl + Y | Command + Y
|
||||
Select an area | Ctrl + X | Command + X
|
||||
Take the mouse | Ctrl + M | Command + M
|
||||
Take the pen | Ctrl + P | Command + P
|
||||
Draw a line | Ctrl + L | Command + L
|
||||
Draw a rectangle | Ctrl + R | Command + R
|
||||
Draw a circle | Ctrl + C | Command + C
|
||||
Toggle between line, rectangle and circle | Ctrl + Shift + F | Command + Shift + F
|
||||
Toggle between pen and eraser | Ctrl + Shift + X | Command + Shift + X
|
||||
Toggle between main clolors (black, blue, green, yellow and red) | Ctrl + Shift + R | Command + Shift + R
|
||||
Write text | Ctrl + A | Command + A
|
||||
Take the eraser | Ctrl + E | Command + E
|
||||
Increase thickness | Ctrl + Up Arrow | Command + Up Arrow
|
||||
Decrease thickness | Ctrl + Down Arrow | Command + Down Arrow
|
||||
Colorpicker | Ctrl + Shift + C | Command + Shift + C
|
||||
Set black color | Ctrl + Shift + 1 | Command + Shift + 1
|
||||
Set blue color | Ctrl + Shift + 2 | Command + Shift + 2
|
||||
Set green color | Ctrl + Shift + 3 | Command + Shift + 3
|
||||
Set yellow color | Ctrl + Shift + 4 | Command + Shift + 4
|
||||
Set red color | Ctrl + Shift + 5 | Command + Shift + 5
|
||||
Save whiteboard as image | Ctrl + S | Command + S
|
||||
Save whiteboard as JSON | Ctrl + Shift + K | Command + Shift + K
|
||||
Save whiteboard to WebDav | Ctrl + Shift + I (i) | Command + Shift + I (i)
|
||||
Load saved JSON to whiteboard | Ctrl + Shift + J | Command + Shift + J
|
||||
Share whiteboard | Ctrl + Shift + S | Command + Shift + S
|
||||
Hide or show toolbar | Tab | Tab
|
||||
Move selected object up | Up Arrow | Up Arrow
|
||||
Move selected object down | Down Arrow | Down Arrow
|
||||
Move selected object left | Left Arrow | Left Arrow
|
||||
Move selected object right | Right Arrow | Right Arrow
|
||||
Drop object | Ctrl + Enter | Command + Enter
|
||||
Add Image to backgroud | Shift + Enter | Shift + Enter
|
||||
Cancel all actions | Escape | Escape
|
||||
Delete selected object | Delete | Delete
|
||||
Use Line tool when pen is active (Not changeable) | Shift (Hold) | Shift (Hold)
|
||||
| Result | Windows and Linux | macOS |
|
||||
| ---------------------------------------------------------------- | -------------------- | ----------------------- |
|
||||
| Clear the whiteboard | Ctrl + Shift + Z | Command + Shift + Z |
|
||||
| Undo your last step | Ctrl + Z | Command + Z |
|
||||
| Redo your last undo | Ctrl + Y | Command + Y |
|
||||
| Select an area | Ctrl + X | Command + X |
|
||||
| Take the mouse | Ctrl + M | Command + M |
|
||||
| Take the pen | Ctrl + P | Command + P |
|
||||
| Draw a line | Ctrl + L | Command + L |
|
||||
| Draw a rectangle | Ctrl + R | Command + R |
|
||||
| Draw a circle | Ctrl + C | Command + C |
|
||||
| Toggle between line, rectangle and circle | Ctrl + Shift + F | Command + Shift + F |
|
||||
| Toggle between pen and eraser | Ctrl + Shift + X | Command + Shift + X |
|
||||
| Toggle between main clolors (black, blue, green, yellow and red) | Ctrl + Shift + R | Command + Shift + R |
|
||||
| Write text | Ctrl + A | Command + A |
|
||||
| Take the eraser | Ctrl + E | Command + E |
|
||||
| Increase thickness | Ctrl + Up Arrow | Command + Up Arrow |
|
||||
| Decrease thickness | Ctrl + Down Arrow | Command + Down Arrow |
|
||||
| Colorpicker | Ctrl + Shift + C | Command + Shift + C |
|
||||
| Set black color | Ctrl + Shift + 1 | Command + Shift + 1 |
|
||||
| Set blue color | Ctrl + Shift + 2 | Command + Shift + 2 |
|
||||
| Set green color | Ctrl + Shift + 3 | Command + Shift + 3 |
|
||||
| Set yellow color | Ctrl + Shift + 4 | Command + Shift + 4 |
|
||||
| Set red color | Ctrl + Shift + 5 | Command + Shift + 5 |
|
||||
| Save whiteboard as image | Ctrl + S | Command + S |
|
||||
| Save whiteboard as JSON | Ctrl + Shift + K | Command + Shift + K |
|
||||
| Save whiteboard to WebDav | Ctrl + Shift + I (i) | Command + Shift + I (i) |
|
||||
| Load saved JSON to whiteboard | Ctrl + Shift + J | Command + Shift + J |
|
||||
| Share whiteboard | Ctrl + Shift + S | Command + Shift + S |
|
||||
| Hide or show toolbar | Tab | Tab |
|
||||
| Move selected object up | Up Arrow | Up Arrow |
|
||||
| Move selected object down | Down Arrow | Down Arrow |
|
||||
| Move selected object left | Left Arrow | Left Arrow |
|
||||
| Move selected object right | Right Arrow | Right Arrow |
|
||||
| Drop object | Ctrl + Enter | Command + Enter |
|
||||
| Add Image to backgroud | Shift + Enter | Shift + Enter |
|
||||
| Cancel all actions | Escape | Escape |
|
||||
| Delete selected object | Delete | Delete |
|
||||
| Use Line tool when pen is active (Not changeable) | Shift (Hold) | Shift (Hold) |
|
||||
|
||||
## URL Parameters
|
||||
|
||||
Call your site with GET parameters to change the WhiteboardID or the Username
|
||||
|
||||
`http://YOURIP:8080?whiteboardid=MYID&username=MYNAME`
|
||||
|
||||
* whiteboardid => All people with the same ID are drawing on the same board
|
||||
* username => The name witch is showing to others while drawing
|
||||
* title => Change the name of the Browser Tab
|
||||
* randomid => if set to true, a random whiteboardId will be generated if not given aswell
|
||||
- whiteboardid => All people with the same ID are drawing on the same board
|
||||
- username => The name witch is showing to others while drawing
|
||||
- title => Change the name of the Browser Tab
|
||||
- randomid => if set to true, a random whiteboardId will be generated if not given aswell
|
||||
|
||||
## Security - AccessToken (Optional)
|
||||
|
||||
To prevent clients who might know or guess the base URL from abusing the server to upload files and stuff..., you can set an accesstoken at server start.
|
||||
|
||||
<b>Server (Without docker):</b> `node scripts/server.js --accesstoken="mySecToken"`
|
||||
@ -107,6 +117,7 @@ Then set the same token on the client side as well:
|
||||
Done!
|
||||
|
||||
## WebDAV (Optional)
|
||||
|
||||
This function allows your users to save the whiteboard directly to a webdav server (Nextcloud) as image without downloading it.
|
||||
|
||||
To enable it:
|
||||
@ -125,21 +136,25 @@ Note: For the most owncloud/nextcloud setups you have to set the WebDav-Server U
|
||||
|
||||
Done!
|
||||
|
||||
|
||||
## Things you may want to know
|
||||
* Whiteboards are gone if you restart the Server, so keep that in mind (or save your whiteboard)
|
||||
* You should be able to customize the layout without ever touching the whiteboard.js (take a look at index.html & main.js)
|
||||
|
||||
- Whiteboards are gone if you restart the Server, so keep that in mind (or save your whiteboard)
|
||||
- You should be able to customize the layout without ever touching the whiteboard.js (take a look at index.html & main.js)
|
||||
|
||||
## All server start parameters (also docker)
|
||||
* accesstoken => take a look at "Security - AccessToken" for a full explanation
|
||||
* disablesmallestscreen => set this to "true" if you don't want show the "smallest screen" indicator (A dotted gray line) to the users
|
||||
* webdav => Enable the function to save to a webdav-server (Must also be enabled on the client; Take a look at the webdav section)
|
||||
|
||||
- accesstoken => take a look at "Security - AccessToken" for a full explanation
|
||||
- disablesmallestscreen => set this to "true" if you don't want show the "smallest screen" indicator (A dotted gray line) to the users
|
||||
- webdav => Enable the function to save to a webdav-server (Must also be enabled on the client; Take a look at the webdav section)
|
||||
|
||||
## ToDo
|
||||
* Make undo function more reliable on texts
|
||||
|
||||
- Make undo function more reliable on texts
|
||||
|
||||
## Nginx Reverse Proxy configuration
|
||||
|
||||
Add this to your server part:
|
||||
|
||||
```
|
||||
location /whiteboard/ {
|
||||
proxy_set_header HOST $host;
|
||||
@ -149,22 +164,22 @@ Add this to your server part:
|
||||
proxy_pass http://YOURIP:8080/;
|
||||
}
|
||||
```
|
||||
|
||||
To run it at /whiteboard. Don't forget to change -> YOURIP!
|
||||
|
||||
## Nextcloud integration
|
||||
|
||||
1. Install this app on your server
|
||||
2. Enable and go to "external sites" (app) on your Nextcloud
|
||||
2. Add a link to your server: `https://YOURIP/whiteboard/?whiteboardid=WHITEBOARDNAME&username={uid}`
|
||||
You can give each group its own whiteboard by changeing the WHITEBOARDNAME in the URL if you want.
|
||||
3. Add a link to your server: `https://YOURIP/whiteboard/?whiteboardid=WHITEBOARDNAME&username={uid}`
|
||||
You can give each group its own whiteboard by changeing the WHITEBOARDNAME in the URL if you want.
|
||||
|
||||
Note: You might have to serve the app with https (If your nextcloud server runs https). To do so, its recommend to run this app behind a reverse proxy. (as shown above)
|
||||
|
||||
#### (Optional) Set whiteboard icon in nextcloud
|
||||
|
||||
![start](https://raw.githubusercontent.com/cracker0dks/whiteboard/master/doc/iconPrev.jpg)
|
||||
|
||||
Upload both icons present at /doc/nextcloud_icons/ to your nextcloud at the "external sites" admin section. Then set it as symbol on your link.
|
||||
|
||||
|
||||
|
||||
|
||||
___ MIT License ___
|
||||
**_ MIT License _**
|
||||
|
@ -1,61 +1,59 @@
|
||||
const webpack = require("webpack");
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const path = require("path");
|
||||
|
||||
const config = {
|
||||
entry: {
|
||||
main: ["./src/js/index.js"],
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, "..", "dist"),
|
||||
filename: "[name]-[hash].js"
|
||||
},
|
||||
resolve: {
|
||||
extensions: ["*", ".json", ".js"]
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
compact: true
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
},
|
||||
entry: {
|
||||
main: ["./src/js/index.js"],
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, "..", "dist"),
|
||||
filename: "[name]-[hash].js",
|
||||
},
|
||||
resolve: {
|
||||
extensions: ["*", ".json", ".js"],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
compact: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: "file-loader",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new webpack.ProvidePlugin({
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
"window.jQuery": "jquery",
|
||||
"window.$": "jquery",
|
||||
}),
|
||||
new CopyPlugin([
|
||||
{ from: 'assets', to: '' },
|
||||
]),
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'src/index.html',
|
||||
minify: false,
|
||||
inject: true
|
||||
})
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new webpack.ProvidePlugin({
|
||||
$: "jquery",
|
||||
jQuery: "jquery",
|
||||
"window.jQuery": "jquery",
|
||||
"window.$": "jquery",
|
||||
}),
|
||||
new CopyPlugin([{ from: "assets", to: "" }]),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "src/index.html",
|
||||
minify: false,
|
||||
inject: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
@ -2,10 +2,10 @@ const merge = require("webpack-merge");
|
||||
const baseConfig = require("./webpack.base");
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: "production",
|
||||
optimization: {
|
||||
minimize: true,
|
||||
nodeEnv: "production",
|
||||
},
|
||||
devtool: false
|
||||
mode: "production",
|
||||
optimization: {
|
||||
minimize: true,
|
||||
nodeEnv: "production",
|
||||
},
|
||||
devtool: false,
|
||||
});
|
||||
|
@ -3,16 +3,16 @@ const baseConfig = require("./webpack.base");
|
||||
const webpack = require("webpack");
|
||||
|
||||
const devConfig = merge(baseConfig, {
|
||||
mode: "development",
|
||||
devtool: "eval-source-map",
|
||||
optimization: {
|
||||
minimize: false,
|
||||
},
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NamedModulesPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
].concat(baseConfig.plugins),
|
||||
mode: "development",
|
||||
devtool: "eval-source-map",
|
||||
optimization: {
|
||||
minimize: false,
|
||||
},
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NamedModulesPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
].concat(baseConfig.plugins),
|
||||
});
|
||||
|
||||
module.exports = devConfig;
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: '3.1'
|
||||
version: "3.1"
|
||||
services:
|
||||
whiteboard:
|
||||
image: rofl256/whiteboard
|
||||
|
521
package-lock.json
generated
521
package-lock.json
generated
@ -1069,6 +1069,12 @@
|
||||
"integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/color-name": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
||||
@ -1104,6 +1110,12 @@
|
||||
"integrity": "sha512-WE4IOAC6r/yBZss1oQGM5zs2D7RuKR6Q+w+X2SouPofnWn+LbCqClRyhO3ZE7Ix8nmFgo/oVuuE01cJT2XB13A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/source-list-map": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||
@ -1469,6 +1481,12 @@
|
||||
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
|
||||
"dev": true
|
||||
},
|
||||
"array-differ": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
|
||||
"integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
|
||||
"dev": true
|
||||
},
|
||||
"array-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
|
||||
@ -1505,6 +1523,12 @@
|
||||
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
|
||||
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
|
||||
},
|
||||
"arrify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
|
||||
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
|
||||
"dev": true
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||
@ -2304,6 +2328,12 @@
|
||||
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
||||
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
|
||||
},
|
||||
"callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"camel-case": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz",
|
||||
@ -2377,6 +2407,12 @@
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"ci-info": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
|
||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
@ -2491,6 +2527,12 @@
|
||||
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
|
||||
"dev": true
|
||||
},
|
||||
"compare-versions": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
|
||||
"integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
|
||||
"dev": true
|
||||
},
|
||||
"component-bind": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
|
||||
@ -2764,6 +2806,27 @@
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
|
||||
"integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.1.0",
|
||||
"parse-json": "^5.0.0",
|
||||
"path-type": "^4.0.0",
|
||||
"yaml": "^1.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"create-ecdh": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
|
||||
@ -3365,6 +3428,15 @@
|
||||
"prr": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.17.5",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
|
||||
@ -3774,6 +3846,15 @@
|
||||
"locate-path": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"find-versions": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz",
|
||||
"integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"findup-sync": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
|
||||
@ -4899,6 +4980,140 @@
|
||||
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
|
||||
"dev": true
|
||||
},
|
||||
"husky": {
|
||||
"version": "4.2.5",
|
||||
"resolved": "https://registry.npmjs.org/husky/-/husky-4.2.5.tgz",
|
||||
"integrity": "sha512-SYZ95AjKcX7goYVZtVZF2i6XiZcHknw50iXvY7b0MiGoj5RwdgRQNEHdb+gPDPCXKlzwrybjFjkL6FOj8uRhZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.0.0",
|
||||
"ci-info": "^2.0.0",
|
||||
"compare-versions": "^3.6.0",
|
||||
"cosmiconfig": "^6.0.0",
|
||||
"find-versions": "^3.2.0",
|
||||
"opencollective-postinstall": "^2.0.2",
|
||||
"pkg-dir": "^4.2.0",
|
||||
"please-upgrade-node": "^3.2.0",
|
||||
"slash": "^3.0.0",
|
||||
"which-pm-runs": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/color-name": "^1.1.1",
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
|
||||
"integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"find-up": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true
|
||||
},
|
||||
"pkg-dir": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
|
||||
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"find-up": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
||||
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
|
||||
@ -4931,6 +5146,24 @@
|
||||
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
|
||||
"dev": true
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
|
||||
"integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"import-local": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
|
||||
@ -5073,6 +5306,12 @@
|
||||
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
|
||||
"dev": true
|
||||
},
|
||||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
|
||||
"dev": true
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
|
||||
@ -5460,6 +5699,12 @@
|
||||
"type-check": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"lines-and-columns": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
|
||||
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
|
||||
"dev": true
|
||||
},
|
||||
"loader-runner": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
|
||||
@ -5628,6 +5873,12 @@
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"dev": true
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
@ -5775,6 +6026,12 @@
|
||||
"run-queue": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"mri": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.1.5.tgz",
|
||||
"integrity": "sha512-d2RKzMD4JNyHMbnbWnznPaa8vbdlq/4pNZ3IgdaGrVbBhebBsGUUE/6qorTMYNS6TwuH3ilfOlD2bf4Igh8CKg==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@ -5796,6 +6053,27 @@
|
||||
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
|
||||
"dev": true
|
||||
},
|
||||
"multimatch": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz",
|
||||
"integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/minimatch": "^3.0.3",
|
||||
"array-differ": "^3.0.0",
|
||||
"array-union": "^2.1.0",
|
||||
"arrify": "^2.0.1",
|
||||
"minimatch": "^3.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"array-union": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
@ -6078,6 +6356,21 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"onetime": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
|
||||
"integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mimic-fn": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"opencollective-postinstall": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz",
|
||||
"integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==",
|
||||
"dev": true
|
||||
},
|
||||
"opn": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
|
||||
@ -6210,6 +6503,15 @@
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"callsites": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"parse-asn1": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz",
|
||||
@ -6224,6 +6526,18 @@
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
|
||||
"integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1",
|
||||
"lines-and-columns": "^1.1.6"
|
||||
}
|
||||
},
|
||||
"parse-passwd": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
|
||||
@ -6452,6 +6766,15 @@
|
||||
"find-up": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"please-upgrade-node": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
|
||||
"integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver-compare": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"pn": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
|
||||
@ -6576,6 +6899,12 @@
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz",
|
||||
"integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty-error": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
|
||||
@ -6586,6 +6915,165 @@
|
||||
"utila": "~0.4"
|
||||
}
|
||||
},
|
||||
"pretty-quick": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-2.0.1.tgz",
|
||||
"integrity": "sha512-y7bJt77XadjUr+P1uKqZxFWLddvj3SKY6EU4BuQtMxmmEFSMpbN132pUWdSG1g1mtUfO0noBvn7wBf0BVeomHg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"execa": "^2.1.0",
|
||||
"find-up": "^4.1.0",
|
||||
"ignore": "^5.1.4",
|
||||
"mri": "^1.1.4",
|
||||
"multimatch": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"cross-spawn": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz",
|
||||
"integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"execa": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz",
|
||||
"integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"get-stream": "^5.0.0",
|
||||
"is-stream": "^2.0.0",
|
||||
"merge-stream": "^2.0.0",
|
||||
"npm-run-path": "^3.0.0",
|
||||
"onetime": "^5.1.0",
|
||||
"p-finally": "^2.0.0",
|
||||
"signal-exit": "^3.0.2",
|
||||
"strip-final-newline": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"find-up": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
|
||||
"integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pump": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
|
||||
"integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
|
||||
"dev": true
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz",
|
||||
"integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-key": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"p-finally": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
|
||||
"integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==",
|
||||
"dev": true
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true
|
||||
},
|
||||
"path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"private": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
|
||||
@ -7200,6 +7688,18 @@
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"semver-compare": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
|
||||
"integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
|
||||
"dev": true
|
||||
},
|
||||
"semver-regex": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz",
|
||||
"integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==",
|
||||
"dev": true
|
||||
},
|
||||
"send": {
|
||||
"version": "0.16.1",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz",
|
||||
@ -7833,6 +8333,12 @@
|
||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
||||
"dev": true
|
||||
},
|
||||
"strip-final-newline": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
||||
"dev": true
|
||||
},
|
||||
"style-loader": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.1.4.tgz",
|
||||
@ -9269,6 +9775,12 @@
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
|
||||
"dev": true
|
||||
},
|
||||
"which-pm-runs": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
|
||||
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
|
||||
"dev": true
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
@ -9377,6 +9889,15 @@
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"dev": true
|
||||
},
|
||||
"yaml": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.9.2.tgz",
|
||||
"integrity": "sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
},
|
||||
"yargs": {
|
||||
"version": "13.2.4",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
|
||||
|
13
package.json
13
package.json
@ -8,7 +8,10 @@
|
||||
"build": "webpack --config config/webpack.build.js",
|
||||
"start:dev": "node scripts/server.js --mode=development",
|
||||
"start:prod": "npm run build && node scripts/server.js --mode=production",
|
||||
"test": "echo \"No tests needed!\" && exit 1"
|
||||
"test": "echo \"No tests needed!\" && exit 1",
|
||||
"pretty-quick": "pretty-quick",
|
||||
"format": "prettier --write .",
|
||||
"style": "prettier --check ."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -19,6 +22,11 @@
|
||||
"Sketchboard",
|
||||
"lightweight"
|
||||
],
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"dompurify": "^2.0.7",
|
||||
"express": "4.*",
|
||||
@ -45,9 +53,12 @@
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^3.5.2",
|
||||
"html-webpack-plugin": "^4.2.0",
|
||||
"husky": "^4.2.5",
|
||||
"jquery": "^3.2.1",
|
||||
"jquery-ui": "^1.12.1",
|
||||
"keymage": "^1.1.3",
|
||||
"prettier": "^2.0.5",
|
||||
"pretty-quick": "^2.0.1",
|
||||
"style-loader": "^1.1.4",
|
||||
"vanilla-picker": "^2.10.1",
|
||||
"webpack": "^4.42.1",
|
||||
|
@ -7,10 +7,12 @@ module.exports = {
|
||||
var tool = content["t"]; //Tool witch is used
|
||||
var wid = content["wid"]; //whiteboard ID
|
||||
var username = content["username"];
|
||||
if (tool === "clear") { //Clear the whiteboard
|
||||
if (tool === "clear") {
|
||||
//Clear the whiteboard
|
||||
delete savedBoards[wid];
|
||||
delete savedUndos[wid];
|
||||
} else if (tool === "undo") { //Undo an action
|
||||
} else if (tool === "undo") {
|
||||
//Undo an action
|
||||
if (!savedUndos[wid]) {
|
||||
savedUndos[wid] = [];
|
||||
}
|
||||
@ -19,7 +21,10 @@ module.exports = {
|
||||
if (savedBoards[wid][i]["username"] == username) {
|
||||
var drawId = savedBoards[wid][i]["drawId"];
|
||||
for (var i = savedBoards[wid].length - 1; i >= 0; i--) {
|
||||
if (savedBoards[wid][i]["drawId"] == drawId && savedBoards[wid][i]["username"] == username) {
|
||||
if (
|
||||
savedBoards[wid][i]["drawId"] == drawId &&
|
||||
savedBoards[wid][i]["username"] == username
|
||||
) {
|
||||
savedUndos[wid].push(savedBoards[wid][i]);
|
||||
savedBoards[wid].splice(i, 1);
|
||||
}
|
||||
@ -27,7 +32,7 @@ module.exports = {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(savedUndos[wid].length > 1000) {
|
||||
if (savedUndos[wid].length > 1000) {
|
||||
savedUndos[wid].splice(0, savedUndos[wid].length - 1000);
|
||||
}
|
||||
}
|
||||
@ -42,7 +47,10 @@ module.exports = {
|
||||
if (savedUndos[wid][i]["username"] == username) {
|
||||
var drawId = savedUndos[wid][i]["drawId"];
|
||||
for (var i = savedUndos[wid].length - 1; i >= 0; i--) {
|
||||
if (savedUndos[wid][i]["drawId"] == drawId && savedUndos[wid][i]["username"] == username) {
|
||||
if (
|
||||
savedUndos[wid][i]["drawId"] == drawId &&
|
||||
savedUndos[wid][i]["username"] == username
|
||||
) {
|
||||
savedBoards[wid].push(savedUndos[wid][i]);
|
||||
savedUndos[wid].splice(i, 1);
|
||||
}
|
||||
@ -50,14 +58,36 @@ module.exports = {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (["line", "pen", "rect", "circle", "eraser", "addImgBG", "recSelect", "eraseRec", "addTextBox", "setTextboxText", "removeTextbox", "setTextboxPosition", "setTextboxFontSize", "setTextboxFontColor"].includes(tool)) { //Save all this actions
|
||||
} else if (
|
||||
[
|
||||
"line",
|
||||
"pen",
|
||||
"rect",
|
||||
"circle",
|
||||
"eraser",
|
||||
"addImgBG",
|
||||
"recSelect",
|
||||
"eraseRec",
|
||||
"addTextBox",
|
||||
"setTextboxText",
|
||||
"removeTextbox",
|
||||
"setTextboxPosition",
|
||||
"setTextboxFontSize",
|
||||
"setTextboxFontColor",
|
||||
].includes(tool)
|
||||
) {
|
||||
//Save all this actions
|
||||
if (!savedBoards[wid]) {
|
||||
savedBoards[wid] = [];
|
||||
}
|
||||
delete content["wid"]; //Delete id from content so we don't store it twice
|
||||
if (tool === "setTextboxText") {
|
||||
for (var i = savedBoards[wid].length - 1; i >= 0; i--) { //Remove old textbox tex -> dont store it twice
|
||||
if (savedBoards[wid][i]["t"] === "setTextboxText" && savedBoards[wid][i]["d"][0] === content["d"][0]) {
|
||||
for (var i = savedBoards[wid].length - 1; i >= 0; i--) {
|
||||
//Remove old textbox tex -> dont store it twice
|
||||
if (
|
||||
savedBoards[wid][i]["t"] === "setTextboxText" &&
|
||||
savedBoards[wid][i]["d"][0] === content["d"][0]
|
||||
) {
|
||||
savedBoards[wid].splice(i, 1);
|
||||
}
|
||||
}
|
||||
@ -65,7 +95,8 @@ module.exports = {
|
||||
savedBoards[wid].push(content);
|
||||
}
|
||||
},
|
||||
loadStoredData: function (wid) { //Load saved whiteboard
|
||||
loadStoredData: function (wid) {
|
||||
//Load saved whiteboard
|
||||
return savedBoards[wid] ? savedBoards[wid] : [];
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -5,26 +5,26 @@ function startBackendServer(port) {
|
||||
var accessToken = ""; //Can be set here or as start parameter (node server.js --accesstoken=MYTOKEN)
|
||||
var disableSmallestScreen = false; //Can be set to true if you dont want to show (node server.js --disablesmallestscreen=true)
|
||||
var webdav = false; //Can be set to true if you want to allow webdav save (node server.js --webdav=true)
|
||||
|
||||
|
||||
var fs = require("fs-extra");
|
||||
var express = require('express');
|
||||
var formidable = require('formidable'); //form upload processing
|
||||
|
||||
const createDOMPurify = require('dompurify'); //Prevent xss
|
||||
const { JSDOM } = require('jsdom');
|
||||
const window = (new JSDOM('')).window;
|
||||
var express = require("express");
|
||||
var formidable = require("formidable"); //form upload processing
|
||||
|
||||
const createDOMPurify = require("dompurify"); //Prevent xss
|
||||
const { JSDOM } = require("jsdom");
|
||||
const window = new JSDOM("").window;
|
||||
const DOMPurify = createDOMPurify(window);
|
||||
|
||||
|
||||
const { createClient } = require("webdav");
|
||||
|
||||
|
||||
var s_whiteboard = require("./s_whiteboard.js");
|
||||
|
||||
|
||||
var app = express();
|
||||
app.use(express.static(path.join(__dirname, '..', 'dist')));
|
||||
app.use("/uploads", express.static(path.join(__dirname, '..', 'public', 'uploads')));
|
||||
var server = require('http').Server(app);
|
||||
app.use(express.static(path.join(__dirname, "..", "dist")));
|
||||
app.use("/uploads", express.static(path.join(__dirname, "..", "public", "uploads")));
|
||||
var server = require("http").Server(app);
|
||||
server.listen(port);
|
||||
var io = require('socket.io')(server, {path: "/ws-api", });
|
||||
var io = require("socket.io")(server, { path: "/ws-api" });
|
||||
console.log("Webserver & socketserver running on port:" + port);
|
||||
if (process.env.accesstoken) {
|
||||
accessToken = process.env.accesstoken;
|
||||
@ -35,7 +35,7 @@ function startBackendServer(port) {
|
||||
if (process.env.webdav) {
|
||||
webdav = true;
|
||||
}
|
||||
|
||||
|
||||
var startArgs = getArgs();
|
||||
if (startArgs["accesstoken"]) {
|
||||
accessToken = startArgs["accesstoken"];
|
||||
@ -46,7 +46,7 @@ function startBackendServer(port) {
|
||||
if (startArgs["webdav"]) {
|
||||
webdav = true;
|
||||
}
|
||||
|
||||
|
||||
if (accessToken !== "") {
|
||||
console.log("AccessToken set to: " + accessToken);
|
||||
}
|
||||
@ -56,8 +56,8 @@ function startBackendServer(port) {
|
||||
if (webdav) {
|
||||
console.log("Webdav save is enabled!");
|
||||
}
|
||||
|
||||
app.get('/api/loadwhiteboard', function (req, res) {
|
||||
|
||||
app.get("/api/loadwhiteboard", function (req, res) {
|
||||
var wid = req["query"]["wid"];
|
||||
var at = req["query"]["at"]; //accesstoken
|
||||
if (accessToken === "" || accessToken == at) {
|
||||
@ -65,31 +65,32 @@ function startBackendServer(port) {
|
||||
res.send(ret);
|
||||
res.end();
|
||||
} else {
|
||||
res.status(401); //Unauthorized
|
||||
res.status(401); //Unauthorized
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/upload', function (req, res) { //File upload
|
||||
|
||||
app.post("/api/upload", function (req, res) {
|
||||
//File upload
|
||||
var form = new formidable.IncomingForm(); //Receive form
|
||||
var formData = {
|
||||
files: {},
|
||||
fields: {}
|
||||
}
|
||||
|
||||
form.on('file', function (name, file) {
|
||||
fields: {},
|
||||
};
|
||||
|
||||
form.on("file", function (name, file) {
|
||||
formData["files"][file.name] = file;
|
||||
});
|
||||
|
||||
form.on('field', function (name, value) {
|
||||
|
||||
form.on("field", function (name, value) {
|
||||
formData["fields"][name] = value;
|
||||
});
|
||||
|
||||
form.on('error', function (err) {
|
||||
console.log('File uplaod Error!');
|
||||
|
||||
form.on("error", function (err) {
|
||||
console.log("File uplaod Error!");
|
||||
});
|
||||
|
||||
form.on('end', function () {
|
||||
|
||||
form.on("end", function () {
|
||||
if (accessToken === "" || accessToken == formData["fields"]["at"]) {
|
||||
progressUploadFormData(formData, function (err) {
|
||||
if (err) {
|
||||
@ -104,22 +105,22 @@ function startBackendServer(port) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(401); //Unauthorized
|
||||
res.status(401); //Unauthorized
|
||||
res.end();
|
||||
}
|
||||
//End file upload
|
||||
});
|
||||
form.parse(req);
|
||||
});
|
||||
|
||||
|
||||
function progressUploadFormData(formData, callback) {
|
||||
console.log("Progress new Form Data");
|
||||
var fields = escapeAllContentStrings(formData.fields);
|
||||
var files = formData.files;
|
||||
var whiteboardId = fields["whiteboardId"];
|
||||
|
||||
|
||||
var name = fields["name"] || "";
|
||||
var date = fields["date"] || (+new Date());
|
||||
var date = fields["date"] || +new Date();
|
||||
var filename = whiteboardId + "_" + date + ".png";
|
||||
var webdavaccess = fields["webdavaccess"] || false;
|
||||
try {
|
||||
@ -133,24 +134,33 @@ function startBackendServer(port) {
|
||||
return;
|
||||
}
|
||||
var imagedata = fields["imagedata"];
|
||||
if (imagedata && imagedata != "") { //Save from base64 data
|
||||
imagedata = imagedata.replace(/^data:image\/png;base64,/, "").replace(/^data:image\/jpeg;base64,/, "");
|
||||
if (imagedata && imagedata != "") {
|
||||
//Save from base64 data
|
||||
imagedata = imagedata
|
||||
.replace(/^data:image\/png;base64,/, "")
|
||||
.replace(/^data:image\/jpeg;base64,/, "");
|
||||
console.log(filename, "uploaded");
|
||||
fs.writeFile('./public/uploads/' + filename, imagedata, 'base64', function (err) {
|
||||
fs.writeFile("./public/uploads/" + filename, imagedata, "base64", function (err) {
|
||||
if (err) {
|
||||
console.log("error", err);
|
||||
callback(err);
|
||||
} else {
|
||||
if (webdavaccess) { //Save image to webdav
|
||||
if (webdavaccess) {
|
||||
//Save image to webdav
|
||||
if (webdav) {
|
||||
saveImageToWebdav('./public/uploads/' + filename, filename, webdavaccess, function (err) {
|
||||
if (err) {
|
||||
console.log("error", err);
|
||||
callback(err);
|
||||
} else {
|
||||
callback();
|
||||
saveImageToWebdav(
|
||||
"./public/uploads/" + filename,
|
||||
filename,
|
||||
webdavaccess,
|
||||
function (err) {
|
||||
if (err) {
|
||||
console.log("error", err);
|
||||
callback(err);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
callback("Webdav is not enabled on the server!");
|
||||
}
|
||||
@ -165,78 +175,92 @@ function startBackendServer(port) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function saveImageToWebdav(imagepath, filename, webdavaccess, callback) {
|
||||
if (webdavaccess) {
|
||||
var webdavserver = webdavaccess["webdavserver"] || "";
|
||||
var webdavpath = webdavaccess["webdavpath"] || "/";
|
||||
var webdavusername = webdavaccess["webdavusername"] || "";
|
||||
var webdavpassword = webdavaccess["webdavpassword"] || "";
|
||||
|
||||
const client = createClient(
|
||||
webdavserver,
|
||||
{
|
||||
username: webdavusername,
|
||||
password: webdavpassword
|
||||
}
|
||||
)
|
||||
client.getDirectoryContents(webdavpath).then((items) => {
|
||||
var cloudpath = webdavpath+ '' + filename;
|
||||
console.log("webdav saving to:", cloudpath);
|
||||
fs.createReadStream(imagepath).pipe(client.createWriteStream(cloudpath));
|
||||
callback();
|
||||
}).catch((error) => {
|
||||
callback("403");
|
||||
console.log("Could not connect to webdav!")
|
||||
|
||||
const client = createClient(webdavserver, {
|
||||
username: webdavusername,
|
||||
password: webdavpassword,
|
||||
});
|
||||
client
|
||||
.getDirectoryContents(webdavpath)
|
||||
.then((items) => {
|
||||
var cloudpath = webdavpath + "" + filename;
|
||||
console.log("webdav saving to:", cloudpath);
|
||||
fs.createReadStream(imagepath).pipe(client.createWriteStream(cloudpath));
|
||||
callback();
|
||||
})
|
||||
.catch((error) => {
|
||||
callback("403");
|
||||
console.log("Could not connect to webdav!");
|
||||
});
|
||||
} else {
|
||||
callback("Error: no access data!")
|
||||
callback("Error: no access data!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var smallestScreenResolutions = {};
|
||||
io.on('connection', function (socket) {
|
||||
io.on("connection", function (socket) {
|
||||
var whiteboardId = null;
|
||||
|
||||
socket.on('disconnect', function () {
|
||||
if (smallestScreenResolutions && smallestScreenResolutions[whiteboardId] && socket && socket.id) {
|
||||
|
||||
socket.on("disconnect", function () {
|
||||
if (
|
||||
smallestScreenResolutions &&
|
||||
smallestScreenResolutions[whiteboardId] &&
|
||||
socket &&
|
||||
socket.id
|
||||
) {
|
||||
delete smallestScreenResolutions[whiteboardId][socket.id];
|
||||
}
|
||||
socket.compress(false).broadcast.emit('refreshUserBadges', null); //Removes old user Badges
|
||||
socket.compress(false).broadcast.emit("refreshUserBadges", null); //Removes old user Badges
|
||||
sendSmallestScreenResolution();
|
||||
});
|
||||
|
||||
socket.on('drawToWhiteboard', function (content) {
|
||||
|
||||
socket.on("drawToWhiteboard", function (content) {
|
||||
content = escapeAllContentStrings(content);
|
||||
if (accessToken === "" || accessToken == content["at"]) {
|
||||
socket.compress(false).broadcast.to(whiteboardId).emit('drawToWhiteboard', content); //Send to all users in the room (not own socket)
|
||||
socket.compress(false).broadcast.to(whiteboardId).emit("drawToWhiteboard", content); //Send to all users in the room (not own socket)
|
||||
s_whiteboard.handleEventsAndData(content); //save whiteboardchanges on the server
|
||||
} else {
|
||||
socket.emit('wrongAccessToken', true);
|
||||
socket.emit("wrongAccessToken", true);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('joinWhiteboard', function (content) {
|
||||
|
||||
socket.on("joinWhiteboard", function (content) {
|
||||
content = escapeAllContentStrings(content);
|
||||
if (accessToken === "" || accessToken == content["at"]) {
|
||||
whiteboardId = content["wid"];
|
||||
socket.join(whiteboardId); //Joins room name=wid
|
||||
smallestScreenResolutions[whiteboardId] = smallestScreenResolutions[whiteboardId] ? smallestScreenResolutions[whiteboardId] : {};
|
||||
smallestScreenResolutions[whiteboardId][socket.id] = content["windowWidthHeight"] || { w: 10000, h: 10000 };
|
||||
smallestScreenResolutions[whiteboardId] = smallestScreenResolutions[whiteboardId]
|
||||
? smallestScreenResolutions[whiteboardId]
|
||||
: {};
|
||||
smallestScreenResolutions[whiteboardId][socket.id] = content[
|
||||
"windowWidthHeight"
|
||||
] || { w: 10000, h: 10000 };
|
||||
sendSmallestScreenResolution();
|
||||
} else {
|
||||
socket.emit('wrongAccessToken', true);
|
||||
socket.emit("wrongAccessToken", true);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('updateScreenResolution', function (content) {
|
||||
|
||||
socket.on("updateScreenResolution", function (content) {
|
||||
content = escapeAllContentStrings(content);
|
||||
if (smallestScreenResolutions[whiteboardId] && (accessToken === "" || accessToken == content["at"])) {
|
||||
smallestScreenResolutions[whiteboardId][socket.id] = content["windowWidthHeight"] || { w: 10000, h: 10000 };
|
||||
if (
|
||||
smallestScreenResolutions[whiteboardId] &&
|
||||
(accessToken === "" || accessToken == content["at"])
|
||||
) {
|
||||
smallestScreenResolutions[whiteboardId][socket.id] = content[
|
||||
"windowWidthHeight"
|
||||
] || { w: 10000, h: 10000 };
|
||||
sendSmallestScreenResolution();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function sendSmallestScreenResolution() {
|
||||
if (disableSmallestScreen) {
|
||||
return;
|
||||
@ -244,35 +268,44 @@ function startBackendServer(port) {
|
||||
var smallestWidth = 10000;
|
||||
var smallestHeight = 10000;
|
||||
for (var i in smallestScreenResolutions[whiteboardId]) {
|
||||
smallestWidth = smallestWidth > smallestScreenResolutions[whiteboardId][i]["w"] ? smallestScreenResolutions[whiteboardId][i]["w"] : smallestWidth;
|
||||
smallestHeight = smallestHeight > smallestScreenResolutions[whiteboardId][i]["h"] ? smallestScreenResolutions[whiteboardId][i]["h"] : smallestHeight;
|
||||
smallestWidth =
|
||||
smallestWidth > smallestScreenResolutions[whiteboardId][i]["w"]
|
||||
? smallestScreenResolutions[whiteboardId][i]["w"]
|
||||
: smallestWidth;
|
||||
smallestHeight =
|
||||
smallestHeight > smallestScreenResolutions[whiteboardId][i]["h"]
|
||||
? smallestScreenResolutions[whiteboardId][i]["h"]
|
||||
: smallestHeight;
|
||||
}
|
||||
io.to(whiteboardId).emit('updateSmallestScreenResolution', { w: smallestWidth, h: smallestHeight });
|
||||
io.to(whiteboardId).emit("updateSmallestScreenResolution", {
|
||||
w: smallestWidth,
|
||||
h: smallestHeight,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//Prevent cross site scripting (xss)
|
||||
function escapeAllContentStrings(content, cnt) {
|
||||
if (!cnt)
|
||||
cnt = 0;
|
||||
|
||||
if (typeof (content) === "string") {
|
||||
if (!cnt) cnt = 0;
|
||||
|
||||
if (typeof content === "string") {
|
||||
return DOMPurify.sanitize(content);
|
||||
}
|
||||
for (var i in content) {
|
||||
if (typeof (content[i]) === "string") {
|
||||
if (typeof content[i] === "string") {
|
||||
content[i] = DOMPurify.sanitize(content[i]);
|
||||
} if (typeof (content[i]) === "object" && cnt < 10) {
|
||||
}
|
||||
if (typeof content[i] === "object" && cnt < 10) {
|
||||
content[i] = escapeAllContentStrings(content[i], ++cnt);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', error => {
|
||||
|
||||
process.on("unhandledRejection", (error) => {
|
||||
// Will print "unhandledRejection err is not defined"
|
||||
console.log('unhandledRejection', error.message);
|
||||
})
|
||||
console.log("unhandledRejection", error.message);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = startBackendServer;
|
||||
module.exports = startBackendServer;
|
||||
|
@ -1,34 +1,33 @@
|
||||
const devServerConfig = {
|
||||
hot: true,
|
||||
inline: true,
|
||||
stats: {
|
||||
children: false,
|
||||
maxModules: 0
|
||||
},
|
||||
proxy: {
|
||||
// proxies for the backend
|
||||
'/api': 'http://localhost:3000',
|
||||
'/uploads': 'http://localhost:3000',
|
||||
'/ws-api': {
|
||||
target: 'ws://localhost:3000',
|
||||
ws: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
hot: true,
|
||||
inline: true,
|
||||
stats: {
|
||||
children: false,
|
||||
maxModules: 0,
|
||||
},
|
||||
proxy: {
|
||||
// proxies for the backend
|
||||
"/api": "http://localhost:3000",
|
||||
"/uploads": "http://localhost:3000",
|
||||
"/ws-api": {
|
||||
target: "ws://localhost:3000",
|
||||
ws: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function startFrontendDevServer(port) {
|
||||
// require here to prevent prod dependency to webpack
|
||||
const webpack = require("webpack");
|
||||
const WebpackDevServer = require("webpack-dev-server");
|
||||
const config = require("../config/webpack.dev");
|
||||
// require here to prevent prod dependency to webpack
|
||||
const webpack = require("webpack");
|
||||
const WebpackDevServer = require("webpack-dev-server");
|
||||
const config = require("../config/webpack.dev");
|
||||
|
||||
new WebpackDevServer(webpack(config), devServerConfig)
|
||||
.listen(port, (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
new WebpackDevServer(webpack(config), devServerConfig).listen(port, (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
console.log("Listening on port " + port);
|
||||
console.log("Listening on port " + port);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4,23 +4,23 @@ const startBackendServer = require("./server-backend");
|
||||
|
||||
const SERVER_MODES = {
|
||||
PRODUCTION: 1,
|
||||
DEVELOPMENT: 2
|
||||
}
|
||||
DEVELOPMENT: 2,
|
||||
};
|
||||
|
||||
const args = getArgs();
|
||||
|
||||
if ( typeof args.mode === "undefined") {
|
||||
if (typeof args.mode === "undefined") {
|
||||
// default to production mode
|
||||
args.mode = "production";
|
||||
}
|
||||
|
||||
if (args.mode !== "production" && args.mode !== "development") {
|
||||
throw new Error("--mode can only be 'development' or 'production'")
|
||||
throw new Error("--mode can only be 'development' or 'production'");
|
||||
}
|
||||
|
||||
const server_mode = args.mode === "production" ? SERVER_MODES.PRODUCTION : SERVER_MODES.DEVELOPMENT;
|
||||
|
||||
if (server_mode === SERVER_MODES.DEVELOPMENT){
|
||||
if (server_mode === SERVER_MODES.DEVELOPMENT) {
|
||||
console.info("Starting server in development mode.");
|
||||
startFrontendDevServer(8080);
|
||||
// this time, it's the frontend server that is on port 8080
|
||||
|
@ -1,22 +1,20 @@
|
||||
function getArgs() {
|
||||
const args = {}
|
||||
process.argv
|
||||
.slice(2, process.argv.length)
|
||||
.forEach(arg => {
|
||||
// long arg
|
||||
if (arg.slice(0, 2) === '--') {
|
||||
const longArg = arg.split('=')
|
||||
args[longArg[0].slice(2, longArg[0].length)] = longArg[1]
|
||||
}
|
||||
// flags
|
||||
else if (arg[0] === '-') {
|
||||
const flags = arg.slice(1, arg.length).split('')
|
||||
flags.forEach(flag => {
|
||||
args[flag] = true
|
||||
})
|
||||
}
|
||||
})
|
||||
return args
|
||||
const args = {};
|
||||
process.argv.slice(2, process.argv.length).forEach((arg) => {
|
||||
// long arg
|
||||
if (arg.slice(0, 2) === "--") {
|
||||
const longArg = arg.split("=");
|
||||
args[longArg[0].slice(2, longArg[0].length)] = longArg[1];
|
||||
}
|
||||
// flags
|
||||
else if (arg[0] === "-") {
|
||||
const flags = arg.slice(1, arg.length).split("");
|
||||
flags.forEach((flag) => {
|
||||
args[flag] = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
return args;
|
||||
}
|
||||
|
||||
module.exports.getArgs = getArgs;
|
||||
module.exports.getArgs = getArgs;
|
||||
|
@ -36,12 +36,11 @@ button::-moz-focus-inner {
|
||||
.whiteboard-edit-group.group-disabled {
|
||||
background: repeating-linear-gradient(
|
||||
45deg,
|
||||
rgba(255, 166, 0, 0.366) ,
|
||||
rgba(255, 166, 0, 0.366),
|
||||
rgba(255, 166, 0, 0.366) 10px,
|
||||
rgba(255, 166, 0, 0.666) 10px,
|
||||
rgba(255, 166, 0, 0.666) 20px
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -90,19 +89,21 @@ button {
|
||||
background: transparent;
|
||||
outline: none;
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity .15s ease-in-out;
|
||||
transition: opacity .15s ease-in-out;
|
||||
-webkit-transition: opacity 0.15s ease-in-out;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.textBox.active {
|
||||
border: 1px dashed gray;
|
||||
}
|
||||
|
||||
.textBox>.removeIcon, .textBox>.moveIcon {
|
||||
.textBox > .removeIcon,
|
||||
.textBox > .moveIcon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.textBox.active>.removeIcon, .textBox.active>.moveIcon {
|
||||
.textBox.active > .removeIcon,
|
||||
.textBox.active > .moveIcon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
367
src/index.html
367
src/index.html
@ -1,140 +1,255 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Whiteboard</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/vnd.microsoft.icon" href="favicon.ico" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<title>Whiteboard</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/vnd.microsoft.icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<!---Whiteboard container -!-->
|
||||
<div id="whiteboardContainer"></div>
|
||||
|
||||
<body>
|
||||
<!---Whiteboard container -!-->
|
||||
<div id="whiteboardContainer"></div>
|
||||
<!---Toolbar -!-->
|
||||
<div id="toolbar" style="position: absolute; top: 10px; left: 10px;">
|
||||
<div class="btn-group">
|
||||
<button
|
||||
id="whiteboardLockBtn"
|
||||
style="background-color: orange;"
|
||||
title="View and Write"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa fa-lock"></i>
|
||||
</button>
|
||||
<button id="whiteboardUnlockBtn" title="View Only" type="button">
|
||||
<i class="fa fa-lock-open"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!---Toolbar -!-->
|
||||
<div id="toolbar" style="position: absolute; top: 10px; left: 10px;">
|
||||
<div class="btn-group">
|
||||
<button id="whiteboardLockBtn" style="background-color: orange;" title="View and Write" type="button">
|
||||
<i class="fa fa-lock"></i>
|
||||
</button>
|
||||
<button id="whiteboardUnlockBtn" title="View Only" type="button">
|
||||
<i class="fa fa-lock-open"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button id="whiteboardTrashBtn" title="Clear the whiteboard" type="button">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
<button
|
||||
style="position: absolute; left: 0px; top: 0px; width: 46px; display: none;"
|
||||
id="whiteboardTrashBtnConfirm"
|
||||
title="Confirm clear..."
|
||||
type="button"
|
||||
>
|
||||
<i class="fa fa-check"></i>
|
||||
</button>
|
||||
<button id="whiteboardUndoBtn" title="Undo your last step" type="button">
|
||||
<i class="fa fa-undo"></i>
|
||||
</button>
|
||||
<button id="whiteboardRedoBtn" title="Redo your last undo" type="button">
|
||||
<i class="fa fa-redo"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button id="whiteboardTrashBtn" title="Clear the whiteboard" type="button">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
<button style="position:absolute; left:0px; top:0px; width: 46px; display:none;"
|
||||
id="whiteboardTrashBtnConfirm" title="Confirm clear..." type="button">
|
||||
<i class="fa fa-check"></i>
|
||||
</button>
|
||||
<button id="whiteboardUndoBtn" title="Undo your last step" type="button">
|
||||
<i class="fa fa-undo"></i>
|
||||
</button>
|
||||
<button id="whiteboardRedoBtn" title="Redo your last undo" type="button">
|
||||
<i class="fa fa-redo"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button tool="mouse" title="Take the mouse" type="button" class="whiteboard-tool">
|
||||
<i class="fa fa-mouse-pointer"></i>
|
||||
</button>
|
||||
<button
|
||||
style="padding-bottom: 11px;"
|
||||
tool="recSelect"
|
||||
title="Select an area"
|
||||
type="button"
|
||||
class="whiteboard-tool"
|
||||
>
|
||||
<img src="./images/dottedRec.png" />
|
||||
</button>
|
||||
<button
|
||||
tool="pen"
|
||||
title="Take the pen"
|
||||
type="button"
|
||||
class="whiteboard-tool active"
|
||||
>
|
||||
<i class="fa fa-pencil-alt"></i>
|
||||
</button>
|
||||
<button
|
||||
style="padding-bottom: 8px; padding-top: 6px;"
|
||||
tool="line"
|
||||
title="draw a line"
|
||||
type="button"
|
||||
class="whiteboard-tool"
|
||||
>
|
||||
╱
|
||||
</button>
|
||||
<button tool="rect" title="draw a rectangle" type="button" class="whiteboard-tool">
|
||||
<i class="far fa-square"></i>
|
||||
</button>
|
||||
<button tool="circle" title="draw a circle" type="button" class="whiteboard-tool">
|
||||
<i class="far fa-circle"></i>
|
||||
</button>
|
||||
<button tool="text" title="write text" type="button" class="whiteboard-tool">
|
||||
<i class="fas fa-font"></i>
|
||||
</button>
|
||||
<button tool="eraser" title="take the eraser" type="button" class="whiteboard-tool">
|
||||
<i class="fa fa-eraser"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button tool="mouse" title="Take the mouse" type="button" class="whiteboard-tool">
|
||||
<i class="fa fa-mouse-pointer"></i>
|
||||
</button>
|
||||
<button style="padding-bottom: 11px;" tool="recSelect" title="Select an area" type="button"
|
||||
class="whiteboard-tool">
|
||||
<img src="./images/dottedRec.png">
|
||||
</button>
|
||||
<button tool="pen" title="Take the pen" type="button" class="whiteboard-tool active">
|
||||
<i class="fa fa-pencil-alt"></i>
|
||||
</button>
|
||||
<button style="padding-bottom: 8px; padding-top: 6px;" tool="line" title="draw a line" type="button"
|
||||
class="whiteboard-tool">
|
||||
╱
|
||||
</button>
|
||||
<button tool="rect" title="draw a rectangle" type="button" class="whiteboard-tool">
|
||||
<i class="far fa-square"></i>
|
||||
</button>
|
||||
<button tool="circle" title="draw a circle" type="button" class="whiteboard-tool">
|
||||
<i class="far fa-circle"></i>
|
||||
</button>
|
||||
<button tool="text" title="write text" type="button" class="whiteboard-tool">
|
||||
<i class="fas fa-font"></i>
|
||||
</button>
|
||||
<button tool="eraser" title="take the eraser" type="button" class="whiteboard-tool">
|
||||
<i class="fa fa-eraser"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button style="width: 190px; cursor: default;">
|
||||
<div
|
||||
class="activeToolIcon"
|
||||
style="position: absolute; top: 2px; left: 2px; font-size: 0.6em;"
|
||||
>
|
||||
<i class="fa fa-pencil-alt"></i>
|
||||
</div>
|
||||
<img
|
||||
style="
|
||||
position: absolute;
|
||||
left: 11px;
|
||||
top: 16px;
|
||||
height: 14px;
|
||||
width: 130px;
|
||||
"
|
||||
src="./images/slider-background.svg"
|
||||
/>
|
||||
<input
|
||||
title="Thickness"
|
||||
id="whiteboardThicknessSlider"
|
||||
style="position: absolute; left: 9px; width: 130px; top: 15px;"
|
||||
type="range"
|
||||
min="1"
|
||||
max="50"
|
||||
value="3"
|
||||
/>
|
||||
<div
|
||||
id="whiteboardColorpicker"
|
||||
style="
|
||||
position: absolute;
|
||||
left: 155px;
|
||||
top: 10px;
|
||||
width: 26px;
|
||||
height: 23px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid darkgrey;
|
||||
"
|
||||
data-color="#000000"
|
||||
></div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button style="width: 190px; cursor:default;">
|
||||
<div class="activeToolIcon" style="position:absolute; top:2px; left:2px; font-size: 0.6em;"><i
|
||||
class="fa fa-pencil-alt"></i></div>
|
||||
<img style="position: absolute; left: 11px; top: 16px; height:14px; width:130px;"
|
||||
src="./images/slider-background.svg">
|
||||
<input title="Thickness" id="whiteboardThicknessSlider"
|
||||
style="position: absolute; left:9px; width: 130px; top: 15px;" type="range" min="1" max="50"
|
||||
value="3">
|
||||
<div id="whiteboardColorpicker"
|
||||
style="position: absolute; left: 155px; top: 10px; width: 26px; height: 23px; border-radius: 3px; border: 1px solid darkgrey;"
|
||||
data-color="#000000">
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button id="addImgToCanvasBtn" title="Upload Image to whiteboard" type="button">
|
||||
<i class="fas fa-image"></i>
|
||||
<i
|
||||
style="
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 2px;
|
||||
color: #000000;
|
||||
font-size: 0.5em;
|
||||
"
|
||||
class="fas fa-upload"
|
||||
></i>
|
||||
</button>
|
||||
|
||||
<div class="btn-group whiteboard-edit-group">
|
||||
<button id="addImgToCanvasBtn" title="Upload Image to whiteboard" type="button">
|
||||
<i class="fas fa-image"></i>
|
||||
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
|
||||
class="fas fa-upload"></i>
|
||||
</button>
|
||||
<button
|
||||
style="position: relative;"
|
||||
id="uploadJsonBtn"
|
||||
title="Load saved JSON to whiteboard"
|
||||
type="button"
|
||||
>
|
||||
<i class="far fa-file-alt"></i>
|
||||
<i
|
||||
style="
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 2px;
|
||||
color: #000000;
|
||||
font-size: 0.5em;
|
||||
"
|
||||
class="fas fa-upload"
|
||||
></i>
|
||||
</button>
|
||||
|
||||
<button style="position: relative;" id="uploadJsonBtn" title="Load saved JSON to whiteboard" type="button">
|
||||
<i class="far fa-file-alt"></i>
|
||||
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
|
||||
class="fas fa-upload"></i>
|
||||
</button>
|
||||
<input style="display: none;" id="myFile" type="file" />
|
||||
</div>
|
||||
|
||||
<input style="display:none;" id="myFile" type="file" />
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button id="saveAsImageBtn" title="Save whiteboard as image" type="button">
|
||||
<i class="fas fa-image"></i>
|
||||
<i
|
||||
style="
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 2px;
|
||||
color: #000000;
|
||||
font-size: 0.5em;
|
||||
"
|
||||
class="fas fa-save"
|
||||
></i>
|
||||
</button>
|
||||
<button
|
||||
style="position: relative; display: none;"
|
||||
id="uploadWebDavBtn"
|
||||
title="Save whiteboard to webdav"
|
||||
type="button"
|
||||
>
|
||||
<i class="fas fa-globe"></i>
|
||||
<i
|
||||
style="
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 2px;
|
||||
color: #000000;
|
||||
font-size: 0.5em;
|
||||
"
|
||||
class="fas fa-save"
|
||||
></i>
|
||||
</button>
|
||||
<button
|
||||
style="position: relative;"
|
||||
id="saveAsJSONBtn"
|
||||
title="Save whiteboard as JSON"
|
||||
type="button"
|
||||
>
|
||||
<i class="far fa-file-alt"></i>
|
||||
<i
|
||||
style="
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 2px;
|
||||
color: #000000;
|
||||
font-size: 0.5em;
|
||||
"
|
||||
class="fas fa-save"
|
||||
></i>
|
||||
</button>
|
||||
|
||||
<div class="btn-group">
|
||||
<button id="saveAsImageBtn" title="Save whiteboard as image" type="button">
|
||||
<i class="fas fa-image"></i>
|
||||
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
|
||||
class="fas fa-save"></i>
|
||||
</button>
|
||||
<button style="position: relative; display: none;" id="uploadWebDavBtn" title="Save whiteboard to webdav"
|
||||
type="button">
|
||||
<button id="shareWhiteboardBtn" title="share whiteboard" type="button">
|
||||
<i class="fas fa-share-square"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<i class="fas fa-globe"></i>
|
||||
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
|
||||
class="fas fa-save"></i>
|
||||
</button>
|
||||
<button style="position: relative;" id="saveAsJSONBtn" title="Save whiteboard as JSON" type="button">
|
||||
<i class="far fa-file-alt"></i>
|
||||
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
|
||||
class="fas fa-save"></i>
|
||||
</button>
|
||||
<div class="btn-group minGroup">
|
||||
<button
|
||||
style="width: 25px; padding: 11px 11px;"
|
||||
id="minMaxBtn"
|
||||
title="hide buttons"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
id="minBtn"
|
||||
style="position: relative; left: -5px;"
|
||||
class="fas fa-angle-left"
|
||||
></i>
|
||||
<i
|
||||
id="maxBtn"
|
||||
style="position: relative; left: -5px; display: none;"
|
||||
class="fas fa-angle-right"
|
||||
></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="shareWhiteboardBtn" title="share whiteboard" type="button">
|
||||
<i class="fas fa-share-square"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-group minGroup">
|
||||
<button style="width: 25px; padding: 11px 11px;" id="minMaxBtn" title="hide buttons" type="button">
|
||||
<i id="minBtn" style="position:relative; left:-5px;" class="fas fa-angle-left"></i>
|
||||
<i id="maxBtn" style="position:relative; left:-5px; display: none;" class="fas fa-angle-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; bottom: 10px; right: 10px; display:none;">
|
||||
<p># msg. sent to server: <i id="messageSentCount">0</i></p>
|
||||
<p># msg. received from server: <i id="messageReceivedCount">0</i></p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<div style="position: absolute; bottom: 10px; right: 10px; display: none;">
|
||||
<p># msg. sent to server: <i id="messageSentCount">0</i></p>
|
||||
<p># msg. received from server: <i id="messageReceivedCount">0</i></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {computeDist} from "../utils";
|
||||
import { computeDist } from "../utils";
|
||||
|
||||
class Point {
|
||||
/**
|
||||
@ -42,7 +42,8 @@ class Point {
|
||||
let x = (e.offsetX || e.pageX - $(e.target).offset().left) + epsilon;
|
||||
let y = (e.offsetY || e.pageY - $(e.target).offset().top) + epsilon;
|
||||
|
||||
if (Number.isNaN(x) || Number.isNaN(y) || (x === epsilon && y === epsilon)) { // if it's a touch actually
|
||||
if (Number.isNaN(x) || Number.isNaN(y) || (x === epsilon && y === epsilon)) {
|
||||
// if it's a touch actually
|
||||
if (e.touches && e.touches.length && e.touches.length > 0) {
|
||||
const touch = e.touches[0];
|
||||
x = touch.clientX - $("#mouseOverlay").offset().left;
|
||||
@ -65,7 +66,7 @@ class Point {
|
||||
|
||||
/**
|
||||
* Compute euclidean distance between points
|
||||
*
|
||||
*
|
||||
* @param {Point} otherPoint
|
||||
* @returns {number}
|
||||
*/
|
||||
@ -74,4 +75,4 @@ class Point {
|
||||
}
|
||||
}
|
||||
|
||||
export default Point;
|
||||
export default Point;
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
faSortDown,
|
||||
faExpandArrowsAlt,
|
||||
faLock,
|
||||
faLockOpen
|
||||
faLockOpen,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faSquare,
|
||||
@ -53,4 +53,4 @@ library.add(
|
||||
faLockOpen
|
||||
);
|
||||
|
||||
dom.i2svg()
|
||||
dom.i2svg();
|
||||
|
@ -8,19 +8,19 @@ import "./icons";
|
||||
import main from "./main";
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// Set correct width height on mobile browsers
|
||||
const isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
|
||||
if (isChrome) {
|
||||
$('head').append('<meta name="viewport" content="width=device-width, initial-scale=0.52, maximum-scale=1" />');
|
||||
$("head").append(
|
||||
'<meta name="viewport" content="width=device-width, initial-scale=0.52, maximum-scale=1" />'
|
||||
);
|
||||
} else {
|
||||
$('head').append('<meta name="viewport" content="width=1400" />');
|
||||
$("head").append('<meta name="viewport" content="width=1400" />');
|
||||
}
|
||||
|
||||
main();
|
||||
});
|
||||
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept();
|
||||
}
|
||||
|
@ -1,48 +1,48 @@
|
||||
/* -----------
|
||||
KEYBINDINGS
|
||||
----------- */
|
||||
----------- */
|
||||
|
||||
//> defmod is "command" on OS X and "ctrl" elsewhere
|
||||
//Advanced Example: 'defmod-k j' -> For this to fire you have to first press both ctrl and k, and then j.
|
||||
//Advanced Example: 'defmod-k j' -> For this to fire you have to first press both ctrl and k, and then j.
|
||||
|
||||
const keybinds = {
|
||||
// 'key(s)' : 'function',
|
||||
'defmod-shift-z' : 'clearWhiteboard',
|
||||
'defmod-z' : 'undoStep',
|
||||
'defmod-y' : 'redoStep',
|
||||
'defmod-x' : 'setTool_recSelect',
|
||||
'defmod-m' : 'setTool_mouse',
|
||||
'defmod-p' : 'setTool_pen',
|
||||
'defmod-l' : 'setTool_line',
|
||||
'defmod-r' : 'setTool_rect',
|
||||
'defmod-c' : 'setTool_circle',
|
||||
'defmod-shift-f' : 'toggleLineRecCircle',
|
||||
'defmod-shift-x' : 'togglePenEraser',
|
||||
'defmod-shift-r' : 'toggleMainColors',
|
||||
'defmod-a' : 'setTool_text',
|
||||
'defmod-e' : 'setTool_eraser',
|
||||
'defmod-up' : 'thickness_bigger',
|
||||
'defmod-down' : 'thickness_smaller',
|
||||
'defmod-shift-c' : 'openColorPicker',
|
||||
'defmod-shift-1' : 'setDrawColorBlack',
|
||||
'defmod-shift-2' : 'setDrawColorBlue',
|
||||
'defmod-shift-3' : 'setDrawColorGreen',
|
||||
'defmod-shift-4' : 'setDrawColorYellow',
|
||||
'defmod-shift-5' : 'setDrawColorRed',
|
||||
'defmod-s' : 'saveWhiteboardAsImage',
|
||||
'defmod-shift-k' : 'saveWhiteboardAsJson',
|
||||
'defmod-shift-i' : 'uploadWhiteboardToWebDav',
|
||||
'defmod-shift-j' : 'uploadJsonToWhiteboard',
|
||||
'defmod-shift-s' : 'shareWhiteboard',
|
||||
'tab' : 'hideShowControls',
|
||||
'up' : 'moveDraggableUp',
|
||||
'down' : 'moveDraggableDown',
|
||||
'left' : 'moveDraggableLeft',
|
||||
'right' : 'moveDraggableRight',
|
||||
'defmod-enter' : 'dropDraggable',
|
||||
'shift-enter' : 'addToBackground',
|
||||
'escape' : 'cancelAllActions',
|
||||
'del' : 'deleteSelection'
|
||||
}
|
||||
"defmod-shift-z": "clearWhiteboard",
|
||||
"defmod-z": "undoStep",
|
||||
"defmod-y": "redoStep",
|
||||
"defmod-x": "setTool_recSelect",
|
||||
"defmod-m": "setTool_mouse",
|
||||
"defmod-p": "setTool_pen",
|
||||
"defmod-l": "setTool_line",
|
||||
"defmod-r": "setTool_rect",
|
||||
"defmod-c": "setTool_circle",
|
||||
"defmod-shift-f": "toggleLineRecCircle",
|
||||
"defmod-shift-x": "togglePenEraser",
|
||||
"defmod-shift-r": "toggleMainColors",
|
||||
"defmod-a": "setTool_text",
|
||||
"defmod-e": "setTool_eraser",
|
||||
"defmod-up": "thickness_bigger",
|
||||
"defmod-down": "thickness_smaller",
|
||||
"defmod-shift-c": "openColorPicker",
|
||||
"defmod-shift-1": "setDrawColorBlack",
|
||||
"defmod-shift-2": "setDrawColorBlue",
|
||||
"defmod-shift-3": "setDrawColorGreen",
|
||||
"defmod-shift-4": "setDrawColorYellow",
|
||||
"defmod-shift-5": "setDrawColorRed",
|
||||
"defmod-s": "saveWhiteboardAsImage",
|
||||
"defmod-shift-k": "saveWhiteboardAsJson",
|
||||
"defmod-shift-i": "uploadWhiteboardToWebDav",
|
||||
"defmod-shift-j": "uploadJsonToWhiteboard",
|
||||
"defmod-shift-s": "shareWhiteboard",
|
||||
tab: "hideShowControls",
|
||||
up: "moveDraggableUp",
|
||||
down: "moveDraggableDown",
|
||||
left: "moveDraggableLeft",
|
||||
right: "moveDraggableRight",
|
||||
"defmod-enter": "dropDraggable",
|
||||
"shift-enter": "addToBackground",
|
||||
escape: "cancelAllActions",
|
||||
del: "deleteSelection",
|
||||
};
|
||||
|
||||
export default keybinds;
|
||||
export default keybinds;
|
||||
|
505
src/js/main.js
505
src/js/main.js
@ -1,5 +1,5 @@
|
||||
import keymage from "keymage";
|
||||
import io from 'socket.io-client';
|
||||
import io from "socket.io-client";
|
||||
import whiteboard from "./whiteboard";
|
||||
import keybinds from "./keybinds";
|
||||
import Picker from "vanilla-picker";
|
||||
@ -9,13 +9,16 @@ import shortcutFunctions from "./shortcutFunctions";
|
||||
import ReadOnlyService from "./services/ReadOnlyService";
|
||||
|
||||
function main() {
|
||||
|
||||
var whiteboardId = getQueryVariable("whiteboardid");
|
||||
var randomid = getQueryVariable("randomid");
|
||||
if (randomid && !whiteboardId) { //set random whiteboard on empty whiteboardid
|
||||
whiteboardId = Array(2).fill(null).map(() => Math.random().toString(36).substr(2)).join('');
|
||||
if (randomid && !whiteboardId) {
|
||||
//set random whiteboard on empty whiteboardid
|
||||
whiteboardId = Array(2)
|
||||
.fill(null)
|
||||
.map(() => Math.random().toString(36).substr(2))
|
||||
.join("");
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
urlParams.set('whiteboardid', whiteboardId);
|
||||
urlParams.set("whiteboardid", whiteboardId);
|
||||
window.location.search = urlParams;
|
||||
}
|
||||
|
||||
@ -33,40 +36,44 @@ function main() {
|
||||
document.title = decodeURIComponent(title);
|
||||
}
|
||||
|
||||
var url = document.URL.substr(0, document.URL.lastIndexOf('/'));
|
||||
var url = document.URL.substr(0, document.URL.lastIndexOf("/"));
|
||||
var signaling_socket = null;
|
||||
var urlSplit = url.split("/");
|
||||
var subdir = "";
|
||||
for (var i = 3; i < urlSplit.length; i++) {
|
||||
subdir = subdir + '/' + urlSplit[i];
|
||||
subdir = subdir + "/" + urlSplit[i];
|
||||
}
|
||||
signaling_socket = io("", { "path": subdir + "/ws-api" }); // Connect even if we are in a subdir behind a reverse proxy
|
||||
signaling_socket = io("", { path: subdir + "/ws-api" }); // Connect even if we are in a subdir behind a reverse proxy
|
||||
|
||||
signaling_socket.on('connect', function () {
|
||||
signaling_socket.on("connect", function () {
|
||||
console.log("Websocket connected!");
|
||||
|
||||
let messageReceivedCount = 0;
|
||||
signaling_socket.on('drawToWhiteboard', function (content) {
|
||||
signaling_socket.on("drawToWhiteboard", function (content) {
|
||||
whiteboard.handleEventsAndData(content, true);
|
||||
$('#messageReceivedCount')[0].innerText = String(messageReceivedCount++);
|
||||
$("#messageReceivedCount")[0].innerText = String(messageReceivedCount++);
|
||||
});
|
||||
|
||||
signaling_socket.on('refreshUserBadges', function () {
|
||||
signaling_socket.on("refreshUserBadges", function () {
|
||||
whiteboard.refreshUserBadges();
|
||||
});
|
||||
|
||||
signaling_socket.on('wrongAccessToken', function () {
|
||||
signaling_socket.on("wrongAccessToken", function () {
|
||||
if (!accessDenied) {
|
||||
accessDenied = true;
|
||||
showBasicAlert("Access denied! Wrong accessToken!")
|
||||
showBasicAlert("Access denied! Wrong accessToken!");
|
||||
}
|
||||
});
|
||||
|
||||
signaling_socket.on('updateSmallestScreenResolution', function (widthHeight) {
|
||||
signaling_socket.on("updateSmallestScreenResolution", function (widthHeight) {
|
||||
whiteboard.updateSmallestScreenResolution(widthHeight["w"], widthHeight["h"]);
|
||||
});
|
||||
|
||||
signaling_socket.emit('joinWhiteboard', { wid: whiteboardId, at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() } });
|
||||
signaling_socket.emit("joinWhiteboard", {
|
||||
wid: whiteboardId,
|
||||
at: accessToken,
|
||||
windowWidthHeight: { w: $(window).width(), h: $(window).height() },
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
@ -78,29 +85,35 @@ function main() {
|
||||
}
|
||||
|
||||
let messageSentCount = 0;
|
||||
whiteboard.loadWhiteboard("#whiteboardContainer", { //Load the whiteboard
|
||||
whiteboard.loadWhiteboard("#whiteboardContainer", {
|
||||
//Load the whiteboard
|
||||
whiteboardId: whiteboardId,
|
||||
username: btoa(myUsername),
|
||||
sendFunction: function (content) {
|
||||
if (ReadOnlyService.readOnlyActive) return;
|
||||
//ADD IN LATER THROUGH CONFIG
|
||||
// if (content.t === 'cursor') {
|
||||
//ADD IN LATER THROUGH CONFIG
|
||||
// if (content.t === 'cursor') {
|
||||
// if (whiteboard.drawFlag) return;
|
||||
// }
|
||||
content["at"] = accessToken;
|
||||
signaling_socket.emit('drawToWhiteboard', content);
|
||||
$('#messageSentCount')[0].innerText = String(messageSentCount++);
|
||||
}
|
||||
signaling_socket.emit("drawToWhiteboard", content);
|
||||
$("#messageSentCount")[0].innerText = String(messageSentCount++);
|
||||
},
|
||||
});
|
||||
|
||||
// request whiteboard from server
|
||||
$.get(subdir + "/api/loadwhiteboard", { wid: whiteboardId, at: accessToken }).done(function (data) {
|
||||
whiteboard.loadData(data)
|
||||
});
|
||||
$.get(subdir + "/api/loadwhiteboard", { wid: whiteboardId, at: accessToken }).done(
|
||||
function (data) {
|
||||
whiteboard.loadData(data);
|
||||
}
|
||||
);
|
||||
|
||||
$(window).resize(function () {
|
||||
signaling_socket.emit('updateScreenResolution', { at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() } });
|
||||
})
|
||||
signaling_socket.emit("updateScreenResolution", {
|
||||
at: accessToken,
|
||||
windowWidthHeight: { w: $(window).width(), h: $(window).height() },
|
||||
});
|
||||
});
|
||||
|
||||
/*----------------/
|
||||
Whiteboard actions
|
||||
@ -115,12 +128,18 @@ function main() {
|
||||
tempLineTool = true;
|
||||
whiteboard.ownCursor.hide();
|
||||
if (whiteboard.drawFlag) {
|
||||
whiteboard.mouseup({ offsetX: whiteboard.prevPos.x, offsetY: whiteboard.prevPos.y })
|
||||
whiteboard.mouseup({
|
||||
offsetX: whiteboard.prevPos.x,
|
||||
offsetY: whiteboard.prevPos.y,
|
||||
});
|
||||
shortcutFunctions.setTool_line();
|
||||
whiteboard.mousedown({ offsetX: whiteboard.prevPos.x, offsetY: whiteboard.prevPos.y })
|
||||
whiteboard.mousedown({
|
||||
offsetX: whiteboard.prevPos.x,
|
||||
offsetY: whiteboard.prevPos.y,
|
||||
});
|
||||
} else {
|
||||
shortcutFunctions.setTool_line();
|
||||
}
|
||||
}
|
||||
}
|
||||
whiteboard.pressedKeys["shift"] = true; //Used for straight lines...
|
||||
} else if (e.which == 17) {
|
||||
@ -147,9 +166,15 @@ function main() {
|
||||
if (associatedShortcutFunction) {
|
||||
keymage(key, associatedShortcutFunction, { preventDefault: true });
|
||||
} else {
|
||||
console.error("Function you want to keybind on key:", key, "named:", functionName, "is not available!")
|
||||
console.error(
|
||||
"Function you want to keybind on key:",
|
||||
key,
|
||||
"named:",
|
||||
functionName,
|
||||
"is not available!"
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// whiteboard clear button
|
||||
$("#whiteboardTrashBtn").click(function () {
|
||||
@ -211,15 +236,18 @@ function main() {
|
||||
$("#saveAsImageBtn").click(function () {
|
||||
var imgData = whiteboard.getImageDataBase64();
|
||||
|
||||
var w = window.open('about:blank'); //Firefox will not allow downloads without extra window
|
||||
setTimeout(function () { //FireFox seems to require a setTimeout for this to work.
|
||||
var a = document.createElement('a');
|
||||
var w = window.open("about:blank"); //Firefox will not allow downloads without extra window
|
||||
setTimeout(function () {
|
||||
//FireFox seems to require a setTimeout for this to work.
|
||||
var a = document.createElement("a");
|
||||
a.href = imgData;
|
||||
a.download = 'whiteboard.png';
|
||||
a.download = "whiteboard.png";
|
||||
w.document.body.appendChild(a);
|
||||
a.click();
|
||||
w.document.body.removeChild(a);
|
||||
setTimeout(function () { w.close(); }, 100);
|
||||
setTimeout(function () {
|
||||
w.close();
|
||||
}, 100);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
@ -227,15 +255,18 @@ function main() {
|
||||
$("#saveAsJSONBtn").click(function () {
|
||||
var imgData = whiteboard.getImageDataJson();
|
||||
|
||||
var w = window.open('about:blank'); //Firefox will not allow downloads without extra window
|
||||
setTimeout(function () { //FireFox seems to require a setTimeout for this to work.
|
||||
var a = document.createElement('a');
|
||||
a.href = window.URL.createObjectURL(new Blob([imgData], { type: 'text/json' }));
|
||||
a.download = 'whiteboard.json';
|
||||
var w = window.open("about:blank"); //Firefox will not allow downloads without extra window
|
||||
setTimeout(function () {
|
||||
//FireFox seems to require a setTimeout for this to work.
|
||||
var a = document.createElement("a");
|
||||
a.href = window.URL.createObjectURL(new Blob([imgData], { type: "text/json" }));
|
||||
a.download = "whiteboard.json";
|
||||
w.document.body.appendChild(a);
|
||||
a.click();
|
||||
w.document.body.removeChild(a);
|
||||
setTimeout(function () { w.close(); }, 100);
|
||||
setTimeout(function () {
|
||||
w.close();
|
||||
}, 100);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
@ -244,57 +275,67 @@ function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
var webdavserver = localStorage.getItem('webdavserver') || ""
|
||||
var webdavpath = localStorage.getItem('webdavpath') || "/"
|
||||
var webdavusername = localStorage.getItem('webdavusername') || ""
|
||||
var webdavpassword = localStorage.getItem('webdavpassword') || ""
|
||||
var webDavHtml = $('<div>' +
|
||||
'<table>' +
|
||||
'<tr>' +
|
||||
'<td>Server URL:</td>' +
|
||||
'<td><input class="webdavserver" type="text" value="' + webdavserver + '" placeholder="https://yourserver.com/remote.php/webdav/"></td>' +
|
||||
'<td></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td>Path:</td>' +
|
||||
'<td><input class="webdavpath" type="text" placeholder="folder" value="' + webdavpath + '"></td>' +
|
||||
'<td style="font-size: 0.7em;"><i>path always have to start & end with "/"</i></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td>Username:</td>' +
|
||||
'<td><input class="webdavusername" type="text" value="' + webdavusername + '" placeholder="username"></td>' +
|
||||
'<td style="font-size: 0.7em;"></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td>Password:</td>' +
|
||||
'<td><input class="webdavpassword" type="password" value="' + webdavpassword + '" placeholder="password"></td>' +
|
||||
'<td style="font-size: 0.7em;"></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td style="font-size: 0.7em;" colspan="3">Note: You have to generate and use app credentials if you have 2 Factor Auth activated on your dav/nextcloud server!</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td></td>' +
|
||||
'<td colspan="2"><span class="loadingWebdavText" style="display:none;">Saving to webdav, please wait...</span><button class="modalBtn webdavUploadBtn"><i class="fas fa-upload"></i> Start Upload</button></td>' +
|
||||
'</tr>' +
|
||||
'</table>' +
|
||||
'</div>');
|
||||
var webdavserver = localStorage.getItem("webdavserver") || "";
|
||||
var webdavpath = localStorage.getItem("webdavpath") || "/";
|
||||
var webdavusername = localStorage.getItem("webdavusername") || "";
|
||||
var webdavpassword = localStorage.getItem("webdavpassword") || "";
|
||||
var webDavHtml = $(
|
||||
"<div>" +
|
||||
"<table>" +
|
||||
"<tr>" +
|
||||
"<td>Server URL:</td>" +
|
||||
'<td><input class="webdavserver" type="text" value="' +
|
||||
webdavserver +
|
||||
'" placeholder="https://yourserver.com/remote.php/webdav/"></td>' +
|
||||
"<td></td>" +
|
||||
"</tr>" +
|
||||
"<tr>" +
|
||||
"<td>Path:</td>" +
|
||||
'<td><input class="webdavpath" type="text" placeholder="folder" value="' +
|
||||
webdavpath +
|
||||
'"></td>' +
|
||||
'<td style="font-size: 0.7em;"><i>path always have to start & end with "/"</i></td>' +
|
||||
"</tr>" +
|
||||
"<tr>" +
|
||||
"<td>Username:</td>" +
|
||||
'<td><input class="webdavusername" type="text" value="' +
|
||||
webdavusername +
|
||||
'" placeholder="username"></td>' +
|
||||
'<td style="font-size: 0.7em;"></td>' +
|
||||
"</tr>" +
|
||||
"<tr>" +
|
||||
"<td>Password:</td>" +
|
||||
'<td><input class="webdavpassword" type="password" value="' +
|
||||
webdavpassword +
|
||||
'" placeholder="password"></td>' +
|
||||
'<td style="font-size: 0.7em;"></td>' +
|
||||
"</tr>" +
|
||||
"<tr>" +
|
||||
'<td style="font-size: 0.7em;" colspan="3">Note: You have to generate and use app credentials if you have 2 Factor Auth activated on your dav/nextcloud server!</td>' +
|
||||
"</tr>" +
|
||||
"<tr>" +
|
||||
"<td></td>" +
|
||||
'<td colspan="2"><span class="loadingWebdavText" style="display:none;">Saving to webdav, please wait...</span><button class="modalBtn webdavUploadBtn"><i class="fas fa-upload"></i> Start Upload</button></td>' +
|
||||
"</tr>" +
|
||||
"</table>" +
|
||||
"</div>"
|
||||
);
|
||||
webDavHtml.find(".webdavUploadBtn").click(function () {
|
||||
var webdavserver = webDavHtml.find(".webdavserver").val();
|
||||
localStorage.setItem('webdavserver', webdavserver);
|
||||
localStorage.setItem("webdavserver", webdavserver);
|
||||
var webdavpath = webDavHtml.find(".webdavpath").val();
|
||||
localStorage.setItem('webdavpath', webdavpath);
|
||||
localStorage.setItem("webdavpath", webdavpath);
|
||||
var webdavusername = webDavHtml.find(".webdavusername").val();
|
||||
localStorage.setItem('webdavusername', webdavusername);
|
||||
localStorage.setItem("webdavusername", webdavusername);
|
||||
var webdavpassword = webDavHtml.find(".webdavpassword").val();
|
||||
localStorage.setItem('webdavpassword', webdavpassword);
|
||||
localStorage.setItem("webdavpassword", webdavpassword);
|
||||
var base64data = whiteboard.getImageDataBase64();
|
||||
var webdavaccess = {
|
||||
webdavserver: webdavserver,
|
||||
webdavpath: webdavpath,
|
||||
webdavusername: webdavusername,
|
||||
webdavpassword: webdavpassword
|
||||
}
|
||||
webdavpassword: webdavpassword,
|
||||
};
|
||||
webDavHtml.find(".loadingWebdavText").show();
|
||||
webDavHtml.find(".webdavUploadBtn").hide();
|
||||
saveWhiteboardToWebdav(base64data, webdavaccess, function (err) {
|
||||
@ -305,12 +346,12 @@ function main() {
|
||||
webDavHtml.parents(".basicalert").remove();
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
showBasicAlert(webDavHtml, {
|
||||
header: "Save to Webdav",
|
||||
okBtnText: "cancel",
|
||||
headercolor: "#0082c9"
|
||||
})
|
||||
headercolor: "#0082c9",
|
||||
});
|
||||
// render newly added icons
|
||||
dom.i2svg();
|
||||
});
|
||||
@ -330,10 +371,15 @@ function main() {
|
||||
endSplit = endSplit.splice(1, 1);
|
||||
urlStart += "&" + endSplit.join("&");
|
||||
}
|
||||
$("<textarea/>").appendTo("body").val(urlStart).select().each(function () {
|
||||
document.execCommand('copy');
|
||||
}).remove();
|
||||
showBasicAlert("Copied Whiteboard-URL to clipboard.", { hideAfter: 2 })
|
||||
$("<textarea/>")
|
||||
.appendTo("body")
|
||||
.val(urlStart)
|
||||
.select()
|
||||
.each(function () {
|
||||
document.execCommand("copy");
|
||||
})
|
||||
.remove();
|
||||
showBasicAlert("Copied Whiteboard-URL to clipboard.", { hideAfter: 2 });
|
||||
});
|
||||
|
||||
var btnsMini = false;
|
||||
@ -348,7 +394,7 @@ function main() {
|
||||
$(this).find("#maxBtn").hide();
|
||||
}
|
||||
btnsMini = !btnsMini;
|
||||
})
|
||||
});
|
||||
|
||||
// load json to whiteboard
|
||||
$("#myFile").on("change", function () {
|
||||
@ -374,7 +420,7 @@ function main() {
|
||||
|
||||
// handle drag&drop
|
||||
var dragCounter = 0;
|
||||
$('#whiteboardContainer').on("dragenter", function (e) {
|
||||
$("#whiteboardContainer").on("dragenter", function (e) {
|
||||
if (ReadOnlyService.readOnlyActive) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@ -382,7 +428,7 @@ function main() {
|
||||
whiteboard.dropIndicator.show();
|
||||
});
|
||||
|
||||
$('#whiteboardContainer').on("dragleave", function (e) {
|
||||
$("#whiteboardContainer").on("dragleave", function (e) {
|
||||
if (ReadOnlyService.readOnlyActive) return;
|
||||
|
||||
e.preventDefault();
|
||||
@ -393,11 +439,13 @@ function main() {
|
||||
}
|
||||
});
|
||||
|
||||
$('#whiteboardContainer').on('drop', function (e) { //Handle drop
|
||||
$("#whiteboardContainer").on("drop", function (e) {
|
||||
//Handle drop
|
||||
if (ReadOnlyService.readOnlyActive) return;
|
||||
|
||||
if (e.originalEvent.dataTransfer) {
|
||||
if (e.originalEvent.dataTransfer.files.length) { //File from harddisc
|
||||
if (e.originalEvent.dataTransfer.files.length) {
|
||||
//File from harddisc
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var filename = e.originalEvent.dataTransfer.files[0]["name"];
|
||||
@ -408,8 +456,9 @@ function main() {
|
||||
reader.onloadend = function () {
|
||||
const base64data = reader.result;
|
||||
uploadImgAndAddToWhiteboard(base64data);
|
||||
}
|
||||
} else if (isPDFFileName(filename)) { //Handle PDF Files
|
||||
};
|
||||
} else if (isPDFFileName(filename)) {
|
||||
//Handle PDF Files
|
||||
var blob = e.originalEvent.dataTransfer.files[0];
|
||||
|
||||
var reader = new window.FileReader();
|
||||
@ -417,86 +466,91 @@ function main() {
|
||||
var pdfData = new Uint8Array(this.result);
|
||||
|
||||
var loadingTask = pdfjsLib.getDocument({ data: pdfData });
|
||||
loadingTask.promise.then(function (pdf) {
|
||||
console.log('PDF loaded');
|
||||
loadingTask.promise.then(
|
||||
function (pdf) {
|
||||
console.log("PDF loaded");
|
||||
|
||||
var currentDataUrl = null;
|
||||
var modalDiv = $('<div>' +
|
||||
'Page: <select></select> ' +
|
||||
'<button style="margin-bottom: 3px;" class="modalBtn"><i class="fas fa-upload"></i> Upload to Whiteboard</button>' +
|
||||
'<img style="width:100%;" src=""/>' +
|
||||
'</div>')
|
||||
var currentDataUrl = null;
|
||||
var modalDiv = $(
|
||||
"<div>" +
|
||||
"Page: <select></select> " +
|
||||
'<button style="margin-bottom: 3px;" class="modalBtn"><i class="fas fa-upload"></i> Upload to Whiteboard</button>' +
|
||||
'<img style="width:100%;" src=""/>' +
|
||||
"</div>"
|
||||
);
|
||||
|
||||
modalDiv.find("select").change(function () {
|
||||
showPDFPageAsImage(parseInt($(this).val()));
|
||||
})
|
||||
|
||||
modalDiv.find("button").click(function () {
|
||||
if (currentDataUrl) {
|
||||
$(".basicalert").remove();
|
||||
uploadImgAndAddToWhiteboard(currentDataUrl);
|
||||
}
|
||||
})
|
||||
|
||||
for (var i = 1; i < pdf.numPages + 1; i++) {
|
||||
modalDiv.find("select").append('<option value="' + i + '">' + i + '</option>')
|
||||
}
|
||||
|
||||
showBasicAlert(modalDiv, {
|
||||
header: "Pdf to Image",
|
||||
okBtnText: "cancel",
|
||||
headercolor: "#0082c9"
|
||||
})
|
||||
|
||||
showPDFPageAsImage(1);
|
||||
function showPDFPageAsImage(pageNumber) {
|
||||
|
||||
// Fetch the page
|
||||
pdf.getPage(pageNumber).then(function (page) {
|
||||
console.log('Page loaded');
|
||||
|
||||
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale });
|
||||
|
||||
// Prepare canvas using PDF page dimensions
|
||||
var canvas = $("<canvas></canvas>")[0];
|
||||
var context = canvas.getContext('2d');
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
// Render PDF page into canvas context
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport
|
||||
};
|
||||
var renderTask = page.render(renderContext);
|
||||
renderTask.promise.then(function () {
|
||||
var dataUrl = canvas.toDataURL("image/jpeg", 1.0);
|
||||
currentDataUrl = dataUrl;
|
||||
modalDiv.find("img").attr("src", dataUrl);
|
||||
console.log('Page rendered');
|
||||
|
||||
});
|
||||
modalDiv.find("select").change(function () {
|
||||
showPDFPageAsImage(parseInt($(this).val()));
|
||||
});
|
||||
|
||||
modalDiv.find("button").click(function () {
|
||||
if (currentDataUrl) {
|
||||
$(".basicalert").remove();
|
||||
uploadImgAndAddToWhiteboard(currentDataUrl);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 1; i < pdf.numPages + 1; i++) {
|
||||
modalDiv
|
||||
.find("select")
|
||||
.append('<option value="' + i + '">' + i + "</option>");
|
||||
}
|
||||
|
||||
showBasicAlert(modalDiv, {
|
||||
header: "Pdf to Image",
|
||||
okBtnText: "cancel",
|
||||
headercolor: "#0082c9",
|
||||
});
|
||||
|
||||
showPDFPageAsImage(1);
|
||||
function showPDFPageAsImage(pageNumber) {
|
||||
// Fetch the page
|
||||
pdf.getPage(pageNumber).then(function (page) {
|
||||
console.log("Page loaded");
|
||||
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale });
|
||||
|
||||
// Prepare canvas using PDF page dimensions
|
||||
var canvas = $("<canvas></canvas>")[0];
|
||||
var context = canvas.getContext("2d");
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
// Render PDF page into canvas context
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
};
|
||||
var renderTask = page.render(renderContext);
|
||||
renderTask.promise.then(function () {
|
||||
var dataUrl = canvas.toDataURL("image/jpeg", 1.0);
|
||||
currentDataUrl = dataUrl;
|
||||
modalDiv.find("img").attr("src", dataUrl);
|
||||
console.log("Page rendered");
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
function (reason) {
|
||||
// PDF loading error
|
||||
|
||||
showBasicAlert(
|
||||
"Error loading pdf as image! Check that this is a vaild pdf file!"
|
||||
);
|
||||
console.error(reason);
|
||||
}
|
||||
|
||||
}, function (reason) {
|
||||
// PDF loading error
|
||||
|
||||
showBasicAlert("Error loading pdf as image! Check that this is a vaild pdf file!");
|
||||
console.error(reason);
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
};
|
||||
reader.readAsArrayBuffer(blob);
|
||||
} else {
|
||||
showBasicAlert("File must be an image!");
|
||||
}
|
||||
} else { //File from other browser
|
||||
} else {
|
||||
//File from other browser
|
||||
|
||||
var fileUrl = e.originalEvent.dataTransfer.getData('URL');
|
||||
var imageUrl = e.originalEvent.dataTransfer.getData('text/html');
|
||||
var fileUrl = e.originalEvent.dataTransfer.getData("URL");
|
||||
var imageUrl = e.originalEvent.dataTransfer.getData("text/html");
|
||||
var rex = /src="?([^"\s]+)"?\s*/;
|
||||
var url = rex.exec(imageUrl);
|
||||
if (url && url.length > 1) {
|
||||
@ -529,11 +583,11 @@ function main() {
|
||||
});
|
||||
|
||||
new Picker({
|
||||
parent: $('#whiteboardColorpicker')[0],
|
||||
parent: $("#whiteboardColorpicker")[0],
|
||||
color: "#000000",
|
||||
onChange: function (color) {
|
||||
whiteboard.setDrawColor(color.rgbaString);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// on startup select mouse
|
||||
@ -549,64 +603,76 @@ function main() {
|
||||
});
|
||||
|
||||
//Prevent site from changing tab on drag&drop
|
||||
window.addEventListener("dragover", function (e) {
|
||||
e = e || event;
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
window.addEventListener("drop", function (e) {
|
||||
e = e || event;
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
window.addEventListener(
|
||||
"dragover",
|
||||
function (e) {
|
||||
e = e || event;
|
||||
e.preventDefault();
|
||||
},
|
||||
false
|
||||
);
|
||||
window.addEventListener(
|
||||
"drop",
|
||||
function (e) {
|
||||
e = e || event;
|
||||
e.preventDefault();
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
function uploadImgAndAddToWhiteboard(base64data) {
|
||||
var date = (+new Date());
|
||||
var date = +new Date();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: document.URL.substr(0, document.URL.lastIndexOf('/')) + '/api/upload',
|
||||
type: "POST",
|
||||
url: document.URL.substr(0, document.URL.lastIndexOf("/")) + "/api/upload",
|
||||
data: {
|
||||
'imagedata': base64data,
|
||||
'whiteboardId': whiteboardId,
|
||||
'date': date,
|
||||
'at': accessToken
|
||||
imagedata: base64data,
|
||||
whiteboardId: whiteboardId,
|
||||
date: date,
|
||||
at: accessToken,
|
||||
},
|
||||
success: function (msg) {
|
||||
var filename = whiteboardId + "_" + date + ".png";
|
||||
whiteboard.addImgToCanvasByUrl(document.URL.substr(0, document.URL.lastIndexOf('/')) + "/uploads/" + filename); //Add image to canvas
|
||||
whiteboard.addImgToCanvasByUrl(
|
||||
document.URL.substr(0, document.URL.lastIndexOf("/")) + "/uploads/" + filename
|
||||
); //Add image to canvas
|
||||
console.log("Image uploaded!");
|
||||
},
|
||||
error: function (err) {
|
||||
showBasicAlert("Failed to upload frame: " + JSON.stringify(err));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function saveWhiteboardToWebdav(base64data, webdavaccess, callback) {
|
||||
var date = (+new Date());
|
||||
var date = +new Date();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: document.URL.substr(0, document.URL.lastIndexOf('/')) + 'api/upload',
|
||||
type: "POST",
|
||||
url: document.URL.substr(0, document.URL.lastIndexOf("/")) + "api/upload",
|
||||
data: {
|
||||
'imagedata': base64data,
|
||||
'whiteboardId': whiteboardId,
|
||||
'date': date,
|
||||
'at': accessToken,
|
||||
'webdavaccess': JSON.stringify(webdavaccess)
|
||||
imagedata: base64data,
|
||||
whiteboardId: whiteboardId,
|
||||
date: date,
|
||||
at: accessToken,
|
||||
webdavaccess: JSON.stringify(webdavaccess),
|
||||
},
|
||||
success: function (msg) {
|
||||
showBasicAlert("Whiteboard was saved to Webdav!", {
|
||||
headercolor: "#5c9e5c"
|
||||
headercolor: "#5c9e5c",
|
||||
});
|
||||
console.log("Image uploaded for webdav!");
|
||||
callback();
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.status == 403) {
|
||||
showBasicAlert("Could not connect to Webdav folder! Please check the credentials and paths and try again!");
|
||||
showBasicAlert(
|
||||
"Could not connect to Webdav folder! Please check the credentials and paths and try again!"
|
||||
);
|
||||
} else {
|
||||
showBasicAlert("Unknown Webdav error! ", err);
|
||||
}
|
||||
callback(err);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -664,13 +730,15 @@ function main() {
|
||||
console.log("Uploading image!");
|
||||
let base64data = reader.result;
|
||||
uploadImgAndAddToWhiteboard(base64data);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!imgItemFound && whiteboard.tool != "text") {
|
||||
showBasicAlert("Please Drag&Drop the image or pdf into the Whiteboard. (Browsers don't allow copy+past from the filesystem directly)");
|
||||
showBasicAlert(
|
||||
"Please Drag&Drop the image or pdf into the Whiteboard. (Browsers don't allow copy+past from the filesystem directly)"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -681,21 +749,28 @@ function main() {
|
||||
okBtnText: "Ok",
|
||||
headercolor: "#d25d5d",
|
||||
hideAfter: false,
|
||||
onOkClick: false
|
||||
}
|
||||
onOkClick: false,
|
||||
};
|
||||
if (newOptions) {
|
||||
for (var i in newOptions) {
|
||||
options[i] = newOptions[i];
|
||||
}
|
||||
}
|
||||
var alertHtml = $('<div class="basicalert" style="position:absolute; left:0px; width:100%; top:70px; font-family: monospace;">' +
|
||||
'<div style="width: 30%; margin: auto; background: #aaaaaa; border-radius: 5px; font-size: 1.2em; border: 1px solid gray;">' +
|
||||
'<div style="border-bottom: 1px solid #676767; background: ' + options["headercolor"] + '; padding-left: 5px; font-size: 0.8em;">' + options["header"] +
|
||||
'<div style="float: right; margin-right: 4px; color: #373737; cursor: pointer;" class="closeAlert">x</div></div>' +
|
||||
'<div style="padding: 10px;" class="htmlcontent"></div>' +
|
||||
'<div style="height: 20px; padding: 10px;"><button class="modalBtn okbtn" style="float: right;">' + options["okBtnText"] + '</button></div>' +
|
||||
'</div>' +
|
||||
'</div>');
|
||||
var alertHtml = $(
|
||||
'<div class="basicalert" style="position:absolute; left:0px; width:100%; top:70px; font-family: monospace;">' +
|
||||
'<div style="width: 30%; margin: auto; background: #aaaaaa; border-radius: 5px; font-size: 1.2em; border: 1px solid gray;">' +
|
||||
'<div style="border-bottom: 1px solid #676767; background: ' +
|
||||
options["headercolor"] +
|
||||
'; padding-left: 5px; font-size: 0.8em;">' +
|
||||
options["header"] +
|
||||
'<div style="float: right; margin-right: 4px; color: #373737; cursor: pointer;" class="closeAlert">x</div></div>' +
|
||||
'<div style="padding: 10px;" class="htmlcontent"></div>' +
|
||||
'<div style="height: 20px; padding: 10px;"><button class="modalBtn okbtn" style="float: right;">' +
|
||||
options["okBtnText"] +
|
||||
"</button></div>" +
|
||||
"</div>" +
|
||||
"</div>"
|
||||
);
|
||||
alertHtml.find(".htmlcontent").append(html);
|
||||
$("body").append(alertHtml);
|
||||
alertHtml.find(".okbtn").click(function () {
|
||||
@ -703,15 +778,15 @@ function main() {
|
||||
options.onOkClick();
|
||||
}
|
||||
alertHtml.remove();
|
||||
})
|
||||
});
|
||||
alertHtml.find(".closeAlert").click(function () {
|
||||
alertHtml.remove();
|
||||
})
|
||||
});
|
||||
|
||||
if (options.hideAfter) {
|
||||
setTimeout(function () {
|
||||
alertHtml.find(".okbtn").click();
|
||||
}, 1000 * options.hideAfter)
|
||||
}, 1000 * options.hideAfter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,4 +804,4 @@ function main() {
|
||||
}
|
||||
}
|
||||
|
||||
export default main;
|
||||
export default main;
|
||||
|
@ -57,4 +57,4 @@ class ReadOnlyService {
|
||||
}
|
||||
}
|
||||
|
||||
export default new ReadOnlyService();
|
||||
export default new ReadOnlyService();
|
||||
|
@ -9,7 +9,7 @@ function defineShortcut(callback, readOnlySensitive = true) {
|
||||
return () => {
|
||||
if (readOnlySensitive && ReadOnlyService.readOnlyActive) return;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const shortcutFunctions = {
|
||||
@ -103,33 +103,45 @@ const shortcutFunctions = {
|
||||
}
|
||||
}),
|
||||
moveDraggableUp: defineShortcut(() => {
|
||||
const elm = whiteboard.tool === "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
const elm =
|
||||
whiteboard.tool === "text"
|
||||
? $("#" + whiteboard.latestActiveTextBoxId)
|
||||
: $(".dragMe")[0];
|
||||
const p = $(elm).position();
|
||||
if (p) $(elm).css({top: p.top - 5, left: p.left})
|
||||
if (p) $(elm).css({ top: p.top - 5, left: p.left });
|
||||
}),
|
||||
moveDraggableDown: defineShortcut(() => {
|
||||
const elm = whiteboard.tool === "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
const elm =
|
||||
whiteboard.tool === "text"
|
||||
? $("#" + whiteboard.latestActiveTextBoxId)
|
||||
: $(".dragMe")[0];
|
||||
const p = $(elm).position();
|
||||
if (p) $(elm).css({top: p.top + 5, left: p.left})
|
||||
if (p) $(elm).css({ top: p.top + 5, left: p.left });
|
||||
}),
|
||||
moveDraggableLeft: defineShortcut(() => {
|
||||
const elm = whiteboard.tool === "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
const elm =
|
||||
whiteboard.tool === "text"
|
||||
? $("#" + whiteboard.latestActiveTextBoxId)
|
||||
: $(".dragMe")[0];
|
||||
const p = $(elm).position();
|
||||
if (p) $(elm).css({top: p.top, left: p.left - 5})
|
||||
if (p) $(elm).css({ top: p.top, left: p.left - 5 });
|
||||
}),
|
||||
moveDraggableRight: defineShortcut(() => {
|
||||
const elm = whiteboard.tool === "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
const elm =
|
||||
whiteboard.tool === "text"
|
||||
? $("#" + whiteboard.latestActiveTextBoxId)
|
||||
: $(".dragMe")[0];
|
||||
const p = $(elm).position();
|
||||
if (p) $(elm).css({top: p.top, left: p.left + 5})
|
||||
if (p) $(elm).css({ top: p.top, left: p.left + 5 });
|
||||
}),
|
||||
dropDraggable: defineShortcut(() => {
|
||||
$($(".dragMe")[0]).find('.addToCanvasBtn').click();
|
||||
$($(".dragMe")[0]).find(".addToCanvasBtn").click();
|
||||
}),
|
||||
addToBackground: defineShortcut(() => {
|
||||
$($(".dragMe")[0]).find('.addToBackgroundBtn').click();
|
||||
$($(".dragMe")[0]).find(".addToBackgroundBtn").click();
|
||||
}),
|
||||
cancelAllActions: defineShortcut(() => whiteboard.escKeyAction()),
|
||||
deleteSelection: defineShortcut(() => whiteboard.delKeyAction()),
|
||||
}
|
||||
};
|
||||
|
||||
export default shortcutFunctions;
|
||||
|
@ -4,9 +4,7 @@
|
||||
* @param {Point} p2
|
||||
*/
|
||||
export function computeDist(p1, p2) {
|
||||
return Math.sqrt(
|
||||
Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)
|
||||
);
|
||||
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -14,5 +12,5 @@ export function computeDist(p1, p2) {
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getCurrentTimeMs() {
|
||||
return (new Date()).getTime();
|
||||
}
|
||||
return new Date().getTime();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user