mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-25 19:26:31 -05:00
commit
6dfc186691
21 changed files with 864 additions and 933 deletions
8
.babelrc
Normal file
8
.babelrc
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"presets": [
|
||||
"es2015"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-runtime"
|
||||
]
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
],
|
||||
"array-callback-return": "error",
|
||||
"arrow-body-style": "error",
|
||||
"arrow-parens": "error",
|
||||
"arrow-spacing": "error",
|
||||
"block-scoped-var": "off",
|
||||
"block-spacing": "error",
|
||||
|
@ -123,7 +122,7 @@
|
|||
"no-extend-native": "error",
|
||||
"no-extra-bind": "error",
|
||||
"no-extra-label": "error",
|
||||
"no-extra-parens": "error",
|
||||
"no-extra-parens": "warn",
|
||||
"no-floating-decimal": "error",
|
||||
"no-global-assign": "error",
|
||||
"no-implicit-coercion": "error",
|
||||
|
@ -195,7 +194,7 @@
|
|||
"no-unneeded-ternary": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-use-before-define": "error",
|
||||
"no-use-before-define": "warn",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-concat": "error",
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,7 +18,6 @@ backups/
|
|||
|
||||
# ignore config files
|
||||
config.json
|
||||
public/js/config.js
|
||||
.sequelizerc
|
||||
|
||||
# ignore webpack build
|
||||
|
|
20
README.md
20
README.md
|
@ -59,7 +59,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.
|
||||
3. Setup the configs, see more below
|
||||
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)
|
||||
|
||||
Upgrade guide
|
||||
|
@ -70,7 +70,7 @@ If you are upgrading HackMD from an older version, follow these steps:
|
|||
1. Fully stop your old server first (important)
|
||||
2. `git pull` or do whatever that updates the files
|
||||
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
|
||||
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
|
||||
|
@ -97,19 +97,9 @@ Configuration files
|
|||
There are some configs you need to change in the files below
|
||||
|
||||
```
|
||||
./config.json --- for server settings
|
||||
./public/js/config.js --- for client settings
|
||||
./config.json ----application 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)
|
||||
---
|
||||
|
||||
|
@ -158,7 +148,7 @@ Environment variables (will overwrite other server configs)
|
|||
| HMD_S3_REGION | `ap-northeast-1` | AWS S3 region |
|
||||
| HMD_S3_BUCKET | no example | AWS S3 bucket name |
|
||||
|
||||
Server settings `config.json`
|
||||
Application settings `config.json`
|
||||
---
|
||||
|
||||
| variables | example values | description |
|
||||
|
@ -207,7 +197,7 @@ Third-party integration api key settings
|
|||
| ------- | --------- | ----------- |
|
||||
| facebook, twitter, github, gitlab, dropbox, google, ldap | environment variables or `config.json` | for signin |
|
||||
| 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
|
||||
---
|
||||
|
|
|
@ -28,8 +28,6 @@ EOF
|
|||
|
||||
EOF
|
||||
|
||||
cp public/js/config.js.example public/js/config.js
|
||||
|
||||
# build app
|
||||
npm run build:prod
|
||||
npm run build
|
||||
fi
|
||||
|
|
|
@ -21,10 +21,6 @@ if [ ! -f config.json ]; then
|
|||
cp config.json.example config.json
|
||||
fi
|
||||
|
||||
if [ ! -f publis/js/config.js ]; then
|
||||
cp public/js/config.js.example public/js/config.js
|
||||
fi
|
||||
|
||||
if [ ! -f .sequelizerc ]; then
|
||||
cp .sequelizerc.example .sequelizerc
|
||||
fi
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
},
|
||||
"dropbox": {
|
||||
"clientID": "change this",
|
||||
"clientSecret": "change this"
|
||||
"clientSecret": "change this",
|
||||
"appKey": "change this"
|
||||
},
|
||||
"google": {
|
||||
"clientID": "change this",
|
||||
"clientSecret": "change this"
|
||||
"clientSecret": "change this",
|
||||
"apiKey": "change this"
|
||||
},
|
||||
"ldap": {
|
||||
"url": "ldap://change_this",
|
||||
|
|
|
@ -90,11 +90,11 @@ var gitlab = (process.env.HMD_GITLAB_CLIENTID && process.env.HMD_GITLAB_CLIENTSE
|
|||
var dropbox = (process.env.HMD_DROPBOX_CLIENTID && process.env.HMD_DROPBOX_CLIENTSECRET) ? {
|
||||
clientID: process.env.HMD_DROPBOX_CLIENTID,
|
||||
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) ? {
|
||||
clientID: process.env.HMD_GOOGLE_CLIENTID,
|
||||
clientSecret: process.env.HMD_GOOGLE_CLIENTSECRET
|
||||
} : config.google || false;
|
||||
} : (config.google && config.google.clientID && config.google.clientSecret && config.google) || false;
|
||||
var ldap = config.ldap || (
|
||||
process.env.HMD_LDAP_URL ||
|
||||
process.env.HMD_LDAP_BINDDN ||
|
||||
|
|
10
package.json
10
package.json
|
@ -5,8 +5,8 @@
|
|||
"main": "app.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build:dev": "webpack --config webpack.config.js --progress --colors --watch",
|
||||
"build:prod": "webpack --config webpack.production.js --progress --colors",
|
||||
"dev": "webpack --config webpack.config.js --progress --colors --watch",
|
||||
"build": "webpack --config webpack.production.js --progress --colors",
|
||||
"postinstall": "bin/heroku",
|
||||
"start": "node app.js"
|
||||
},
|
||||
|
@ -140,6 +140,12 @@
|
|||
"url": "https://github.com/hackmdio/hackmd.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.18.0",
|
||||
"babel-core": "^6.21.0",
|
||||
"babel-loader": "^6.2.10",
|
||||
"babel-plugin-transform-runtime": "^6.15.0",
|
||||
"babel-preset-es2015": "^6.18.0",
|
||||
"babel-runtime": "^6.20.0",
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"css-loader": "^0.26.1",
|
||||
"ejs-loader": "^0.3.0",
|
||||
|
|
|
@ -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,37 +3,39 @@ require('./locale');
|
|||
require('../css/cover.css');
|
||||
require('../css/site.css');
|
||||
|
||||
var common = require('./common');
|
||||
var checkIfAuth = common.checkIfAuth;
|
||||
var urlpath = common.urlpath;
|
||||
var resetCheckAuth = common.resetCheckAuth;
|
||||
var getLoginState = common.getLoginState;
|
||||
var clearLoginState = common.clearLoginState;
|
||||
import {
|
||||
checkIfAuth,
|
||||
clearLoginState,
|
||||
getLoginState,
|
||||
resetCheckAuth,
|
||||
setloginStateChangeEvent
|
||||
} from './lib/common/login';
|
||||
|
||||
var historyModule = require('./history');
|
||||
var parseStorageToHistory = historyModule.parseStorageToHistory;
|
||||
var parseHistory = historyModule.parseHistory;
|
||||
var getStorageHistory = historyModule.getStorageHistory;
|
||||
var getHistory = historyModule.getHistory;
|
||||
var saveHistory = historyModule.saveHistory;
|
||||
var removeHistory = historyModule.removeHistory;
|
||||
var postHistoryToServer = historyModule.postHistoryToServer;
|
||||
var deleteServerHistory = historyModule.deleteServerHistory;
|
||||
var parseServerToHistory = historyModule.parseServerToHistory;
|
||||
var saveStorageHistoryToServer = historyModule.saveStorageHistoryToServer;
|
||||
var clearDuplicatedHistory = historyModule.clearDuplicatedHistory;
|
||||
import {
|
||||
clearDuplicatedHistory,
|
||||
deleteServerHistory,
|
||||
getHistory,
|
||||
getStorageHistory,
|
||||
parseHistory,
|
||||
parseServerToHistory,
|
||||
parseStorageToHistory,
|
||||
postHistoryToServer,
|
||||
removeHistory,
|
||||
saveHistory,
|
||||
saveStorageHistoryToServer
|
||||
} from './history';
|
||||
|
||||
var saveAs = require('file-saver').saveAs;
|
||||
var List = require('list.js');
|
||||
var S = require('string');
|
||||
import { saveAs } from 'file-saver';
|
||||
import List from 'list.js';
|
||||
import S from 'string';
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'],
|
||||
item: '<li class="col-xs-12 col-sm-6 col-md-6 col-lg-4">\
|
||||
<span class="id" style="display:none;"></span>\
|
||||
<a href="#">\
|
||||
<div class="item">\
|
||||
<div class="ui-history-pin fa fa-thumb-tack fa-fw"></div>\
|
||||
<div class="ui-history-pin fa fa-thumb-tack fa-fw"></div>\
|
||||
<div class="ui-history-close fa fa-close fa-fw" data-toggle="modal" data-target=".delete-modal"></div>\
|
||||
<div class="content">\
|
||||
<h4 class="text"></h4>\
|
||||
|
@ -55,15 +57,16 @@ var options = {
|
|||
})
|
||||
]
|
||||
};
|
||||
var historyList = new List('history', options);
|
||||
const historyList = new List('history', options);
|
||||
|
||||
migrateHistoryFromTempCallback = pageInit;
|
||||
loginStateChangeEvent = pageInit;
|
||||
setloginStateChangeEvent(pageInit);
|
||||
|
||||
pageInit();
|
||||
|
||||
function pageInit() {
|
||||
checkIfAuth(
|
||||
function (data) {
|
||||
data => {
|
||||
$('.ui-signin').hide();
|
||||
$('.ui-or').hide();
|
||||
$('.ui-welcome').show();
|
||||
|
@ -74,7 +77,7 @@ function pageInit() {
|
|||
$(".ui-history").click();
|
||||
parseServerToHistory(historyList, parseHistoryCallback);
|
||||
},
|
||||
function () {
|
||||
() => {
|
||||
$('.ui-signin').show();
|
||||
$('.ui-or').show();
|
||||
$('.ui-welcome').hide();
|
||||
|
@ -103,7 +106,7 @@ $(".ui-home").click(function (e) {
|
|||
}
|
||||
});
|
||||
|
||||
$(".ui-history").click(function (e) {
|
||||
$(".ui-history").click(() => {
|
||||
if (!$("#history").is(':visible')) {
|
||||
$(".section:visible").hide();
|
||||
$("#history").fadeIn();
|
||||
|
@ -118,7 +121,7 @@ function checkHistoryList() {
|
|||
} else if ($("#history-list").children().length == 0) {
|
||||
$('.pagination').hide();
|
||||
$(".ui-nohistory").slideDown();
|
||||
getStorageHistory(function (data) {
|
||||
getStorageHistory(data => {
|
||||
if (data && data.length > 0 && getLoginState() && historyList.items.length == 0) {
|
||||
$(".ui-import-from-browser").slideDown();
|
||||
}
|
||||
|
@ -128,35 +131,35 @@ function checkHistoryList() {
|
|||
|
||||
function parseHistoryCallback(list, notehistory) {
|
||||
checkHistoryList();
|
||||
//sort by pinned then timestamp
|
||||
list.sort('', {
|
||||
sortFunction: function (a, b) {
|
||||
var notea = a.values();
|
||||
var noteb = b.values();
|
||||
if (notea.pinned && !noteb.pinned) {
|
||||
//sort by pinned then timestamp
|
||||
list.sort('', {
|
||||
sortFunction(a, b) {
|
||||
const notea = a.values();
|
||||
const noteb = b.values();
|
||||
if (notea.pinned && !noteb.pinned) {
|
||||
return -1;
|
||||
} else if (!notea.pinned && noteb.pinned) {
|
||||
return 1;
|
||||
} else {
|
||||
if (notea.timestamp > noteb.timestamp) {
|
||||
return -1;
|
||||
} else if (notea.timestamp < noteb.timestamp) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (notea.timestamp > noteb.timestamp) {
|
||||
return -1;
|
||||
} else if (notea.timestamp < noteb.timestamp) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// parse filter tags
|
||||
var filtertags = [];
|
||||
for (var i = 0, l = list.items.length; i < l; i++) {
|
||||
var tags = list.items[i]._values.tags;
|
||||
const filtertags = [];
|
||||
for (let i = 0, l = list.items.length; i < l; i++) {
|
||||
const tags = list.items[i]._values.tags;
|
||||
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
|
||||
var found = false;
|
||||
if (filtertags.indexOf(tags[j]) != -1)
|
||||
let found = false;
|
||||
if (filtertags.includes(tags[j]))
|
||||
found = true;
|
||||
if (!found)
|
||||
filtertags.push(tags[j]);
|
||||
|
@ -167,17 +170,17 @@ function parseHistoryCallback(list, notehistory) {
|
|||
}
|
||||
|
||||
// update items whenever list updated
|
||||
historyList.on('updated', function (e) {
|
||||
for (var i = 0, l = e.items.length; i < l; i++) {
|
||||
var item = e.items[i];
|
||||
historyList.on('updated', e => {
|
||||
for (let i = 0, l = e.items.length; i < l; i++) {
|
||||
const item = e.items[i];
|
||||
if (item.visible()) {
|
||||
var itemEl = $(item.elm);
|
||||
var values = item._values;
|
||||
var a = itemEl.find("a");
|
||||
var pin = itemEl.find(".ui-history-pin");
|
||||
var tagsEl = itemEl.find(".tags");
|
||||
const itemEl = $(item.elm);
|
||||
const values = item._values;
|
||||
const a = itemEl.find("a");
|
||||
const pin = itemEl.find(".ui-history-pin");
|
||||
const tagsEl = itemEl.find(".tags");
|
||||
//parse link to element a
|
||||
a.attr('href', serverurl + '/' + values.id);
|
||||
a.attr('href', `${serverurl}/${values.id}`);
|
||||
//parse pinned
|
||||
if (values.pinned) {
|
||||
pin.addClass('active');
|
||||
|
@ -185,12 +188,12 @@ historyList.on('updated', function (e) {
|
|||
pin.removeClass('active');
|
||||
}
|
||||
//parse tags
|
||||
var tags = values.tags;
|
||||
const tags = values.tags;
|
||||
if (tags && tags.length > 0 && tagsEl.children().length <= 0) {
|
||||
var labels = [];
|
||||
for (var j = 0; j < tags.length; j++) {
|
||||
const labels = [];
|
||||
for (let j = 0; j < tags.length; j++) {
|
||||
//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(' '));
|
||||
}
|
||||
|
@ -204,21 +207,21 @@ historyList.on('updated', function (e) {
|
|||
|
||||
function historyCloseClick(e) {
|
||||
e.preventDefault();
|
||||
var id = $(this).closest("a").siblings("span").html();
|
||||
var value = historyList.get('id', id)[0]._values;
|
||||
const id = $(this).closest("a").siblings("span").html();
|
||||
const value = historyList.get('id', id)[0]._values;
|
||||
$('.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;
|
||||
deleteId = id;
|
||||
}
|
||||
|
||||
function historyPinClick(e) {
|
||||
e.preventDefault();
|
||||
var $this = $(this);
|
||||
var id = $this.closest("a").siblings("span").html();
|
||||
var item = historyList.get('id', id)[0];
|
||||
var values = item._values;
|
||||
var pinned = values.pinned;
|
||||
const $this = $(this);
|
||||
const id = $this.closest("a").siblings("span").html();
|
||||
const item = historyList.get('id', id)[0];
|
||||
const values = item._values;
|
||||
let pinned = values.pinned;
|
||||
if (!values.pinned) {
|
||||
pinned = true;
|
||||
item._values.pinned = true;
|
||||
|
@ -226,10 +229,10 @@ function historyPinClick(e) {
|
|||
pinned = false;
|
||||
item._values.pinned = false;
|
||||
}
|
||||
checkIfAuth(function () {
|
||||
checkIfAuth(() => {
|
||||
postHistoryToServer(id, {
|
||||
pinned: pinned
|
||||
}, function (err, result) {
|
||||
pinned
|
||||
}, (err, result) => {
|
||||
if (!err) {
|
||||
if (pinned)
|
||||
$this.addClass('active');
|
||||
|
@ -237,9 +240,9 @@ function historyPinClick(e) {
|
|||
$this.removeClass('active');
|
||||
}
|
||||
});
|
||||
}, function () {
|
||||
getHistory(function (notehistory) {
|
||||
for(var i = 0; i < notehistory.length; i++) {
|
||||
}, () => {
|
||||
getHistory(notehistory => {
|
||||
for(let i = 0; i < notehistory.length; i++) {
|
||||
if (notehistory[i].id == id) {
|
||||
notehistory[i].pinned = pinned;
|
||||
break;
|
||||
|
@ -258,10 +261,10 @@ function historyPinClick(e) {
|
|||
setInterval(updateItemFromNow, 60000);
|
||||
|
||||
function updateItemFromNow() {
|
||||
var items = $('.item').toArray();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = $(items[i]);
|
||||
var timestamp = parseInt(item.find('.timestamp').text());
|
||||
const items = $('.item').toArray();
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = $(items[i]);
|
||||
const timestamp = parseInt(item.find('.timestamp').text());
|
||||
item.find('.fromNow').text(moment(timestamp).fromNow());
|
||||
}
|
||||
}
|
||||
|
@ -270,8 +273,8 @@ var clearHistory = false;
|
|||
var deleteId = null;
|
||||
|
||||
function deleteHistory() {
|
||||
checkIfAuth(function () {
|
||||
deleteServerHistory(deleteId, function (err, result) {
|
||||
checkIfAuth(() => {
|
||||
deleteServerHistory(deleteId, (err, result) => {
|
||||
if (!err) {
|
||||
if (clearHistory) {
|
||||
historyList.clear();
|
||||
|
@ -285,7 +288,7 @@ function deleteHistory() {
|
|||
deleteId = null;
|
||||
clearHistory = false;
|
||||
});
|
||||
}, function () {
|
||||
}, () => {
|
||||
if (clearHistory) {
|
||||
saveHistory([]);
|
||||
historyList.clear();
|
||||
|
@ -293,8 +296,8 @@ function deleteHistory() {
|
|||
deleteId = null;
|
||||
} else {
|
||||
if (!deleteId) return;
|
||||
getHistory(function (notehistory) {
|
||||
var newnotehistory = removeHistory(deleteId, notehistory);
|
||||
getHistory(notehistory => {
|
||||
const newnotehistory = removeHistory(deleteId, notehistory);
|
||||
saveHistory(newnotehistory);
|
||||
historyList.remove('id', deleteId);
|
||||
checkHistoryList();
|
||||
|
@ -306,36 +309,36 @@ function deleteHistory() {
|
|||
});
|
||||
}
|
||||
|
||||
$(".ui-delete-modal-confirm").click(function () {
|
||||
$(".ui-delete-modal-confirm").click(() => {
|
||||
deleteHistory();
|
||||
});
|
||||
|
||||
$(".ui-import-from-browser").click(function () {
|
||||
saveStorageHistoryToServer(function () {
|
||||
$(".ui-import-from-browser").click(() => {
|
||||
saveStorageHistoryToServer(() => {
|
||||
parseStorageToHistory(historyList, parseHistoryCallback);
|
||||
});
|
||||
});
|
||||
|
||||
$(".ui-save-history").click(function () {
|
||||
getHistory(function (data) {
|
||||
var history = JSON.stringify(data);
|
||||
var blob = new Blob([history], {
|
||||
$(".ui-save-history").click(() => {
|
||||
getHistory(data => {
|
||||
const history = JSON.stringify(data);
|
||||
const blob = new Blob([history], {
|
||||
type: "application/json;charset=utf-8"
|
||||
});
|
||||
saveAs(blob, 'hackmd_history_' + moment().format('YYYYMMDDHHmmss'));
|
||||
saveAs(blob, `hackmd_history_${moment().format('YYYYMMDDHHmmss')}`);
|
||||
});
|
||||
});
|
||||
|
||||
$(".ui-open-history").bind("change", function (e) {
|
||||
var files = e.target.files || e.dataTransfer.files;
|
||||
var file = files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var notehistory = JSON.parse(reader.result);
|
||||
$(".ui-open-history").bind("change", e => {
|
||||
const files = e.target.files || e.dataTransfer.files;
|
||||
const file = files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const notehistory = JSON.parse(reader.result);
|
||||
//console.log(notehistory);
|
||||
if (!reader.result) return;
|
||||
getHistory(function (data) {
|
||||
var mergedata = data.concat(notehistory);
|
||||
getHistory(data => {
|
||||
let mergedata = data.concat(notehistory);
|
||||
mergedata = clearDuplicatedHistory(mergedata);
|
||||
saveHistory(mergedata);
|
||||
parseHistory(historyList, parseHistoryCallback);
|
||||
|
@ -345,18 +348,18 @@ $(".ui-open-history").bind("change", function (e) {
|
|||
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-item').html('There is no turning back.');
|
||||
clearHistory = true;
|
||||
deleteId = null;
|
||||
});
|
||||
|
||||
$(".ui-refresh-history").click(function () {
|
||||
var lastTags = $(".ui-use-tags").select2('val');
|
||||
$(".ui-refresh-history").click(() => {
|
||||
const lastTags = $(".ui-use-tags").select2('val');
|
||||
$(".ui-use-tags").select2('val', '');
|
||||
historyList.filter();
|
||||
var lastKeyword = $('.search').val();
|
||||
const lastKeyword = $('.search').val();
|
||||
$('.search').val('');
|
||||
historyList.search();
|
||||
$('#history-list').slideUp('fast');
|
||||
|
@ -364,7 +367,7 @@ $(".ui-refresh-history").click(function () {
|
|||
|
||||
resetCheckAuth();
|
||||
historyList.clear();
|
||||
parseHistory(historyList, function (list, notehistory) {
|
||||
parseHistory(historyList, (list, notehistory) => {
|
||||
parseHistoryCallback(list, notehistory);
|
||||
$(".ui-use-tags").select2('val', lastTags);
|
||||
$(".ui-use-tags").trigger('change');
|
||||
|
@ -375,16 +378,16 @@ $(".ui-refresh-history").click(function () {
|
|||
});
|
||||
});
|
||||
|
||||
$(".ui-logout").click(function () {
|
||||
$(".ui-logout").click(() => {
|
||||
clearLoginState();
|
||||
location.href = serverurl + '/logout';
|
||||
location.href = `${serverurl}/logout`;
|
||||
});
|
||||
|
||||
var filtertags = [];
|
||||
let filtertags = [];
|
||||
$(".ui-use-tags").select2({
|
||||
placeholder: $(".ui-use-tags").attr('placeholder'),
|
||||
multiple: true,
|
||||
data: function () {
|
||||
data() {
|
||||
return {
|
||||
results: filtertags
|
||||
};
|
||||
|
@ -394,7 +397,7 @@ $('.select2-input').css('width', 'inherit');
|
|||
buildTagsFilter([]);
|
||||
|
||||
function buildTagsFilter(tags) {
|
||||
for (var i = 0; i < tags.length; i++)
|
||||
for (let i = 0; i < tags.length; i++)
|
||||
tags[i] = {
|
||||
id: i,
|
||||
text: S(tags[i]).unescapeHTML().s
|
||||
|
@ -402,17 +405,17 @@ function buildTagsFilter(tags) {
|
|||
filtertags = tags;
|
||||
}
|
||||
$(".ui-use-tags").on('change', function () {
|
||||
var tags = [];
|
||||
var data = $(this).select2('data');
|
||||
for (var i = 0; i < data.length; i++)
|
||||
const tags = [];
|
||||
const data = $(this).select2('data');
|
||||
for (let i = 0; i < data.length; i++)
|
||||
tags.push(data[i].text);
|
||||
if (tags.length > 0) {
|
||||
historyList.filter(function (item) {
|
||||
var values = item.values();
|
||||
historyList.filter(item => {
|
||||
const values = item.values();
|
||||
if (!values.tags) return false;
|
||||
var found = false;
|
||||
for (var i = 0; i < tags.length; i++) {
|
||||
if (values.tags.indexOf(tags[i]) != -1) {
|
||||
let found = false;
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
if (values.tags.includes(tags[i])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -425,6 +428,6 @@ $(".ui-use-tags").on('change', function () {
|
|||
checkHistoryList();
|
||||
});
|
||||
|
||||
$('.search').keyup(function () {
|
||||
$('.search').keyup(() => {
|
||||
checkHistoryList();
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,13 @@
|
|||
var store = require('store');
|
||||
var S = require('string');
|
||||
import store from 'store';
|
||||
import S from 'string';
|
||||
|
||||
var common = require('./common');
|
||||
var checkIfAuth = common.checkIfAuth;
|
||||
var urlpath = common.urlpath;
|
||||
var getLoginState = common.getLoginState;
|
||||
import {
|
||||
checkIfAuth
|
||||
} from './lib/common/login';
|
||||
|
||||
import {
|
||||
urlpath
|
||||
} from './lib/config';
|
||||
|
||||
window.migrateHistoryFromTempCallback = null;
|
||||
|
||||
|
@ -12,22 +15,22 @@ migrateHistoryFromTemp();
|
|||
|
||||
function migrateHistoryFromTemp() {
|
||||
if (url('#tempid')) {
|
||||
$.get(serverurl + '/temp', {
|
||||
$.get(`${serverurl}/temp`, {
|
||||
tempid: url('#tempid')
|
||||
})
|
||||
.done(function (data) {
|
||||
.done(data => {
|
||||
if (data && data.temp) {
|
||||
getStorageHistory(function (olddata) {
|
||||
getStorageHistory(olddata => {
|
||||
if (!olddata || olddata.length == 0) {
|
||||
saveHistoryToStorage(JSON.parse(data.temp));
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.always(function () {
|
||||
var hash = location.hash.split('#')[1];
|
||||
.always(() => {
|
||||
let hash = location.hash.split('#')[1];
|
||||
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) {
|
||||
hash.splice(i, 1);
|
||||
i--;
|
||||
|
@ -40,12 +43,12 @@ function migrateHistoryFromTemp() {
|
|||
}
|
||||
}
|
||||
|
||||
function saveHistory(notehistory) {
|
||||
export function saveHistory(notehistory) {
|
||||
checkIfAuth(
|
||||
function () {
|
||||
() => {
|
||||
saveHistoryToServer(notehistory);
|
||||
},
|
||||
function () {
|
||||
() => {
|
||||
saveHistoryToStorage(notehistory);
|
||||
}
|
||||
);
|
||||
|
@ -65,7 +68,7 @@ function saveHistoryToCookie(notehistory) {
|
|||
}
|
||||
|
||||
function saveHistoryToServer(notehistory) {
|
||||
$.post(serverurl + '/history', {
|
||||
$.post(`${serverurl}/history`, {
|
||||
history: JSON.stringify(notehistory)
|
||||
});
|
||||
}
|
||||
|
@ -75,37 +78,37 @@ function saveCookieHistoryToStorage(callback) {
|
|||
callback();
|
||||
}
|
||||
|
||||
function saveStorageHistoryToServer(callback) {
|
||||
var data = store.get('notehistory');
|
||||
export function saveStorageHistoryToServer(callback) {
|
||||
const data = store.get('notehistory');
|
||||
if (data) {
|
||||
$.post(serverurl + '/history', {
|
||||
$.post(`${serverurl}/history`, {
|
||||
history: data
|
||||
})
|
||||
.done(function (data) {
|
||||
.done(data => {
|
||||
callback(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function saveCookieHistoryToServer(callback) {
|
||||
$.post(serverurl + '/history', {
|
||||
$.post(`${serverurl}/history`, {
|
||||
history: Cookies.get('notehistory')
|
||||
})
|
||||
.done(function (data) {
|
||||
.done(data => {
|
||||
callback(data);
|
||||
});
|
||||
}
|
||||
|
||||
function clearDuplicatedHistory(notehistory) {
|
||||
var newnotehistory = [];
|
||||
for (var i = 0; i < notehistory.length; i++) {
|
||||
var found = false;
|
||||
for (var j = 0; j < newnotehistory.length; j++) {
|
||||
var id = notehistory[i].id.replace(/\=+$/, '');
|
||||
var newId = newnotehistory[j].id.replace(/\=+$/, '');
|
||||
export function clearDuplicatedHistory(notehistory) {
|
||||
const newnotehistory = [];
|
||||
for (let i = 0; i < notehistory.length; i++) {
|
||||
let found = false;
|
||||
for (let j = 0; j < newnotehistory.length; j++) {
|
||||
const id = notehistory[i].id.replace(/\=+$/, '');
|
||||
const newId = newnotehistory[j].id.replace(/\=+$/, '');
|
||||
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'));
|
||||
var newTime = (typeof newnotehistory[i].time === 'number' ? moment(newnotehistory[i].time) : moment(newnotehistory[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'));
|
||||
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) {
|
||||
newnotehistory[j] = notehistory[i];
|
||||
}
|
||||
|
@ -123,42 +126,42 @@ function addHistory(id, text, time, tags, pinned, notehistory) {
|
|||
// only add when note id exists
|
||||
if (id) {
|
||||
notehistory.push({
|
||||
id: id,
|
||||
text: text,
|
||||
time: time,
|
||||
tags: tags,
|
||||
pinned: pinned
|
||||
id,
|
||||
text,
|
||||
time,
|
||||
tags,
|
||||
pinned
|
||||
});
|
||||
}
|
||||
return notehistory;
|
||||
}
|
||||
|
||||
function removeHistory(id, notehistory) {
|
||||
for (var i = 0; i < notehistory.length; i++) {
|
||||
export function removeHistory(id, notehistory) {
|
||||
for (let i = 0; i < notehistory.length; i++) {
|
||||
if (notehistory[i].id == id) {
|
||||
notehistory.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
return notehistory;
|
||||
}
|
||||
|
||||
//used for inner
|
||||
function writeHistory(title, tags) {
|
||||
export function writeHistory(title, tags) {
|
||||
checkIfAuth(
|
||||
function () {
|
||||
() => {
|
||||
// no need to do this anymore, this will count from server-side
|
||||
// writeHistoryToServer(title, tags);
|
||||
},
|
||||
function () {
|
||||
() => {
|
||||
writeHistoryToStorage(title, tags);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function writeHistoryToServer(title, tags) {
|
||||
$.get(serverurl + '/history')
|
||||
.done(function (data) {
|
||||
$.get(`${serverurl}/history`)
|
||||
.done(data => {
|
||||
try {
|
||||
if (data.history) {
|
||||
var notehistory = data.history;
|
||||
|
@ -171,10 +174,10 @@ function writeHistoryToServer(title, tags) {
|
|||
if (!notehistory)
|
||||
notehistory = [];
|
||||
|
||||
var newnotehistory = generateHistory(title, tags, notehistory);
|
||||
const newnotehistory = generateHistory(title, tags, notehistory);
|
||||
saveHistoryToServer(newnotehistory);
|
||||
})
|
||||
.fail(function (xhr, status, error) {
|
||||
.fail((xhr, status, error) => {
|
||||
console.error(xhr.responseText);
|
||||
});
|
||||
}
|
||||
|
@ -188,13 +191,13 @@ function writeHistoryToCookie(title, tags) {
|
|||
if (!notehistory)
|
||||
notehistory = [];
|
||||
|
||||
var newnotehistory = generateHistory(title, tags, notehistory);
|
||||
const newnotehistory = generateHistory(title, tags, notehistory);
|
||||
saveHistoryToCookie(newnotehistory);
|
||||
}
|
||||
|
||||
function writeHistoryToStorage(title, tags) {
|
||||
if (store.enabled) {
|
||||
var data = store.get('notehistory');
|
||||
let data = store.get('notehistory');
|
||||
if (data) {
|
||||
if (typeof data == "string")
|
||||
data = JSON.parse(data);
|
||||
|
@ -204,7 +207,7 @@ function writeHistoryToStorage(title, tags) {
|
|||
if (!notehistory)
|
||||
notehistory = [];
|
||||
|
||||
var newnotehistory = generateHistory(title, tags, notehistory);
|
||||
const newnotehistory = generateHistory(title, tags, notehistory);
|
||||
saveHistoryToStorage(newnotehistory);
|
||||
} else {
|
||||
writeHistoryToCookie(title, tags);
|
||||
|
@ -212,32 +215,30 @@ function writeHistoryToStorage(title, tags) {
|
|||
}
|
||||
|
||||
if (!Array.isArray) {
|
||||
Array.isArray = function(arg) {
|
||||
return Object.prototype.toString.call(arg) === '[object Array]';
|
||||
};
|
||||
Array.isArray = arg => Object.prototype.toString.call(arg) === '[object Array]';
|
||||
}
|
||||
|
||||
function renderHistory(title, 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 {
|
||||
id: id,
|
||||
id,
|
||||
text: title,
|
||||
time: moment().valueOf(),
|
||||
tags: tags
|
||||
tags
|
||||
};
|
||||
}
|
||||
|
||||
function generateHistory(title, tags, notehistory) {
|
||||
var info = renderHistory(title, tags);
|
||||
//keep any pinned data
|
||||
var pinned = false;
|
||||
for (var i = 0; i < notehistory.length; i++) {
|
||||
if (notehistory[i].id == info.id && notehistory[i].pinned) {
|
||||
pinned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const info = renderHistory(title, tags);
|
||||
//keep any pinned data
|
||||
let pinned = false;
|
||||
for (let i = 0; i < notehistory.length; i++) {
|
||||
if (notehistory[i].id == info.id && notehistory[i].pinned) {
|
||||
pinned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
notehistory = removeHistory(info.id, notehistory);
|
||||
notehistory = addHistory(info.id, info.text, info.time, info.tags, pinned, notehistory);
|
||||
notehistory = clearDuplicatedHistory(notehistory);
|
||||
|
@ -245,25 +246,25 @@ function generateHistory(title, tags, notehistory) {
|
|||
}
|
||||
|
||||
//used for outer
|
||||
function getHistory(callback) {
|
||||
export function getHistory(callback) {
|
||||
checkIfAuth(
|
||||
function () {
|
||||
() => {
|
||||
getServerHistory(callback);
|
||||
},
|
||||
function () {
|
||||
() => {
|
||||
getStorageHistory(callback);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getServerHistory(callback) {
|
||||
$.get(serverurl + '/history')
|
||||
.done(function (data) {
|
||||
$.get(`${serverurl}/history`)
|
||||
.done(data => {
|
||||
if (data.history) {
|
||||
callback(data.history);
|
||||
}
|
||||
})
|
||||
.fail(function (xhr, status, error) {
|
||||
.fail((xhr, status, error) => {
|
||||
console.error(xhr.responseText);
|
||||
});
|
||||
}
|
||||
|
@ -272,9 +273,9 @@ function getCookieHistory(callback) {
|
|||
callback(Cookies.getJSON('notehistory'));
|
||||
}
|
||||
|
||||
function getStorageHistory(callback) {
|
||||
export function getStorageHistory(callback) {
|
||||
if (store.enabled) {
|
||||
var data = store.get('notehistory');
|
||||
let data = store.get('notehistory');
|
||||
if (data) {
|
||||
if (typeof data == "string")
|
||||
data = JSON.parse(data);
|
||||
|
@ -286,37 +287,37 @@ function getStorageHistory(callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function parseHistory(list, callback) {
|
||||
export function parseHistory(list, callback) {
|
||||
checkIfAuth(
|
||||
function () {
|
||||
() => {
|
||||
parseServerToHistory(list, callback);
|
||||
},
|
||||
function () {
|
||||
() => {
|
||||
parseStorageToHistory(list, callback);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function parseServerToHistory(list, callback) {
|
||||
$.get(serverurl + '/history')
|
||||
.done(function (data) {
|
||||
export function parseServerToHistory(list, callback) {
|
||||
$.get(`${serverurl}/history`)
|
||||
.done(data => {
|
||||
if (data.history) {
|
||||
parseToHistory(list, data.history, callback);
|
||||
}
|
||||
})
|
||||
.fail(function (xhr, status, error) {
|
||||
.fail((xhr, status, error) => {
|
||||
console.error(xhr.responseText);
|
||||
});
|
||||
}
|
||||
|
||||
function parseCookieToHistory(list, callback) {
|
||||
var notehistory = Cookies.getJSON('notehistory');
|
||||
const notehistory = Cookies.getJSON('notehistory');
|
||||
parseToHistory(list, notehistory, callback);
|
||||
}
|
||||
|
||||
function parseStorageToHistory(list, callback) {
|
||||
export function parseStorageToHistory(list, callback) {
|
||||
if (store.enabled) {
|
||||
var data = store.get('notehistory');
|
||||
let data = store.get('notehistory');
|
||||
if (data) {
|
||||
if (typeof data == "string")
|
||||
data = JSON.parse(data);
|
||||
|
@ -332,9 +333,9 @@ function parseToHistory(list, notehistory, callback) {
|
|||
if (!callback) return;
|
||||
else if (!list || !notehistory) callback(list, notehistory);
|
||||
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
|
||||
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].fromNow = timestamp.fromNow();
|
||||
notehistory[i].time = timestamp.format('llll');
|
||||
|
@ -349,42 +350,23 @@ function parseToHistory(list, notehistory, callback) {
|
|||
callback(list, notehistory);
|
||||
}
|
||||
|
||||
function postHistoryToServer(noteId, data, callback) {
|
||||
$.post(serverurl + '/history/' + noteId, data)
|
||||
.done(function (result) {
|
||||
return callback(null, result);
|
||||
})
|
||||
.fail(function (xhr, status, error) {
|
||||
export function postHistoryToServer(noteId, data, callback) {
|
||||
$.post(`${serverurl}/history/${noteId}`, data)
|
||||
.done(result => callback(null, result))
|
||||
.fail((xhr, status, error) => {
|
||||
console.error(xhr.responseText);
|
||||
return callback(error, null);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteServerHistory(noteId, callback) {
|
||||
export function deleteServerHistory(noteId, callback) {
|
||||
$.ajax({
|
||||
url: serverurl + '/history' + (noteId ? '/' + noteId : ""),
|
||||
url: `${serverurl}/history${noteId ? '/' + noteId : ""}`,
|
||||
type: 'DELETE'
|
||||
})
|
||||
.done(function (result) {
|
||||
return callback(null, result);
|
||||
})
|
||||
.fail(function (xhr, status, error) {
|
||||
.done(result => callback(null, result))
|
||||
.fail((xhr, status, error) => {
|
||||
console.error(xhr.responseText);
|
||||
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 common = require('./common.js');
|
||||
var urlpath = common.urlpath;
|
||||
var noteid = common.noteid;
|
||||
var debug = common.debug;
|
||||
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;
|
||||
import {
|
||||
checkLoginStateChanged,
|
||||
setloginStateChangeEvent
|
||||
} from './lib/common/login';
|
||||
|
||||
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');
|
||||
var md = extra.md;
|
||||
var updateLastChange = extra.updateLastChange;
|
||||
var postProcess = extra.postProcess;
|
||||
var finishView = extra.finishView;
|
||||
var autoLinkify = extra.autoLinkify;
|
||||
var generateToc = extra.generateToc;
|
||||
var smoothHashScroll = extra.smoothHashScroll;
|
||||
var deduplicatedHeaderId = extra.deduplicatedHeaderId;
|
||||
var renderTOC = extra.renderTOC;
|
||||
var renderTitle = extra.renderTitle;
|
||||
var renderFilename = extra.renderFilename;
|
||||
var renderTags = extra.renderTags;
|
||||
var isValidURL = extra.isValidURL;
|
||||
var scrollToHash = extra.scrollToHash;
|
||||
var updateLastChangeUser = extra.updateLastChangeUser;
|
||||
var updateOwner = extra.updateOwner;
|
||||
var parseMeta = extra.parseMeta;
|
||||
var exportToHTML = extra.exportToHTML;
|
||||
var exportToRawHTML = extra.exportToRawHTML;
|
||||
import {
|
||||
autoLinkify,
|
||||
deduplicatedHeaderId,
|
||||
exportToHTML,
|
||||
exportToRawHTML,
|
||||
finishView,
|
||||
generateToc,
|
||||
isValidURL,
|
||||
md,
|
||||
parseMeta,
|
||||
postProcess,
|
||||
renderFilename,
|
||||
renderTOC,
|
||||
renderTags,
|
||||
renderTitle,
|
||||
scrollToHash,
|
||||
smoothHashScroll,
|
||||
updateLastChange,
|
||||
updateLastChangeUser,
|
||||
updateOwner
|
||||
} from './extra';
|
||||
|
||||
var syncScroll = require('./syncscroll');
|
||||
var setupSyncAreas = syncScroll.setupSyncAreas;
|
||||
var clearMap = syncScroll.clearMap;
|
||||
var syncScrollToEdit = syncScroll.syncScrollToEdit;
|
||||
var syncScrollToView = syncScroll.syncScrollToView;
|
||||
import {
|
||||
clearMap,
|
||||
setupSyncAreas,
|
||||
syncScrollToEdit,
|
||||
syncScrollToView
|
||||
} from './syncscroll';
|
||||
|
||||
var historyModule = require('./history');
|
||||
var writeHistory = historyModule.writeHistory;
|
||||
var deleteServerHistory = historyModule.deleteServerHistory;
|
||||
var getHistory = historyModule.getHistory;
|
||||
var saveHistory = historyModule.saveHistory;
|
||||
var removeHistory = historyModule.removeHistory;
|
||||
import {
|
||||
writeHistory,
|
||||
deleteServerHistory,
|
||||
getHistory,
|
||||
saveHistory,
|
||||
removeHistory
|
||||
} from './history';
|
||||
|
||||
var renderer = require('./render');
|
||||
var preventXSS = renderer.preventXSS;
|
||||
|
@ -963,10 +970,10 @@ function setNeedRefresh() {
|
|||
showStatus(statusType.offline);
|
||||
}
|
||||
|
||||
loginStateChangeEvent = function () {
|
||||
setloginStateChangeEvent(function () {
|
||||
setRefreshModal('user-state-changed');
|
||||
setNeedRefresh();
|
||||
};
|
||||
});
|
||||
|
||||
//visibility
|
||||
var wasFocus = false;
|
||||
|
@ -3717,6 +3724,7 @@ function checkCursorMenuInner() {
|
|||
var offsetLeft = 0;
|
||||
var offsetTop = defaultTextHeight;
|
||||
// set up side down
|
||||
window.upSideDown = false;
|
||||
var lastUpSideDown = upSideDown = false;
|
||||
// only do when have width and height
|
||||
if (width > 0 && height > 0) {
|
||||
|
|
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,32 +4,34 @@ require('../css/site.css');
|
|||
|
||||
require('highlight.js/styles/github-gist.css');
|
||||
|
||||
var extra = require('./extra');
|
||||
var md = extra.md;
|
||||
var finishView = extra.finishView;
|
||||
var autoLinkify = extra.autoLinkify;
|
||||
var deduplicatedHeaderId = extra.deduplicatedHeaderId;
|
||||
var renderTOC = extra.renderTOC;
|
||||
var generateToc = extra.generateToc;
|
||||
var smoothHashScroll = extra.smoothHashScroll;
|
||||
var postProcess = extra.postProcess;
|
||||
var updateLastChange = extra.updateLastChange;
|
||||
var parseMeta = extra.parseMeta;
|
||||
var scrollToHash = extra.scrollToHash;
|
||||
var preventXSS = require('./render').preventXSS;
|
||||
import {
|
||||
autoLinkify,
|
||||
deduplicatedHeaderId,
|
||||
finishView,
|
||||
generateToc,
|
||||
md,
|
||||
parseMeta,
|
||||
postProcess,
|
||||
renderTOC,
|
||||
scrollToHash,
|
||||
smoothHashScroll,
|
||||
updateLastChange
|
||||
} from './extra';
|
||||
|
||||
var markdown = $("#doc.markdown-body");
|
||||
var text = markdown.text();
|
||||
var lastMeta = md.meta;
|
||||
import { preventXSS } from './render';
|
||||
|
||||
const markdown = $("#doc.markdown-body");
|
||||
const text = markdown.text();
|
||||
const lastMeta = md.meta;
|
||||
md.meta = {};
|
||||
delete md.metaError;
|
||||
var rendered = md.render(text);
|
||||
let rendered = md.render(text);
|
||||
if (md.meta.type && md.meta.type === 'slide') {
|
||||
var slideOptions = {
|
||||
const slideOptions = {
|
||||
separator: '^(\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);
|
||||
RevealMarkdown.initialize();
|
||||
// prevent XSS
|
||||
|
@ -47,10 +49,11 @@ if (md.meta.type && md.meta.type === 'slide') {
|
|||
}
|
||||
// prevent XSS
|
||||
rendered = preventXSS(rendered);
|
||||
var result = postProcess(rendered);
|
||||
const result = postProcess(rendered);
|
||||
markdown.html(result.html());
|
||||
}
|
||||
$(document.body).show();
|
||||
|
||||
finishView(markdown);
|
||||
autoLinkify(markdown);
|
||||
deduplicatedHeaderId(markdown);
|
||||
|
@ -61,17 +64,18 @@ smoothHashScroll();
|
|||
createtime = lastchangeui.time.attr('data-createtime');
|
||||
lastchangetime = lastchangeui.time.attr('data-updatetime');
|
||||
updateLastChange();
|
||||
var url = window.location.pathname;
|
||||
$('.ui-edit').attr('href', url + '/edit');
|
||||
var toc = $('.ui-toc');
|
||||
var tocAffix = $('.ui-affix-toc');
|
||||
var tocDropdown = $('.ui-toc-dropdown');
|
||||
|
||||
const url = window.location.pathname;
|
||||
$('.ui-edit').attr('href', `${url}/edit`);
|
||||
const toc = $('.ui-toc');
|
||||
const tocAffix = $('.ui-affix-toc');
|
||||
const tocDropdown = $('.ui-toc-dropdown');
|
||||
//toc
|
||||
tocDropdown.click(function (e) {
|
||||
tocDropdown.click(e => {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
var enoughForAffixToc = true;
|
||||
let enoughForAffixToc = true;
|
||||
|
||||
function generateScrollspy() {
|
||||
$(document.body).scrollspy({
|
||||
|
@ -90,18 +94,18 @@ function generateScrollspy() {
|
|||
|
||||
function windowResize() {
|
||||
//toc right
|
||||
var paddingRight = parseFloat(markdown.css('padding-right'));
|
||||
var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
|
||||
toc.css('right', right + 'px');
|
||||
const paddingRight = parseFloat(markdown.css('padding-right'));
|
||||
const right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
|
||||
toc.css('right', `${right}px`);
|
||||
//affix toc left
|
||||
var newbool;
|
||||
var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
|
||||
let newbool;
|
||||
const rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
|
||||
//for ipad or wider device
|
||||
if (rightMargin >= 133) {
|
||||
newbool = true;
|
||||
var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
|
||||
var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
|
||||
tocAffix.css('left', left + 'px');
|
||||
const affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
|
||||
const left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
|
||||
tocAffix.css('left', `${left}px`);
|
||||
} else {
|
||||
newbool = false;
|
||||
}
|
||||
|
@ -110,10 +114,10 @@ function windowResize() {
|
|||
generateScrollspy();
|
||||
}
|
||||
}
|
||||
$(window).resize(function () {
|
||||
$(window).resize(() => {
|
||||
windowResize();
|
||||
});
|
||||
$(document).ready(function () {
|
||||
$(document).ready(() => {
|
||||
windowResize();
|
||||
generateScrollspy();
|
||||
setTimeout(scrollToHash, 0);
|
||||
|
@ -121,13 +125,13 @@ $(document).ready(function () {
|
|||
$('[data-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
|
||||
function scrollToTop() {
|
||||
export function scrollToTop() {
|
||||
$('body, html').stop(true, true).animate({
|
||||
scrollTop: 0
|
||||
}, 100, "linear");
|
||||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
export function scrollToBottom() {
|
||||
$('body, html').stop(true, true).animate({
|
||||
scrollTop: $(document.body)[0].scrollHeight
|
||||
}, 100, "linear");
|
||||
|
@ -135,8 +139,3 @@ function scrollToBottom() {
|
|||
|
||||
window.scrollToTop = scrollToTop;
|
||||
window.scrollToBottom = scrollToBottom;
|
||||
|
||||
module.exports = {
|
||||
scrollToBottom: scrollToBottom,
|
||||
scrollToTop: scrollToTop
|
||||
}
|
||||
|
|
|
@ -1,67 +1,65 @@
|
|||
require('../css/extra.css');
|
||||
require('../css/site.css');
|
||||
|
||||
var extraModule = require('./extra');
|
||||
var md = extraModule.md;
|
||||
var updateLastChange = extraModule.updateLastChange;
|
||||
var finishView = extraModule.finishView;
|
||||
import { md, updateLastChange, finishView } from './extra';
|
||||
|
||||
var preventXSS = require('./render').preventXSS;
|
||||
import { preventXSS } from './render';
|
||||
|
||||
var body = $(".slides").text();
|
||||
const body = $(".slides").text();
|
||||
|
||||
createtime = lastchangeui.time.attr('data-createtime');
|
||||
lastchangetime = lastchangeui.time.attr('data-updatetime');
|
||||
updateLastChange();
|
||||
var url = window.location.pathname;
|
||||
$('.ui-edit').attr('href', url + '/edit');
|
||||
const url = window.location.pathname;
|
||||
$('.ui-edit').attr('href', `${url}/edit`);
|
||||
|
||||
$(document).ready(function () {
|
||||
$(document).ready(() => {
|
||||
//tooltip
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
|
||||
function extend() {
|
||||
var target = {};
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var source = arguments[i];
|
||||
for (var key in source) {
|
||||
const target = {};
|
||||
|
||||
for (const source of arguments) {
|
||||
for (const key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Optional libraries used to extend on reveal.js
|
||||
var deps = [{
|
||||
src: serverurl + '/build/reveal.js/lib/js/classList.js',
|
||||
condition: function() {
|
||||
const deps = [{
|
||||
src: `${serverurl}/build/reveal.js/lib/js/classList.js`,
|
||||
condition() {
|
||||
return !document.body.classList;
|
||||
}
|
||||
}, {
|
||||
src: serverurl + '/js/reveal-markdown.js',
|
||||
callback: function () {
|
||||
var slideOptions = {
|
||||
src: `${serverurl}/js/reveal-markdown.js`,
|
||||
callback() {
|
||||
const slideOptions = {
|
||||
separator: '^(\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);
|
||||
RevealMarkdown.initialize();
|
||||
$(".slides").show();
|
||||
}
|
||||
}, {
|
||||
src: serverurl + '/build/reveal.js/plugin/notes/notes.js',
|
||||
src: `${serverurl}/build/reveal.js/plugin/notes/notes.js`,
|
||||
async: true,
|
||||
condition: function() {
|
||||
condition() {
|
||||
return !!document.body.classList;
|
||||
}
|
||||
}];
|
||||
|
||||
// default options to init reveal.js
|
||||
var defaultOptions = {
|
||||
const defaultOptions = {
|
||||
controls: true,
|
||||
progress: true,
|
||||
slideNumber: true,
|
||||
|
@ -72,10 +70,10 @@ var defaultOptions = {
|
|||
};
|
||||
|
||||
// options from yaml meta
|
||||
var meta = JSON.parse($("#meta").text());
|
||||
const meta = JSON.parse($("#meta").text());
|
||||
var options = meta.slideOptions || {};
|
||||
|
||||
var view = $('.reveal');
|
||||
const view = $('.reveal');
|
||||
|
||||
//text language
|
||||
if (meta.lang && typeof meta.lang == "string") {
|
||||
|
@ -97,24 +95,24 @@ if (typeof meta.breaks === 'boolean' && !meta.breaks) {
|
|||
}
|
||||
|
||||
// options from URL query string
|
||||
var queryOptions = Reveal.getQueryHash() || {};
|
||||
const queryOptions = Reveal.getQueryHash() || {};
|
||||
|
||||
var options = extend(defaultOptions, options, queryOptions);
|
||||
Reveal.initialize(options);
|
||||
|
||||
window.viewAjaxCallback = function () {
|
||||
window.viewAjaxCallback = () => {
|
||||
Reveal.layout();
|
||||
};
|
||||
|
||||
function renderSlide(event) {
|
||||
if (window.location.search.match( /print-pdf/gi )) {
|
||||
var slides = $('.slides');
|
||||
const slides = $('.slides');
|
||||
var title = document.title;
|
||||
finishView(slides);
|
||||
document.title = title;
|
||||
Reveal.layout();
|
||||
} else {
|
||||
var markdown = $(event.currentSlide);
|
||||
const markdown = $(event.currentSlide);
|
||||
if (!markdown.attr('data-rendered')) {
|
||||
var title = document.title;
|
||||
finishView(markdown);
|
||||
|
@ -125,16 +123,16 @@ function renderSlide(event) {
|
|||
}
|
||||
}
|
||||
|
||||
Reveal.addEventListener('ready', function (event) {
|
||||
Reveal.addEventListener('ready', event => {
|
||||
renderSlide(event);
|
||||
var markdown = $(event.currentSlide);
|
||||
const markdown = $(event.currentSlide);
|
||||
// force browser redraw
|
||||
setTimeout(function () {
|
||||
setTimeout(() => {
|
||||
markdown.hide().show(0);
|
||||
}, 0);
|
||||
});
|
||||
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');
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
// Inject line numbers for sync scroll.
|
||||
|
||||
var extra = require('./extra');
|
||||
var md = extra.md;
|
||||
import markdownitContainer from 'markdown-it-container';
|
||||
|
||||
import { md } from './extra';
|
||||
|
||||
function addPart(tokens, idx) {
|
||||
if (tokens[idx].map && tokens[idx].level === 0) {
|
||||
var startline = tokens[idx].map[0] + 1;
|
||||
var endline = tokens[idx].map[1];
|
||||
const startline = tokens[idx].map[0] + 1;
|
||||
const endline = tokens[idx].map[1];
|
||||
tokens[idx].attrJoin('class', 'part');
|
||||
tokens[idx].attrJoin('data-startline', startline);
|
||||
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) {
|
||||
tokens[idx].attrJoin('class', 'raw');
|
||||
addPart(tokens, idx);
|
||||
return self.renderToken.apply(self, arguments);
|
||||
return self.renderToken(...arguments);
|
||||
};
|
||||
md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
|
||||
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) {
|
||||
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) {
|
||||
tokens[idx].attrJoin('class', 'raw');
|
||||
if (tokens[idx].map) {
|
||||
var startline = tokens[idx].map[0] + 1;
|
||||
var endline = tokens[idx].map[1];
|
||||
const startline = tokens[idx].map[0] + 1;
|
||||
const endline = tokens[idx].map[1];
|
||||
tokens[idx].attrJoin('data-startline', startline);
|
||||
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) {
|
||||
addPart(tokens, idx);
|
||||
return self.renderToken.apply(self, arguments);
|
||||
return self.renderToken(...arguments);
|
||||
};
|
||||
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
||||
addPart(tokens, idx);
|
||||
return self.renderToken.apply(self, arguments);
|
||||
return self.renderToken(...arguments);
|
||||
};
|
||||
md.renderer.rules.paragraph_open = function (tokens, idx, options, env, self) {
|
||||
addPart(tokens, idx);
|
||||
return self.renderToken.apply(self, arguments);
|
||||
return self.renderToken(...arguments);
|
||||
};
|
||||
md.renderer.rules.heading_open = function (tokens, idx, options, env, self) {
|
||||
tokens[idx].attrJoin('class', 'raw');
|
||||
addPart(tokens, idx);
|
||||
return self.renderToken.apply(self, arguments);
|
||||
return self.renderToken(...arguments);
|
||||
};
|
||||
md.renderer.rules.fence = function (tokens, idx, options, env, self) {
|
||||
var token = tokens[idx],
|
||||
info = token.info ? md.utils.unescapeAll(token.info).trim() : '',
|
||||
langName = '',
|
||||
highlighted;
|
||||
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
|
||||
const token = tokens[idx];
|
||||
const info = token.info ? md.utils.unescapeAll(token.info).trim() : '';
|
||||
let langName = '';
|
||||
let highlighted;
|
||||
|
||||
if (info) {
|
||||
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) {
|
||||
return highlighted + '\n';
|
||||
return `${highlighted}\n`;
|
||||
}
|
||||
|
||||
if (tokens[idx].map && tokens[idx].level === 0) {
|
||||
var startline = tokens[idx].map[0] + 1;
|
||||
var endline = tokens[idx].map[1];
|
||||
return '<pre class="part" data-startline="' + startline + '" data-endline="' + endline + '"><code' + self.renderAttrs(token) + '>'
|
||||
+ highlighted
|
||||
+ '</code></pre>\n';
|
||||
const startline = tokens[idx].map[0] + 1;
|
||||
const endline = tokens[idx].map[1];
|
||||
return `<pre class="part" data-startline="${startline}" data-endline="${endline}"><code${self.renderAttrs(token)}>${highlighted}</code></pre>\n`;
|
||||
}
|
||||
|
||||
return '<pre><code' + self.renderAttrs(token) + '>'
|
||||
+ highlighted
|
||||
+ '</code></pre>\n';
|
||||
return `<pre><code${self.renderAttrs(token)}>${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) {
|
||||
var startline = tokens[idx].map[0] + 1;
|
||||
var 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';
|
||||
const startline = tokens[idx].map[0] + 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><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) {
|
||||
tokens[idx].attrJoin('role', '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);
|
||||
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, 'info', { render: renderContainer });
|
||||
md.use(markdownitContainer, 'warning', { render: renderContainer });
|
||||
|
@ -117,18 +113,18 @@ window.syncscroll = true;
|
|||
window.preventSyncScrollToEdit = false;
|
||||
window.preventSyncScrollToView = false;
|
||||
|
||||
var editScrollThrottle = 5;
|
||||
var viewScrollThrottle = 5;
|
||||
var buildMapThrottle = 100;
|
||||
const editScrollThrottle = 5;
|
||||
const viewScrollThrottle = 5;
|
||||
const buildMapThrottle = 100;
|
||||
|
||||
var viewScrolling = false;
|
||||
var editScrolling = false;
|
||||
let viewScrolling = false;
|
||||
let editScrolling = false;
|
||||
|
||||
var editArea = null;
|
||||
var viewArea = null;
|
||||
var markdownArea = null;
|
||||
let editArea = null;
|
||||
let viewArea = null;
|
||||
let markdownArea = null;
|
||||
|
||||
function setupSyncAreas(edit, view, markdown) {
|
||||
export function setupSyncAreas(edit, view, markdown) {
|
||||
editArea = edit;
|
||||
viewArea = view;
|
||||
markdownArea = markdown;
|
||||
|
@ -136,26 +132,24 @@ function setupSyncAreas(edit, view, markdown) {
|
|||
viewArea.on('scroll', _.throttle(syncScrollToEdit, viewScrollThrottle));
|
||||
}
|
||||
|
||||
var scrollMap, lineHeightMap, viewTop, viewBottom;
|
||||
let scrollMap, lineHeightMap, viewTop, viewBottom;
|
||||
|
||||
window.viewAjaxCallback = clearMap;
|
||||
|
||||
function clearMap() {
|
||||
export function clearMap() {
|
||||
scrollMap = null;
|
||||
lineHeightMap = null;
|
||||
viewTop = 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)
|
||||
// That's a bit dirty to process each line everytime, but ok for demo.
|
||||
// Optimizations are required only for big texts.
|
||||
function buildMapInner(callback) {
|
||||
if (!viewArea || !markdownArea) return;
|
||||
var i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount,
|
||||
acc, _scrollMap;
|
||||
let i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount, acc, _scrollMap;
|
||||
|
||||
offset = viewArea.scrollTop() - viewArea.offset().top;
|
||||
_scrollMap = [];
|
||||
|
@ -165,10 +159,10 @@ function buildMapInner(callback) {
|
|||
viewBottom = viewArea[0].scrollHeight - viewArea.height();
|
||||
|
||||
acc = 0;
|
||||
var lines = editor.getValue().split('\n');
|
||||
var lineHeight = editor.defaultTextHeight();
|
||||
const lines = editor.getValue().split('\n');
|
||||
const lineHeight = editor.defaultTextHeight();
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
var str = lines[i];
|
||||
const str = lines[i];
|
||||
|
||||
_lineHeightMap.push(acc);
|
||||
|
||||
|
@ -177,7 +171,7 @@ function buildMapInner(callback) {
|
|||
continue;
|
||||
}
|
||||
|
||||
var h = editor.heightAtLine(i + 1) - editor.heightAtLine(i);
|
||||
const h = editor.heightAtLine(i + 1) - editor.heightAtLine(i);
|
||||
acc += Math.round(h / lineHeight);
|
||||
}
|
||||
_lineHeightMap.push(acc);
|
||||
|
@ -191,10 +185,10 @@ function buildMapInner(callback) {
|
|||
// make the first line go top
|
||||
_scrollMap[0] = viewTop;
|
||||
|
||||
var parts = markdownArea.find('.part').toArray();
|
||||
const parts = markdownArea.find('.part').toArray();
|
||||
for (i = 0; i < parts.length; i++) {
|
||||
var $el = $(parts[i]),
|
||||
t = $el.attr('data-startline') - 1;
|
||||
const $el = $(parts[i]);
|
||||
let t = $el.attr('data-startline') - 1;
|
||||
if (t === '') {
|
||||
return;
|
||||
}
|
||||
|
@ -229,9 +223,9 @@ function buildMapInner(callback) {
|
|||
}
|
||||
|
||||
// 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 (preventSyncScrollToEdit) {
|
||||
if (typeof preventSyncScrollToEdit === 'number') {
|
||||
|
@ -242,15 +236,15 @@ function syncScrollToEdit(event, preventAnimate) {
|
|||
return;
|
||||
}
|
||||
if (!scrollMap || !lineHeightMap) {
|
||||
buildMap(function () {
|
||||
buildMap(() => {
|
||||
syncScrollToEdit(event, preventAnimate);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (editScrolling) return;
|
||||
|
||||
var scrollTop = viewArea[0].scrollTop;
|
||||
var lineIndex = 0;
|
||||
const scrollTop = viewArea[0].scrollTop;
|
||||
let lineIndex = 0;
|
||||
for (var i = 0, l = scrollMap.length; i < l; i++) {
|
||||
if (scrollMap[i] > scrollTop) {
|
||||
break;
|
||||
|
@ -258,8 +252,8 @@ function syncScrollToEdit(event, preventAnimate) {
|
|||
lineIndex = i;
|
||||
}
|
||||
}
|
||||
var lineNo = 0;
|
||||
var lineDiff = 0;
|
||||
let lineNo = 0;
|
||||
let lineDiff = 0;
|
||||
for (var i = 0, l = lineHeightMap.length; i < l; i++) {
|
||||
if (lineHeightMap[i] > lineIndex) {
|
||||
break;
|
||||
|
@ -269,14 +263,14 @@ function syncScrollToEdit(event, preventAnimate) {
|
|||
}
|
||||
}
|
||||
|
||||
var posTo = 0;
|
||||
var topDiffPercent = 0;
|
||||
var posToNextDiff = 0;
|
||||
var scrollInfo = editor.getScrollInfo();
|
||||
var textHeight = editor.defaultTextHeight();
|
||||
var preLastLineHeight = scrollInfo.height - scrollInfo.clientHeight - textHeight;
|
||||
var preLastLineNo = Math.round(preLastLineHeight / textHeight);
|
||||
var preLastLinePos = scrollMap[preLastLineNo];
|
||||
let posTo = 0;
|
||||
let topDiffPercent = 0;
|
||||
let posToNextDiff = 0;
|
||||
const scrollInfo = editor.getScrollInfo();
|
||||
const textHeight = editor.defaultTextHeight();
|
||||
const preLastLineHeight = scrollInfo.height - scrollInfo.clientHeight - textHeight;
|
||||
const preLastLineNo = Math.round(preLastLineHeight / textHeight);
|
||||
const preLastLinePos = scrollMap[preLastLineNo];
|
||||
|
||||
if (scrollInfo.height > scrollInfo.clientHeight && scrollTop >= preLastLinePos) {
|
||||
posTo = preLastLineHeight;
|
||||
|
@ -293,7 +287,7 @@ function syncScrollToEdit(event, preventAnimate) {
|
|||
if (preventAnimate) {
|
||||
editArea.scrollTop(posTo);
|
||||
} else {
|
||||
var posDiff = Math.abs(scrollInfo.top - posTo);
|
||||
const posDiff = Math.abs(scrollInfo.top - posTo);
|
||||
var duration = posDiff / 50;
|
||||
duration = duration >= 100 ? duration : 100;
|
||||
editArea.stop(true, true).animate({
|
||||
|
@ -311,9 +305,9 @@ function viewScrollingTimeoutInner() {
|
|||
}
|
||||
|
||||
// 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 (preventSyncScrollToView) {
|
||||
if (typeof preventSyncScrollToView === 'number') {
|
||||
|
@ -324,20 +318,20 @@ function syncScrollToView(event, preventAnimate) {
|
|||
return;
|
||||
}
|
||||
if (!scrollMap || !lineHeightMap) {
|
||||
buildMap(function () {
|
||||
buildMap(() => {
|
||||
syncScrollToView(event, preventAnimate);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (viewScrolling) return;
|
||||
|
||||
var lineNo, posTo;
|
||||
var topDiffPercent, posToNextDiff;
|
||||
var scrollInfo = editor.getScrollInfo();
|
||||
var textHeight = editor.defaultTextHeight();
|
||||
let lineNo, posTo;
|
||||
let topDiffPercent, posToNextDiff;
|
||||
const scrollInfo = editor.getScrollInfo();
|
||||
const textHeight = editor.defaultTextHeight();
|
||||
lineNo = Math.floor(scrollInfo.top / textHeight);
|
||||
// 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) {
|
||||
topDiffPercent = diffToBottom / textHeight;
|
||||
posTo = scrollMap[lineNo + 1];
|
||||
|
@ -353,7 +347,7 @@ function syncScrollToView(event, preventAnimate) {
|
|||
if (preventAnimate) {
|
||||
viewArea.scrollTop(posTo);
|
||||
} else {
|
||||
var posDiff = Math.abs(viewArea.scrollTop() - posTo);
|
||||
const posDiff = Math.abs(viewArea.scrollTop() - posTo);
|
||||
var duration = posDiff / 50;
|
||||
duration = duration >= 100 ? duration : 100;
|
||||
viewArea.stop(true, true).animate({
|
||||
|
@ -369,10 +363,3 @@ function syncScrollToView(event, preventAnimate) {
|
|||
function editScrollingTimeoutInner() {
|
||||
editScrolling = false;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setupSyncAreas: setupSyncAreas,
|
||||
clearMap: clearMap,
|
||||
syncScrollToEdit: syncScrollToEdit,
|
||||
syncScrollToView: syncScrollToView
|
||||
};
|
||||
|
|
|
@ -372,6 +372,10 @@ module.exports = {
|
|||
loaders: [{
|
||||
test: /\.json$/,
|
||||
loader: 'json-loader'
|
||||
}, {
|
||||
test: /\.js$/,
|
||||
loader: 'babel',
|
||||
exclude: [/node_modules/, /public\/vendor/]
|
||||
}, {
|
||||
test: /\.css$/,
|
||||
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
|
||||
|
|
Loading…
Reference in a new issue