Merge branch 'master' into feature/addSecrets
This commit is contained in:
commit
48592d692c
62 changed files with 1374 additions and 1397 deletions
8
.babelrc
Normal file
8
.babelrc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
"es2015"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"transform-runtime"
|
||||||
|
]
|
||||||
|
}
|
1
.eslintignore
Normal file
1
.eslintignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.min.js
|
|
@ -16,7 +16,6 @@
|
||||||
],
|
],
|
||||||
"array-callback-return": "error",
|
"array-callback-return": "error",
|
||||||
"arrow-body-style": "error",
|
"arrow-body-style": "error",
|
||||||
"arrow-parens": "error",
|
|
||||||
"arrow-spacing": "error",
|
"arrow-spacing": "error",
|
||||||
"block-scoped-var": "off",
|
"block-scoped-var": "off",
|
||||||
"block-spacing": "error",
|
"block-spacing": "error",
|
||||||
|
@ -123,7 +122,7 @@
|
||||||
"no-extend-native": "error",
|
"no-extend-native": "error",
|
||||||
"no-extra-bind": "error",
|
"no-extra-bind": "error",
|
||||||
"no-extra-label": "error",
|
"no-extra-label": "error",
|
||||||
"no-extra-parens": "error",
|
"no-extra-parens": "warn",
|
||||||
"no-floating-decimal": "error",
|
"no-floating-decimal": "error",
|
||||||
"no-global-assign": "error",
|
"no-global-assign": "error",
|
||||||
"no-implicit-coercion": "error",
|
"no-implicit-coercion": "error",
|
||||||
|
@ -195,7 +194,7 @@
|
||||||
"no-unneeded-ternary": "error",
|
"no-unneeded-ternary": "error",
|
||||||
"no-unsafe-negation": "error",
|
"no-unsafe-negation": "error",
|
||||||
"no-unused-expressions": "error",
|
"no-unused-expressions": "error",
|
||||||
"no-use-before-define": "error",
|
"no-use-before-define": "warn",
|
||||||
"no-useless-call": "error",
|
"no-useless-call": "error",
|
||||||
"no-useless-computed-key": "error",
|
"no-useless-computed-key": "error",
|
||||||
"no-useless-concat": "error",
|
"no-useless-concat": "error",
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,7 +18,6 @@ backups/
|
||||||
|
|
||||||
# ignore config files
|
# ignore config files
|
||||||
config.json
|
config.json
|
||||||
public/js/config.js
|
|
||||||
.sequelizerc
|
.sequelizerc
|
||||||
|
|
||||||
# ignore webpack build
|
# ignore webpack build
|
||||||
|
|
13
.travis.yml
Normal file
13
.travis.yml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 6
|
||||||
|
- 7
|
||||||
|
- stable
|
||||||
|
env:
|
||||||
|
- CXX=g++-4.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-4.8
|
46
README.md
46
README.md
|
@ -1,7 +1,9 @@
|
||||||
HackMD
|
HackMD
|
||||||
===
|
===
|
||||||
|
|
||||||
[![Join the chat at https://gitter.im/hackmdio/hackmd](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hackmdio/hackmd?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[![Join the chat at https://gitter.im/hackmdio/hackmd][gitter-image]][gitter-url]
|
||||||
|
[![build status][travis-image]][travis-url]
|
||||||
|
|
||||||
|
|
||||||
HackMD lets you create realtime collaborative markdown notes on all platforms.
|
HackMD lets you create realtime collaborative markdown notes on all platforms.
|
||||||
Inspired by Hackpad, with more focus on speed and flexibility.
|
Inspired by Hackpad, with more focus on speed and flexibility.
|
||||||
|
@ -48,9 +50,9 @@ Browsers Requirement
|
||||||
Prerequisite
|
Prerequisite
|
||||||
---
|
---
|
||||||
|
|
||||||
- Node.js 4.x or up (test up to 6.7.0)
|
- Node.js 6.x or up (test up to 7.5.0)
|
||||||
- Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8`
|
- Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8`
|
||||||
- npm
|
- npm (and its dependencies, especially [uWebSockets](https://github.com/uWebSockets/uWebSockets#nodejs-developers), [node-gyp](https://github.com/nodejs/node-gyp#installation))
|
||||||
|
|
||||||
Get started
|
Get started
|
||||||
---
|
---
|
||||||
|
@ -59,7 +61,7 @@ Get started
|
||||||
2. Enter the directory and type `bin/setup`, which will install npm dependencies and create configs. The setup script is written in Bash, you would need bash as a prerequisite.
|
2. Enter the directory and type `bin/setup`, which will install npm dependencies and create configs. The setup script is written in Bash, you would need bash as a prerequisite.
|
||||||
3. Setup the configs, see more below
|
3. Setup the configs, see more below
|
||||||
4. Setup environment variables which will overwrite the configs
|
4. Setup environment variables which will overwrite the configs
|
||||||
5. Build front-end bundle by `npm run build:prod` (use `npm run build:dev` if you are in development)
|
5. Build front-end bundle by `npm run build` (use `npm run dev` if you are in development)
|
||||||
6. Run the server as you like (node, forever, pm2)
|
6. Run the server as you like (node, forever, pm2)
|
||||||
|
|
||||||
Upgrade guide
|
Upgrade guide
|
||||||
|
@ -70,7 +72,7 @@ If you are upgrading HackMD from an older version, follow these steps:
|
||||||
1. Fully stop your old server first (important)
|
1. Fully stop your old server first (important)
|
||||||
2. `git pull` or do whatever that updates the files
|
2. `git pull` or do whatever that updates the files
|
||||||
3. `npm install` to update dependencies
|
3. `npm install` to update dependencies
|
||||||
4. Build front-end bundle by `npm run build:prod` (use `npm run build:dev` if you are in development)
|
4. Build front-end bundle by `npm run build` (use `npm run dev` if you are in development)
|
||||||
5. Modify the file named `.sequelizerc`, change the value of the variable `url` with your db connection string
|
5. Modify the file named `.sequelizerc`, change the value of the variable `url` with your db connection string
|
||||||
For example: `postgres://username:password@localhost:5432/hackmd`
|
For example: `postgres://username:password@localhost:5432/hackmd`
|
||||||
6. Run `node_modules/.bin/sequelize db:migrate`, this step will migrate your db to the latest schema
|
6. Run `node_modules/.bin/sequelize db:migrate`, this step will migrate your db to the latest schema
|
||||||
|
@ -97,19 +99,9 @@ Configuration files
|
||||||
There are some configs you need to change in the files below
|
There are some configs you need to change in the files below
|
||||||
|
|
||||||
```
|
```
|
||||||
./config.json --- for server settings
|
./config.json ----application settings
|
||||||
./public/js/config.js --- for client settings
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Client settings `config.js`
|
|
||||||
---
|
|
||||||
|
|
||||||
| variables | example values | description |
|
|
||||||
| --------- | ------ | ----------- |
|
|
||||||
| debug | `true` or `false` | set debug mode, show more logs |
|
|
||||||
| domain | `localhost` | domain name |
|
|
||||||
| urlpath | `hackmd` | sub url path, like: `www.example.com/<urlpath>` |
|
|
||||||
|
|
||||||
Environment variables (will overwrite other server configs)
|
Environment variables (will overwrite other server configs)
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -126,6 +118,7 @@ Environment variables (will overwrite other server configs)
|
||||||
| HMD_USECDN | `true` or `false` | set to use CDN resources or not (default is `true`) |
|
| HMD_USECDN | `true` or `false` | set to use CDN resources or not (default is `true`) |
|
||||||
| HMD_ALLOW_ANONYMOUS | `true` or `false` | set to allow anonymous usage (default is `true`) |
|
| HMD_ALLOW_ANONYMOUS | `true` or `false` | set to allow anonymous usage (default is `true`) |
|
||||||
| HMD_ALLOW_FREEURL | `true` or `false` | set to allow new note by accessing not exist note url |
|
| HMD_ALLOW_FREEURL | `true` or `false` | set to allow new note by accessing not exist note url |
|
||||||
|
| HMD_DEFAULT_PERMISSION | `freely`, `editable`, `limited`, `locked` or `private` | set notes default permission (only applied on signed users) |
|
||||||
| HMD_DB_URL | `mysql://localhost:3306/database` | set the db url |
|
| HMD_DB_URL | `mysql://localhost:3306/database` | set the db url |
|
||||||
| HMD_FACEBOOK_CLIENTID | no example | Facebook API client id |
|
| HMD_FACEBOOK_CLIENTID | no example | Facebook API client id |
|
||||||
| HMD_FACEBOOK_CLIENTSECRET | no example | Facebook API client secret |
|
| HMD_FACEBOOK_CLIENTSECRET | no example | Facebook API client secret |
|
||||||
|
@ -140,15 +133,15 @@ Environment variables (will overwrite other server configs)
|
||||||
| HMD_DROPBOX_CLIENTSECRET | no example | Dropbox API client secret |
|
| HMD_DROPBOX_CLIENTSECRET | no example | Dropbox API client secret |
|
||||||
| HMD_GOOGLE_CLIENTID | no example | Google API client id |
|
| HMD_GOOGLE_CLIENTID | no example | Google API client id |
|
||||||
| HMD_GOOGLE_CLIENTSECRET | no example | Google API client secret |
|
| HMD_GOOGLE_CLIENTSECRET | no example | Google API client secret |
|
||||||
| HMD_LDAP_URL | ldap://example.com | url of LDAP server |
|
| HMD_LDAP_URL | `ldap://example.com` | url of LDAP server |
|
||||||
| HMD_LDAP_BINDDN | no example | bindDn for LDAP access |
|
| HMD_LDAP_BINDDN | no example | bindDn for LDAP access |
|
||||||
| HMD_LDAP_BINDCREDENTIALS | no example | bindCredentials for LDAP access |
|
| HMD_LDAP_BINDCREDENTIALS | no example | bindCredentials for LDAP access |
|
||||||
| HMD_LDAP_TOKENSECRET | supersecretkey | secret used for generating access/refresh tokens |
|
| HMD_LDAP_TOKENSECRET | `supersecretkey` | secret used for generating access/refresh tokens |
|
||||||
| HMD_LDAP_SEARCHBASE | o=users,dc=example,dc=com | LDAP directory to begin search from |
|
| HMD_LDAP_SEARCHBASE | `o=users,dc=example,dc=com` | LDAP directory to begin search from |
|
||||||
| HMD_LDAP_SEARCHFILTER | (uid={{username}}) | LDAP filter to search with |
|
| HMD_LDAP_SEARCHFILTER | `(uid={{username}})` | LDAP filter to search with |
|
||||||
| HMD_LDAP_SEARCHATTRIBUTES | no example | LDAP attributes to search with |
|
| HMD_LDAP_SEARCHATTRIBUTES | no example | LDAP attributes to search with |
|
||||||
| HMD_LDAP_TLS_CA | no example | Root CA for LDAP TLS in PEM format |
|
| HMD_LDAP_TLS_CA | `server-cert.pem, root.pem` | Root CA for LDAP TLS in PEM format (use comma to separate) |
|
||||||
| HMD_LDAP_PROVIDERNAME | My institution | Optional name to be displayed at login form indicating the LDAP provider |
|
| HMD_LDAP_PROVIDERNAME | `My institution` | Optional name to be displayed at login form indicating the LDAP provider |
|
||||||
| HMD_IMGUR_CLIENTID | no example | Imgur API client id |
|
| HMD_IMGUR_CLIENTID | no example | Imgur API client id |
|
||||||
| HMD_EMAIL | `true` or `false` | set to allow email signin |
|
| HMD_EMAIL | `true` or `false` | set to allow email signin |
|
||||||
| HMD_ALLOW_EMAIL_REGISTER | `true` or `false` | set to allow email register (only applied when email is set, default is `true`) |
|
| HMD_ALLOW_EMAIL_REGISTER | `true` or `false` | set to allow email register (only applied when email is set, default is `true`) |
|
||||||
|
@ -158,7 +151,7 @@ Environment variables (will overwrite other server configs)
|
||||||
| HMD_S3_REGION | `ap-northeast-1` | AWS S3 region |
|
| HMD_S3_REGION | `ap-northeast-1` | AWS S3 region |
|
||||||
| HMD_S3_BUCKET | no example | AWS S3 bucket name |
|
| HMD_S3_BUCKET | no example | AWS S3 bucket name |
|
||||||
|
|
||||||
Server settings `config.json`
|
Application settings `config.json`
|
||||||
---
|
---
|
||||||
|
|
||||||
| variables | example values | description |
|
| variables | example values | description |
|
||||||
|
@ -174,6 +167,7 @@ Server settings `config.json`
|
||||||
| usecdn | `true` or `false` | set to use CDN resources or not (default is `true`) |
|
| usecdn | `true` or `false` | set to use CDN resources or not (default is `true`) |
|
||||||
| allowanonymous | `true` or `false` | set to allow anonymous usage (default is `true`) |
|
| allowanonymous | `true` or `false` | set to allow anonymous usage (default is `true`) |
|
||||||
| allowfreeurl | `true` or `false` | set to allow new note by accessing not exist note url |
|
| allowfreeurl | `true` or `false` | set to allow new note by accessing not exist note url |
|
||||||
|
| defaultpermission | `freely`, `editable`, `limited`, `locked` or `private` | set notes default permission (only applied on signed users) |
|
||||||
| dburl | `mysql://localhost:3306/database` | set the db url, if set this variable then below db config won't be applied |
|
| dburl | `mysql://localhost:3306/database` | set the db url, if set this variable then below db config won't be applied |
|
||||||
| db | `{ "dialect": "sqlite", "storage": "./db.hackmd.sqlite" }` | set the db configs, [see more here](http://sequelize.readthedocs.org/en/latest/api/sequelize/) |
|
| db | `{ "dialect": "sqlite", "storage": "./db.hackmd.sqlite" }` | set the db configs, [see more here](http://sequelize.readthedocs.org/en/latest/api/sequelize/) |
|
||||||
| sslkeypath | `./cert/client.key` | ssl key path (only need when you set usessl) |
|
| sslkeypath | `./cert/client.key` | ssl key path (only need when you set usessl) |
|
||||||
|
@ -207,7 +201,7 @@ Third-party integration api key settings
|
||||||
| ------- | --------- | ----------- |
|
| ------- | --------- | ----------- |
|
||||||
| facebook, twitter, github, gitlab, dropbox, google, ldap | environment variables or `config.json` | for signin |
|
| facebook, twitter, github, gitlab, dropbox, google, ldap | environment variables or `config.json` | for signin |
|
||||||
| imgur | environment variables or `config.json` | for image upload |
|
| imgur | environment variables or `config.json` | for image upload |
|
||||||
| google drive, dropbox | `public/js/config.js` | for export and import |
|
| google drive(`google/apiKey`, `google/clientID`), dropbox(`dropbox/appKey`) | `config.json` | for export and import |
|
||||||
|
|
||||||
Third-party integration oauth callback urls
|
Third-party integration oauth callback urls
|
||||||
---
|
---
|
||||||
|
@ -230,3 +224,7 @@ Additionally, now can show other clients' selections.
|
||||||
See more at [http://operational-transformation.github.io/](http://operational-transformation.github.io/)
|
See more at [http://operational-transformation.github.io/](http://operational-transformation.github.io/)
|
||||||
|
|
||||||
**License under MIT.**
|
**License under MIT.**
|
||||||
|
[gitter-image]: https://badges.gitter.im/Join%20Chat.svg
|
||||||
|
[gitter-url]: https://gitter.im/hackmdio/hackmd?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||||
|
[travis-image]: https://travis-ci.org/hackmdio/hackmd.svg?branch=master
|
||||||
|
[travis-url]: https://travis-ci.org/hackmdio/hackmd
|
||||||
|
|
8
app.js
8
app.js
|
@ -26,7 +26,6 @@ var validator = require('validator');
|
||||||
var config = require("./lib/config.js");
|
var config = require("./lib/config.js");
|
||||||
var logger = require("./lib/logger.js");
|
var logger = require("./lib/logger.js");
|
||||||
var auth = require("./lib/auth.js");
|
var auth = require("./lib/auth.js");
|
||||||
var history = require("./lib/history.js");
|
|
||||||
var response = require("./lib/response.js");
|
var response = require("./lib/response.js");
|
||||||
var models = require("./lib/models");
|
var models = require("./lib/models");
|
||||||
|
|
||||||
|
@ -443,6 +442,7 @@ app.get('/logout', function (req, res) {
|
||||||
req.logout();
|
req.logout();
|
||||||
res.redirect(config.serverurl + '/');
|
res.redirect(config.serverurl + '/');
|
||||||
});
|
});
|
||||||
|
var history = require("./lib/history.js");
|
||||||
//get history
|
//get history
|
||||||
app.get('/history', history.historyGet);
|
app.get('/history', history.historyGet);
|
||||||
//post history
|
//post history
|
||||||
|
@ -502,7 +502,7 @@ app.post('/uploadimage', function (req, res) {
|
||||||
switch (config.imageUploadType) {
|
switch (config.imageUploadType) {
|
||||||
case 'filesystem':
|
case 'filesystem':
|
||||||
res.send({
|
res.send({
|
||||||
link: url.resolve(config.serverurl, files.image.path.match(/^public(.+$)/)[1])
|
link: url.resolve(config.serverurl + '/', files.image.path.match(/^public\/(.+$)/)[1])
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -608,7 +608,7 @@ function startListen() {
|
||||||
// sync db then start listen
|
// sync db then start listen
|
||||||
models.sequelize.sync().then(function () {
|
models.sequelize.sync().then(function () {
|
||||||
// check if realtime is ready
|
// check if realtime is ready
|
||||||
if (history.isReady() && realtime.isReady()) {
|
if (realtime.isReady()) {
|
||||||
models.Revision.checkAllNotesRevision(function (err, notes) {
|
models.Revision.checkAllNotesRevision(function (err, notes) {
|
||||||
if (err) throw new Error(err);
|
if (err) throw new Error(err);
|
||||||
if (!notes || notes.length <= 0) return startListen();
|
if (!notes || notes.length <= 0) return startListen();
|
||||||
|
@ -639,7 +639,7 @@ function handleTermSignals() {
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
var checkCleanTimer = setInterval(function () {
|
var checkCleanTimer = setInterval(function () {
|
||||||
if (history.isReady() && realtime.isReady()) {
|
if (realtime.isReady()) {
|
||||||
models.Revision.checkAllNotesRevision(function (err, notes) {
|
models.Revision.checkAllNotesRevision(function (err, notes) {
|
||||||
if (err) return logger.error(err);
|
if (err) return logger.error(err);
|
||||||
if (!notes || notes.length <= 0) {
|
if (!notes || notes.length <= 0) {
|
||||||
|
|
|
@ -28,8 +28,6 @@ EOF
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cp public/js/config.js.example public/js/config.js
|
|
||||||
|
|
||||||
# build app
|
# build app
|
||||||
npm run build:prod
|
npm run build
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
# run command at repo root
|
# run command at repo root
|
||||||
CURRENT_PATH=$PWD
|
CURRENT_PATH=$PWD
|
||||||
if [ -d .git ]; then
|
if [ -d .git ]; then
|
||||||
|
@ -21,10 +23,6 @@ if [ ! -f config.json ]; then
|
||||||
cp config.json.example config.json
|
cp config.json.example config.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f publis/js/config.js ]; then
|
|
||||||
cp public/js/config.js.example public/js/config.js
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f .sequelizerc ]; then
|
if [ ! -f .sequelizerc ]; then
|
||||||
cp .sequelizerc.example .sequelizerc
|
cp .sequelizerc.example .sequelizerc
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -2,18 +2,13 @@
|
||||||
"test": {
|
"test": {
|
||||||
"db": {
|
"db": {
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"storage": "./db.hackmd.sqlite"
|
"storage": ":memory:"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
"domain": "localhost",
|
|
||||||
"db": {
|
"db": {
|
||||||
"username": "",
|
"dialect": "sqlite",
|
||||||
"password": "",
|
"storage": "./db.hackmd.sqlite"
|
||||||
"database": "hackmd",
|
|
||||||
"host": "localhost",
|
|
||||||
"port": "3306",
|
|
||||||
"dialect": "mysql"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
|
@ -45,11 +40,13 @@
|
||||||
},
|
},
|
||||||
"dropbox": {
|
"dropbox": {
|
||||||
"clientID": "change this",
|
"clientID": "change this",
|
||||||
"clientSecret": "change this"
|
"clientSecret": "change this",
|
||||||
|
"appKey": "change this"
|
||||||
},
|
},
|
||||||
"google": {
|
"google": {
|
||||||
"clientID": "change this",
|
"clientID": "change this",
|
||||||
"clientSecret": "change this"
|
"clientSecret": "change this",
|
||||||
|
"apiKey": "change this"
|
||||||
},
|
},
|
||||||
"ldap": {
|
"ldap": {
|
||||||
"url": "ldap://change_this",
|
"url": "ldap://change_this",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// external modules
|
// external modules
|
||||||
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
|
@ -27,8 +28,16 @@ var allowanonymous = process.env.HMD_ALLOW_ANONYMOUS ? (process.env.HMD_ALLOW_AN
|
||||||
|
|
||||||
var allowfreeurl = process.env.HMD_ALLOW_FREEURL ? (process.env.HMD_ALLOW_FREEURL === 'true') : !!config.allowfreeurl;
|
var allowfreeurl = process.env.HMD_ALLOW_FREEURL ? (process.env.HMD_ALLOW_FREEURL === 'true') : !!config.allowfreeurl;
|
||||||
|
|
||||||
|
var permissions = ['editable', 'limited', 'locked', 'protected', 'private'];
|
||||||
|
if (allowanonymous) {
|
||||||
|
permissions.unshift('freely');
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultpermission = process.env.HMD_DEFAULT_PERMISSION || config.defaultpermission;
|
||||||
|
defaultpermission = permissions.indexOf(defaultpermission) != -1 ? defaultpermission : 'editable';
|
||||||
|
|
||||||
// db
|
// db
|
||||||
var dburl = config.dburl || process.env.HMD_DB_URL || process.env.DATABASE_URL;
|
var dburl = process.env.HMD_DB_URL || process.env.DATABASE_URL || config.dburl;
|
||||||
var db = config.db || {};
|
var db = config.db || {};
|
||||||
|
|
||||||
// ssl path
|
// ssl path
|
||||||
|
@ -91,15 +100,16 @@ var gitlab = (process.env.HMD_GITLAB_CLIENTID && process.env.HMD_GITLAB_CLIENTSE
|
||||||
clientID: handleDockerSecret('gitlab_clientID') || process.env.HMD_GITLAB_CLIENTID,
|
clientID: handleDockerSecret('gitlab_clientID') || process.env.HMD_GITLAB_CLIENTID,
|
||||||
clientSecret: handleDockerSecret('gitlab_clientSecret') || process.env.HMD_GITLAB_CLIENTSECRET
|
clientSecret: handleDockerSecret('gitlab_clientSecret') || process.env.HMD_GITLAB_CLIENTSECRET
|
||||||
} : config.gitlab || false;
|
} : config.gitlab || false;
|
||||||
var dropbox = (process.env.HMD_DROPBOX_CLIENTID && process.env.HMD_DROPBOX_CLIENTSECRET || fs.existsSync('/run/secrets/dropbox_clientID') && fs.existsSync('/run/secrets/dropbox_clientSecret')) ? {
|
var dropbox = ((process.env.HMD_DROPBOX_CLIENTID && process.env.HMD_DROPBOX_CLIENTSECRET) || (fs.existsSync('/run/secrets/dropbox_clientID') && fs.existsSync('/run/secrets/dropbox_clientSecret'))) ? {
|
||||||
clientID: handleDockerSecret('dropbox_clientID') || process.env.HMD_DROPBOX_CLIENTID,
|
clientID: handleDockerSecret('dropbox_clientID') || process.env.HMD_DROPBOX_CLIENTID,
|
||||||
clientSecret: handleDockerSecret('dropbox_clientSecret') || process.env.HMD_DROPBOX_CLIENTSECRET
|
clientSecret: handleDockerSecret('dropbox_clientSecret') || process.env.HMD_DROPBOX_CLIENTSECRET
|
||||||
} : config.dropbox || false;
|
} : (config.dropbox && config.dropbox.clientID && config.dropbox.clientSecret && config.dropbox) || false;
|
||||||
var google = (process.env.HMD_GOOGLE_CLIENTID && process.env.HMD_GOOGLE_CLIENTSECRET || fs.existsSync('/run/secrets/google_clientID') && fs.existsSync('/run/secrets/google_clientSecret')) ? {
|
var google = ((process.env.HMD_GOOGLE_CLIENTID && process.env.HMD_GOOGLE_CLIENTSECRET)
|
||||||
clientID: process.env.HMD_GOOGLE_CLIENTID,
|
|| (fs.existsSync('/run/secrets/google_clientID') && fs.existsSync('/run/secrets/google_clientSecret'))) ? {
|
||||||
clientSecret: process.env.HMD_GOOGLE_CLIENTSECRET
|
clientID: handleDockerSecret('google_clientID') || process.env.HMD_GOOGLE_CLIENTID,
|
||||||
} : config.google || false;
|
clientSecret: handleDockerSecret('google_clientSecret') || process.env.HMD_GOOGLE_CLIENTSECRET
|
||||||
var ldap = config.ldap || (
|
} : (config.google && config.google.clientID && config.google.clientSecret && config.google) || false;
|
||||||
|
var ldap = config.ldap || ((
|
||||||
process.env.HMD_LDAP_URL ||
|
process.env.HMD_LDAP_URL ||
|
||||||
process.env.HMD_LDAP_BINDDN ||
|
process.env.HMD_LDAP_BINDDN ||
|
||||||
process.env.HMD_LDAP_BINDCREDENTIALS ||
|
process.env.HMD_LDAP_BINDCREDENTIALS ||
|
||||||
|
@ -107,10 +117,9 @@ var ldap = config.ldap || (
|
||||||
process.env.HMD_LDAP_SEARCHBASE ||
|
process.env.HMD_LDAP_SEARCHBASE ||
|
||||||
process.env.HMD_LDAP_SEARCHFILTER ||
|
process.env.HMD_LDAP_SEARCHFILTER ||
|
||||||
process.env.HMD_LDAP_SEARCHATTRIBUTES ||
|
process.env.HMD_LDAP_SEARCHATTRIBUTES ||
|
||||||
|
process.env.HMD_LDAP_TLS_CA ||
|
||||||
process.env.HMD_LDAP_PROVIDERNAME
|
process.env.HMD_LDAP_PROVIDERNAME
|
||||||
) || false;
|
) ? {} : false);
|
||||||
if (ldap == true)
|
|
||||||
ldap = {};
|
|
||||||
if (process.env.HMD_LDAP_URL)
|
if (process.env.HMD_LDAP_URL)
|
||||||
ldap.url = process.env.HMD_LDAP_URL;
|
ldap.url = process.env.HMD_LDAP_URL;
|
||||||
if (process.env.HMD_LDAP_BINDDN)
|
if (process.env.HMD_LDAP_BINDDN)
|
||||||
|
@ -127,9 +136,17 @@ if (process.env.HMD_LDAP_SEARCHATTRIBUTES)
|
||||||
ldap.searchAttributes = process.env.HMD_LDAP_SEARCHATTRIBUTES;
|
ldap.searchAttributes = process.env.HMD_LDAP_SEARCHATTRIBUTES;
|
||||||
if (process.env.HMD_LDAP_TLS_CA) {
|
if (process.env.HMD_LDAP_TLS_CA) {
|
||||||
var ca = {
|
var ca = {
|
||||||
ca: process.env.HMD_LDAP_TLS_CA
|
ca: process.env.HMD_LDAP_TLS_CA.split(',')
|
||||||
|
}
|
||||||
|
ldap.tlsOptions = ldap.tlsOptions ? Object.assign(ldap.tlsOptions, ca) : ca;
|
||||||
|
if (Array.isArray(ldap.tlsOptions.ca) && ldap.tlsOptions.ca.length > 0) {
|
||||||
|
var i, len, results;
|
||||||
|
results = [];
|
||||||
|
for (i = 0, len = ldap.tlsOptions.ca.length; i < len; i++) {
|
||||||
|
results.push(fs.readFileSync(ldap.tlsOptions.ca[i], 'utf8'));
|
||||||
|
}
|
||||||
|
ldap.tlsOptions.ca = results;
|
||||||
}
|
}
|
||||||
ldap.tlsOptions = ldap.tlsOptions ? Object.assign(ldap.tlsOptions, ca) : ca
|
|
||||||
}
|
}
|
||||||
if (process.env.HMD_LDAP_PROVIDERNAME) {
|
if (process.env.HMD_LDAP_PROVIDERNAME) {
|
||||||
ldap.providerName = process.env.HMD_LDAP_PROVIDERNAME;
|
ldap.providerName = process.env.HMD_LDAP_PROVIDERNAME;
|
||||||
|
@ -169,6 +186,7 @@ module.exports = {
|
||||||
usecdn: usecdn,
|
usecdn: usecdn,
|
||||||
allowanonymous: allowanonymous,
|
allowanonymous: allowanonymous,
|
||||||
allowfreeurl: allowfreeurl,
|
allowfreeurl: allowfreeurl,
|
||||||
|
defaultpermission: defaultpermission,
|
||||||
dburl: dburl,
|
dburl: dburl,
|
||||||
db: db,
|
db: db,
|
||||||
sslkeypath: path.join(cwd, sslkeypath),
|
sslkeypath: path.join(cwd, sslkeypath),
|
||||||
|
|
131
lib/history.js
131
lib/history.js
|
@ -1,7 +1,6 @@
|
||||||
//history
|
//history
|
||||||
//external modules
|
//external modules
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var moment = require('moment');
|
|
||||||
|
|
||||||
//core
|
//core
|
||||||
var config = require("./config.js");
|
var config = require("./config.js");
|
||||||
|
@ -14,71 +13,10 @@ var History = {
|
||||||
historyGet: historyGet,
|
historyGet: historyGet,
|
||||||
historyPost: historyPost,
|
historyPost: historyPost,
|
||||||
historyDelete: historyDelete,
|
historyDelete: historyDelete,
|
||||||
isReady: isReady,
|
|
||||||
updateHistory: updateHistory
|
updateHistory: updateHistory
|
||||||
};
|
};
|
||||||
|
|
||||||
var caches = {};
|
|
||||||
//update when the history is dirty
|
|
||||||
var updater = setInterval(function () {
|
|
||||||
var deleted = [];
|
|
||||||
async.each(Object.keys(caches), function (key, callback) {
|
|
||||||
var cache = caches[key];
|
|
||||||
if (cache.isDirty) {
|
|
||||||
if (config.debug) logger.info("history updater found dirty history: " + key);
|
|
||||||
var history = parseHistoryToArray(cache.history);
|
|
||||||
cache.isDirty = false;
|
|
||||||
finishUpdateHistory(key, history, function (err, count) {
|
|
||||||
if (err) return callback(err, null);
|
|
||||||
if (!count) return callback(null, null);
|
|
||||||
cache.updateAt = Date.now();
|
|
||||||
return callback(null, null);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (moment().isAfter(moment(cache.updateAt).add(5, 'minutes'))) {
|
|
||||||
deleted.push(key);
|
|
||||||
}
|
|
||||||
return callback(null, null);
|
|
||||||
}
|
|
||||||
}, function (err) {
|
|
||||||
if (err) return logger.error('history updater error', err);
|
|
||||||
});
|
|
||||||
// delete specified caches
|
|
||||||
for (var i = 0, l = deleted.length; i < l; i++) {
|
|
||||||
caches[deleted[i]].history = {};
|
|
||||||
delete caches[deleted[i]];
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
function finishUpdateHistory(userid, history, callback) {
|
|
||||||
models.User.update({
|
|
||||||
history: JSON.stringify(history)
|
|
||||||
}, {
|
|
||||||
where: {
|
|
||||||
id: userid
|
|
||||||
}
|
|
||||||
}).then(function (count) {
|
|
||||||
return callback(null, count);
|
|
||||||
}).catch(function (err) {
|
|
||||||
return callback(err, null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReady() {
|
|
||||||
var dirtyCount = 0;
|
|
||||||
async.each(Object.keys(caches), function (key, callback) {
|
|
||||||
if (caches[key].isDirty) dirtyCount++;
|
|
||||||
return callback(null, null);
|
|
||||||
}, function (err) {
|
|
||||||
if (err) return logger.error('history ready check error', err);
|
|
||||||
});
|
|
||||||
return dirtyCount > 0 ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHistory(userid, callback) {
|
function getHistory(userid, callback) {
|
||||||
if (caches[userid]) {
|
|
||||||
return callback(null, caches[userid].history);
|
|
||||||
} else {
|
|
||||||
models.User.findOne({
|
models.User.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: userid
|
id: userid
|
||||||
|
@ -86,46 +24,49 @@ function getHistory(userid, callback) {
|
||||||
}).then(function (user) {
|
}).then(function (user) {
|
||||||
if (!user)
|
if (!user)
|
||||||
return callback(null, null);
|
return callback(null, null);
|
||||||
var history = [];
|
var history = {};
|
||||||
if (user.history)
|
if (user.history)
|
||||||
history = JSON.parse(user.history);
|
history = parseHistoryToObject(JSON.parse(user.history));
|
||||||
if (config.debug)
|
if (config.debug)
|
||||||
logger.info('read history success: ' + user.id);
|
logger.info('read history success: ' + user.id);
|
||||||
setHistory(userid, history);
|
|
||||||
return callback(null, history);
|
return callback(null, history);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
logger.error('read history failed: ' + err);
|
logger.error('read history failed: ' + err);
|
||||||
return callback(err, null);
|
return callback(err, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setHistory(userid, history, callback) {
|
||||||
|
models.User.update({
|
||||||
|
history: JSON.stringify(parseHistoryToArray(history))
|
||||||
|
}, {
|
||||||
|
where: {
|
||||||
|
id: userid
|
||||||
|
}
|
||||||
|
}).then(function (count) {
|
||||||
|
return callback(null, count);
|
||||||
|
}).catch(function (err) {
|
||||||
|
logger.error('set history failed: ' + err);
|
||||||
|
return callback(err, null);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setHistory(userid, history) {
|
function updateHistory(userid, noteId, document, time) {
|
||||||
if (Array.isArray(history)) history = parseHistoryToObject(history);
|
|
||||||
if (!caches[userid]) {
|
|
||||||
caches[userid] = {
|
|
||||||
history: {},
|
|
||||||
isDirty: false,
|
|
||||||
updateAt: Date.now()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
caches[userid].history = history;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateHistory(userid, noteId, document) {
|
|
||||||
if (userid && noteId && typeof document !== 'undefined') {
|
if (userid && noteId && typeof document !== 'undefined') {
|
||||||
getHistory(userid, function (err, history) {
|
getHistory(userid, function (err, history) {
|
||||||
if (err || !history) return;
|
if (err || !history) return;
|
||||||
if (!caches[userid].history[noteId]) {
|
if (!history[noteId]) {
|
||||||
caches[userid].history[noteId] = {};
|
history[noteId] = {};
|
||||||
}
|
}
|
||||||
var noteHistory = caches[userid].history[noteId];
|
var noteHistory = history[noteId];
|
||||||
var noteInfo = models.Note.parseNoteInfo(document);
|
var noteInfo = models.Note.parseNoteInfo(document);
|
||||||
noteHistory.id = noteId;
|
noteHistory.id = noteId;
|
||||||
noteHistory.text = noteInfo.title;
|
noteHistory.text = noteInfo.title;
|
||||||
noteHistory.time = moment().valueOf();
|
noteHistory.time = time || Date.now();
|
||||||
noteHistory.tags = noteInfo.tags;
|
noteHistory.tags = noteInfo.tags;
|
||||||
caches[userid].isDirty = true;
|
setHistory(userid, history, function (err, count) {
|
||||||
|
return;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,9 +116,10 @@ function historyPost(req, res) {
|
||||||
return response.errorBadRequest(res);
|
return response.errorBadRequest(res);
|
||||||
}
|
}
|
||||||
if (Array.isArray(history)) {
|
if (Array.isArray(history)) {
|
||||||
setHistory(req.user.id, history);
|
setHistory(req.user.id, history, function (err, count) {
|
||||||
caches[req.user.id].isDirty = true;
|
if (err) return response.errorInternalError(res);
|
||||||
res.end();
|
res.end();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return response.errorBadRequest(res);
|
return response.errorBadRequest(res);
|
||||||
}
|
}
|
||||||
|
@ -186,11 +128,13 @@ function historyPost(req, res) {
|
||||||
getHistory(req.user.id, function (err, history) {
|
getHistory(req.user.id, function (err, history) {
|
||||||
if (err) return response.errorInternalError(res);
|
if (err) return response.errorInternalError(res);
|
||||||
if (!history) return response.errorNotFound(res);
|
if (!history) return response.errorNotFound(res);
|
||||||
if (!caches[req.user.id].history[noteId]) return response.errorNotFound(res);
|
if (!history[noteId]) return response.errorNotFound(res);
|
||||||
if (req.body.pinned === 'true' || req.body.pinned === 'false') {
|
if (req.body.pinned === 'true' || req.body.pinned === 'false') {
|
||||||
caches[req.user.id].history[noteId].pinned = (req.body.pinned === 'true');
|
history[noteId].pinned = (req.body.pinned === 'true');
|
||||||
caches[req.user.id].isDirty = true;
|
setHistory(req.user.id, history, function (err, count) {
|
||||||
|
if (err) return response.errorInternalError(res);
|
||||||
res.end();
|
res.end();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return response.errorBadRequest(res);
|
return response.errorBadRequest(res);
|
||||||
}
|
}
|
||||||
|
@ -205,17 +149,20 @@ function historyDelete(req, res) {
|
||||||
if (req.isAuthenticated()) {
|
if (req.isAuthenticated()) {
|
||||||
var noteId = req.params.noteId;
|
var noteId = req.params.noteId;
|
||||||
if (!noteId) {
|
if (!noteId) {
|
||||||
setHistory(req.user.id, []);
|
setHistory(req.user.id, [], function (err, count) {
|
||||||
caches[req.user.id].isDirty = true;
|
if (err) return response.errorInternalError(res);
|
||||||
res.end();
|
res.end();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
getHistory(req.user.id, function (err, history) {
|
getHistory(req.user.id, function (err, history) {
|
||||||
if (err) return response.errorInternalError(res);
|
if (err) return response.errorInternalError(res);
|
||||||
if (!history) return response.errorNotFound(res);
|
if (!history) return response.errorNotFound(res);
|
||||||
delete caches[req.user.id].history[noteId];
|
delete history[noteId];
|
||||||
caches[req.user.id].isDirty = true;
|
setHistory(req.user.id, history, function (err, count) {
|
||||||
|
if (err) return response.errorInternalError(res);
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return response.errorForbidden(res);
|
return response.errorForbidden(res);
|
||||||
|
|
|
@ -6,6 +6,6 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
down: function (queryInterface, Sequelize) {
|
down: function (queryInterface, Sequelize) {
|
||||||
queryInterface.removeColumn('Notes', 'deletedAt', Sequelize.DATE);
|
queryInterface.removeColumn('Notes', 'deletedAt');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
down: function (queryInterface, Sequelize) {
|
down: function (queryInterface, Sequelize) {
|
||||||
queryInterface.removeColumn('Users', 'email', Sequelize.TEXT);
|
queryInterface.removeColumn('Users', 'email');
|
||||||
queryInterface.removeColumn('Users', 'password', Sequelize.TEXT);
|
queryInterface.removeColumn('Users', 'password');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -513,10 +513,10 @@ module.exports = function (sequelize, DataTypes) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if no permission specified and have owner then give editable permission, else default permission is freely
|
// if no permission specified and have owner then give default permission in config, else default permission is freely
|
||||||
if (!note.permission) {
|
if (!note.permission) {
|
||||||
if (note.ownerId) {
|
if (note.ownerId) {
|
||||||
note.permission = "editable";
|
note.permission = config.defaultpermission;
|
||||||
} else {
|
} else {
|
||||||
note.permission = "freely";
|
note.permission = "freely";
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,39 +79,54 @@ module.exports = function (sequelize, DataTypes) {
|
||||||
if (profile) {
|
if (profile) {
|
||||||
profile = {
|
profile = {
|
||||||
name: profile.displayName || profile.username,
|
name: profile.displayName || profile.username,
|
||||||
photo: User.parsePhotoByProfile(profile)
|
photo: User.parsePhotoByProfile(profile),
|
||||||
|
biggerphoto: User.parsePhotoByProfile(profile, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return profile;
|
return profile;
|
||||||
},
|
},
|
||||||
parsePhotoByProfile: function (profile) {
|
parsePhotoByProfile: function (profile, bigger) {
|
||||||
var photo = null;
|
var photo = null;
|
||||||
switch (profile.provider) {
|
switch (profile.provider) {
|
||||||
case "facebook":
|
case "facebook":
|
||||||
photo = 'https://graph.facebook.com/' + profile.id + '/picture?width=96';
|
photo = 'https://graph.facebook.com/' + profile.id + '/picture';
|
||||||
|
if (bigger) photo += '?width=400';
|
||||||
|
else photo += '?width=96';
|
||||||
break;
|
break;
|
||||||
case "twitter":
|
case "twitter":
|
||||||
photo = 'https://twitter.com/' + profile.username + '/profile_image?size=bigger';
|
photo = 'https://twitter.com/' + profile.username + '/profile_image';
|
||||||
|
if (bigger) photo += '?size=original';
|
||||||
|
else photo += '?size=bigger';
|
||||||
break;
|
break;
|
||||||
case "github":
|
case "github":
|
||||||
photo = 'https://avatars.githubusercontent.com/u/' + profile.id + '?s=96';
|
photo = 'https://avatars.githubusercontent.com/u/' + profile.id;
|
||||||
|
if (bigger) photo += '?s=400';
|
||||||
|
else photo += '?s=96';
|
||||||
break;
|
break;
|
||||||
case "gitlab":
|
case "gitlab":
|
||||||
photo = profile.avatarUrl.replace(/(\?s=)\d*$/i, '$196');
|
photo = profile.avatarUrl;
|
||||||
|
if (bigger) photo = photo.replace(/(\?s=)\d*$/i, '$1400');
|
||||||
|
else photo = photo.replace(/(\?s=)\d*$/i, '$196');
|
||||||
break;
|
break;
|
||||||
case "dropbox":
|
case "dropbox":
|
||||||
//no image api provided, use gravatar
|
//no image api provided, use gravatar
|
||||||
photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value) + '?s=96';
|
photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value);
|
||||||
|
if (bigger) photo += '?s=400';
|
||||||
|
else photo += '?s=96';
|
||||||
break;
|
break;
|
||||||
case "google":
|
case "google":
|
||||||
photo = profile.photos[0].value.replace(/(\?sz=)\d*$/i, '$196');
|
photo = profile.photos[0].value;
|
||||||
|
if (bigger) photo = photo.replace(/(\?sz=)\d*$/i, '$1400');
|
||||||
|
else photo = photo.replace(/(\?sz=)\d*$/i, '$196');
|
||||||
break;
|
break;
|
||||||
case "ldap":
|
case "ldap":
|
||||||
//no image api provided,
|
//no image api provided,
|
||||||
//use gravatar if email exists,
|
//use gravatar if email exists,
|
||||||
//otherwise generate a letter avatar
|
//otherwise generate a letter avatar
|
||||||
if (profile.emails[0]) {
|
if (profile.emails[0]) {
|
||||||
photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0]) + '?s=96';
|
photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0]);
|
||||||
|
if (bigger) photo += '?s=400';
|
||||||
|
else photo += '?s=96';
|
||||||
} else {
|
} else {
|
||||||
photo = letterAvatars(profile.username);
|
photo = letterAvatars(profile.username);
|
||||||
}
|
}
|
||||||
|
@ -123,7 +138,8 @@ module.exports = function (sequelize, DataTypes) {
|
||||||
var photoUrl = 'https://www.gravatar.com/avatar/' + md5(email);
|
var photoUrl = 'https://www.gravatar.com/avatar/' + md5(email);
|
||||||
return {
|
return {
|
||||||
name: email.substring(0, email.lastIndexOf("@")),
|
name: email.substring(0, email.lastIndexOf("@")),
|
||||||
photo: photoUrl += '?s=96'
|
photo: photoUrl += '?s=96',
|
||||||
|
biggerphoto: photoUrl += '?s=400'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,12 @@ function updateNote(note, callback) {
|
||||||
}
|
}
|
||||||
}).then(function (_note) {
|
}).then(function (_note) {
|
||||||
if (!_note) return callback(null, null);
|
if (!_note) return callback(null, null);
|
||||||
|
// update user note history
|
||||||
|
var tempUsers = Object.assign({}, note.tempUsers);
|
||||||
|
note.tempUsers = {};
|
||||||
|
Object.keys(tempUsers).forEach(function (key) {
|
||||||
|
updateHistory(key, note, tempUsers[key]);
|
||||||
|
});
|
||||||
if (note.lastchangeuser) {
|
if (note.lastchangeuser) {
|
||||||
if (_note.lastchangeuserId != note.lastchangeuser) {
|
if (_note.lastchangeuserId != note.lastchangeuser) {
|
||||||
models.User.findOne({
|
models.User.findOne({
|
||||||
|
@ -348,10 +354,13 @@ function clearSocketQueue(queue, socket) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectNextSocket() {
|
function connectNextSocket() {
|
||||||
|
setTimeout(function () {
|
||||||
isConnectionBusy = false;
|
isConnectionBusy = false;
|
||||||
if (connectionSocketQueue.length > 0)
|
if (connectionSocketQueue.length > 0) {
|
||||||
startConnection(connectionSocketQueue[0]);
|
startConnection(connectionSocketQueue[0]);
|
||||||
}
|
}
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
function interruptConnection(socket, note, user) {
|
function interruptConnection(socket, note, user) {
|
||||||
if (note) delete note;
|
if (note) delete note;
|
||||||
|
@ -405,10 +414,7 @@ function finishConnection(socket, note, user) {
|
||||||
note.server.setColor(socket, user.color);
|
note.server.setColor(socket, user.color);
|
||||||
|
|
||||||
// update user note history
|
// update user note history
|
||||||
setTimeout(function () {
|
updateHistory(user.userid, note);
|
||||||
var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id);
|
|
||||||
if (note.server) history.updateHistory(user.userid, noteId, note.server.document);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
emitOnlineUsers(socket);
|
emitOnlineUsers(socket);
|
||||||
emitRefresh(socket);
|
emitRefresh(socket);
|
||||||
|
@ -497,6 +503,7 @@ function startConnection(socket) {
|
||||||
lastchangeuserprofile: lastchangeuserprofile,
|
lastchangeuserprofile: lastchangeuserprofile,
|
||||||
socks: [],
|
socks: [],
|
||||||
users: {},
|
users: {},
|
||||||
|
tempUsers: {},
|
||||||
createtime: moment(createtime).valueOf(),
|
createtime: moment(createtime).valueOf(),
|
||||||
updatetime: moment(updatetime).valueOf(),
|
updatetime: moment(updatetime).valueOf(),
|
||||||
server: server,
|
server: server,
|
||||||
|
@ -687,15 +694,17 @@ function operationCallback(socket, operation) {
|
||||||
return logger.error('operation callback failed: ' + err);
|
return logger.error('operation callback failed: ' + err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// update user note history
|
note.tempUsers[userId] = Date.now();
|
||||||
setTimeout(function() {
|
|
||||||
var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id);
|
|
||||||
if (note.server) history.updateHistory(userId, noteId, note.server.document);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// save authorship
|
// save authorship - use timer here because it's an O(n) complexity algorithm
|
||||||
|
setImmediate(function () {
|
||||||
note.authorship = models.Note.updateAuthorshipByOperation(operation, userId, note.authorship);
|
note.authorship = models.Note.updateAuthorshipByOperation(operation, userId, note.authorship);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHistory(userId, note, time) {
|
||||||
|
var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id);
|
||||||
|
if (note.server) history.updateHistory(userId, noteId, note.server.document, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
function connection(socket) {
|
function connection(socket) {
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
"View": "Anzeigen",
|
"View": "Anzeigen",
|
||||||
"Both": "Beides",
|
"Both": "Beides",
|
||||||
"Help": "Hilfe",
|
"Help": "Hilfe",
|
||||||
"Upload Image": "Foto hochloaden",
|
"Upload Image": "Foto hochladen",
|
||||||
"Menu": "Menü",
|
"Menu": "Menü",
|
||||||
"This page need refresh": "Bitte laden Sie die Seite neu",
|
"This page need refresh": "Bitte laden Sie die Seite neu",
|
||||||
"You have an incompatible client version.": "Ihre Client Version ist nicht mit dem Server kompatibel",
|
"You have an incompatible client version.": "Ihre Client Version ist nicht mit dem Server kompatibel",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"Collaborative markdown notes": "Συνεργατικές σημειώσεις markdown",
|
"Collaborative markdown notes": "Συνεργατικές σημειώσεις markdown",
|
||||||
"Realtime collaborative markdown notes on all platforms.": "Συνεργατική σημειώσεις markdown σε όλες τις πλατφόρμες σε πραγματικό χρόνο.",
|
"Realtime collaborative markdown notes on all platforms.": "Συνεργατική σημειώσεις markdown σε όλες τις πλατφόρμες σε πραγματικό χρόνο.",
|
||||||
"Best way to write and share your knowledge in markdown.": "Ο καλύτερος τρόπς να γράψεις και να μοιρατσείς την γνώση σου in markdown.",
|
"Best way to write and share your knowledge in markdown.": "Ο καλύτερος τρόπος να γράψεις και να μοιραστείς την γνώση σου σε markdown.",
|
||||||
"Intro": "Εισαγωγή",
|
"Intro": "Εισαγωγή",
|
||||||
"History": "Ιστορία",
|
"History": "Ιστορία",
|
||||||
"New guest note": "Νέα σημείωση επισκέπτη",
|
"New guest note": "Νέα σημείωση επισκέπτη",
|
||||||
|
@ -54,9 +54,9 @@
|
||||||
"Refresh to update.": "Ανανεώστε για ενημέρωση",
|
"Refresh to update.": "Ανανεώστε για ενημέρωση",
|
||||||
"New version available!": "Νέα διαθέσιμη έκδοση ",
|
"New version available!": "Νέα διαθέσιμη έκδοση ",
|
||||||
"See releases notes here": "Δείτε τις κυκλοφορίες της σημείωσης εδώ",
|
"See releases notes here": "Δείτε τις κυκλοφορίες της σημείωσης εδώ",
|
||||||
"Refresh to enjoy new features.": "Ανανεώστε για να δείτε τις κανούργίες λειτουργίες",
|
"Refresh to enjoy new features.": "Ανανεώστε για να δείτε τις κανούργιες λειτουργίες",
|
||||||
"Your user state has changed.": "Η κατάσταση χρήστη έχει αλλάξει.",
|
"Your user state has changed.": "Η κατάσταση χρήστη έχει αλλάξει.",
|
||||||
"Refresh to load new user state.": "Ανανεώστε για να φορτωσετε την νέα κατάσταση χρήστη.",
|
"Refresh to load new user state.": "Ανανεώστε για να φορτώσετε την νέα κατάσταση χρήστη.",
|
||||||
"Refresh": "Ανανέωση",
|
"Refresh": "Ανανέωση",
|
||||||
"Contacts": "Επαφές",
|
"Contacts": "Επαφές",
|
||||||
"Report an issue": "Αναφέρετε ένα θέμα",
|
"Report an issue": "Αναφέρετε ένα θέμα",
|
||||||
|
@ -73,29 +73,29 @@
|
||||||
"Ordered List": "Αριθμημένη λίστα",
|
"Ordered List": "Αριθμημένη λίστα",
|
||||||
"Todo List": "Todo List",
|
"Todo List": "Todo List",
|
||||||
"Blockquote": "Παράγραφος",
|
"Blockquote": "Παράγραφος",
|
||||||
"Bold font": "Εντονη γραμματόσειρά",
|
"Bold font": "Εντονη γραμματοσειρά",
|
||||||
"Italics font": "Italics γραμματόσειρά",
|
"Italics font": "Πλάγια γραμματοσειρά",
|
||||||
"Strikethrough": "Διακριτή διαγραφή",
|
"Strikethrough": "Διαγραμένη γραμματοσειρά",
|
||||||
"Inserted text": "Εισαγμένο κείμενο",
|
"Inserted text": "Εισαγμένο κείμενο",
|
||||||
"Marked text": "Επιλεγμένο κέιμενο",
|
"Marked text": "Επιλεγμένο κείμενο",
|
||||||
"Link": "Σύνδεσμος",
|
"Link": "Σύνδεσμος",
|
||||||
"Image": "Εικόνα",
|
"Image": "Εικόνα",
|
||||||
"Code": "Κώδικας",
|
"Code": "Κώδικας",
|
||||||
"Externals": "Εξωτερικά",
|
"Externals": "Εξωτερικά",
|
||||||
"This is a alert area.": "Αυτή είνια μια περιοχή ειδοποίησης",
|
"This is a alert area.": "Αυτή είναι μια περιοχή ειδοποίησης",
|
||||||
"Revert": "Επαναστροφή",
|
"Revert": "Επαναστροφή",
|
||||||
"Import from clipboard": "Εισαγωγή από πρόχειρο",
|
"Import from clipboard": "Εισαγωγή από πρόχειρο",
|
||||||
"Paste your markdown or webpage here...": "Επικολλήστε το markdown ή την ιστοσελίδα σας εδώ...",
|
"Paste your markdown or webpage here...": "Επικολλήστε markdown ή την ιστοσελίδα σας εδώ...",
|
||||||
"Clear": "Καθαρισμός",
|
"Clear": "Καθαρισμός",
|
||||||
"This note is locked": "Η σημείωση είναι κλειδωμένη",
|
"This note is locked": "Η σημείωση είναι κλειδωμένη",
|
||||||
"Sorry, only owner can edit this note.": "Συγνώμη, μόνο ο ιδικτήτης μπορεί να επεξεργαστεί αυτη την σημείωση.",
|
"Sorry, only owner can edit this note.": "Συγνώμη, μόνο ο ιδιοκτήτης μπορεί να επεξεργαστεί αυτη την σημείωση.",
|
||||||
"OK": "Εντάξει",
|
"OK": "Εντάξει",
|
||||||
"Reach the limit": "Φτάσατε το όριο",
|
"Reach the limit": "Φτάσατε το όριο",
|
||||||
"Sorry, you've reached the max length this note can be.": "Συγνώμη, φτάσατε το μέγιστο μέγεθος αυτής της σημείωσης.",
|
"Sorry, you've reached the max length this note can be.": "Συγνώμη, φτάσατε το μέγιστο μέγεθος αυτής της σημείωσης.",
|
||||||
"Please reduce the content or divide it to more notes, thank you!": "Παρακαλώ μειώστε το περιεχόμενο η διαιρεστε το σε περισσότερες σημειώσεις, ευχαριστώ!",
|
"Please reduce the content or divide it to more notes, thank you!": "Παρακαλώ μειώστε το περιεχόμενο η διαιρέστε το σε περισσότερες σημειώσεις, ευχαριστώ!",
|
||||||
"Import from Gist": "Εισαγωγή από Gist",
|
"Import from Gist": "Εισαγωγή από Gist",
|
||||||
"Paste your gist url here...": "Κάντε επικκόληση του gist url εδώ...",
|
"Paste your gist url here...": "Κάντε επικκόληση του gist url εδώ...",
|
||||||
"Import from Snippet": "Εισαγωγή απο Snippet",
|
"Import from Snippet": "Εισαγωγή από Snippet",
|
||||||
"Select From Available Projects": "Eπιλογή από διαθέσιμα Projects",
|
"Select From Available Projects": "Eπιλογή από διαθέσιμα Projects",
|
||||||
"Select From Available Snippets": "Eπιλογή από διαθέσιμα Snippets",
|
"Select From Available Snippets": "Eπιλογή από διαθέσιμα Snippets",
|
||||||
"OR": "Ή",
|
"OR": "Ή",
|
||||||
|
|
23
package.json
23
package.json
|
@ -5,8 +5,10 @@
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:dev": "webpack --config webpack.config.js --progress --colors --watch",
|
"test": "npm run-script lint",
|
||||||
"build:prod": "webpack --config webpack.production.js --progress --colors",
|
"lint": "eslint .",
|
||||||
|
"dev": "webpack --config webpack.config.js --progress --colors --watch",
|
||||||
|
"build": "webpack --config webpack.production.js --progress --colors",
|
||||||
"postinstall": "bin/heroku",
|
"postinstall": "bin/heroku",
|
||||||
"start": "node app.js"
|
"start": "node app.js"
|
||||||
},
|
},
|
||||||
|
@ -71,7 +73,7 @@
|
||||||
"markdown-it-sup": "^1.0.0",
|
"markdown-it-sup": "^1.0.0",
|
||||||
"markdown-pdf": "^7.0.0",
|
"markdown-pdf": "^7.0.0",
|
||||||
"mathjax": "~2.7.0",
|
"mathjax": "~2.7.0",
|
||||||
"mermaid": "~6.0.0",
|
"mermaid": "~7.0.0",
|
||||||
"meta-marked": "^0.4.2",
|
"meta-marked": "^0.4.2",
|
||||||
"method-override": "^2.3.7",
|
"method-override": "^2.3.7",
|
||||||
"moment": "^2.17.1",
|
"moment": "^2.17.1",
|
||||||
|
@ -115,12 +117,12 @@
|
||||||
"validator": "^6.2.0",
|
"validator": "^6.2.0",
|
||||||
"velocity-animate": "^1.4.0",
|
"velocity-animate": "^1.4.0",
|
||||||
"visibilityjs": "^1.2.4",
|
"visibilityjs": "^1.2.4",
|
||||||
"viz.js": "^1.4.1",
|
"viz.js": "^1.7.0",
|
||||||
"winston": "^2.3.0",
|
"winston": "^2.3.0",
|
||||||
"xss": "^0.3.3"
|
"xss": "^0.3.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.x"
|
"node": ">=6.x"
|
||||||
},
|
},
|
||||||
"bugs": "https://github.com/hackmdio/hackmd/issues",
|
"bugs": "https://github.com/hackmdio/hackmd/issues",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -140,9 +142,17 @@
|
||||||
"url": "https://github.com/hackmdio/hackmd.git"
|
"url": "https://github.com/hackmdio/hackmd.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"babel-cli": "^6.18.0",
|
||||||
|
"babel-core": "^6.21.0",
|
||||||
|
"babel-loader": "^6.2.10",
|
||||||
|
"babel-plugin-transform-runtime": "^6.15.0",
|
||||||
|
"babel-polyfill": "^6.22.0",
|
||||||
|
"babel-preset-es2015": "^6.18.0",
|
||||||
|
"babel-runtime": "^6.20.0",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
"css-loader": "^0.26.1",
|
"css-loader": "^0.26.1",
|
||||||
"ejs-loader": "^0.3.0",
|
"ejs-loader": "^0.3.0",
|
||||||
|
"eslint": "^3.15.0",
|
||||||
"exports-loader": "^0.6.3",
|
"exports-loader": "^0.6.3",
|
||||||
"expose-loader": "^0.7.1",
|
"expose-loader": "^0.7.1",
|
||||||
"extract-text-webpack-plugin": "^1.0.1",
|
"extract-text-webpack-plugin": "^1.0.1",
|
||||||
|
@ -156,6 +166,7 @@
|
||||||
"script-loader": "^0.7.0",
|
"script-loader": "^0.7.0",
|
||||||
"style-loader": "^0.13.1",
|
"style-loader": "^0.13.1",
|
||||||
"url-loader": "^0.5.7",
|
"url-loader": "^0.5.7",
|
||||||
"webpack": "^1.14.0"
|
"webpack": "^1.14.0",
|
||||||
|
"webpack-parallel-uglify-plugin": "^0.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,6 +354,12 @@ input {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.screenshot {
|
||||||
|
margin: 30px auto;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,9 @@ There are four possible options:
|
||||||
|
|
||||||
<i class="fa fa-leaf fa-fw"></i> **Freely**: Anyone can edit this note.
|
<i class="fa fa-leaf fa-fw"></i> **Freely**: Anyone can edit this note.
|
||||||
<i class="fa fa-pencil fa-fw"></i> **Editable**: A signed-in user can edit this note.
|
<i class="fa fa-pencil fa-fw"></i> **Editable**: A signed-in user can edit this note.
|
||||||
<i class="fa fa-lock fa-fw"></i> **Locked**: Only the owner can edit this note.
|
<i class="fa fa-id-card fa-fw"></i> **Limited**: People have to sign-in to view and edit this note.
|
||||||
|
<i class="fa fa-lock fa-fw"></i> **Locked**: Anyone can view this note but only the owner can edit it.
|
||||||
|
<i class="fa fa-umbrella fa-fw"></i> **Protected**: People have to sign-in to view this note but only owner can edit.
|
||||||
<i class="fa fa-hand-stop-o fa-fw"></i> **Private**: Only the owner can view and edit this note.
|
<i class="fa fa-hand-stop-o fa-fw"></i> **Private**: Only the owner can view and edit this note.
|
||||||
|
|
||||||
**Only the owner of the note can change the note's permissions.**
|
**Only the owner of the note can change the note's permissions.**
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
var config = require('./config');
|
|
||||||
var domain = config.domain; // domain name
|
|
||||||
var urlpath = config.urlpath; // sub url path, like: www.example.com/<urlpath>
|
|
||||||
var debug = config.debug;
|
|
||||||
var GOOGLE_API_KEY = config.GOOGLE_API_KEY;
|
|
||||||
var GOOGLE_CLIENT_ID = config.GOOGLE_CLIENT_ID;
|
|
||||||
var DROPBOX_APP_KEY = config.DROPBOX_APP_KEY;
|
|
||||||
|
|
||||||
//common
|
|
||||||
var port = window.location.port;
|
|
||||||
window.serverurl = window.location.protocol + '//' + (domain ? domain : window.location.hostname) + (port ? ':' + port : '') + (urlpath ? '/' + urlpath : '');
|
|
||||||
var noteid = urlpath ? window.location.pathname.slice(urlpath.length + 1, window.location.pathname.length).split('/')[1] : window.location.pathname.split('/')[1];
|
|
||||||
var noteurl = serverurl + '/' + noteid;
|
|
||||||
|
|
||||||
var version = '0.5.0';
|
|
||||||
|
|
||||||
var checkAuth = false;
|
|
||||||
var profile = null;
|
|
||||||
var lastLoginState = getLoginState();
|
|
||||||
var lastUserId = getUserId();
|
|
||||||
|
|
||||||
window.loginStateChangeEvent = null;
|
|
||||||
|
|
||||||
function resetCheckAuth() {
|
|
||||||
checkAuth = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLoginState(bool, id) {
|
|
||||||
Cookies.set('loginstate', bool, {
|
|
||||||
expires: 365
|
|
||||||
});
|
|
||||||
if (id) {
|
|
||||||
Cookies.set('userid', id, {
|
|
||||||
expires: 365
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Cookies.remove('userid');
|
|
||||||
}
|
|
||||||
lastLoginState = bool;
|
|
||||||
lastUserId = id;
|
|
||||||
checkLoginStateChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkLoginStateChanged() {
|
|
||||||
if (getLoginState() != lastLoginState || getUserId() != lastUserId) {
|
|
||||||
if(loginStateChangeEvent) setTimeout(loginStateChangeEvent, 100);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLoginState() {
|
|
||||||
var state = Cookies.get('loginstate');
|
|
||||||
return state === "true" || state === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUserId() {
|
|
||||||
return Cookies.get('userid');
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearLoginState() {
|
|
||||||
Cookies.remove('loginstate');
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkIfAuth(yesCallback, noCallback) {
|
|
||||||
var cookieLoginState = getLoginState();
|
|
||||||
if (checkLoginStateChanged()) checkAuth = false;
|
|
||||||
if (!checkAuth || typeof cookieLoginState == 'undefined') {
|
|
||||||
$.get(serverurl + '/me')
|
|
||||||
.done(function (data) {
|
|
||||||
if (data && data.status == 'ok') {
|
|
||||||
profile = data;
|
|
||||||
yesCallback(profile);
|
|
||||||
setLoginState(true, data.id);
|
|
||||||
} else {
|
|
||||||
noCallback();
|
|
||||||
setLoginState(false);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function () {
|
|
||||||
noCallback();
|
|
||||||
})
|
|
||||||
.always(function () {
|
|
||||||
checkAuth = true;
|
|
||||||
});
|
|
||||||
} else if (cookieLoginState) {
|
|
||||||
yesCallback(profile);
|
|
||||||
} else {
|
|
||||||
noCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
domain: domain,
|
|
||||||
urlpath: urlpath,
|
|
||||||
debug: debug,
|
|
||||||
GOOGLE_API_KEY: GOOGLE_API_KEY,
|
|
||||||
GOOGLE_CLIENT_ID: GOOGLE_CLIENT_ID,
|
|
||||||
DROPBOX_APP_KEY: DROPBOX_APP_KEY,
|
|
||||||
port: port,
|
|
||||||
noteid: noteid,
|
|
||||||
noteurl: noteurl,
|
|
||||||
version: version,
|
|
||||||
checkAuth: checkAuth,
|
|
||||||
profile: profile,
|
|
||||||
lastLoginState: lastLoginState,
|
|
||||||
lastUserId: lastUserId,
|
|
||||||
|
|
||||||
/* export functions */
|
|
||||||
resetCheckAuth: resetCheckAuth,
|
|
||||||
setLoginState: setLoginState,
|
|
||||||
checkLoginStateChanged: checkLoginStateChanged,
|
|
||||||
getLoginState: getLoginState,
|
|
||||||
getUserId: getUserId,
|
|
||||||
clearLoginState: clearLoginState,
|
|
||||||
checkIfAuth: checkIfAuth
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
domain: '', // domain name
|
|
||||||
urlpath: '', // sub url path, like: www.example.com/<urlpath>
|
|
||||||
|
|
||||||
// settings
|
|
||||||
debug: false,
|
|
||||||
|
|
||||||
GOOGLE_API_KEY: '',
|
|
||||||
GOOGLE_CLIENT_ID: '',
|
|
||||||
DROPBOX_APP_KEY: ''
|
|
||||||
};
|
|
|
@ -3,31 +3,33 @@ require('./locale');
|
||||||
require('../css/cover.css');
|
require('../css/cover.css');
|
||||||
require('../css/site.css');
|
require('../css/site.css');
|
||||||
|
|
||||||
var common = require('./common');
|
import {
|
||||||
var checkIfAuth = common.checkIfAuth;
|
checkIfAuth,
|
||||||
var urlpath = common.urlpath;
|
clearLoginState,
|
||||||
var resetCheckAuth = common.resetCheckAuth;
|
getLoginState,
|
||||||
var getLoginState = common.getLoginState;
|
resetCheckAuth,
|
||||||
var clearLoginState = common.clearLoginState;
|
setloginStateChangeEvent
|
||||||
|
} from './lib/common/login';
|
||||||
|
|
||||||
var historyModule = require('./history');
|
import {
|
||||||
var parseStorageToHistory = historyModule.parseStorageToHistory;
|
clearDuplicatedHistory,
|
||||||
var parseHistory = historyModule.parseHistory;
|
deleteServerHistory,
|
||||||
var getStorageHistory = historyModule.getStorageHistory;
|
getHistory,
|
||||||
var getHistory = historyModule.getHistory;
|
getStorageHistory,
|
||||||
var saveHistory = historyModule.saveHistory;
|
parseHistory,
|
||||||
var removeHistory = historyModule.removeHistory;
|
parseServerToHistory,
|
||||||
var postHistoryToServer = historyModule.postHistoryToServer;
|
parseStorageToHistory,
|
||||||
var deleteServerHistory = historyModule.deleteServerHistory;
|
postHistoryToServer,
|
||||||
var parseServerToHistory = historyModule.parseServerToHistory;
|
removeHistory,
|
||||||
var saveStorageHistoryToServer = historyModule.saveStorageHistoryToServer;
|
saveHistory,
|
||||||
var clearDuplicatedHistory = historyModule.clearDuplicatedHistory;
|
saveStorageHistoryToServer
|
||||||
|
} from './history';
|
||||||
|
|
||||||
var saveAs = require('file-saver').saveAs;
|
import { saveAs } from 'file-saver';
|
||||||
var List = require('list.js');
|
import List from 'list.js';
|
||||||
var S = require('string');
|
import S from 'string';
|
||||||
|
|
||||||
var options = {
|
const options = {
|
||||||
valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'],
|
valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'],
|
||||||
item: '<li class="col-xs-12 col-sm-6 col-md-6 col-lg-4">\
|
item: '<li class="col-xs-12 col-sm-6 col-md-6 col-lg-4">\
|
||||||
<span class="id" style="display:none;"></span>\
|
<span class="id" style="display:none;"></span>\
|
||||||
|
@ -55,15 +57,16 @@ var options = {
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
var historyList = new List('history', options);
|
const historyList = new List('history', options);
|
||||||
|
|
||||||
migrateHistoryFromTempCallback = pageInit;
|
migrateHistoryFromTempCallback = pageInit;
|
||||||
loginStateChangeEvent = pageInit;
|
setloginStateChangeEvent(pageInit);
|
||||||
|
|
||||||
pageInit();
|
pageInit();
|
||||||
|
|
||||||
function pageInit() {
|
function pageInit() {
|
||||||
checkIfAuth(
|
checkIfAuth(
|
||||||
function (data) {
|
data => {
|
||||||
$('.ui-signin').hide();
|
$('.ui-signin').hide();
|
||||||
$('.ui-or').hide();
|
$('.ui-or').hide();
|
||||||
$('.ui-welcome').show();
|
$('.ui-welcome').show();
|
||||||
|
@ -74,7 +77,7 @@ function pageInit() {
|
||||||
$(".ui-history").click();
|
$(".ui-history").click();
|
||||||
parseServerToHistory(historyList, parseHistoryCallback);
|
parseServerToHistory(historyList, parseHistoryCallback);
|
||||||
},
|
},
|
||||||
function () {
|
() => {
|
||||||
$('.ui-signin').show();
|
$('.ui-signin').show();
|
||||||
$('.ui-or').show();
|
$('.ui-or').show();
|
||||||
$('.ui-welcome').hide();
|
$('.ui-welcome').hide();
|
||||||
|
@ -103,7 +106,7 @@ $(".ui-home").click(function (e) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".ui-history").click(function (e) {
|
$(".ui-history").click(() => {
|
||||||
if (!$("#history").is(':visible')) {
|
if (!$("#history").is(':visible')) {
|
||||||
$(".section:visible").hide();
|
$(".section:visible").hide();
|
||||||
$("#history").fadeIn();
|
$("#history").fadeIn();
|
||||||
|
@ -118,7 +121,7 @@ function checkHistoryList() {
|
||||||
} else if ($("#history-list").children().length == 0) {
|
} else if ($("#history-list").children().length == 0) {
|
||||||
$('.pagination').hide();
|
$('.pagination').hide();
|
||||||
$(".ui-nohistory").slideDown();
|
$(".ui-nohistory").slideDown();
|
||||||
getStorageHistory(function (data) {
|
getStorageHistory(data => {
|
||||||
if (data && data.length > 0 && getLoginState() && historyList.items.length == 0) {
|
if (data && data.length > 0 && getLoginState() && historyList.items.length == 0) {
|
||||||
$(".ui-import-from-browser").slideDown();
|
$(".ui-import-from-browser").slideDown();
|
||||||
}
|
}
|
||||||
|
@ -130,9 +133,9 @@ function parseHistoryCallback(list, notehistory) {
|
||||||
checkHistoryList();
|
checkHistoryList();
|
||||||
//sort by pinned then timestamp
|
//sort by pinned then timestamp
|
||||||
list.sort('', {
|
list.sort('', {
|
||||||
sortFunction: function (a, b) {
|
sortFunction(a, b) {
|
||||||
var notea = a.values();
|
const notea = a.values();
|
||||||
var noteb = b.values();
|
const noteb = b.values();
|
||||||
if (notea.pinned && !noteb.pinned) {
|
if (notea.pinned && !noteb.pinned) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (!notea.pinned && noteb.pinned) {
|
} else if (!notea.pinned && noteb.pinned) {
|
||||||
|
@ -149,14 +152,14 @@ function parseHistoryCallback(list, notehistory) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// parse filter tags
|
// parse filter tags
|
||||||
var filtertags = [];
|
const filtertags = [];
|
||||||
for (var i = 0, l = list.items.length; i < l; i++) {
|
for (let i = 0, l = list.items.length; i < l; i++) {
|
||||||
var tags = list.items[i]._values.tags;
|
const tags = list.items[i]._values.tags;
|
||||||
if (tags && tags.length > 0) {
|
if (tags && tags.length > 0) {
|
||||||
for (var j = 0; j < tags.length; j++) {
|
for (let j = 0; j < tags.length; j++) {
|
||||||
//push info filtertags if not found
|
//push info filtertags if not found
|
||||||
var found = false;
|
let found = false;
|
||||||
if (filtertags.indexOf(tags[j]) != -1)
|
if (filtertags.includes(tags[j]))
|
||||||
found = true;
|
found = true;
|
||||||
if (!found)
|
if (!found)
|
||||||
filtertags.push(tags[j]);
|
filtertags.push(tags[j]);
|
||||||
|
@ -167,17 +170,17 @@ function parseHistoryCallback(list, notehistory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update items whenever list updated
|
// update items whenever list updated
|
||||||
historyList.on('updated', function (e) {
|
historyList.on('updated', e => {
|
||||||
for (var i = 0, l = e.items.length; i < l; i++) {
|
for (let i = 0, l = e.items.length; i < l; i++) {
|
||||||
var item = e.items[i];
|
const item = e.items[i];
|
||||||
if (item.visible()) {
|
if (item.visible()) {
|
||||||
var itemEl = $(item.elm);
|
const itemEl = $(item.elm);
|
||||||
var values = item._values;
|
const values = item._values;
|
||||||
var a = itemEl.find("a");
|
const a = itemEl.find("a");
|
||||||
var pin = itemEl.find(".ui-history-pin");
|
const pin = itemEl.find(".ui-history-pin");
|
||||||
var tagsEl = itemEl.find(".tags");
|
const tagsEl = itemEl.find(".tags");
|
||||||
//parse link to element a
|
//parse link to element a
|
||||||
a.attr('href', serverurl + '/' + values.id);
|
a.attr('href', `${serverurl}/${values.id}`);
|
||||||
//parse pinned
|
//parse pinned
|
||||||
if (values.pinned) {
|
if (values.pinned) {
|
||||||
pin.addClass('active');
|
pin.addClass('active');
|
||||||
|
@ -185,12 +188,12 @@ historyList.on('updated', function (e) {
|
||||||
pin.removeClass('active');
|
pin.removeClass('active');
|
||||||
}
|
}
|
||||||
//parse tags
|
//parse tags
|
||||||
var tags = values.tags;
|
const tags = values.tags;
|
||||||
if (tags && tags.length > 0 && tagsEl.children().length <= 0) {
|
if (tags && tags.length > 0 && tagsEl.children().length <= 0) {
|
||||||
var labels = [];
|
const labels = [];
|
||||||
for (var j = 0; j < tags.length; j++) {
|
for (let j = 0; j < tags.length; j++) {
|
||||||
//push into the item label
|
//push into the item label
|
||||||
labels.push("<span class='label label-default'>" + tags[j] + "</span>");
|
labels.push(`<span class='label label-default'>${tags[j]}</span>`);
|
||||||
}
|
}
|
||||||
tagsEl.html(labels.join(' '));
|
tagsEl.html(labels.join(' '));
|
||||||
}
|
}
|
||||||
|
@ -204,21 +207,21 @@ historyList.on('updated', function (e) {
|
||||||
|
|
||||||
function historyCloseClick(e) {
|
function historyCloseClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var id = $(this).closest("a").siblings("span").html();
|
const id = $(this).closest("a").siblings("span").html();
|
||||||
var value = historyList.get('id', id)[0]._values;
|
const value = historyList.get('id', id)[0]._values;
|
||||||
$('.ui-delete-modal-msg').text('Do you really want to delete below history?');
|
$('.ui-delete-modal-msg').text('Do you really want to delete below history?');
|
||||||
$('.ui-delete-modal-item').html('<i class="fa fa-file-text"></i> ' + value.text + '<br><i class="fa fa-clock-o"></i> ' + value.time);
|
$('.ui-delete-modal-item').html(`<i class="fa fa-file-text"></i> ${value.text}<br><i class="fa fa-clock-o"></i> ${value.time}`);
|
||||||
clearHistory = false;
|
clearHistory = false;
|
||||||
deleteId = id;
|
deleteId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function historyPinClick(e) {
|
function historyPinClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $this = $(this);
|
const $this = $(this);
|
||||||
var id = $this.closest("a").siblings("span").html();
|
const id = $this.closest("a").siblings("span").html();
|
||||||
var item = historyList.get('id', id)[0];
|
const item = historyList.get('id', id)[0];
|
||||||
var values = item._values;
|
const values = item._values;
|
||||||
var pinned = values.pinned;
|
let pinned = values.pinned;
|
||||||
if (!values.pinned) {
|
if (!values.pinned) {
|
||||||
pinned = true;
|
pinned = true;
|
||||||
item._values.pinned = true;
|
item._values.pinned = true;
|
||||||
|
@ -226,10 +229,10 @@ function historyPinClick(e) {
|
||||||
pinned = false;
|
pinned = false;
|
||||||
item._values.pinned = false;
|
item._values.pinned = false;
|
||||||
}
|
}
|
||||||
checkIfAuth(function () {
|
checkIfAuth(() => {
|
||||||
postHistoryToServer(id, {
|
postHistoryToServer(id, {
|
||||||
pinned: pinned
|
pinned
|
||||||
}, function (err, result) {
|
}, (err, result) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (pinned)
|
if (pinned)
|
||||||
$this.addClass('active');
|
$this.addClass('active');
|
||||||
|
@ -237,9 +240,9 @@ function historyPinClick(e) {
|
||||||
$this.removeClass('active');
|
$this.removeClass('active');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, function () {
|
}, () => {
|
||||||
getHistory(function (notehistory) {
|
getHistory(notehistory => {
|
||||||
for(var i = 0; i < notehistory.length; i++) {
|
for(let i = 0; i < notehistory.length; i++) {
|
||||||
if (notehistory[i].id == id) {
|
if (notehistory[i].id == id) {
|
||||||
notehistory[i].pinned = pinned;
|
notehistory[i].pinned = pinned;
|
||||||
break;
|
break;
|
||||||
|
@ -258,10 +261,10 @@ function historyPinClick(e) {
|
||||||
setInterval(updateItemFromNow, 60000);
|
setInterval(updateItemFromNow, 60000);
|
||||||
|
|
||||||
function updateItemFromNow() {
|
function updateItemFromNow() {
|
||||||
var items = $('.item').toArray();
|
const items = $('.item').toArray();
|
||||||
for (var i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
var item = $(items[i]);
|
const item = $(items[i]);
|
||||||
var timestamp = parseInt(item.find('.timestamp').text());
|
const timestamp = parseInt(item.find('.timestamp').text());
|
||||||
item.find('.fromNow').text(moment(timestamp).fromNow());
|
item.find('.fromNow').text(moment(timestamp).fromNow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,8 +273,8 @@ var clearHistory = false;
|
||||||
var deleteId = null;
|
var deleteId = null;
|
||||||
|
|
||||||
function deleteHistory() {
|
function deleteHistory() {
|
||||||
checkIfAuth(function () {
|
checkIfAuth(() => {
|
||||||
deleteServerHistory(deleteId, function (err, result) {
|
deleteServerHistory(deleteId, (err, result) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (clearHistory) {
|
if (clearHistory) {
|
||||||
historyList.clear();
|
historyList.clear();
|
||||||
|
@ -285,7 +288,7 @@ function deleteHistory() {
|
||||||
deleteId = null;
|
deleteId = null;
|
||||||
clearHistory = false;
|
clearHistory = false;
|
||||||
});
|
});
|
||||||
}, function () {
|
}, () => {
|
||||||
if (clearHistory) {
|
if (clearHistory) {
|
||||||
saveHistory([]);
|
saveHistory([]);
|
||||||
historyList.clear();
|
historyList.clear();
|
||||||
|
@ -293,8 +296,8 @@ function deleteHistory() {
|
||||||
deleteId = null;
|
deleteId = null;
|
||||||
} else {
|
} else {
|
||||||
if (!deleteId) return;
|
if (!deleteId) return;
|
||||||
getHistory(function (notehistory) {
|
getHistory(notehistory => {
|
||||||
var newnotehistory = removeHistory(deleteId, notehistory);
|
const newnotehistory = removeHistory(deleteId, notehistory);
|
||||||
saveHistory(newnotehistory);
|
saveHistory(newnotehistory);
|
||||||
historyList.remove('id', deleteId);
|
historyList.remove('id', deleteId);
|
||||||
checkHistoryList();
|
checkHistoryList();
|
||||||
|
@ -306,36 +309,36 @@ function deleteHistory() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".ui-delete-modal-confirm").click(function () {
|
$(".ui-delete-modal-confirm").click(() => {
|
||||||
deleteHistory();
|
deleteHistory();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".ui-import-from-browser").click(function () {
|
$(".ui-import-from-browser").click(() => {
|
||||||
saveStorageHistoryToServer(function () {
|
saveStorageHistoryToServer(() => {
|
||||||
parseStorageToHistory(historyList, parseHistoryCallback);
|
parseStorageToHistory(historyList, parseHistoryCallback);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".ui-save-history").click(function () {
|
$(".ui-save-history").click(() => {
|
||||||
getHistory(function (data) {
|
getHistory(data => {
|
||||||
var history = JSON.stringify(data);
|
const history = JSON.stringify(data);
|
||||||
var blob = new Blob([history], {
|
const blob = new Blob([history], {
|
||||||
type: "application/json;charset=utf-8"
|
type: "application/json;charset=utf-8"
|
||||||
});
|
});
|
||||||
saveAs(blob, 'hackmd_history_' + moment().format('YYYYMMDDHHmmss'));
|
saveAs(blob, `hackmd_history_${moment().format('YYYYMMDDHHmmss')}`, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".ui-open-history").bind("change", function (e) {
|
$(".ui-open-history").bind("change", e => {
|
||||||
var files = e.target.files || e.dataTransfer.files;
|
const files = e.target.files || e.dataTransfer.files;
|
||||||
var file = files[0];
|
const file = files[0];
|
||||||
var reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = function () {
|
reader.onload = () => {
|
||||||
var notehistory = JSON.parse(reader.result);
|
const notehistory = JSON.parse(reader.result);
|
||||||
//console.log(notehistory);
|
//console.log(notehistory);
|
||||||
if (!reader.result) return;
|
if (!reader.result) return;
|
||||||
getHistory(function (data) {
|
getHistory(data => {
|
||||||
var mergedata = data.concat(notehistory);
|
let mergedata = data.concat(notehistory);
|
||||||
mergedata = clearDuplicatedHistory(mergedata);
|
mergedata = clearDuplicatedHistory(mergedata);
|
||||||
saveHistory(mergedata);
|
saveHistory(mergedata);
|
||||||
parseHistory(historyList, parseHistoryCallback);
|
parseHistory(historyList, parseHistoryCallback);
|
||||||
|
@ -345,18 +348,18 @@ $(".ui-open-history").bind("change", function (e) {
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".ui-clear-history").click(function () {
|
$(".ui-clear-history").click(() => {
|
||||||
$('.ui-delete-modal-msg').text('Do you really want to clear all history?');
|
$('.ui-delete-modal-msg').text('Do you really want to clear all history?');
|
||||||
$('.ui-delete-modal-item').html('There is no turning back.');
|
$('.ui-delete-modal-item').html('There is no turning back.');
|
||||||
clearHistory = true;
|
clearHistory = true;
|
||||||
deleteId = null;
|
deleteId = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".ui-refresh-history").click(function () {
|
$(".ui-refresh-history").click(() => {
|
||||||
var lastTags = $(".ui-use-tags").select2('val');
|
const lastTags = $(".ui-use-tags").select2('val');
|
||||||
$(".ui-use-tags").select2('val', '');
|
$(".ui-use-tags").select2('val', '');
|
||||||
historyList.filter();
|
historyList.filter();
|
||||||
var lastKeyword = $('.search').val();
|
const lastKeyword = $('.search').val();
|
||||||
$('.search').val('');
|
$('.search').val('');
|
||||||
historyList.search();
|
historyList.search();
|
||||||
$('#history-list').slideUp('fast');
|
$('#history-list').slideUp('fast');
|
||||||
|
@ -364,7 +367,7 @@ $(".ui-refresh-history").click(function () {
|
||||||
|
|
||||||
resetCheckAuth();
|
resetCheckAuth();
|
||||||
historyList.clear();
|
historyList.clear();
|
||||||
parseHistory(historyList, function (list, notehistory) {
|
parseHistory(historyList, (list, notehistory) => {
|
||||||
parseHistoryCallback(list, notehistory);
|
parseHistoryCallback(list, notehistory);
|
||||||
$(".ui-use-tags").select2('val', lastTags);
|
$(".ui-use-tags").select2('val', lastTags);
|
||||||
$(".ui-use-tags").trigger('change');
|
$(".ui-use-tags").trigger('change');
|
||||||
|
@ -375,16 +378,16 @@ $(".ui-refresh-history").click(function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".ui-logout").click(function () {
|
$(".ui-logout").click(() => {
|
||||||
clearLoginState();
|
clearLoginState();
|
||||||
location.href = serverurl + '/logout';
|
location.href = `${serverurl}/logout`;
|
||||||
});
|
});
|
||||||
|
|
||||||
var filtertags = [];
|
let filtertags = [];
|
||||||
$(".ui-use-tags").select2({
|
$(".ui-use-tags").select2({
|
||||||
placeholder: $(".ui-use-tags").attr('placeholder'),
|
placeholder: $(".ui-use-tags").attr('placeholder'),
|
||||||
multiple: true,
|
multiple: true,
|
||||||
data: function () {
|
data() {
|
||||||
return {
|
return {
|
||||||
results: filtertags
|
results: filtertags
|
||||||
};
|
};
|
||||||
|
@ -394,7 +397,7 @@ $('.select2-input').css('width', 'inherit');
|
||||||
buildTagsFilter([]);
|
buildTagsFilter([]);
|
||||||
|
|
||||||
function buildTagsFilter(tags) {
|
function buildTagsFilter(tags) {
|
||||||
for (var i = 0; i < tags.length; i++)
|
for (let i = 0; i < tags.length; i++)
|
||||||
tags[i] = {
|
tags[i] = {
|
||||||
id: i,
|
id: i,
|
||||||
text: S(tags[i]).unescapeHTML().s
|
text: S(tags[i]).unescapeHTML().s
|
||||||
|
@ -402,17 +405,17 @@ function buildTagsFilter(tags) {
|
||||||
filtertags = tags;
|
filtertags = tags;
|
||||||
}
|
}
|
||||||
$(".ui-use-tags").on('change', function () {
|
$(".ui-use-tags").on('change', function () {
|
||||||
var tags = [];
|
const tags = [];
|
||||||
var data = $(this).select2('data');
|
const data = $(this).select2('data');
|
||||||
for (var i = 0; i < data.length; i++)
|
for (let i = 0; i < data.length; i++)
|
||||||
tags.push(data[i].text);
|
tags.push(data[i].text);
|
||||||
if (tags.length > 0) {
|
if (tags.length > 0) {
|
||||||
historyList.filter(function (item) {
|
historyList.filter(item => {
|
||||||
var values = item.values();
|
const values = item.values();
|
||||||
if (!values.tags) return false;
|
if (!values.tags) return false;
|
||||||
var found = false;
|
let found = false;
|
||||||
for (var i = 0; i < tags.length; i++) {
|
for (let i = 0; i < tags.length; i++) {
|
||||||
if (values.tags.indexOf(tags[i]) != -1) {
|
if (values.tags.includes(tags[i])) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -425,6 +428,6 @@ $(".ui-use-tags").on('change', function () {
|
||||||
checkHistoryList();
|
checkHistoryList();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.search').keyup(function () {
|
$('.search').keyup(() => {
|
||||||
checkHistoryList();
|
checkHistoryList();
|
||||||
});
|
});
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -52,6 +52,7 @@
|
||||||
var view = new google.picker.DocsView();
|
var view = new google.picker.DocsView();
|
||||||
view.setMimeTypes("text/markdown,text/html");
|
view.setMimeTypes("text/markdown,text/html");
|
||||||
view.setIncludeFolders(true);
|
view.setIncludeFolders(true);
|
||||||
|
view.setOwnedByMe(true);
|
||||||
this.picker = new google.picker.PickerBuilder().
|
this.picker = new google.picker.PickerBuilder().
|
||||||
enableFeature(google.picker.Feature.NAV_HIDDEN).
|
enableFeature(google.picker.Feature.NAV_HIDDEN).
|
||||||
addView(view).
|
addView(view).
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
var store = require('store');
|
import store from 'store';
|
||||||
var S = require('string');
|
import S from 'string';
|
||||||
|
|
||||||
var common = require('./common');
|
import {
|
||||||
var checkIfAuth = common.checkIfAuth;
|
checkIfAuth
|
||||||
var urlpath = common.urlpath;
|
} from './lib/common/login';
|
||||||
var getLoginState = common.getLoginState;
|
|
||||||
|
import {
|
||||||
|
urlpath
|
||||||
|
} from './lib/config';
|
||||||
|
|
||||||
window.migrateHistoryFromTempCallback = null;
|
window.migrateHistoryFromTempCallback = null;
|
||||||
|
|
||||||
|
@ -12,22 +15,22 @@ migrateHistoryFromTemp();
|
||||||
|
|
||||||
function migrateHistoryFromTemp() {
|
function migrateHistoryFromTemp() {
|
||||||
if (url('#tempid')) {
|
if (url('#tempid')) {
|
||||||
$.get(serverurl + '/temp', {
|
$.get(`${serverurl}/temp`, {
|
||||||
tempid: url('#tempid')
|
tempid: url('#tempid')
|
||||||
})
|
})
|
||||||
.done(function (data) {
|
.done(data => {
|
||||||
if (data && data.temp) {
|
if (data && data.temp) {
|
||||||
getStorageHistory(function (olddata) {
|
getStorageHistory(olddata => {
|
||||||
if (!olddata || olddata.length == 0) {
|
if (!olddata || olddata.length == 0) {
|
||||||
saveHistoryToStorage(JSON.parse(data.temp));
|
saveHistoryToStorage(JSON.parse(data.temp));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.always(function () {
|
.always(() => {
|
||||||
var hash = location.hash.split('#')[1];
|
let hash = location.hash.split('#')[1];
|
||||||
hash = hash.split('&');
|
hash = hash.split('&');
|
||||||
for (var i = 0; i < hash.length; i++)
|
for (let i = 0; i < hash.length; i++)
|
||||||
if (hash[i].indexOf('tempid') == 0) {
|
if (hash[i].indexOf('tempid') == 0) {
|
||||||
hash.splice(i, 1);
|
hash.splice(i, 1);
|
||||||
i--;
|
i--;
|
||||||
|
@ -40,12 +43,12 @@ function migrateHistoryFromTemp() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveHistory(notehistory) {
|
export function saveHistory(notehistory) {
|
||||||
checkIfAuth(
|
checkIfAuth(
|
||||||
function () {
|
() => {
|
||||||
saveHistoryToServer(notehistory);
|
saveHistoryToServer(notehistory);
|
||||||
},
|
},
|
||||||
function () {
|
() => {
|
||||||
saveHistoryToStorage(notehistory);
|
saveHistoryToStorage(notehistory);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -65,7 +68,7 @@ function saveHistoryToCookie(notehistory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveHistoryToServer(notehistory) {
|
function saveHistoryToServer(notehistory) {
|
||||||
$.post(serverurl + '/history', {
|
$.post(`${serverurl}/history`, {
|
||||||
history: JSON.stringify(notehistory)
|
history: JSON.stringify(notehistory)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -75,37 +78,37 @@ function saveCookieHistoryToStorage(callback) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveStorageHistoryToServer(callback) {
|
export function saveStorageHistoryToServer(callback) {
|
||||||
var data = store.get('notehistory');
|
const data = store.get('notehistory');
|
||||||
if (data) {
|
if (data) {
|
||||||
$.post(serverurl + '/history', {
|
$.post(`${serverurl}/history`, {
|
||||||
history: data
|
history: data
|
||||||
})
|
})
|
||||||
.done(function (data) {
|
.done(data => {
|
||||||
callback(data);
|
callback(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveCookieHistoryToServer(callback) {
|
function saveCookieHistoryToServer(callback) {
|
||||||
$.post(serverurl + '/history', {
|
$.post(`${serverurl}/history`, {
|
||||||
history: Cookies.get('notehistory')
|
history: Cookies.get('notehistory')
|
||||||
})
|
})
|
||||||
.done(function (data) {
|
.done(data => {
|
||||||
callback(data);
|
callback(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearDuplicatedHistory(notehistory) {
|
export function clearDuplicatedHistory(notehistory) {
|
||||||
var newnotehistory = [];
|
const newnotehistory = [];
|
||||||
for (var i = 0; i < notehistory.length; i++) {
|
for (let i = 0; i < notehistory.length; i++) {
|
||||||
var found = false;
|
let found = false;
|
||||||
for (var j = 0; j < newnotehistory.length; j++) {
|
for (let j = 0; j < newnotehistory.length; j++) {
|
||||||
var id = notehistory[i].id.replace(/\=+$/, '');
|
const id = notehistory[i].id.replace(/\=+$/, '');
|
||||||
var newId = newnotehistory[j].id.replace(/\=+$/, '');
|
const newId = newnotehistory[j].id.replace(/\=+$/, '');
|
||||||
if (id == newId || notehistory[i].id == newnotehistory[j].id || !notehistory[i].id || !newnotehistory[j].id) {
|
if (id == newId || notehistory[i].id == newnotehistory[j].id || !notehistory[i].id || !newnotehistory[j].id) {
|
||||||
var time = (typeof notehistory[i].time === 'number' ? moment(notehistory[i].time) : moment(notehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'));
|
const time = (typeof notehistory[i].time === 'number' ? moment(notehistory[i].time) : moment(notehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'));
|
||||||
var newTime = (typeof newnotehistory[i].time === 'number' ? moment(newnotehistory[i].time) : moment(newnotehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'));
|
const newTime = (typeof newnotehistory[i].time === 'number' ? moment(newnotehistory[i].time) : moment(newnotehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'));
|
||||||
if(time >= newTime) {
|
if(time >= newTime) {
|
||||||
newnotehistory[j] = notehistory[i];
|
newnotehistory[j] = notehistory[i];
|
||||||
}
|
}
|
||||||
|
@ -123,42 +126,42 @@ function addHistory(id, text, time, tags, pinned, notehistory) {
|
||||||
// only add when note id exists
|
// only add when note id exists
|
||||||
if (id) {
|
if (id) {
|
||||||
notehistory.push({
|
notehistory.push({
|
||||||
id: id,
|
id,
|
||||||
text: text,
|
text,
|
||||||
time: time,
|
time,
|
||||||
tags: tags,
|
tags,
|
||||||
pinned: pinned
|
pinned
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return notehistory;
|
return notehistory;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeHistory(id, notehistory) {
|
export function removeHistory(id, notehistory) {
|
||||||
for (var i = 0; i < notehistory.length; i++) {
|
for (let i = 0; i < notehistory.length; i++) {
|
||||||
if (notehistory[i].id == id) {
|
if (notehistory[i].id == id) {
|
||||||
notehistory.splice(i, 1);
|
notehistory.splice(i, 1);
|
||||||
i--;
|
i -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return notehistory;
|
return notehistory;
|
||||||
}
|
}
|
||||||
|
|
||||||
//used for inner
|
//used for inner
|
||||||
function writeHistory(title, tags) {
|
export function writeHistory(title, tags) {
|
||||||
checkIfAuth(
|
checkIfAuth(
|
||||||
function () {
|
() => {
|
||||||
// no need to do this anymore, this will count from server-side
|
// no need to do this anymore, this will count from server-side
|
||||||
// writeHistoryToServer(title, tags);
|
// writeHistoryToServer(title, tags);
|
||||||
},
|
},
|
||||||
function () {
|
() => {
|
||||||
writeHistoryToStorage(title, tags);
|
writeHistoryToStorage(title, tags);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeHistoryToServer(title, tags) {
|
function writeHistoryToServer(title, tags) {
|
||||||
$.get(serverurl + '/history')
|
$.get(`${serverurl}/history`)
|
||||||
.done(function (data) {
|
.done(data => {
|
||||||
try {
|
try {
|
||||||
if (data.history) {
|
if (data.history) {
|
||||||
var notehistory = data.history;
|
var notehistory = data.history;
|
||||||
|
@ -171,10 +174,10 @@ function writeHistoryToServer(title, tags) {
|
||||||
if (!notehistory)
|
if (!notehistory)
|
||||||
notehistory = [];
|
notehistory = [];
|
||||||
|
|
||||||
var newnotehistory = generateHistory(title, tags, notehistory);
|
const newnotehistory = generateHistory(title, tags, notehistory);
|
||||||
saveHistoryToServer(newnotehistory);
|
saveHistoryToServer(newnotehistory);
|
||||||
})
|
})
|
||||||
.fail(function (xhr, status, error) {
|
.fail((xhr, status, error) => {
|
||||||
console.error(xhr.responseText);
|
console.error(xhr.responseText);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -188,13 +191,13 @@ function writeHistoryToCookie(title, tags) {
|
||||||
if (!notehistory)
|
if (!notehistory)
|
||||||
notehistory = [];
|
notehistory = [];
|
||||||
|
|
||||||
var newnotehistory = generateHistory(title, tags, notehistory);
|
const newnotehistory = generateHistory(title, tags, notehistory);
|
||||||
saveHistoryToCookie(newnotehistory);
|
saveHistoryToCookie(newnotehistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeHistoryToStorage(title, tags) {
|
function writeHistoryToStorage(title, tags) {
|
||||||
if (store.enabled) {
|
if (store.enabled) {
|
||||||
var data = store.get('notehistory');
|
let data = store.get('notehistory');
|
||||||
if (data) {
|
if (data) {
|
||||||
if (typeof data == "string")
|
if (typeof data == "string")
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
|
@ -204,7 +207,7 @@ function writeHistoryToStorage(title, tags) {
|
||||||
if (!notehistory)
|
if (!notehistory)
|
||||||
notehistory = [];
|
notehistory = [];
|
||||||
|
|
||||||
var newnotehistory = generateHistory(title, tags, notehistory);
|
const newnotehistory = generateHistory(title, tags, notehistory);
|
||||||
saveHistoryToStorage(newnotehistory);
|
saveHistoryToStorage(newnotehistory);
|
||||||
} else {
|
} else {
|
||||||
writeHistoryToCookie(title, tags);
|
writeHistoryToCookie(title, tags);
|
||||||
|
@ -212,27 +215,25 @@ function writeHistoryToStorage(title, tags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray) {
|
if (!Array.isArray) {
|
||||||
Array.isArray = function(arg) {
|
Array.isArray = arg => Object.prototype.toString.call(arg) === '[object Array]';
|
||||||
return Object.prototype.toString.call(arg) === '[object Array]';
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderHistory(title, tags) {
|
function renderHistory(title, tags) {
|
||||||
//console.debug(tags);
|
//console.debug(tags);
|
||||||
var id = urlpath ? location.pathname.slice(urlpath.length + 1, location.pathname.length).split('/')[1] : location.pathname.split('/')[1];
|
const id = urlpath ? location.pathname.slice(urlpath.length + 1, location.pathname.length).split('/')[1] : location.pathname.split('/')[1];
|
||||||
return {
|
return {
|
||||||
id: id,
|
id,
|
||||||
text: title,
|
text: title,
|
||||||
time: moment().valueOf(),
|
time: moment().valueOf(),
|
||||||
tags: tags
|
tags
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateHistory(title, tags, notehistory) {
|
function generateHistory(title, tags, notehistory) {
|
||||||
var info = renderHistory(title, tags);
|
const info = renderHistory(title, tags);
|
||||||
//keep any pinned data
|
//keep any pinned data
|
||||||
var pinned = false;
|
let pinned = false;
|
||||||
for (var i = 0; i < notehistory.length; i++) {
|
for (let i = 0; i < notehistory.length; i++) {
|
||||||
if (notehistory[i].id == info.id && notehistory[i].pinned) {
|
if (notehistory[i].id == info.id && notehistory[i].pinned) {
|
||||||
pinned = true;
|
pinned = true;
|
||||||
break;
|
break;
|
||||||
|
@ -245,25 +246,25 @@ function generateHistory(title, tags, notehistory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//used for outer
|
//used for outer
|
||||||
function getHistory(callback) {
|
export function getHistory(callback) {
|
||||||
checkIfAuth(
|
checkIfAuth(
|
||||||
function () {
|
() => {
|
||||||
getServerHistory(callback);
|
getServerHistory(callback);
|
||||||
},
|
},
|
||||||
function () {
|
() => {
|
||||||
getStorageHistory(callback);
|
getStorageHistory(callback);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServerHistory(callback) {
|
function getServerHistory(callback) {
|
||||||
$.get(serverurl + '/history')
|
$.get(`${serverurl}/history`)
|
||||||
.done(function (data) {
|
.done(data => {
|
||||||
if (data.history) {
|
if (data.history) {
|
||||||
callback(data.history);
|
callback(data.history);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fail(function (xhr, status, error) {
|
.fail((xhr, status, error) => {
|
||||||
console.error(xhr.responseText);
|
console.error(xhr.responseText);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -272,9 +273,9 @@ function getCookieHistory(callback) {
|
||||||
callback(Cookies.getJSON('notehistory'));
|
callback(Cookies.getJSON('notehistory'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStorageHistory(callback) {
|
export function getStorageHistory(callback) {
|
||||||
if (store.enabled) {
|
if (store.enabled) {
|
||||||
var data = store.get('notehistory');
|
let data = store.get('notehistory');
|
||||||
if (data) {
|
if (data) {
|
||||||
if (typeof data == "string")
|
if (typeof data == "string")
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
|
@ -286,37 +287,37 @@ function getStorageHistory(callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseHistory(list, callback) {
|
export function parseHistory(list, callback) {
|
||||||
checkIfAuth(
|
checkIfAuth(
|
||||||
function () {
|
() => {
|
||||||
parseServerToHistory(list, callback);
|
parseServerToHistory(list, callback);
|
||||||
},
|
},
|
||||||
function () {
|
() => {
|
||||||
parseStorageToHistory(list, callback);
|
parseStorageToHistory(list, callback);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseServerToHistory(list, callback) {
|
export function parseServerToHistory(list, callback) {
|
||||||
$.get(serverurl + '/history')
|
$.get(`${serverurl}/history`)
|
||||||
.done(function (data) {
|
.done(data => {
|
||||||
if (data.history) {
|
if (data.history) {
|
||||||
parseToHistory(list, data.history, callback);
|
parseToHistory(list, data.history, callback);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fail(function (xhr, status, error) {
|
.fail((xhr, status, error) => {
|
||||||
console.error(xhr.responseText);
|
console.error(xhr.responseText);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCookieToHistory(list, callback) {
|
function parseCookieToHistory(list, callback) {
|
||||||
var notehistory = Cookies.getJSON('notehistory');
|
const notehistory = Cookies.getJSON('notehistory');
|
||||||
parseToHistory(list, notehistory, callback);
|
parseToHistory(list, notehistory, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStorageToHistory(list, callback) {
|
export function parseStorageToHistory(list, callback) {
|
||||||
if (store.enabled) {
|
if (store.enabled) {
|
||||||
var data = store.get('notehistory');
|
let data = store.get('notehistory');
|
||||||
if (data) {
|
if (data) {
|
||||||
if (typeof data == "string")
|
if (typeof data == "string")
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
|
@ -332,9 +333,9 @@ function parseToHistory(list, notehistory, callback) {
|
||||||
if (!callback) return;
|
if (!callback) return;
|
||||||
else if (!list || !notehistory) callback(list, notehistory);
|
else if (!list || !notehistory) callback(list, notehistory);
|
||||||
else if (notehistory && notehistory.length > 0) {
|
else if (notehistory && notehistory.length > 0) {
|
||||||
for (var i = 0; i < notehistory.length; i++) {
|
for (let i = 0; i < notehistory.length; i++) {
|
||||||
//parse time to timestamp and fromNow
|
//parse time to timestamp and fromNow
|
||||||
var timestamp = (typeof notehistory[i].time === 'number' ? moment(notehistory[i].time) : moment(notehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'));
|
const timestamp = (typeof notehistory[i].time === 'number' ? moment(notehistory[i].time) : moment(notehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'));
|
||||||
notehistory[i].timestamp = timestamp.valueOf();
|
notehistory[i].timestamp = timestamp.valueOf();
|
||||||
notehistory[i].fromNow = timestamp.fromNow();
|
notehistory[i].fromNow = timestamp.fromNow();
|
||||||
notehistory[i].time = timestamp.format('llll');
|
notehistory[i].time = timestamp.format('llll');
|
||||||
|
@ -349,42 +350,23 @@ function parseToHistory(list, notehistory, callback) {
|
||||||
callback(list, notehistory);
|
callback(list, notehistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
function postHistoryToServer(noteId, data, callback) {
|
export function postHistoryToServer(noteId, data, callback) {
|
||||||
$.post(serverurl + '/history/' + noteId, data)
|
$.post(`${serverurl}/history/${noteId}`, data)
|
||||||
.done(function (result) {
|
.done(result => callback(null, result))
|
||||||
return callback(null, result);
|
.fail((xhr, status, error) => {
|
||||||
})
|
|
||||||
.fail(function (xhr, status, error) {
|
|
||||||
console.error(xhr.responseText);
|
console.error(xhr.responseText);
|
||||||
return callback(error, null);
|
return callback(error, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteServerHistory(noteId, callback) {
|
export function deleteServerHistory(noteId, callback) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: serverurl + '/history' + (noteId ? '/' + noteId : ""),
|
url: `${serverurl}/history${noteId ? '/' + noteId : ""}`,
|
||||||
type: 'DELETE'
|
type: 'DELETE'
|
||||||
})
|
})
|
||||||
.done(function (result) {
|
.done(result => callback(null, result))
|
||||||
return callback(null, result);
|
.fail((xhr, status, error) => {
|
||||||
})
|
|
||||||
.fail(function (xhr, status, error) {
|
|
||||||
console.error(xhr.responseText);
|
console.error(xhr.responseText);
|
||||||
return callback(error, null);
|
return callback(error, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
writeHistory: writeHistory,
|
|
||||||
parseHistory: parseHistory,
|
|
||||||
getStorageHistory: getStorageHistory,
|
|
||||||
getHistory: getHistory,
|
|
||||||
saveHistory: saveHistory,
|
|
||||||
removeHistory: removeHistory,
|
|
||||||
parseStorageToHistory: parseStorageToHistory,
|
|
||||||
postHistoryToServer: postHistoryToServer,
|
|
||||||
deleteServerHistory: deleteServerHistory,
|
|
||||||
parseServerToHistory: parseServerToHistory,
|
|
||||||
saveStorageHistoryToServer: saveStorageHistoryToServer,
|
|
||||||
clearDuplicatedHistory: clearDuplicatedHistory
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,51 +17,58 @@ var _ = require("lodash");
|
||||||
|
|
||||||
var List = require('list.js');
|
var List = require('list.js');
|
||||||
|
|
||||||
var common = require('./common.js');
|
import {
|
||||||
var urlpath = common.urlpath;
|
checkLoginStateChanged,
|
||||||
var noteid = common.noteid;
|
setloginStateChangeEvent
|
||||||
var debug = common.debug;
|
} from './lib/common/login';
|
||||||
var version = common.version;
|
|
||||||
var GOOGLE_API_KEY = common.GOOGLE_API_KEY;
|
|
||||||
var GOOGLE_CLIENT_ID = common.GOOGLE_CLIENT_ID;
|
|
||||||
var DROPBOX_APP_KEY = common.DROPBOX_APP_KEY;
|
|
||||||
var noteurl = common.noteurl;
|
|
||||||
|
|
||||||
var checkLoginStateChanged = common.checkLoginStateChanged;
|
import {
|
||||||
|
debug,
|
||||||
|
DROPBOX_APP_KEY,
|
||||||
|
GOOGLE_API_KEY,
|
||||||
|
GOOGLE_CLIENT_ID,
|
||||||
|
noteid,
|
||||||
|
noteurl,
|
||||||
|
urlpath,
|
||||||
|
version
|
||||||
|
} from './lib/config';
|
||||||
|
|
||||||
var extra = require('./extra');
|
import {
|
||||||
var md = extra.md;
|
autoLinkify,
|
||||||
var updateLastChange = extra.updateLastChange;
|
deduplicatedHeaderId,
|
||||||
var postProcess = extra.postProcess;
|
exportToHTML,
|
||||||
var finishView = extra.finishView;
|
exportToRawHTML,
|
||||||
var autoLinkify = extra.autoLinkify;
|
finishView,
|
||||||
var generateToc = extra.generateToc;
|
generateToc,
|
||||||
var smoothHashScroll = extra.smoothHashScroll;
|
isValidURL,
|
||||||
var deduplicatedHeaderId = extra.deduplicatedHeaderId;
|
md,
|
||||||
var renderTOC = extra.renderTOC;
|
parseMeta,
|
||||||
var renderTitle = extra.renderTitle;
|
postProcess,
|
||||||
var renderFilename = extra.renderFilename;
|
renderFilename,
|
||||||
var renderTags = extra.renderTags;
|
renderTOC,
|
||||||
var isValidURL = extra.isValidURL;
|
renderTags,
|
||||||
var scrollToHash = extra.scrollToHash;
|
renderTitle,
|
||||||
var updateLastChangeUser = extra.updateLastChangeUser;
|
scrollToHash,
|
||||||
var updateOwner = extra.updateOwner;
|
smoothHashScroll,
|
||||||
var parseMeta = extra.parseMeta;
|
updateLastChange,
|
||||||
var exportToHTML = extra.exportToHTML;
|
updateLastChangeUser,
|
||||||
var exportToRawHTML = extra.exportToRawHTML;
|
updateOwner
|
||||||
|
} from './extra';
|
||||||
|
|
||||||
var syncScroll = require('./syncscroll');
|
import {
|
||||||
var setupSyncAreas = syncScroll.setupSyncAreas;
|
clearMap,
|
||||||
var clearMap = syncScroll.clearMap;
|
setupSyncAreas,
|
||||||
var syncScrollToEdit = syncScroll.syncScrollToEdit;
|
syncScrollToEdit,
|
||||||
var syncScrollToView = syncScroll.syncScrollToView;
|
syncScrollToView
|
||||||
|
} from './syncscroll';
|
||||||
|
|
||||||
var historyModule = require('./history');
|
import {
|
||||||
var writeHistory = historyModule.writeHistory;
|
writeHistory,
|
||||||
var deleteServerHistory = historyModule.deleteServerHistory;
|
deleteServerHistory,
|
||||||
var getHistory = historyModule.getHistory;
|
getHistory,
|
||||||
var saveHistory = historyModule.saveHistory;
|
saveHistory,
|
||||||
var removeHistory = historyModule.removeHistory;
|
removeHistory
|
||||||
|
} from './history';
|
||||||
|
|
||||||
var renderer = require('./render');
|
var renderer = require('./render');
|
||||||
var preventXSS = renderer.preventXSS;
|
var preventXSS = renderer.preventXSS;
|
||||||
|
@ -401,7 +408,8 @@ window.lastInfo = {
|
||||||
cursor: {
|
cursor: {
|
||||||
line: null,
|
line: null,
|
||||||
ch: null
|
ch: null
|
||||||
}
|
},
|
||||||
|
selections: null
|
||||||
},
|
},
|
||||||
view: {
|
view: {
|
||||||
scroll: {
|
scroll: {
|
||||||
|
@ -963,10 +971,10 @@ function setNeedRefresh() {
|
||||||
showStatus(statusType.offline);
|
showStatus(statusType.offline);
|
||||||
}
|
}
|
||||||
|
|
||||||
loginStateChangeEvent = function () {
|
setloginStateChangeEvent(function () {
|
||||||
setRefreshModal('user-state-changed');
|
setRefreshModal('user-state-changed');
|
||||||
setNeedRefresh();
|
setNeedRefresh();
|
||||||
};
|
});
|
||||||
|
|
||||||
//visibility
|
//visibility
|
||||||
var wasFocus = false;
|
var wasFocus = false;
|
||||||
|
@ -1535,7 +1543,7 @@ ui.toolbar.download.markdown.click(function (e) {
|
||||||
var blob = new Blob([markdown], {
|
var blob = new Blob([markdown], {
|
||||||
type: "text/markdown;charset=utf-8"
|
type: "text/markdown;charset=utf-8"
|
||||||
});
|
});
|
||||||
saveAs(blob, filename);
|
saveAs(blob, filename, true);
|
||||||
});
|
});
|
||||||
//html
|
//html
|
||||||
ui.toolbar.download.html.click(function (e) {
|
ui.toolbar.download.html.click(function (e) {
|
||||||
|
@ -1915,7 +1923,7 @@ $('#revisionModalDownload').click(function () {
|
||||||
var blob = new Blob([revision.content], {
|
var blob = new Blob([revision.content], {
|
||||||
type: "text/markdown;charset=utf-8"
|
type: "text/markdown;charset=utf-8"
|
||||||
});
|
});
|
||||||
saveAs(blob, filename);
|
saveAs(blob, filename, true);
|
||||||
});
|
});
|
||||||
$('#revisionModalRevert').click(function () {
|
$('#revisionModalRevert').click(function () {
|
||||||
if (!revision) return;
|
if (!revision) return;
|
||||||
|
@ -2511,7 +2519,7 @@ var addStyleRule = (function () {
|
||||||
}());
|
}());
|
||||||
function updateAuthorshipInner() {
|
function updateAuthorshipInner() {
|
||||||
// ignore when ot not synced yet
|
// ignore when ot not synced yet
|
||||||
if (cmClient && Object.keys(cmClient.state).length > 0) return;
|
if (havePendingOperation()) return;
|
||||||
authorMarks = {};
|
authorMarks = {};
|
||||||
for (var i = 0; i < authorship.length; i++) {
|
for (var i = 0; i < authorship.length; i++) {
|
||||||
var atom = authorship[i];
|
var atom = authorship[i];
|
||||||
|
@ -2668,7 +2676,7 @@ editor.on('update', function () {
|
||||||
});
|
});
|
||||||
// clear tooltip which described element has been removed
|
// clear tooltip which described element has been removed
|
||||||
$('[id^="tooltip"]').each(function (index, element) {
|
$('[id^="tooltip"]').each(function (index, element) {
|
||||||
$ele = $(element);
|
var $ele = $(element);
|
||||||
if ($('[aria-describedby="' + $ele.attr('id') + '"]').length <= 0) $ele.remove();
|
if ($('[aria-describedby="' + $ele.attr('id') + '"]').length <= 0) $ele.remove();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2726,12 +2734,16 @@ var EditorClient = ot.EditorClient;
|
||||||
var SocketIOAdapter = ot.SocketIOAdapter;
|
var SocketIOAdapter = ot.SocketIOAdapter;
|
||||||
var CodeMirrorAdapter = ot.CodeMirrorAdapter;
|
var CodeMirrorAdapter = ot.CodeMirrorAdapter;
|
||||||
var cmClient = null;
|
var cmClient = null;
|
||||||
|
var synchronized_ = null;
|
||||||
|
|
||||||
|
function havePendingOperation() {
|
||||||
|
return (cmClient && cmClient.state && cmClient.state.hasOwnProperty('outstanding')) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
socket.on('doc', function (obj) {
|
socket.on('doc', function (obj) {
|
||||||
var body = obj.str;
|
var body = obj.str;
|
||||||
var bodyMismatch = editor.getValue() !== body;
|
var bodyMismatch = editor.getValue() !== body;
|
||||||
var havePendingOperation = cmClient && Object.keys(cmClient.state).length > 0;
|
var setDoc = !cmClient || (cmClient && (cmClient.revision === -1 || (cmClient.revision !== obj.revision && !havePendingOperation()))) || obj.force;
|
||||||
var setDoc = !cmClient || (cmClient && (cmClient.revision === -1 || (cmClient.revision !== obj.revision && !havePendingOperation))) || obj.force;
|
|
||||||
|
|
||||||
saveInfo();
|
saveInfo();
|
||||||
if (setDoc && bodyMismatch) {
|
if (setDoc && bodyMismatch) {
|
||||||
|
@ -2756,16 +2768,17 @@ socket.on('doc', function (obj) {
|
||||||
obj.revision, obj.clients,
|
obj.revision, obj.clients,
|
||||||
new SocketIOAdapter(socket), new CodeMirrorAdapter(editor)
|
new SocketIOAdapter(socket), new CodeMirrorAdapter(editor)
|
||||||
);
|
);
|
||||||
|
synchronized_ = cmClient.state;
|
||||||
} else if (setDoc) {
|
} else if (setDoc) {
|
||||||
if (bodyMismatch) {
|
if (bodyMismatch) {
|
||||||
cmClient.undoManager.undoStack.length = 0;
|
cmClient.undoManager.undoStack.length = 0;
|
||||||
cmClient.undoManager.redoStack.length = 0;
|
cmClient.undoManager.redoStack.length = 0;
|
||||||
}
|
}
|
||||||
cmClient.revision = obj.revision;
|
cmClient.revision = obj.revision;
|
||||||
cmClient.setState(new ot.Client.Synchronized());
|
cmClient.setState(synchronized_);
|
||||||
cmClient.initializeClientList();
|
cmClient.initializeClientList();
|
||||||
cmClient.initializeClients(obj.clients);
|
cmClient.initializeClients(obj.clients);
|
||||||
} else if (havePendingOperation) {
|
} else if (havePendingOperation()) {
|
||||||
cmClient.serverReconnect();
|
cmClient.serverReconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3387,6 +3400,7 @@ function saveInfo() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lastInfo.edit.cursor = editor.getCursor();
|
lastInfo.edit.cursor = editor.getCursor();
|
||||||
|
lastInfo.edit.selections = editor.listSelections();
|
||||||
lastInfo.needRestore = true;
|
lastInfo.needRestore = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3396,6 +3410,7 @@ function restoreInfo() {
|
||||||
var line = lastInfo.edit.cursor.line;
|
var line = lastInfo.edit.cursor.line;
|
||||||
var ch = lastInfo.edit.cursor.ch;
|
var ch = lastInfo.edit.cursor.ch;
|
||||||
editor.setCursor(line, ch);
|
editor.setCursor(line, ch);
|
||||||
|
editor.setSelections(lastInfo.edit.selections);
|
||||||
switch (currentMode) {
|
switch (currentMode) {
|
||||||
case modeType.edit:
|
case modeType.edit:
|
||||||
if (scrollbarStyle == 'native') {
|
if (scrollbarStyle == 'native') {
|
||||||
|
@ -3445,6 +3460,7 @@ function updateViewInner() {
|
||||||
var value = editor.getValue();
|
var value = editor.getValue();
|
||||||
var lastMeta = md.meta;
|
var lastMeta = md.meta;
|
||||||
md.meta = {};
|
md.meta = {};
|
||||||
|
delete md.metaError;
|
||||||
var rendered = md.render(value);
|
var rendered = md.render(value);
|
||||||
if (md.meta.type && md.meta.type === 'slide') {
|
if (md.meta.type && md.meta.type === 'slide') {
|
||||||
var slideOptions = {
|
var slideOptions = {
|
||||||
|
@ -3716,6 +3732,7 @@ function checkCursorMenuInner() {
|
||||||
var offsetLeft = 0;
|
var offsetLeft = 0;
|
||||||
var offsetTop = defaultTextHeight;
|
var offsetTop = defaultTextHeight;
|
||||||
// set up side down
|
// set up side down
|
||||||
|
window.upSideDown = false;
|
||||||
var lastUpSideDown = upSideDown = false;
|
var lastUpSideDown = upSideDown = false;
|
||||||
// only do when have width and height
|
// only do when have width and height
|
||||||
if (width > 0 && height > 0) {
|
if (width > 0 && height > 0) {
|
||||||
|
@ -3944,7 +3961,7 @@ $(editor.getInputField())
|
||||||
match: /(?:^|\n|\s)(\>.*|\s|)((\^|)\[(\^|)\](\[\]|\(\)|\:|)\s*\w*)$/,
|
match: /(?:^|\n|\s)(\>.*|\s|)((\^|)\[(\^|)\](\[\]|\(\)|\:|)\s*\w*)$/,
|
||||||
search: function (term, callback) {
|
search: function (term, callback) {
|
||||||
var line = editor.getLine(editor.getCursor().line);
|
var line = editor.getLine(editor.getCursor().line);
|
||||||
quote = line.match(this.match)[1].trim();
|
var quote = line.match(this.match)[1].trim();
|
||||||
var list = [];
|
var list = [];
|
||||||
if (quote.indexOf('>') == 0) {
|
if (quote.indexOf('>') == 0) {
|
||||||
$.map(supportExtraTags, function (extratag) {
|
$.map(supportExtraTags, function (extratag) {
|
||||||
|
|
89
public/js/lib/common/login.js
Normal file
89
public/js/lib/common/login.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import { serverurl } from '../config';
|
||||||
|
|
||||||
|
let checkAuth = false;
|
||||||
|
let profile = null;
|
||||||
|
let lastLoginState = getLoginState();
|
||||||
|
let lastUserId = getUserId();
|
||||||
|
var loginStateChangeEvent = null;
|
||||||
|
|
||||||
|
export function setloginStateChangeEvent(func) {
|
||||||
|
loginStateChangeEvent = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetCheckAuth() {
|
||||||
|
checkAuth = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setLoginState(bool, id) {
|
||||||
|
Cookies.set('loginstate', bool, {
|
||||||
|
expires: 365
|
||||||
|
});
|
||||||
|
if (id) {
|
||||||
|
Cookies.set('userid', id, {
|
||||||
|
expires: 365
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Cookies.remove('userid');
|
||||||
|
}
|
||||||
|
lastLoginState = bool;
|
||||||
|
lastUserId = id;
|
||||||
|
checkLoginStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkLoginStateChanged() {
|
||||||
|
if (getLoginState() != lastLoginState || getUserId() != lastUserId) {
|
||||||
|
if (loginStateChangeEvent) setTimeout(loginStateChangeEvent, 100);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLoginState() {
|
||||||
|
const state = Cookies.get('loginstate');
|
||||||
|
return state === "true" || state === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserId() {
|
||||||
|
return Cookies.get('userid');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearLoginState() {
|
||||||
|
Cookies.remove('loginstate');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkIfAuth(yesCallback, noCallback) {
|
||||||
|
const cookieLoginState = getLoginState();
|
||||||
|
if (checkLoginStateChanged()) checkAuth = false;
|
||||||
|
if (!checkAuth || typeof cookieLoginState == 'undefined') {
|
||||||
|
$.get(`${serverurl}/me`)
|
||||||
|
.done(data => {
|
||||||
|
if (data && data.status == 'ok') {
|
||||||
|
profile = data;
|
||||||
|
yesCallback(profile);
|
||||||
|
setLoginState(true, data.id);
|
||||||
|
} else {
|
||||||
|
noCallback();
|
||||||
|
setLoginState(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(() => {
|
||||||
|
noCallback();
|
||||||
|
})
|
||||||
|
.always(() => {
|
||||||
|
checkAuth = true;
|
||||||
|
});
|
||||||
|
} else if (cookieLoginState) {
|
||||||
|
yesCallback(profile);
|
||||||
|
} else {
|
||||||
|
noCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
checkAuth,
|
||||||
|
profile,
|
||||||
|
lastLoginState,
|
||||||
|
lastUserId,
|
||||||
|
loginStateChangeEvent
|
||||||
|
};
|
19
public/js/lib/config/index.js
Normal file
19
public/js/lib/config/index.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import configJson from '../../../../config.json'; // root path json config
|
||||||
|
|
||||||
|
const config = 'production' === process.env.NODE_ENV ? configJson.production : configJson.development;
|
||||||
|
|
||||||
|
export const GOOGLE_API_KEY = (config.google && config.google.apiKey) || '';
|
||||||
|
export const GOOGLE_CLIENT_ID = (config.google && config.google.clientID) || '';
|
||||||
|
export const DROPBOX_APP_KEY = (config.dropbox && config.dropbox.appKey) || '';
|
||||||
|
|
||||||
|
export const domain = config.domain || ''; // domain name
|
||||||
|
export const urlpath = config.urlpath || ''; // sub url path, like: www.example.com/<urlpath>
|
||||||
|
export const debug = config.debug || false;
|
||||||
|
|
||||||
|
export const port = window.location.port;
|
||||||
|
export const serverurl = `${window.location.protocol}//${domain ? domain : window.location.hostname}${port ? ':' + port : ''}${urlpath ? '/' + urlpath : ''}`;
|
||||||
|
window.serverurl = serverurl;
|
||||||
|
export const noteid = urlpath ? window.location.pathname.slice(urlpath.length + 1, window.location.pathname.length).split('/')[1] : window.location.pathname.split('/')[1];
|
||||||
|
export const noteurl = `${serverurl}/${noteid}`;
|
||||||
|
|
||||||
|
export const version = '0.5.0';
|
|
@ -4,31 +4,34 @@ require('../css/site.css');
|
||||||
|
|
||||||
require('highlight.js/styles/github-gist.css');
|
require('highlight.js/styles/github-gist.css');
|
||||||
|
|
||||||
var extra = require('./extra');
|
import {
|
||||||
var md = extra.md;
|
autoLinkify,
|
||||||
var finishView = extra.finishView;
|
deduplicatedHeaderId,
|
||||||
var autoLinkify = extra.autoLinkify;
|
finishView,
|
||||||
var deduplicatedHeaderId = extra.deduplicatedHeaderId;
|
generateToc,
|
||||||
var renderTOC = extra.renderTOC;
|
md,
|
||||||
var generateToc = extra.generateToc;
|
parseMeta,
|
||||||
var smoothHashScroll = extra.smoothHashScroll;
|
postProcess,
|
||||||
var postProcess = extra.postProcess;
|
renderTOC,
|
||||||
var updateLastChange = extra.updateLastChange;
|
scrollToHash,
|
||||||
var parseMeta = extra.parseMeta;
|
smoothHashScroll,
|
||||||
var scrollToHash = extra.scrollToHash;
|
updateLastChange
|
||||||
var preventXSS = require('./render').preventXSS;
|
} from './extra';
|
||||||
|
|
||||||
var markdown = $("#doc.markdown-body");
|
import { preventXSS } from './render';
|
||||||
var text = markdown.text();
|
|
||||||
var lastMeta = md.meta;
|
const markdown = $("#doc.markdown-body");
|
||||||
|
const text = markdown.text();
|
||||||
|
const lastMeta = md.meta;
|
||||||
md.meta = {};
|
md.meta = {};
|
||||||
var rendered = md.render(text);
|
delete md.metaError;
|
||||||
|
let rendered = md.render(text);
|
||||||
if (md.meta.type && md.meta.type === 'slide') {
|
if (md.meta.type && md.meta.type === 'slide') {
|
||||||
var slideOptions = {
|
const slideOptions = {
|
||||||
separator: '^(\r\n?|\n)---(\r\n?|\n)$',
|
separator: '^(\r\n?|\n)---(\r\n?|\n)$',
|
||||||
verticalSeparator: '^(\r\n?|\n)----(\r\n?|\n)$'
|
verticalSeparator: '^(\r\n?|\n)----(\r\n?|\n)$'
|
||||||
};
|
};
|
||||||
var slides = RevealMarkdown.slidify(text, slideOptions);
|
const slides = RevealMarkdown.slidify(text, slideOptions);
|
||||||
markdown.html(slides);
|
markdown.html(slides);
|
||||||
RevealMarkdown.initialize();
|
RevealMarkdown.initialize();
|
||||||
// prevent XSS
|
// prevent XSS
|
||||||
|
@ -46,10 +49,11 @@ if (md.meta.type && md.meta.type === 'slide') {
|
||||||
}
|
}
|
||||||
// prevent XSS
|
// prevent XSS
|
||||||
rendered = preventXSS(rendered);
|
rendered = preventXSS(rendered);
|
||||||
var result = postProcess(rendered);
|
const result = postProcess(rendered);
|
||||||
markdown.html(result.html());
|
markdown.html(result.html());
|
||||||
}
|
}
|
||||||
$(document.body).show();
|
$(document.body).show();
|
||||||
|
|
||||||
finishView(markdown);
|
finishView(markdown);
|
||||||
autoLinkify(markdown);
|
autoLinkify(markdown);
|
||||||
deduplicatedHeaderId(markdown);
|
deduplicatedHeaderId(markdown);
|
||||||
|
@ -60,17 +64,18 @@ smoothHashScroll();
|
||||||
createtime = lastchangeui.time.attr('data-createtime');
|
createtime = lastchangeui.time.attr('data-createtime');
|
||||||
lastchangetime = lastchangeui.time.attr('data-updatetime');
|
lastchangetime = lastchangeui.time.attr('data-updatetime');
|
||||||
updateLastChange();
|
updateLastChange();
|
||||||
var url = window.location.pathname;
|
|
||||||
$('.ui-edit').attr('href', url + '/edit');
|
const url = window.location.pathname;
|
||||||
var toc = $('.ui-toc');
|
$('.ui-edit').attr('href', `${url}/edit`);
|
||||||
var tocAffix = $('.ui-affix-toc');
|
const toc = $('.ui-toc');
|
||||||
var tocDropdown = $('.ui-toc-dropdown');
|
const tocAffix = $('.ui-affix-toc');
|
||||||
|
const tocDropdown = $('.ui-toc-dropdown');
|
||||||
//toc
|
//toc
|
||||||
tocDropdown.click(function (e) {
|
tocDropdown.click(e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
var enoughForAffixToc = true;
|
let enoughForAffixToc = true;
|
||||||
|
|
||||||
function generateScrollspy() {
|
function generateScrollspy() {
|
||||||
$(document.body).scrollspy({
|
$(document.body).scrollspy({
|
||||||
|
@ -89,18 +94,18 @@ function generateScrollspy() {
|
||||||
|
|
||||||
function windowResize() {
|
function windowResize() {
|
||||||
//toc right
|
//toc right
|
||||||
var paddingRight = parseFloat(markdown.css('padding-right'));
|
const paddingRight = parseFloat(markdown.css('padding-right'));
|
||||||
var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
|
const right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
|
||||||
toc.css('right', right + 'px');
|
toc.css('right', `${right}px`);
|
||||||
//affix toc left
|
//affix toc left
|
||||||
var newbool;
|
let newbool;
|
||||||
var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
|
const rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
|
||||||
//for ipad or wider device
|
//for ipad or wider device
|
||||||
if (rightMargin >= 133) {
|
if (rightMargin >= 133) {
|
||||||
newbool = true;
|
newbool = true;
|
||||||
var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
|
const affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
|
||||||
var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
|
const left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
|
||||||
tocAffix.css('left', left + 'px');
|
tocAffix.css('left', `${left}px`);
|
||||||
} else {
|
} else {
|
||||||
newbool = false;
|
newbool = false;
|
||||||
}
|
}
|
||||||
|
@ -109,10 +114,10 @@ function windowResize() {
|
||||||
generateScrollspy();
|
generateScrollspy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$(window).resize(function () {
|
$(window).resize(() => {
|
||||||
windowResize();
|
windowResize();
|
||||||
});
|
});
|
||||||
$(document).ready(function () {
|
$(document).ready(() => {
|
||||||
windowResize();
|
windowResize();
|
||||||
generateScrollspy();
|
generateScrollspy();
|
||||||
setTimeout(scrollToHash, 0);
|
setTimeout(scrollToHash, 0);
|
||||||
|
@ -120,13 +125,13 @@ $(document).ready(function () {
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
});
|
});
|
||||||
|
|
||||||
function scrollToTop() {
|
export function scrollToTop() {
|
||||||
$('body, html').stop(true, true).animate({
|
$('body, html').stop(true, true).animate({
|
||||||
scrollTop: 0
|
scrollTop: 0
|
||||||
}, 100, "linear");
|
}, 100, "linear");
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollToBottom() {
|
export function scrollToBottom() {
|
||||||
$('body, html').stop(true, true).animate({
|
$('body, html').stop(true, true).animate({
|
||||||
scrollTop: $(document.body)[0].scrollHeight
|
scrollTop: $(document.body)[0].scrollHeight
|
||||||
}, 100, "linear");
|
}, 100, "linear");
|
||||||
|
@ -134,8 +139,3 @@ function scrollToBottom() {
|
||||||
|
|
||||||
window.scrollToTop = scrollToTop;
|
window.scrollToTop = scrollToTop;
|
||||||
window.scrollToBottom = scrollToBottom;
|
window.scrollToBottom = scrollToBottom;
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
scrollToBottom: scrollToBottom,
|
|
||||||
scrollToTop: scrollToTop
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ var dataUriRegex = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base
|
||||||
var whiteList = filterXSS.whiteList;
|
var whiteList = filterXSS.whiteList;
|
||||||
// allow ol specify start number
|
// allow ol specify start number
|
||||||
whiteList['ol'] = ['start'];
|
whiteList['ol'] = ['start'];
|
||||||
|
// allow li specify value number
|
||||||
|
whiteList['li'] = ['value'];
|
||||||
// allow style tag
|
// allow style tag
|
||||||
whiteList['style'] = [];
|
whiteList['style'] = [];
|
||||||
// allow kbd tag
|
// allow kbd tag
|
||||||
|
|
|
@ -1,67 +1,65 @@
|
||||||
require('../css/extra.css');
|
require('../css/extra.css');
|
||||||
require('../css/site.css');
|
require('../css/site.css');
|
||||||
|
|
||||||
var extraModule = require('./extra');
|
import { md, updateLastChange, finishView } from './extra';
|
||||||
var md = extraModule.md;
|
|
||||||
var updateLastChange = extraModule.updateLastChange;
|
|
||||||
var finishView = extraModule.finishView;
|
|
||||||
|
|
||||||
var preventXSS = require('./render').preventXSS;
|
import { preventXSS } from './render';
|
||||||
|
|
||||||
var body = $(".slides").text();
|
const body = $(".slides").text();
|
||||||
|
|
||||||
createtime = lastchangeui.time.attr('data-createtime');
|
createtime = lastchangeui.time.attr('data-createtime');
|
||||||
lastchangetime = lastchangeui.time.attr('data-updatetime');
|
lastchangetime = lastchangeui.time.attr('data-updatetime');
|
||||||
updateLastChange();
|
updateLastChange();
|
||||||
var url = window.location.pathname;
|
const url = window.location.pathname;
|
||||||
$('.ui-edit').attr('href', url + '/edit');
|
$('.ui-edit').attr('href', `${url}/edit`);
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(() => {
|
||||||
//tooltip
|
//tooltip
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
});
|
});
|
||||||
|
|
||||||
function extend() {
|
function extend() {
|
||||||
var target = {};
|
const target = {};
|
||||||
for (var i = 0; i < arguments.length; i++) {
|
|
||||||
var source = arguments[i];
|
for (const source of arguments) {
|
||||||
for (var key in source) {
|
for (const key in source) {
|
||||||
if (source.hasOwnProperty(key)) {
|
if (source.hasOwnProperty(key)) {
|
||||||
target[key] = source[key];
|
target[key] = source[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional libraries used to extend on reveal.js
|
// Optional libraries used to extend on reveal.js
|
||||||
var deps = [{
|
const deps = [{
|
||||||
src: serverurl + '/build/reveal.js/lib/js/classList.js',
|
src: `${serverurl}/build/reveal.js/lib/js/classList.js`,
|
||||||
condition: function() {
|
condition() {
|
||||||
return !document.body.classList;
|
return !document.body.classList;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
src: serverurl + '/js/reveal-markdown.js',
|
src: `${serverurl}/js/reveal-markdown.js`,
|
||||||
callback: function () {
|
callback() {
|
||||||
var slideOptions = {
|
const slideOptions = {
|
||||||
separator: '^(\r\n?|\n)---(\r\n?|\n)$',
|
separator: '^(\r\n?|\n)---(\r\n?|\n)$',
|
||||||
verticalSeparator: '^(\r\n?|\n)----(\r\n?|\n)$'
|
verticalSeparator: '^(\r\n?|\n)----(\r\n?|\n)$'
|
||||||
};
|
};
|
||||||
var slides = RevealMarkdown.slidify(body, slideOptions);
|
const slides = RevealMarkdown.slidify(body, slideOptions);
|
||||||
$(".slides").html(slides);
|
$(".slides").html(slides);
|
||||||
RevealMarkdown.initialize();
|
RevealMarkdown.initialize();
|
||||||
$(".slides").show();
|
$(".slides").show();
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
src: serverurl + '/build/reveal.js/plugin/notes/notes.js',
|
src: `${serverurl}/build/reveal.js/plugin/notes/notes.js`,
|
||||||
async: true,
|
async: true,
|
||||||
condition: function() {
|
condition() {
|
||||||
return !!document.body.classList;
|
return !!document.body.classList;
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// default options to init reveal.js
|
// default options to init reveal.js
|
||||||
var defaultOptions = {
|
const defaultOptions = {
|
||||||
controls: true,
|
controls: true,
|
||||||
progress: true,
|
progress: true,
|
||||||
slideNumber: true,
|
slideNumber: true,
|
||||||
|
@ -72,10 +70,10 @@ var defaultOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// options from yaml meta
|
// options from yaml meta
|
||||||
var meta = JSON.parse($("#meta").text());
|
const meta = JSON.parse($("#meta").text());
|
||||||
var options = meta.slideOptions || {};
|
var options = meta.slideOptions || {};
|
||||||
|
|
||||||
var view = $('.reveal');
|
const view = $('.reveal');
|
||||||
|
|
||||||
//text language
|
//text language
|
||||||
if (meta.lang && typeof meta.lang == "string") {
|
if (meta.lang && typeof meta.lang == "string") {
|
||||||
|
@ -97,24 +95,24 @@ if (typeof meta.breaks === 'boolean' && !meta.breaks) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// options from URL query string
|
// options from URL query string
|
||||||
var queryOptions = Reveal.getQueryHash() || {};
|
const queryOptions = Reveal.getQueryHash() || {};
|
||||||
|
|
||||||
var options = extend(defaultOptions, options, queryOptions);
|
var options = extend(defaultOptions, options, queryOptions);
|
||||||
Reveal.initialize(options);
|
Reveal.initialize(options);
|
||||||
|
|
||||||
window.viewAjaxCallback = function () {
|
window.viewAjaxCallback = () => {
|
||||||
Reveal.layout();
|
Reveal.layout();
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderSlide(event) {
|
function renderSlide(event) {
|
||||||
if (window.location.search.match( /print-pdf/gi )) {
|
if (window.location.search.match( /print-pdf/gi )) {
|
||||||
var slides = $('.slides');
|
const slides = $('.slides');
|
||||||
var title = document.title;
|
var title = document.title;
|
||||||
finishView(slides);
|
finishView(slides);
|
||||||
document.title = title;
|
document.title = title;
|
||||||
Reveal.layout();
|
Reveal.layout();
|
||||||
} else {
|
} else {
|
||||||
var markdown = $(event.currentSlide);
|
const markdown = $(event.currentSlide);
|
||||||
if (!markdown.attr('data-rendered')) {
|
if (!markdown.attr('data-rendered')) {
|
||||||
var title = document.title;
|
var title = document.title;
|
||||||
finishView(markdown);
|
finishView(markdown);
|
||||||
|
@ -125,16 +123,16 @@ function renderSlide(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Reveal.addEventListener('ready', function (event) {
|
Reveal.addEventListener('ready', event => {
|
||||||
renderSlide(event);
|
renderSlide(event);
|
||||||
var markdown = $(event.currentSlide);
|
const markdown = $(event.currentSlide);
|
||||||
// force browser redraw
|
// force browser redraw
|
||||||
setTimeout(function () {
|
setTimeout(() => {
|
||||||
markdown.hide().show(0);
|
markdown.hide().show(0);
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
Reveal.addEventListener('slidechanged', renderSlide);
|
Reveal.addEventListener('slidechanged', renderSlide);
|
||||||
|
|
||||||
var isMacLike = navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i) ? true : false;
|
const isMacLike = navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i) ? true : false;
|
||||||
|
|
||||||
if (!isMacLike) $('.container').addClass('hidescrollbar');
|
if (!isMacLike) $('.container').addClass('hidescrollbar');
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
// Inject line numbers for sync scroll.
|
// Inject line numbers for sync scroll.
|
||||||
|
|
||||||
var extra = require('./extra');
|
import markdownitContainer from 'markdown-it-container';
|
||||||
var md = extra.md;
|
|
||||||
|
import { md } from './extra';
|
||||||
|
|
||||||
function addPart(tokens, idx) {
|
function addPart(tokens, idx) {
|
||||||
if (tokens[idx].map && tokens[idx].level === 0) {
|
if (tokens[idx].map && tokens[idx].level === 0) {
|
||||||
var startline = tokens[idx].map[0] + 1;
|
const startline = tokens[idx].map[0] + 1;
|
||||||
var endline = tokens[idx].map[1];
|
const endline = tokens[idx].map[1];
|
||||||
tokens[idx].attrJoin('class', 'part');
|
tokens[idx].attrJoin('class', 'part');
|
||||||
tokens[idx].attrJoin('data-startline', startline);
|
tokens[idx].attrJoin('data-startline', startline);
|
||||||
tokens[idx].attrJoin('data-endline', endline);
|
tokens[idx].attrJoin('data-endline', endline);
|
||||||
|
@ -16,48 +17,48 @@ function addPart(tokens, idx) {
|
||||||
md.renderer.rules.blockquote_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.blockquote_open = function (tokens, idx, options, env, self) {
|
||||||
tokens[idx].attrJoin('class', 'raw');
|
tokens[idx].attrJoin('class', 'raw');
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.bullet_list_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.bullet_list_open = function (tokens, idx, options, env, self) {
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.list_item_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.list_item_open = function (tokens, idx, options, env, self) {
|
||||||
tokens[idx].attrJoin('class', 'raw');
|
tokens[idx].attrJoin('class', 'raw');
|
||||||
if (tokens[idx].map) {
|
if (tokens[idx].map) {
|
||||||
var startline = tokens[idx].map[0] + 1;
|
const startline = tokens[idx].map[0] + 1;
|
||||||
var endline = tokens[idx].map[1];
|
const endline = tokens[idx].map[1];
|
||||||
tokens[idx].attrJoin('data-startline', startline);
|
tokens[idx].attrJoin('data-startline', startline);
|
||||||
tokens[idx].attrJoin('data-endline', endline);
|
tokens[idx].attrJoin('data-endline', endline);
|
||||||
}
|
}
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.ordered_list_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.ordered_list_open = function (tokens, idx, options, env, self) {
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.paragraph_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.paragraph_open = function (tokens, idx, options, env, self) {
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.heading_open = function (tokens, idx, options, env, self) {
|
md.renderer.rules.heading_open = function (tokens, idx, options, env, self) {
|
||||||
tokens[idx].attrJoin('class', 'raw');
|
tokens[idx].attrJoin('class', 'raw');
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
};
|
};
|
||||||
md.renderer.rules.fence = function (tokens, idx, options, env, self) {
|
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
|
||||||
var token = tokens[idx],
|
const token = tokens[idx];
|
||||||
info = token.info ? md.utils.unescapeAll(token.info).trim() : '',
|
const info = token.info ? md.utils.unescapeAll(token.info).trim() : '';
|
||||||
langName = '',
|
let langName = '';
|
||||||
highlighted;
|
let highlighted;
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
langName = info.split(/\s+/g)[0];
|
langName = info.split(/\s+/g)[0];
|
||||||
|
@ -74,38 +75,33 @@ md.renderer.rules.fence = function (tokens, idx, options, env, self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highlighted.indexOf('<pre') === 0) {
|
if (highlighted.indexOf('<pre') === 0) {
|
||||||
return highlighted + '\n';
|
return `${highlighted}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokens[idx].map && tokens[idx].level === 0) {
|
if (tokens[idx].map && tokens[idx].level === 0) {
|
||||||
var startline = tokens[idx].map[0] + 1;
|
const startline = tokens[idx].map[0] + 1;
|
||||||
var endline = tokens[idx].map[1];
|
const endline = tokens[idx].map[1];
|
||||||
return '<pre class="part" data-startline="' + startline + '" data-endline="' + endline + '"><code' + self.renderAttrs(token) + '>'
|
return `<pre class="part" data-startline="${startline}" data-endline="${endline}"><code${self.renderAttrs(token)}>${highlighted}</code></pre>\n`;
|
||||||
+ highlighted
|
|
||||||
+ '</code></pre>\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<pre><code' + self.renderAttrs(token) + '>'
|
return `<pre><code${self.renderAttrs(token)}>${highlighted}</code></pre>\n`;
|
||||||
+ highlighted
|
|
||||||
+ '</code></pre>\n';
|
|
||||||
};
|
};
|
||||||
md.renderer.rules.code_block = function (tokens, idx, options, env, self) {
|
md.renderer.rules.code_block = (tokens, idx, options, env, self) => {
|
||||||
if (tokens[idx].map && tokens[idx].level === 0) {
|
if (tokens[idx].map && tokens[idx].level === 0) {
|
||||||
var startline = tokens[idx].map[0] + 1;
|
const startline = tokens[idx].map[0] + 1;
|
||||||
var endline = tokens[idx].map[1];
|
const endline = tokens[idx].map[1];
|
||||||
return '<pre class="part" data-startline="' + startline + '" data-endline="' + endline + '"><code>' + md.utils.escapeHtml(tokens[idx].content) + '</code></pre>\n';
|
return `<pre class="part" data-startline="${startline}" data-endline="${endline}"><code>${md.utils.escapeHtml(tokens[idx].content)}</code></pre>\n`;
|
||||||
}
|
}
|
||||||
return '<pre><code>' + md.utils.escapeHtml(tokens[idx].content) + '</code></pre>\n';
|
return `<pre><code>${md.utils.escapeHtml(tokens[idx].content)}</code></pre>\n`;
|
||||||
};
|
};
|
||||||
function renderContainer(tokens, idx, options, env, self) {
|
function renderContainer(tokens, idx, options, env, self) {
|
||||||
tokens[idx].attrJoin('role', 'alert');
|
tokens[idx].attrJoin('role', 'alert');
|
||||||
tokens[idx].attrJoin('class', 'alert');
|
tokens[idx].attrJoin('class', 'alert');
|
||||||
tokens[idx].attrJoin('class', 'alert-' + tokens[idx].info.trim());
|
tokens[idx].attrJoin('class', `alert-${tokens[idx].info.trim()}`);
|
||||||
addPart(tokens, idx);
|
addPart(tokens, idx);
|
||||||
return self.renderToken.apply(self, arguments);
|
return self.renderToken(...arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
var markdownitContainer = require('markdown-it-container');
|
|
||||||
md.use(markdownitContainer, 'success', { render: renderContainer });
|
md.use(markdownitContainer, 'success', { render: renderContainer });
|
||||||
md.use(markdownitContainer, 'info', { render: renderContainer });
|
md.use(markdownitContainer, 'info', { render: renderContainer });
|
||||||
md.use(markdownitContainer, 'warning', { render: renderContainer });
|
md.use(markdownitContainer, 'warning', { render: renderContainer });
|
||||||
|
@ -117,18 +113,18 @@ window.syncscroll = true;
|
||||||
window.preventSyncScrollToEdit = false;
|
window.preventSyncScrollToEdit = false;
|
||||||
window.preventSyncScrollToView = false;
|
window.preventSyncScrollToView = false;
|
||||||
|
|
||||||
var editScrollThrottle = 5;
|
const editScrollThrottle = 5;
|
||||||
var viewScrollThrottle = 5;
|
const viewScrollThrottle = 5;
|
||||||
var buildMapThrottle = 100;
|
const buildMapThrottle = 100;
|
||||||
|
|
||||||
var viewScrolling = false;
|
let viewScrolling = false;
|
||||||
var editScrolling = false;
|
let editScrolling = false;
|
||||||
|
|
||||||
var editArea = null;
|
let editArea = null;
|
||||||
var viewArea = null;
|
let viewArea = null;
|
||||||
var markdownArea = null;
|
let markdownArea = null;
|
||||||
|
|
||||||
function setupSyncAreas(edit, view, markdown) {
|
export function setupSyncAreas(edit, view, markdown) {
|
||||||
editArea = edit;
|
editArea = edit;
|
||||||
viewArea = view;
|
viewArea = view;
|
||||||
markdownArea = markdown;
|
markdownArea = markdown;
|
||||||
|
@ -136,26 +132,24 @@ function setupSyncAreas(edit, view, markdown) {
|
||||||
viewArea.on('scroll', _.throttle(syncScrollToEdit, viewScrollThrottle));
|
viewArea.on('scroll', _.throttle(syncScrollToEdit, viewScrollThrottle));
|
||||||
}
|
}
|
||||||
|
|
||||||
var scrollMap, lineHeightMap, viewTop, viewBottom;
|
let scrollMap, lineHeightMap, viewTop, viewBottom;
|
||||||
|
|
||||||
window.viewAjaxCallback = clearMap;
|
export function clearMap() {
|
||||||
|
|
||||||
function clearMap() {
|
|
||||||
scrollMap = null;
|
scrollMap = null;
|
||||||
lineHeightMap = null;
|
lineHeightMap = null;
|
||||||
viewTop = null;
|
viewTop = null;
|
||||||
viewBottom = null;
|
viewBottom = null;
|
||||||
}
|
}
|
||||||
|
window.viewAjaxCallback = clearMap;
|
||||||
|
|
||||||
var buildMap = _.throttle(buildMapInner, buildMapThrottle);
|
const buildMap = _.throttle(buildMapInner, buildMapThrottle);
|
||||||
|
|
||||||
// Build offsets for each line (lines can be wrapped)
|
// Build offsets for each line (lines can be wrapped)
|
||||||
// That's a bit dirty to process each line everytime, but ok for demo.
|
// That's a bit dirty to process each line everytime, but ok for demo.
|
||||||
// Optimizations are required only for big texts.
|
// Optimizations are required only for big texts.
|
||||||
function buildMapInner(callback) {
|
function buildMapInner(callback) {
|
||||||
if (!viewArea || !markdownArea) return;
|
if (!viewArea || !markdownArea) return;
|
||||||
var i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount,
|
let i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount, acc, _scrollMap;
|
||||||
acc, _scrollMap;
|
|
||||||
|
|
||||||
offset = viewArea.scrollTop() - viewArea.offset().top;
|
offset = viewArea.scrollTop() - viewArea.offset().top;
|
||||||
_scrollMap = [];
|
_scrollMap = [];
|
||||||
|
@ -165,10 +159,10 @@ function buildMapInner(callback) {
|
||||||
viewBottom = viewArea[0].scrollHeight - viewArea.height();
|
viewBottom = viewArea[0].scrollHeight - viewArea.height();
|
||||||
|
|
||||||
acc = 0;
|
acc = 0;
|
||||||
var lines = editor.getValue().split('\n');
|
const lines = editor.getValue().split('\n');
|
||||||
var lineHeight = editor.defaultTextHeight();
|
const lineHeight = editor.defaultTextHeight();
|
||||||
for (i = 0; i < lines.length; i++) {
|
for (i = 0; i < lines.length; i++) {
|
||||||
var str = lines[i];
|
const str = lines[i];
|
||||||
|
|
||||||
_lineHeightMap.push(acc);
|
_lineHeightMap.push(acc);
|
||||||
|
|
||||||
|
@ -177,7 +171,7 @@ function buildMapInner(callback) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var h = editor.heightAtLine(i + 1) - editor.heightAtLine(i);
|
const h = editor.heightAtLine(i + 1) - editor.heightAtLine(i);
|
||||||
acc += Math.round(h / lineHeight);
|
acc += Math.round(h / lineHeight);
|
||||||
}
|
}
|
||||||
_lineHeightMap.push(acc);
|
_lineHeightMap.push(acc);
|
||||||
|
@ -191,10 +185,10 @@ function buildMapInner(callback) {
|
||||||
// make the first line go top
|
// make the first line go top
|
||||||
_scrollMap[0] = viewTop;
|
_scrollMap[0] = viewTop;
|
||||||
|
|
||||||
var parts = markdownArea.find('.part').toArray();
|
const parts = markdownArea.find('.part').toArray();
|
||||||
for (i = 0; i < parts.length; i++) {
|
for (i = 0; i < parts.length; i++) {
|
||||||
var $el = $(parts[i]),
|
const $el = $(parts[i]);
|
||||||
t = $el.attr('data-startline') - 1;
|
let t = $el.attr('data-startline') - 1;
|
||||||
if (t === '') {
|
if (t === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -229,9 +223,9 @@ function buildMapInner(callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync view scroll progress to edit
|
// sync view scroll progress to edit
|
||||||
var viewScrollingTimer = null;
|
let viewScrollingTimer = null;
|
||||||
|
|
||||||
function syncScrollToEdit(event, preventAnimate) {
|
export function syncScrollToEdit(event, preventAnimate) {
|
||||||
if (currentMode != modeType.both || !syncscroll || !editArea) return;
|
if (currentMode != modeType.both || !syncscroll || !editArea) return;
|
||||||
if (preventSyncScrollToEdit) {
|
if (preventSyncScrollToEdit) {
|
||||||
if (typeof preventSyncScrollToEdit === 'number') {
|
if (typeof preventSyncScrollToEdit === 'number') {
|
||||||
|
@ -242,15 +236,15 @@ function syncScrollToEdit(event, preventAnimate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!scrollMap || !lineHeightMap) {
|
if (!scrollMap || !lineHeightMap) {
|
||||||
buildMap(function () {
|
buildMap(() => {
|
||||||
syncScrollToEdit(event, preventAnimate);
|
syncScrollToEdit(event, preventAnimate);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (editScrolling) return;
|
if (editScrolling) return;
|
||||||
|
|
||||||
var scrollTop = viewArea[0].scrollTop;
|
const scrollTop = viewArea[0].scrollTop;
|
||||||
var lineIndex = 0;
|
let lineIndex = 0;
|
||||||
for (var i = 0, l = scrollMap.length; i < l; i++) {
|
for (var i = 0, l = scrollMap.length; i < l; i++) {
|
||||||
if (scrollMap[i] > scrollTop) {
|
if (scrollMap[i] > scrollTop) {
|
||||||
break;
|
break;
|
||||||
|
@ -258,8 +252,8 @@ function syncScrollToEdit(event, preventAnimate) {
|
||||||
lineIndex = i;
|
lineIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var lineNo = 0;
|
let lineNo = 0;
|
||||||
var lineDiff = 0;
|
let lineDiff = 0;
|
||||||
for (var i = 0, l = lineHeightMap.length; i < l; i++) {
|
for (var i = 0, l = lineHeightMap.length; i < l; i++) {
|
||||||
if (lineHeightMap[i] > lineIndex) {
|
if (lineHeightMap[i] > lineIndex) {
|
||||||
break;
|
break;
|
||||||
|
@ -269,14 +263,14 @@ function syncScrollToEdit(event, preventAnimate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var posTo = 0;
|
let posTo = 0;
|
||||||
var topDiffPercent = 0;
|
let topDiffPercent = 0;
|
||||||
var posToNextDiff = 0;
|
let posToNextDiff = 0;
|
||||||
var scrollInfo = editor.getScrollInfo();
|
const scrollInfo = editor.getScrollInfo();
|
||||||
var textHeight = editor.defaultTextHeight();
|
const textHeight = editor.defaultTextHeight();
|
||||||
var preLastLineHeight = scrollInfo.height - scrollInfo.clientHeight - textHeight;
|
const preLastLineHeight = scrollInfo.height - scrollInfo.clientHeight - textHeight;
|
||||||
var preLastLineNo = Math.round(preLastLineHeight / textHeight);
|
const preLastLineNo = Math.round(preLastLineHeight / textHeight);
|
||||||
var preLastLinePos = scrollMap[preLastLineNo];
|
const preLastLinePos = scrollMap[preLastLineNo];
|
||||||
|
|
||||||
if (scrollInfo.height > scrollInfo.clientHeight && scrollTop >= preLastLinePos) {
|
if (scrollInfo.height > scrollInfo.clientHeight && scrollTop >= preLastLinePos) {
|
||||||
posTo = preLastLineHeight;
|
posTo = preLastLineHeight;
|
||||||
|
@ -293,7 +287,7 @@ function syncScrollToEdit(event, preventAnimate) {
|
||||||
if (preventAnimate) {
|
if (preventAnimate) {
|
||||||
editArea.scrollTop(posTo);
|
editArea.scrollTop(posTo);
|
||||||
} else {
|
} else {
|
||||||
var posDiff = Math.abs(scrollInfo.top - posTo);
|
const posDiff = Math.abs(scrollInfo.top - posTo);
|
||||||
var duration = posDiff / 50;
|
var duration = posDiff / 50;
|
||||||
duration = duration >= 100 ? duration : 100;
|
duration = duration >= 100 ? duration : 100;
|
||||||
editArea.stop(true, true).animate({
|
editArea.stop(true, true).animate({
|
||||||
|
@ -311,9 +305,9 @@ function viewScrollingTimeoutInner() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync edit scroll progress to view
|
// sync edit scroll progress to view
|
||||||
var editScrollingTimer = null;
|
let editScrollingTimer = null;
|
||||||
|
|
||||||
function syncScrollToView(event, preventAnimate) {
|
export function syncScrollToView(event, preventAnimate) {
|
||||||
if (currentMode != modeType.both || !syncscroll || !viewArea) return;
|
if (currentMode != modeType.both || !syncscroll || !viewArea) return;
|
||||||
if (preventSyncScrollToView) {
|
if (preventSyncScrollToView) {
|
||||||
if (typeof preventSyncScrollToView === 'number') {
|
if (typeof preventSyncScrollToView === 'number') {
|
||||||
|
@ -324,20 +318,20 @@ function syncScrollToView(event, preventAnimate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!scrollMap || !lineHeightMap) {
|
if (!scrollMap || !lineHeightMap) {
|
||||||
buildMap(function () {
|
buildMap(() => {
|
||||||
syncScrollToView(event, preventAnimate);
|
syncScrollToView(event, preventAnimate);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (viewScrolling) return;
|
if (viewScrolling) return;
|
||||||
|
|
||||||
var lineNo, posTo;
|
let lineNo, posTo;
|
||||||
var topDiffPercent, posToNextDiff;
|
let topDiffPercent, posToNextDiff;
|
||||||
var scrollInfo = editor.getScrollInfo();
|
const scrollInfo = editor.getScrollInfo();
|
||||||
var textHeight = editor.defaultTextHeight();
|
const textHeight = editor.defaultTextHeight();
|
||||||
lineNo = Math.floor(scrollInfo.top / textHeight);
|
lineNo = Math.floor(scrollInfo.top / textHeight);
|
||||||
// if reach the last line, will start lerp to the bottom
|
// if reach the last line, will start lerp to the bottom
|
||||||
var diffToBottom = (scrollInfo.top + scrollInfo.clientHeight) - (scrollInfo.height - textHeight);
|
const diffToBottom = (scrollInfo.top + scrollInfo.clientHeight) - (scrollInfo.height - textHeight);
|
||||||
if (scrollInfo.height > scrollInfo.clientHeight && diffToBottom > 0) {
|
if (scrollInfo.height > scrollInfo.clientHeight && diffToBottom > 0) {
|
||||||
topDiffPercent = diffToBottom / textHeight;
|
topDiffPercent = diffToBottom / textHeight;
|
||||||
posTo = scrollMap[lineNo + 1];
|
posTo = scrollMap[lineNo + 1];
|
||||||
|
@ -353,7 +347,7 @@ function syncScrollToView(event, preventAnimate) {
|
||||||
if (preventAnimate) {
|
if (preventAnimate) {
|
||||||
viewArea.scrollTop(posTo);
|
viewArea.scrollTop(posTo);
|
||||||
} else {
|
} else {
|
||||||
var posDiff = Math.abs(viewArea.scrollTop() - posTo);
|
const posDiff = Math.abs(viewArea.scrollTop() - posTo);
|
||||||
var duration = posDiff / 50;
|
var duration = posDiff / 50;
|
||||||
duration = duration >= 100 ? duration : 100;
|
duration = duration >= 100 ? duration : 100;
|
||||||
viewArea.stop(true, true).animate({
|
viewArea.stop(true, true).animate({
|
||||||
|
@ -369,10 +363,3 @@ function syncScrollToView(event, preventAnimate) {
|
||||||
function editScrollingTimeoutInner() {
|
function editScrollingTimeoutInner() {
|
||||||
editScrolling = false;
|
editScrolling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
setupSyncAreas: setupSyncAreas,
|
|
||||||
clearMap: clearMap,
|
|
||||||
syncScrollToEdit: syncScrollToEdit,
|
|
||||||
syncScrollToView: syncScrollToView
|
|
||||||
};
|
|
||||||
|
|
BIN
public/screenshot.png
Normal file
BIN
public/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 233 KiB |
2
public/vendor/ot/codemirror-adapter.js
vendored
2
public/vendor/ot/codemirror-adapter.js
vendored
|
@ -343,7 +343,9 @@ ot.CodeMirrorAdapter = (function (global) {
|
||||||
};
|
};
|
||||||
|
|
||||||
CodeMirrorAdapter.prototype.applyOperation = function (operation) {
|
CodeMirrorAdapter.prototype.applyOperation = function (operation) {
|
||||||
|
if (!operation.isNoop()) {
|
||||||
this.ignoreNextChange = true;
|
this.ignoreNextChange = true;
|
||||||
|
}
|
||||||
CodeMirrorAdapter.applyOperationToCodeMirror(operation, this.cm);
|
CodeMirrorAdapter.applyOperationToCodeMirror(operation, this.cm);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
2
public/vendor/ot/ot.min.js
vendored
2
public/vendor/ot/ot.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -2,18 +2,18 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<%- include head %>
|
<%- include hackmd/head %>
|
||||||
<link rel="stylesheet" href="<%- url %>/css/center.css">
|
<link rel="stylesheet" href="<%- url %>/css/center.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<%- include header %>
|
<%- include hackmd/header %>
|
||||||
<div class="container-fluid text-center">
|
<div class="container-fluid text-center">
|
||||||
<div class="vertical-center-row">
|
<div class="vertical-center-row">
|
||||||
<h1><%- code %> <%- detail %> <small><%- msg %></small></h1>
|
<h1><%- code %> <%- detail %> <small><%- msg %></small></h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%- include footer %>
|
<%- include hackmd/footer %>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -2,14 +2,14 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<%- include head %>
|
<%- include hackmd/head %>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<%- include header %>
|
<%- include hackmd/header %>
|
||||||
<%- include body %>
|
<%- include hackmd/body %>
|
||||||
<%- include footer %>
|
<%- include hackmd/footer %>
|
||||||
<%- include foot %>
|
<%- include hackmd/foot %>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -244,7 +244,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%- include refresh-modal %>
|
<%- include ../shared/refresh-modal %>
|
||||||
<%- include signin-modal %>
|
<%- include ../shared/signin-modal %>
|
||||||
<%- include help-modal %>
|
<%- include ../shared/help-modal %>
|
||||||
<%- include revision-modal %>
|
<%- include ../shared/revision-modal %>
|
|
@ -11,18 +11,18 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/6.0.0/mermaid.min.js" integrity="sha256-Yabf6Mj1TPKd6h4F6z5xRR1/2son0Wg8NhvjYnhcQcY=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/7.0.0/mermaid.min.js" integrity="sha256-1uR+pqxH5fN/rOZcZTb9c5+bR3OIYEKzu2sI11Dnj9A=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js" integrity="sha256-Cv5v4i4SuYvwRYzIONifZjoc99CkwfncROMSWat1cVA=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js" integrity="sha256-Cv5v4i4SuYvwRYzIONifZjoc99CkwfncROMSWat1cVA=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.2/socket.io.min.js" integrity="sha256-WKvqiY0jZHWQZIohYEmr9KUC5rEaYEOFTq+ByllJK8w=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.2/socket.io.min.js" integrity="sha256-WKvqiY0jZHWQZIohYEmr9KUC5rEaYEOFTq+ByllJK8w=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js" integrity="sha256-KbfTjB0WZ8vvXngdpJGY3Yp3xKk+tttbqClO11anCIU=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js" integrity="sha256-KbfTjB0WZ8vvXngdpJGY3Yp3xKk+tttbqClO11anCIU=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.4.1/viz.js" integrity="sha256-U0a9HpXT7zG0N3tVzo58B5S+QXUxo4FdBIjrBMYrxZI=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.7.0/viz.js" integrity="sha256-8t+rndrF+TU4JtelmOH1lDHTMe2ovhO2UbzDArp5lY8=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.8/validator.min.js" integrity="sha256-LHeY7YoYJ0SSXbCx7sR14Pqna+52moaH3bhv0Mjzd/M=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.8/validator.min.js" integrity="sha256-LHeY7YoYJ0SSXbCx7sR14Pqna+52moaH3bhv0Mjzd/M=" crossorigin="anonymous" defer></script>
|
||||||
<%- include build/index-scripts %>
|
<%- include ../build/index-scripts %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<script src="<%- url %>/build/MathJax/MathJax.js" defer></script>
|
<script src="<%- url %>/build/MathJax/MathJax.js" defer></script>
|
||||||
<script src="<%- url %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script>
|
<script src="<%- url %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script>
|
||||||
<%- include build/index-pack-scripts %>
|
<%- include ../build/index-pack-scripts %>
|
||||||
<% } %>
|
<% } %>
|
|
@ -14,9 +14,9 @@
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'>
|
<link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'>
|
||||||
<%- include build/index-header %>
|
<%- include ../build/index-header %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'>
|
<link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'>
|
||||||
<%- include build/index-pack-header %>
|
<%- include ../build/index-pack-header %>
|
||||||
<% } %>
|
<% } %>
|
||||||
<%- include polyfill %>
|
<%- include ../shared/polyfill %>
|
|
@ -2,219 +2,14 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<%- include index/head %>
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<meta name="description" content="<%= __('Best way to write and share your knowledge in markdown.') %>">
|
|
||||||
<meta name="keywords" content="Collaborative, Markdown, Notes">
|
|
||||||
<title>HackMD - <%= __('Collaborative markdown notes') %></title>
|
|
||||||
<link rel="icon" type="image/png" href="<%- url %>/favicon.png">
|
|
||||||
<link rel="apple-touch-icon" href="<%- url %>/apple-touch-icon.png">
|
|
||||||
<% if(useCDN) { %>
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/4.9.0/bootstrap-social.min.css" integrity="sha256-02JtFTurpwBjQJ6q13iJe82/NF0RbZlJroDegK5g87Y=" crossorigin="anonymous" />
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.min.css" integrity="sha256-ijlUKKj3hJCiiT2HWo1kqkI79NTEYpzOsw5Rs3k42dI=" crossorigin="anonymous" />
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2-bootstrap.min.css" integrity="sha256-NAWFcNIZdH+TS1xpWujF/EB/Y8gwBbEOCoaK/eqaer8=" crossorigin="anonymous" />
|
|
||||||
<%- include build/cover-header %>
|
|
||||||
<% } else { %>
|
|
||||||
<%- include build/cover-pack-header %>
|
|
||||||
<% } %>
|
|
||||||
<%- include polyfill %>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="site-wrapper">
|
<%- include index/header %>
|
||||||
<div class="site-wrapper-inner">
|
<%- include index/body %>
|
||||||
<div class="cover-container">
|
<%- include index/footer %>
|
||||||
|
<%- include index/foot %>
|
||||||
<div class="masthead clearfix">
|
|
||||||
<div class="inner">
|
|
||||||
<h3 class="masthead-brand"></h3>
|
|
||||||
<nav>
|
|
||||||
<ul class="nav masthead-nav">
|
|
||||||
<li class="ui-home<% if(!signin) { %> active<% } %>"><a href="#"><%= __('Intro') %></a>
|
|
||||||
</li>
|
|
||||||
<li class="ui-history<% if(signin) { %> active<% } %>"><a href="#"><%= __('History') %></a>
|
|
||||||
</li>
|
|
||||||
<div class="ui-signin" style="float: right; margin-top: 8px;<% if(signin) { %> display: none;<% } %>">
|
|
||||||
<% if(allowAnonymous) { %>
|
|
||||||
<a type="button" href="<%- url %>/new" class="btn btn-sm btn-link"><i class="fa fa-plus"></i> <%= __('New guest note') %></a>
|
|
||||||
<% } %>
|
|
||||||
<% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %>
|
|
||||||
<button class="btn btn-sm btn-success ui-signin" data-toggle="modal" data-target=".signin-modal"><%= __('Sign In') %></button>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
<div class="ui-signout" style="float: right; margin-top: 8px;<% if(!signin) { %> display: none;<% } %>">
|
|
||||||
<a type="button" href="<%- url %>/new" class="btn btn-sm btn-link"><i class="fa fa-plus"></i> <%= __('New note') %></a>
|
|
||||||
<span class="ui-profile dropdown pull-right">
|
|
||||||
<button id="profileLabel" class="btn btn-sm btn-link ui-profile-label" style="padding-right: 0;" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<img class="ui-avatar" width="20" height="20"><span class="hidden-xs hidden-sm"> <span class="ui-name"></span></span> <i class="fa fa-caret-down"></i>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="profileLabel">
|
|
||||||
<li><a href="<%- url %>/logout"><i class="fa fa-sign-out fa-fw"></i> <%= __('Sign Out') %></a></li>
|
|
||||||
</ul>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="home" class="section"<% if(signin) { %> style="display:none;"<% } %>>
|
|
||||||
<div class="inner cover">
|
|
||||||
<h1 class="cover-heading"><i class="fa fa-file-text"></i> HackMD</h1>
|
|
||||||
<p class="lead">
|
|
||||||
<%= __('Best way to write and share your knowledge in markdown.') %>
|
|
||||||
</p>
|
|
||||||
<% if (infoMessage && infoMessage.length > 0) { %>
|
|
||||||
<div class="alert alert-info" style="max-width: 400px; margin: 0 auto;"><%= infoMessage %></div>
|
|
||||||
<% } %>
|
|
||||||
<% if (errorMessage && errorMessage.length > 0) { %>
|
|
||||||
<div class="alert alert-danger" style="max-width: 400px; margin: 0 auto;"><%= errorMessage %></div>
|
|
||||||
<% } %>
|
|
||||||
<% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %>
|
|
||||||
<span class="ui-signin">
|
|
||||||
<br>
|
|
||||||
<a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 200px;"><%= __('Sign In') %></a>
|
|
||||||
</span>
|
|
||||||
<span class="ui-or"><%= __('or') %></span>
|
|
||||||
<% } %>
|
|
||||||
<span class="ui-signin">
|
|
||||||
<a type="button" href="<%- url %>/features" class="btn btn-lg btn-primary" style="min-width: 200px;"><%= __('Explore all features') %></a>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
</span>
|
|
||||||
<div class="lead row" style="width: 90%; margin: 0 auto;">
|
|
||||||
<div class="col-md-4 inner">
|
|
||||||
<a href="<%- url %>/features#share-notes">
|
|
||||||
<i class="fa fa-bolt fa-3x"></i>
|
|
||||||
<h4><%= __('Collaborate with URL') %></h4>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 inner">
|
|
||||||
<a href="<%- url %>/features#mathjax">
|
|
||||||
<i class="fa fa-bar-chart fa-3x"></i>
|
|
||||||
<h4><%= __('Support charts and MathJax') %></h4>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 inner">
|
|
||||||
<a href="<%- url %>/features#slide-mode">
|
|
||||||
<i class="fa fa-tv fa-3x"></i>
|
|
||||||
<h4><%= __('Support slide mode') %></h4>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="history" class="section"<% if(!signin) { %> style="display:none;"<% } %>>
|
|
||||||
<div class="ui-signin"<% if(signin) { %> style="display:none;"<% } %>>
|
|
||||||
<p><%= __('Below is the history from browser') %></p>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<form class="form-inline">
|
|
||||||
<div class="form-group" style="vertical-align: bottom;">
|
|
||||||
<input class="form-control ui-use-tags" placeholder="<%= __('Select tags...') %>" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input class="search form-control" placeholder="<%= __('Search keyword...') %>" />
|
|
||||||
</div>
|
|
||||||
<a href="#" class="sort btn btn-default" data-sort="text" title="<%= __('Sort by title') %>">
|
|
||||||
<%= __('Title') %>
|
|
||||||
</a>
|
|
||||||
<a href="#" class="sort btn btn-default" data-sort="timestamp" title="<%= __('Sort by time') %>">
|
|
||||||
<%= __('Time') %>
|
|
||||||
</a>
|
|
||||||
<span class="hidden-xs hidden-sm">
|
|
||||||
<a href="#" class="btn btn-default ui-save-history" title="<%= __('Export history') %>"><i class="fa fa-save"></i></a>
|
|
||||||
<span class="btn btn-default btn-file ui-open-history" title="<%= __('Import history') %>">
|
|
||||||
<i class="fa fa-folder-open-o"></i><input type="file" />
|
|
||||||
</span>
|
|
||||||
<a href="#" class="btn btn-default ui-clear-history" title="<%= __('Clear history') %>" data-toggle="modal" data-target=".delete-modal"><i class="fa fa-trash-o"></i></a>
|
|
||||||
</span>
|
|
||||||
<a href="#" class="btn btn-default ui-refresh-history" title="<%= __('Refresh history') %>"><i class="fa fa-refresh"></i></a>
|
|
||||||
</form>
|
|
||||||
<h4 class="ui-nohistory" style="display:none;">
|
|
||||||
<%= __('No history') %>
|
|
||||||
</h4>
|
|
||||||
<a href="#" class="btn btn-primary ui-import-from-browser" style="display:none;"><%= __('Import from browser') %></a>
|
|
||||||
<ul id="history-list" class="list">
|
|
||||||
</ul>
|
|
||||||
<ul class="pagination"></ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mastfoot">
|
|
||||||
<div class="inner">
|
|
||||||
<h6 class="social-foot">
|
|
||||||
<iframe src="//ghbtns.com/github-btn.html?user=hackmdio&repo=hackmd&type=star&count=true" frameborder="0" scrolling="0" width="104px" height="20px"></iframe>
|
|
||||||
</h6>
|
|
||||||
<p>
|
|
||||||
© 2017 <a href="https://www.facebook.com/hackmdio" target="_blank"><i class="fa fa-facebook-square"></i> HackMD</a> | <a href="<%- url %>/s/release-notes" target="_blank"><%= __('Releases') %></a>
|
|
||||||
</p>
|
|
||||||
<select class="ui-locale">
|
|
||||||
<option value="en">English</option>
|
|
||||||
<option value="zh">中文</option>
|
|
||||||
<option value="fr">Français</option>
|
|
||||||
<option value="de">Deutsch</option>
|
|
||||||
<option value="ja">日本語</option>
|
|
||||||
<option value="es">Español</option>
|
|
||||||
<option value="el">Ελληνικά</option>
|
|
||||||
<option value="pt">Português</option>
|
|
||||||
<option value="it">italiano</option>
|
|
||||||
<option value="tr">Türkçe</option>
|
|
||||||
<option value="ru">Русский</option>
|
|
||||||
<option value="nl">Nederlands</option>
|
|
||||||
<option value="hr">hrvatski jezik</option>
|
|
||||||
<option value="pl">język polski</option>
|
|
||||||
<option value="uk">Українська</option>
|
|
||||||
<option value="hi">हिन्दी</option>
|
|
||||||
<option value="sv">svenska</option>
|
|
||||||
<option value="eo">Esperanto</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- delete modal -->
|
|
||||||
<div class="modal fade delete-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
<h4 class="modal-title" id="myModalLabel"><%= __('Are you sure?') %></h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body" style="color:black;">
|
|
||||||
<h5 class="ui-delete-modal-msg"></h5>
|
|
||||||
<strong class="ui-delete-modal-item"></strong>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal"><%= __('Cancel') %></button>
|
|
||||||
<button type="button" class="btn btn-danger ui-delete-modal-confirm"><%= __('Yes, do it!') %></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<%- include signin-modal %>
|
|
||||||
|
|
||||||
<% if(useCDN) { %>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.pagination.js/0.1.1/list.pagination.min.js" integrity="sha256-WwTza96H3BgcQTfEfxX7MFaFc/dZA0QrPRKDRLdFHJo=" crossorigin="anonymous" defer></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.2/select2.min.js" integrity="sha256-HzzZFiY4t0PIv02Tm8/R3CVvLpcjHhO1z/YAUCp4oQ4=" crossorigin="anonymous" defer></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-url/2.3.0/url.min.js" integrity="sha256-HOZJz4x+1mn1Si84WT5XKXPtOlTytmZLnMb6n1v4+5Q=" crossorigin="anonymous" defer></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.8/validator.min.js" integrity="sha256-LHeY7YoYJ0SSXbCx7sR14Pqna+52moaH3bhv0Mjzd/M=" crossorigin="anonymous" defer></script>
|
|
||||||
<%- include build/cover-scripts %>
|
|
||||||
<% } else { %>
|
|
||||||
<%- include build/cover-pack-scripts %>
|
|
||||||
<% } %>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
176
public/views/index/body.ejs
Normal file
176
public/views/index/body.ejs
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
<div class="site-wrapper">
|
||||||
|
<div class="site-wrapper-inner">
|
||||||
|
<div class="cover-container">
|
||||||
|
|
||||||
|
<div class="masthead clearfix">
|
||||||
|
<div class="inner">
|
||||||
|
<h3 class="masthead-brand"></h3>
|
||||||
|
<nav>
|
||||||
|
<ul class="nav masthead-nav">
|
||||||
|
<li class="ui-home<% if(!signin) { %> active<% } %>"><a href="#"><%= __('Intro') %></a>
|
||||||
|
</li>
|
||||||
|
<li class="ui-history<% if(signin) { %> active<% } %>"><a href="#"><%= __('History') %></a>
|
||||||
|
</li>
|
||||||
|
<div class="ui-signin" style="float: right; margin-top: 8px;<% if(signin) { %> display: none;<% } %>">
|
||||||
|
<% if(allowAnonymous) { %>
|
||||||
|
<a type="button" href="<%- url %>/new" class="btn btn-sm btn-link"><i class="fa fa-plus"></i> <%= __('New guest note') %></a>
|
||||||
|
<% } %>
|
||||||
|
<% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %>
|
||||||
|
<button class="btn btn-sm btn-success ui-signin" data-toggle="modal" data-target=".signin-modal"><%= __('Sign In') %></button>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<div class="ui-signout" style="float: right; margin-top: 8px;<% if(!signin) { %> display: none;<% } %>">
|
||||||
|
<a type="button" href="<%- url %>/new" class="btn btn-sm btn-link"><i class="fa fa-plus"></i> <%= __('New note') %></a>
|
||||||
|
<span class="ui-profile dropdown pull-right">
|
||||||
|
<button id="profileLabel" class="btn btn-sm btn-link ui-profile-label" style="padding-right: 0;" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<img class="ui-avatar" width="20" height="20"><span class="hidden-xs hidden-sm"> <span class="ui-name"></span></span> <i class="fa fa-caret-down"></i>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="profileLabel">
|
||||||
|
<li><a href="<%- url %>/features"><i class="fa fa-dot-circle-o fa-fw"></i> <%= __('Features') %></a></li>
|
||||||
|
<li><a href="<%- url %>/logout"><i class="fa fa-sign-out fa-fw"></i> <%= __('Sign Out') %></a></li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="home" class="section"<% if(signin) { %> style="display:none;"<% } %>>
|
||||||
|
<div class="inner cover">
|
||||||
|
<h1 class="cover-heading"><i class="fa fa-file-text"></i> HackMD</h1>
|
||||||
|
<p class="lead">
|
||||||
|
<%= __('Best way to write and share your knowledge in markdown.') %>
|
||||||
|
</p>
|
||||||
|
<% if (infoMessage && infoMessage.length > 0) { %>
|
||||||
|
<div class="alert alert-info" style="max-width: 400px; margin: 0 auto;"><%= infoMessage %></div>
|
||||||
|
<% } %>
|
||||||
|
<% if (errorMessage && errorMessage.length > 0) { %>
|
||||||
|
<div class="alert alert-danger" style="max-width: 400px; margin: 0 auto;"><%= errorMessage %></div>
|
||||||
|
<% } %>
|
||||||
|
<% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %>
|
||||||
|
<span class="ui-signin">
|
||||||
|
<br>
|
||||||
|
<a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 200px;"><%= __('Sign In') %></a>
|
||||||
|
</span>
|
||||||
|
<span class="ui-or"><%= __('or') %></span>
|
||||||
|
<% } %>
|
||||||
|
<span class="ui-signin">
|
||||||
|
<a type="button" href="<%- url %>/features" class="btn btn-lg btn-primary" style="min-width: 200px;"><%= __('Explore all features') %></a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<img src="<%- url %>/screenshot.png" class="screenshot ui-signin">
|
||||||
|
</span>
|
||||||
|
<div class="lead row" style="width: 90%; margin: 0 auto;">
|
||||||
|
<div class="col-md-4 inner">
|
||||||
|
<a href="<%- url %>/features#share-notes">
|
||||||
|
<i class="fa fa-bolt fa-3x"></i>
|
||||||
|
<h4><%= __('Collaborate with URL') %></h4>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 inner">
|
||||||
|
<a href="<%- url %>/features#mathjax">
|
||||||
|
<i class="fa fa-bar-chart fa-3x"></i>
|
||||||
|
<h4><%= __('Support charts and MathJax') %></h4>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 inner">
|
||||||
|
<a href="<%- url %>/features#slide-mode">
|
||||||
|
<i class="fa fa-tv fa-3x"></i>
|
||||||
|
<h4><%= __('Support slide mode') %></h4>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="history" class="section"<% if(!signin) { %> style="display:none;"<% } %>>
|
||||||
|
<div class="ui-signin"<% if(signin) { %> style="display:none;"<% } %>>
|
||||||
|
<p><%= __('Below is the history from browser') %></p>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<form class="form-inline">
|
||||||
|
<div class="form-group" style="vertical-align: bottom;">
|
||||||
|
<input class="form-control ui-use-tags" placeholder="<%= __('Select tags...') %>" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input class="search form-control" placeholder="<%= __('Search keyword...') %>" />
|
||||||
|
</div>
|
||||||
|
<a href="#" class="sort btn btn-default" data-sort="text" title="<%= __('Sort by title') %>">
|
||||||
|
<%= __('Title') %>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="sort btn btn-default" data-sort="timestamp" title="<%= __('Sort by time') %>">
|
||||||
|
<%= __('Time') %>
|
||||||
|
</a>
|
||||||
|
<span class="hidden-xs hidden-sm">
|
||||||
|
<a href="#" class="btn btn-default ui-save-history" title="<%= __('Export history') %>"><i class="fa fa-save"></i></a>
|
||||||
|
<span class="btn btn-default btn-file ui-open-history" title="<%= __('Import history') %>">
|
||||||
|
<i class="fa fa-folder-open-o"></i><input type="file" />
|
||||||
|
</span>
|
||||||
|
<a href="#" class="btn btn-default ui-clear-history" title="<%= __('Clear history') %>" data-toggle="modal" data-target=".delete-modal"><i class="fa fa-trash-o"></i></a>
|
||||||
|
</span>
|
||||||
|
<a href="#" class="btn btn-default ui-refresh-history" title="<%= __('Refresh history') %>"><i class="fa fa-refresh"></i></a>
|
||||||
|
</form>
|
||||||
|
<h4 class="ui-nohistory" style="display:none;">
|
||||||
|
<%= __('No history') %>
|
||||||
|
</h4>
|
||||||
|
<a href="#" class="btn btn-primary ui-import-from-browser" style="display:none;"><%= __('Import from browser') %></a>
|
||||||
|
<ul id="history-list" class="list">
|
||||||
|
</ul>
|
||||||
|
<ul class="pagination"></ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mastfoot">
|
||||||
|
<div class="inner">
|
||||||
|
<h6 class="social-foot">
|
||||||
|
<iframe src="//ghbtns.com/github-btn.html?user=hackmdio&repo=hackmd&type=star&count=true" frameborder="0" scrolling="0" width="104px" height="20px"></iframe>
|
||||||
|
</h6>
|
||||||
|
<p>
|
||||||
|
© 2017 <a href="https://www.facebook.com/hackmdio" target="_blank"><i class="fa fa-facebook-square"></i> HackMD</a> | <a href="<%- url %>/s/release-notes" target="_blank"><%= __('Releases') %></a>
|
||||||
|
</p>
|
||||||
|
<select class="ui-locale">
|
||||||
|
<option value="en">English</option>
|
||||||
|
<option value="zh">中文</option>
|
||||||
|
<option value="fr">Français</option>
|
||||||
|
<option value="de">Deutsch</option>
|
||||||
|
<option value="ja">日本語</option>
|
||||||
|
<option value="es">Español</option>
|
||||||
|
<option value="el">Ελληνικά</option>
|
||||||
|
<option value="pt">Português</option>
|
||||||
|
<option value="it">italiano</option>
|
||||||
|
<option value="tr">Türkçe</option>
|
||||||
|
<option value="ru">Русский</option>
|
||||||
|
<option value="nl">Nederlands</option>
|
||||||
|
<option value="hr">hrvatski jezik</option>
|
||||||
|
<option value="pl">język polski</option>
|
||||||
|
<option value="uk">Українська</option>
|
||||||
|
<option value="hi">हिन्दी</option>
|
||||||
|
<option value="sv">svenska</option>
|
||||||
|
<option value="eo">Esperanto</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- delete modal -->
|
||||||
|
<div class="modal fade delete-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title" id="myModalLabel"><%= __('Are you sure?') %></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" style="color:black;">
|
||||||
|
<h5 class="ui-delete-modal-msg"></h5>
|
||||||
|
<strong class="ui-delete-modal-item"></strong>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal"><%= __('Cancel') %></button>
|
||||||
|
<button type="button" class="btn btn-danger ui-delete-modal-confirm"><%= __('Yes, do it!') %></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%- include ../shared/signin-modal %>
|
13
public/views/index/foot.ejs
Normal file
13
public/views/index/foot.ejs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<% if(useCDN) { %>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.pagination.js/0.1.1/list.pagination.min.js" integrity="sha256-WwTza96H3BgcQTfEfxX7MFaFc/dZA0QrPRKDRLdFHJo=" crossorigin="anonymous" defer></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.2/select2.min.js" integrity="sha256-HzzZFiY4t0PIv02Tm8/R3CVvLpcjHhO1z/YAUCp4oQ4=" crossorigin="anonymous" defer></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-url/2.3.0/url.min.js" integrity="sha256-HOZJz4x+1mn1Si84WT5XKXPtOlTytmZLnMb6n1v4+5Q=" crossorigin="anonymous" defer></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.8/validator.min.js" integrity="sha256-LHeY7YoYJ0SSXbCx7sR14Pqna+52moaH3bhv0Mjzd/M=" crossorigin="anonymous" defer></script>
|
||||||
|
<%- include ../build/cover-scripts %>
|
||||||
|
<% } else { %>
|
||||||
|
<%- include ../build/cover-pack-scripts %>
|
||||||
|
<% } %>
|
0
public/views/index/footer.ejs
Normal file
0
public/views/index/footer.ejs
Normal file
22
public/views/index/head.ejs
Normal file
22
public/views/index/head.ejs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="description" content="<%= __('Best way to write and share your knowledge in markdown.') %>">
|
||||||
|
<meta name="keywords" content="Collaborative, Markdown, Notes">
|
||||||
|
<title>HackMD - <%= __('Collaborative markdown notes') %></title>
|
||||||
|
<link rel="icon" type="image/png" href="<%- url %>/favicon.png">
|
||||||
|
<link rel="apple-touch-icon" href="<%- url %>/apple-touch-icon.png">
|
||||||
|
<% if(useCDN) { %>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/4.9.0/bootstrap-social.min.css" integrity="sha256-02JtFTurpwBjQJ6q13iJe82/NF0RbZlJroDegK5g87Y=" crossorigin="anonymous" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.min.css" integrity="sha256-ijlUKKj3hJCiiT2HWo1kqkI79NTEYpzOsw5Rs3k42dI=" crossorigin="anonymous" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2-bootstrap.min.css" integrity="sha256-NAWFcNIZdH+TS1xpWujF/EB/Y8gwBbEOCoaK/eqaer8=" crossorigin="anonymous" />
|
||||||
|
<%- include ../build/cover-header %>
|
||||||
|
<% } else { %>
|
||||||
|
<%- include ../build/cover-pack-header %>
|
||||||
|
<% } %>
|
||||||
|
<%- include ../shared/polyfill %>
|
0
public/views/index/header.ejs
Normal file
0
public/views/index/header.ejs
Normal file
|
@ -28,7 +28,7 @@
|
||||||
<link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'>
|
<link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'>
|
||||||
<%- include build/pretty-pack-header %>
|
<%- include build/pretty-pack-header %>
|
||||||
<% } %>
|
<% } %>
|
||||||
<%- include polyfill %>
|
<%- include shared/polyfill %>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="display:none;">
|
<body style="display:none;">
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="display:none;"></div>
|
<div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="display:none;"></div>
|
||||||
<% if(typeof disqus !== 'undefined' && disqus) { %>
|
<% if(typeof disqus !== 'undefined' && disqus) { %>
|
||||||
<div class="container-fluid" style="max-width: 758px; margin-bottom: 40px;">
|
<div class="container-fluid" style="max-width: 758px; margin-bottom: 40px;">
|
||||||
<%- include disqus %>
|
<%- include shared/disqus %>
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
</body>
|
</body>
|
||||||
|
@ -84,16 +84,16 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/6.0.0/mermaid.min.js" integrity="sha256-Yabf6Mj1TPKd6h4F6z5xRR1/2son0Wg8NhvjYnhcQcY=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/7.0.0/mermaid.min.js" integrity="sha256-1uR+pqxH5fN/rOZcZTb9c5+bR3OIYEKzu2sI11Dnj9A=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js" integrity="sha256-KbfTjB0WZ8vvXngdpJGY3Yp3xKk+tttbqClO11anCIU=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js" integrity="sha256-KbfTjB0WZ8vvXngdpJGY3Yp3xKk+tttbqClO11anCIU=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.4.1/viz.js" integrity="sha256-U0a9HpXT7zG0N3tVzo58B5S+QXUxo4FdBIjrBMYrxZI=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.7.0/viz.js" integrity="sha256-8t+rndrF+TU4JtelmOH1lDHTMe2ovhO2UbzDArp5lY8=" crossorigin="anonymous" defer></script>
|
||||||
<%- include build/pretty-scripts %>
|
<%- include build/pretty-scripts %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<script src="<%- url %>/build/MathJax/MathJax.js" defer></script>
|
<script src="<%- url %>/build/MathJax/MathJax.js" defer></script>
|
||||||
<script src="<%- url %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script>
|
<script src="<%- url %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script>
|
||||||
<%- include build/pretty-pack-scripts %>
|
<%- include build/pretty-pack-scripts %>
|
||||||
<% } %>
|
<% } %>
|
||||||
<%- include ga %>
|
<%- include shared/ga %>
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
document.getElementsByTagName( 'head' )[0].appendChild( link );
|
document.getElementsByTagName( 'head' )[0].appendChild( link );
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<%- include polyfill %>
|
<%- include shared/polyfill %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
</div>
|
</div>
|
||||||
<% if(typeof disqus !== 'undefined' && disqus) { %>
|
<% if(typeof disqus !== 'undefined' && disqus) { %>
|
||||||
<div style="margin-top: 25px; margin-bottom: 15px;">
|
<div style="margin-top: 25px; margin-bottom: 15px;">
|
||||||
<%- include disqus %>
|
<%- include shared/disqus %>
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
|
@ -98,12 +98,12 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/6.0.0/mermaid.min.js" integrity="sha256-Yabf6Mj1TPKd6h4F6z5xRR1/2son0Wg8NhvjYnhcQcY=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/7.0.0/mermaid.min.js" integrity="sha256-1uR+pqxH5fN/rOZcZTb9c5+bR3OIYEKzu2sI11Dnj9A=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js" integrity="sha256-KbfTjB0WZ8vvXngdpJGY3Yp3xKk+tttbqClO11anCIU=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js" integrity="sha256-KbfTjB0WZ8vvXngdpJGY3Yp3xKk+tttbqClO11anCIU=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.4.1/viz.js" integrity="sha256-U0a9HpXT7zG0N3tVzo58B5S+QXUxo4FdBIjrBMYrxZI=" crossorigin="anonymous" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.7.0/viz.js" integrity="sha256-8t+rndrF+TU4JtelmOH1lDHTMe2ovhO2UbzDArp5lY8=" crossorigin="anonymous" defer></script>
|
||||||
<%- include build/slide-scripts %>
|
<%- include build/slide-scripts %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<script src="<%- url %>/build/MathJax/MathJax.js" defer></script>
|
<script src="<%- url %>/build/MathJax/MathJax.js" defer></script>
|
||||||
|
@ -113,4 +113,4 @@
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<%- include ga %>
|
<%- include shared/ga %>
|
||||||
|
|
|
@ -3,6 +3,7 @@ var webpack = require('webpack');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var ExtractTextPlugin = require("extract-text-webpack-plugin");
|
var ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||||
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||||
|
var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
|
||||||
|
|
||||||
module.exports = [Object.assign({}, baseConfig, {
|
module.exports = [Object.assign({}, baseConfig, {
|
||||||
plugins: baseConfig.plugins.concat([
|
plugins: baseConfig.plugins.concat([
|
||||||
|
@ -11,12 +12,14 @@ module.exports = [Object.assign({}, baseConfig, {
|
||||||
'NODE_ENV': JSON.stringify('production')
|
'NODE_ENV': JSON.stringify('production')
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
new ParallelUglifyPlugin({
|
||||||
|
uglifyJS: {
|
||||||
compress: {
|
compress: {
|
||||||
warnings: false
|
warnings: false
|
||||||
},
|
},
|
||||||
mangle: false,
|
mangle: false,
|
||||||
sourceMap: false
|
sourceMap: false
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
new ExtractTextPlugin("[name].[hash].css")
|
new ExtractTextPlugin("[name].[hash].css")
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -158,6 +158,7 @@ module.exports = {
|
||||||
"bootstrap"
|
"bootstrap"
|
||||||
],
|
],
|
||||||
cover: [
|
cover: [
|
||||||
|
"babel-polyfill",
|
||||||
path.join(__dirname, 'public/js/cover.js')
|
path.join(__dirname, 'public/js/cover.js')
|
||||||
],
|
],
|
||||||
"cover-styles-pack": [
|
"cover-styles-pack": [
|
||||||
|
@ -168,6 +169,7 @@ module.exports = {
|
||||||
path.join(__dirname, 'node_modules/select2/select2-bootstrap.css'),
|
path.join(__dirname, 'node_modules/select2/select2-bootstrap.css'),
|
||||||
],
|
],
|
||||||
"cover-pack": [
|
"cover-pack": [
|
||||||
|
"babel-polyfill",
|
||||||
"bootstrap-validator",
|
"bootstrap-validator",
|
||||||
"script!listPagnation",
|
"script!listPagnation",
|
||||||
"expose?select2!select2",
|
"expose?select2!select2",
|
||||||
|
@ -176,6 +178,7 @@ module.exports = {
|
||||||
path.join(__dirname, 'public/js/cover.js')
|
path.join(__dirname, 'public/js/cover.js')
|
||||||
],
|
],
|
||||||
index: [
|
index: [
|
||||||
|
"babel-polyfill",
|
||||||
"script!jquery-ui-resizable",
|
"script!jquery-ui-resizable",
|
||||||
"script!js-url",
|
"script!js-url",
|
||||||
"expose?filterXSS!xss",
|
"expose?filterXSS!xss",
|
||||||
|
@ -221,6 +224,7 @@ module.exports = {
|
||||||
path.join(__dirname, 'node_modules/octicons/octicons/octicons.css')
|
path.join(__dirname, 'node_modules/octicons/octicons/octicons.css')
|
||||||
],
|
],
|
||||||
"index-pack": [
|
"index-pack": [
|
||||||
|
"babel-polyfill",
|
||||||
"expose?Spinner!spin.js",
|
"expose?Spinner!spin.js",
|
||||||
"script!jquery-ui-resizable",
|
"script!jquery-ui-resizable",
|
||||||
"bootstrap-validator",
|
"bootstrap-validator",
|
||||||
|
@ -251,6 +255,7 @@ module.exports = {
|
||||||
path.join(__dirname, 'public/js/index.js')
|
path.join(__dirname, 'public/js/index.js')
|
||||||
],
|
],
|
||||||
pretty: [
|
pretty: [
|
||||||
|
"babel-polyfill",
|
||||||
"expose?filterXSS!xss",
|
"expose?filterXSS!xss",
|
||||||
"flowchart.js",
|
"flowchart.js",
|
||||||
"js-sequence-diagrams",
|
"js-sequence-diagrams",
|
||||||
|
@ -270,6 +275,7 @@ module.exports = {
|
||||||
path.join(__dirname, 'node_modules/octicons/octicons/octicons.css')
|
path.join(__dirname, 'node_modules/octicons/octicons/octicons.css')
|
||||||
],
|
],
|
||||||
"pretty-pack": [
|
"pretty-pack": [
|
||||||
|
"babel-polyfill",
|
||||||
"expose?jsyaml!js-yaml",
|
"expose?jsyaml!js-yaml",
|
||||||
"script!mermaid",
|
"script!mermaid",
|
||||||
"expose?moment!moment",
|
"expose?moment!moment",
|
||||||
|
@ -285,6 +291,7 @@ module.exports = {
|
||||||
path.join(__dirname, 'public/js/pretty.js')
|
path.join(__dirname, 'public/js/pretty.js')
|
||||||
],
|
],
|
||||||
slide: [
|
slide: [
|
||||||
|
"babel-polyfill",
|
||||||
"bootstrap-tooltip",
|
"bootstrap-tooltip",
|
||||||
"expose?filterXSS!xss",
|
"expose?filterXSS!xss",
|
||||||
"flowchart.js",
|
"flowchart.js",
|
||||||
|
@ -304,6 +311,7 @@ module.exports = {
|
||||||
path.join(__dirname, 'node_modules/octicons/octicons/octicons.css')
|
path.join(__dirname, 'node_modules/octicons/octicons/octicons.css')
|
||||||
],
|
],
|
||||||
"slide-pack": [
|
"slide-pack": [
|
||||||
|
"babel-polyfill",
|
||||||
"expose?jQuery!expose?$!jquery",
|
"expose?jQuery!expose?$!jquery",
|
||||||
"velocity-animate",
|
"velocity-animate",
|
||||||
"imports?$=jquery!jquery-mousewheel",
|
"imports?$=jquery!jquery-mousewheel",
|
||||||
|
@ -372,6 +380,10 @@ module.exports = {
|
||||||
loaders: [{
|
loaders: [{
|
||||||
test: /\.json$/,
|
test: /\.json$/,
|
||||||
loader: 'json-loader'
|
loader: 'json-loader'
|
||||||
|
}, {
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel',
|
||||||
|
exclude: [/node_modules/, /public\/vendor/]
|
||||||
}, {
|
}, {
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
|
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
|
||||||
|
|
Loading…
Reference in a new issue