From d6ae7a36aeef3b5c261bb521f5e3f48898b65ede Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 24 Dec 2016 11:09:07 +0800 Subject: [PATCH 01/71] Fix module variable require --- public/js/cover.js | 1 + public/js/index.js | 1 + 2 files changed, 2 insertions(+) diff --git a/public/js/cover.js b/public/js/cover.js index 2f35bd2..ee7d75e 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -9,6 +9,7 @@ var urlpath = common.urlpath; var resetCheckAuth = common.resetCheckAuth; var getLoginState = common.getLoginState; var clearLoginState = common.clearLoginState; +var loginStateChangeEvent = common.loginStateChangeEvent; var historyModule = require('./history'); var parseStorageToHistory = historyModule.parseStorageToHistory; diff --git a/public/js/index.js b/public/js/index.js index 96580fe..4a46624 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -29,6 +29,7 @@ var DROPBOX_APP_KEY = common.DROPBOX_APP_KEY; var noteurl = common.noteurl; var checkLoginStateChanged = common.checkLoginStateChanged; +var loginStateChangeEvent = common.loginStateChangeEvent; var extra = require('./extra'); var md = extra.md; From a06fad974e66c8c5854985fe12fbadbb43cc9c7e Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 24 Dec 2016 11:10:18 +0800 Subject: [PATCH 02/71] Install vue and babel dependency --- .babelrc | 8 ++++++++ package.json | 7 +++++++ public/js/cover.js | 2 ++ webpackBaseConfig.js | 4 ++++ 4 files changed, 21 insertions(+) create mode 100644 .babelrc diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..cbd3ac6 --- /dev/null +++ b/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "transform-runtime" + ] +} diff --git a/package.json b/package.json index 7c2441b..5ac7f55 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,7 @@ "velocity-animate": "^1.4.0", "visibilityjs": "^1.2.4", "viz.js": "^1.4.1", + "vue": "^2.1.6", "winston": "^2.3.0", "xss": "^0.3.2" }, @@ -139,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", diff --git a/public/js/cover.js b/public/js/cover.js index ee7d75e..4696203 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -28,6 +28,8 @@ var saveAs = require('file-saver').saveAs; var List = require('list.js'); var S = require('string'); +import Vue from 'vue'; + var options = { valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'], item: '
  • \ diff --git a/webpackBaseConfig.js b/webpackBaseConfig.js index 400db14..5c715cc 100644 --- a/webpackBaseConfig.js +++ b/webpackBaseConfig.js @@ -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') From 99dd10772422b66b7f98f1483b5fa3225e3e86e0 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 24 Dec 2016 11:50:57 +0800 Subject: [PATCH 03/71] Basic setup for Vue app --- .editorconfig | 4 ++++ package.json | 2 ++ public/js/components/HelloWorld.vue | 21 +++++++++++++++++++++ public/js/cover.js | 6 ++++++ public/js/views/Cover.vue | 15 +++++++++++++++ public/views/index.ejs | 1 + webpackBaseConfig.js | 8 +++++++- 7 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 public/js/components/HelloWorld.vue create mode 100644 public/js/views/Cover.vue diff --git a/.editorconfig b/.editorconfig index 619c178..b3e3025 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,10 @@ indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true +[*.vue] +indent_style = space +indent_size = 2 + [*.md] trim_trailing_whitespace = false diff --git a/package.json b/package.json index 5ac7f55..d44313c 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,7 @@ "visibilityjs": "^1.2.4", "viz.js": "^1.4.1", "vue": "^2.1.6", + "vue-loader": "^10.0.2", "winston": "^2.3.0", "xss": "^0.3.2" }, @@ -162,6 +163,7 @@ "script-loader": "^0.7.0", "style-loader": "^0.13.1", "url-loader": "^0.5.7", + "vue-template-compiler": "^2.1.6", "webpack": "^1.14.0" } } diff --git a/public/js/components/HelloWorld.vue b/public/js/components/HelloWorld.vue new file mode 100644 index 0000000..d8e3007 --- /dev/null +++ b/public/js/components/HelloWorld.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/public/js/cover.js b/public/js/cover.js index 4696203..b888684 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -28,8 +28,14 @@ var saveAs = require('file-saver').saveAs; var List = require('list.js'); var S = require('string'); +import Cover from './views/Cover'; import Vue from 'vue'; +new Vue({ + el: '#cover-app', + render: (h) => h(Cover) +}) + var options = { valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'], item: '
  • \ diff --git a/public/js/views/Cover.vue b/public/js/views/Cover.vue new file mode 100644 index 0000000..767d087 --- /dev/null +++ b/public/js/views/Cover.vue @@ -0,0 +1,15 @@ + + + diff --git a/public/views/index.ejs b/public/views/index.ejs index adcdd34..5b84f4f 100644 --- a/public/views/index.ejs +++ b/public/views/index.ejs @@ -30,6 +30,7 @@
    +
    diff --git a/webpackBaseConfig.js b/webpackBaseConfig.js index 5c715cc..6c569c1 100644 --- a/webpackBaseConfig.js +++ b/webpackBaseConfig.js @@ -338,7 +338,7 @@ module.exports = { path.resolve(__dirname, 'src'), path.resolve(__dirname, 'node_modules') ], - extensions: ["", ".js"], + extensions: ["", ".js", ".vue"], alias: { codemirror: path.join(__dirname, 'node_modules/codemirror/codemirror.min.js'), inlineAttachment: path.join(__dirname, 'public/vendor/inlineAttachment/inline-attachment.js'), @@ -372,6 +372,12 @@ module.exports = { loaders: [{ test: /\.json$/, loader: 'json-loader' + }, { + test: /\.vue$/, + loader: 'vue', + options: { + // vue-loader options go here + } }, { test: /\.js$/, loader: 'babel', From 78c51e5e88bcd4a3d53a87a53f8dc85d9a5a2df4 Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Wed, 4 Jan 2017 14:27:38 +0800 Subject: [PATCH 04/71] Revert "Rename npm script" This reverts commit ed83dfc862768572eab0c2aed629b1700ac9e224. --- README.md | 2 +- bin/heroku | 2 +- package.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a2980ee..cc05872 100644 --- a/README.md +++ b/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 diff --git a/bin/heroku b/bin/heroku index 6ee7fa4..e801003 100755 --- a/bin/heroku +++ b/bin/heroku @@ -31,5 +31,5 @@ EOF cp public/js/config.js.example public/js/config.js # build app - npm run build:prod + npm run build fi diff --git a/package.json b/package.json index edf0364..dde6328 100644 --- a/package.json +++ b/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" }, From 781f495f3e04b863be58226b5af8e6ab94d9355a Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Wed, 4 Jan 2017 23:01:44 +0800 Subject: [PATCH 05/71] Convert synscroll to es6 --- public/js/index.js | 12 +-- public/js/syncscroll.js | 169 +++++++++++++++++++--------------------- 2 files changed, 85 insertions(+), 96 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index 8921eda..46dfffd 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -51,11 +51,12 @@ var parseMeta = extra.parseMeta; var exportToHTML = extra.exportToHTML; var exportToRawHTML = extra.exportToRawHTML; -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; @@ -3693,6 +3694,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) { diff --git a/public/js/syncscroll.js b/public/js/syncscroll.js index 47d0e1c..c969317 100644 --- a/public/js/syncscroll.js +++ b/public/js/syncscroll.js @@ -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('' - + highlighted - + '\n'; + const startline = tokens[idx].map[0] + 1; + const endline = tokens[idx].map[1]; + return `
    ${highlighted}
    \n`; } - return '
    '
    -        + highlighted
    -        + '
    \n'; + return `
    ${highlighted}
    \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 '
    ' + md.utils.escapeHtml(tokens[idx].content) + '
    \n'; + const startline = tokens[idx].map[0] + 1; + const endline = tokens[idx].map[1]; + return `
    ${md.utils.escapeHtml(tokens[idx].content)}
    \n`; } - return '
    ' + md.utils.escapeHtml(tokens[idx].content) + '
    \n'; + return `
    ${md.utils.escapeHtml(tokens[idx].content)}
    \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 -}; From eb5e7ba0d10cf559d73335102513b4c5783e239b Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Thu, 5 Jan 2017 16:17:28 +0800 Subject: [PATCH 06/71] Convert slide.js to es6 --- public/js/slide.js | 64 ++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/public/js/slide.js b/public/js/slide.js index 1ff388a..63cf64c 100644 --- a/public/js/slide.js +++ b/public/js/slide.js @@ -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'); From 45c202172ed293564925d10782ea65d415cb513c Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Thu, 5 Jan 2017 16:19:13 +0800 Subject: [PATCH 07/71] Convert pretty.js to es6 --- public/js/pretty.js | 87 ++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/public/js/pretty.js b/public/js/pretty.js index c1a471a..64d41c4 100644 --- a/public/js/pretty.js +++ b/public/js/pretty.js @@ -4,31 +4,33 @@ 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 = {}; -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 @@ -46,10 +48,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); @@ -60,17 +63,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({ @@ -89,18 +93,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; } @@ -109,10 +113,10 @@ function windowResize() { generateScrollspy(); } } -$(window).resize(function () { +$(window).resize(() => { windowResize(); }); -$(document).ready(function () { +$(document).ready(() => { windowResize(); generateScrollspy(); setTimeout(scrollToHash, 0); @@ -120,13 +124,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"); @@ -134,8 +138,3 @@ function scrollToBottom() { window.scrollToTop = scrollToTop; window.scrollToBottom = scrollToBottom; - -module.exports = { - scrollToBottom: scrollToBottom, - scrollToTop: scrollToTop -} From 6a06c0bb9fea6d499d7fd2f7e6a65e16099cfb05 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Thu, 5 Jan 2017 16:48:23 +0800 Subject: [PATCH 08/71] Convert common.js to es6 --- public/js/common.js | 107 +++++++++++++++++++++----------------------- public/js/index.js | 28 ++++++------ 2 files changed, 65 insertions(+), 70 deletions(-) diff --git a/public/js/common.js b/public/js/common.js index f5bfc8e..6d54b45 100644 --- a/public/js/common.js +++ b/public/js/common.js @@ -1,30 +1,37 @@ -var config = require('./config'); -var domain = config.domain; // domain name -var urlpath = config.urlpath; // sub url path, like: www.example.com/ -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; +// import config from './config'; + +import { + domain, // domain name + urlpath, // sub url path, like: www.example.com/ + debug, + GOOGLE_API_KEY, + GOOGLE_CLIENT_ID, + DROPBOX_APP_KEY +} from './config'; //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; +export const port = window.location.port; +window.serverurl = `${window.location.protocol}//${domain ? domain : window.location.hostname}${port ? ':' + port : ''}${urlpath ? '/' + urlpath : ''}`; +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}`; -var version = '0.5.0'; +export const version = '0.5.0'; -var checkAuth = false; -var profile = null; -var lastLoginState = getLoginState(); -var lastUserId = getUserId(); -var loginStateChangeEvent = null; +let checkAuth = false; +let profile = null; +let lastLoginState = getLoginState(); +let lastUserId = getUserId(); +let loginStateChangeEvent = null; -function resetCheckAuth() { +export function setloginStateChangeEvent(func) { + loginStateChangeEvent = func; +} + +export function resetCheckAuth() { checkAuth = false; } -function setLoginState(bool, id) { +export function setLoginState(bool, id) { Cookies.set('loginstate', bool, { expires: 365 }); @@ -40,36 +47,37 @@ function setLoginState(bool, id) { checkLoginStateChanged(); } -function checkLoginStateChanged() { +export function checkLoginStateChanged() { if (getLoginState() != lastLoginState || getUserId() != lastUserId) { - if(loginStateChangeEvent) + if(loginStateChangeEvent) { loginStateChangeEvent(); + } return true; } else { return false; } } -function getLoginState() { - var state = Cookies.get('loginstate'); +export function getLoginState() { + const state = Cookies.get('loginstate'); return state === "true" || state === true; } -function getUserId() { +export function getUserId() { return Cookies.get('userid'); } -function clearLoginState() { +export function clearLoginState() { Cookies.remove('loginstate'); } -function checkIfAuth(yesCallback, noCallback) { - var cookieLoginState = getLoginState(); +export function checkIfAuth(yesCallback, noCallback) { + const cookieLoginState = getLoginState(); if (checkLoginStateChanged()) checkAuth = false; if (!checkAuth || typeof cookieLoginState == 'undefined') { - $.get(serverurl + '/me') - .done(function (data) { + $.get(`${serverurl}/me`) + .done(data => { if (data && data.status == 'ok') { profile = data; yesCallback(profile); @@ -79,10 +87,10 @@ function checkIfAuth(yesCallback, noCallback) { setLoginState(false); } }) - .fail(function () { + .fail(() => { noCallback(); }) - .always(function () { + .always(() => { checkAuth = true; }); } else if (cookieLoginState) { @@ -92,29 +100,16 @@ function checkIfAuth(yesCallback, 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, - loginStateChangeEvent: loginStateChangeEvent, - - /* export functions */ - resetCheckAuth: resetCheckAuth, - setLoginState: setLoginState, - checkLoginStateChanged: checkLoginStateChanged, - getLoginState: getLoginState, - getUserId: getUserId, - clearLoginState: clearLoginState, - checkIfAuth: checkIfAuth +export default { + domain, + urlpath, + debug, + GOOGLE_API_KEY, + GOOGLE_CLIENT_ID, + DROPBOX_APP_KEY, + checkAuth, + profile, + lastLoginState, + lastUserId, + loginStateChangeEvent }; diff --git a/public/js/index.js b/public/js/index.js index 46dfffd..381f051 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -17,18 +17,18 @@ 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; - -var checkLoginStateChanged = common.checkLoginStateChanged; -var loginStateChangeEvent = common.loginStateChangeEvent; +import { + checkLoginStateChanged, + setloginStateChangeEvent, + debug, + DROPBOX_APP_KEY, + GOOGLE_API_KEY, + GOOGLE_CLIENT_ID, + noteid, + noteurl, + urlpath, + version +} from './common'; var extra = require('./extra'); var md = extra.md; @@ -963,10 +963,10 @@ function setNeedRefresh() { showStatus(statusType.offline); } -loginStateChangeEvent = function () { +setloginStateChangeEvent(function () { setRefreshModal('user-state-changed'); setNeedRefresh(); -}; +}); //visibility var wasFocus = false; From 47d7ff25617ba60790dd2018df56778eaa9bffdb Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Thu, 5 Jan 2017 17:52:32 +0800 Subject: [PATCH 09/71] Convert extra.js to es6 --- public/js/extra.js | 637 ++++++++++++++++++++++----------------------- public/js/index.js | 41 +-- 2 files changed, 326 insertions(+), 352 deletions(-) diff --git a/public/js/extra.js b/public/js/extra.js index ba61a66..f1681b2 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -1,15 +1,17 @@ require('prismjs/themes/prism.css'); - -var Prism = require('prismjs'); require('prismjs/components/prism-wiki'); require('prismjs/components/prism-haskell'); require('prismjs/components/prism-go'); require('prismjs/components/prism-typescript'); require('prismjs/components/prism-jsx'); -var hljs = require('highlight.js'); -var PDFObject = require('pdfobject'); -var S = require('string'); -var saveAs = require('file-saver').saveAs; + +import Prism from 'prismjs'; +import hljs from 'highlight.js'; +import PDFObject from 'pdfobject'; +import S from 'string'; +import { saveAs } from 'file-saver'; + +require('./common'); require('../vendor/md-toc'); //auto update last change @@ -21,9 +23,10 @@ window.lastchangeui = { user: $(".ui-lastchangeuser"), nouser: $(".ui-no-lastchangeuser") } -var ownerui = $(".ui-owner"); -function updateLastChange() { +const ownerui = $(".ui-owner"); + +export function updateLastChange() { if (!lastchangeui) return; if (createtime) { if (createtime && !lastchangetime) { @@ -31,7 +34,7 @@ function updateLastChange() { } else { lastchangeui.status.text('changed'); } - var time = lastchangetime || createtime; + const time = lastchangetime || createtime; lastchangeui.time.html(moment(time).fromNow()); lastchangeui.time.attr('title', moment(time).format('llll')); } @@ -40,13 +43,14 @@ setInterval(updateLastChange, 60000); window.lastchangeuser = null; window.lastchangeuserprofile = null; -function updateLastChangeUser() { + +export function updateLastChangeUser() { if (lastchangeui) { if (lastchangeuser && lastchangeuserprofile) { - var icon = lastchangeui.user.children('i'); + const icon = lastchangeui.user.children('i'); icon.attr('title', lastchangeuserprofile.name).tooltip('fixTitle'); if (lastchangeuserprofile.photo) - icon.attr('style', 'background-image:url(' + lastchangeuserprofile.photo + ')'); + icon.attr('style', `background-image:url(${lastchangeuserprofile.photo})`); lastchangeui.user.show(); lastchangeui.nouser.hide(); } else { @@ -58,12 +62,13 @@ function updateLastChangeUser() { window.owner = null; window.ownerprofile = null; -function updateOwner() { + +export function updateOwner() { if (ownerui) { if (owner && ownerprofile && owner !== lastchangeuser) { - var icon = ownerui.children('i'); + const icon = ownerui.children('i'); icon.attr('title', ownerprofile.name).tooltip('fixTitle'); - var styleString = 'background-image:url(' + ownerprofile.photo + ')'; + const styleString = `background-image:url(${ownerprofile.photo})`; if (ownerprofile.photo && icon.attr('style') !== styleString) icon.attr('style', styleString); ownerui.show(); @@ -75,11 +80,11 @@ function updateOwner() { //get title function getTitle(view) { - var title = ""; + let title = ""; if (md && md.meta && md.meta.title && (typeof md.meta.title == "string" || typeof md.meta.title == "number")) { title = md.meta.title; } else { - var h1s = view.find("h1"); + const h1s = view.find("h1"); if (h1s.length > 0) { title = h1s.first().text(); } else { @@ -90,8 +95,8 @@ function getTitle(view) { } //render title -function renderTitle(view) { - var title = getTitle(view); +export function renderTitle(view) { + let title = getTitle(view); if (title) { title += ' - HackMD'; } else { @@ -101,8 +106,8 @@ function renderTitle(view) { } //render filename -function renderFilename(view) { - var filename = getTitle(view); +export function renderFilename(view) { + let filename = getTitle(view); if (!filename) { filename = 'Untitled'; } @@ -110,29 +115,29 @@ function renderFilename(view) { } // render tags -function renderTags(view) { - var tags = []; - var rawtags = []; +export function renderTags(view) { + const tags = []; + const rawtags = []; if (md && md.meta && md.meta.tags && (typeof md.meta.tags == "string" || typeof md.meta.tags == "number")) { - var metaTags = ('' + md.meta.tags).split(','); + const metaTags = (`${md.meta.tags}`).split(','); for (var i = 0; i < metaTags.length; i++) { - var text = metaTags[i].trim(); + const text = metaTags[i].trim(); if (text) rawtags.push(text); } } else { - view.find('h6').each(function (key, value) { + view.find('h6').each((key, value) => { if (/^tags/gmi.test($(value).text())) { - var codes = $(value).find("code"); - for (var i = 0; i < codes.length; i++) { - var text = codes[i].innerHTML.trim(); + const codes = $(value).find("code"); + for (let i = 0; i < codes.length; i++) { + const text = codes[i].innerHTML.trim(); if (text) rawtags.push(text); } } }); } for (var i = 0; i < rawtags.length; i++) { - var found = false; - for (var j = 0; j < tags.length; j++) { + let found = false; + for (let j = 0; j < tags.length; j++) { if (tags[j] == rawtags[i]) { found = true; break; @@ -145,13 +150,13 @@ function renderTags(view) { } function slugifyWithUTF8(text) { - var newText = S(text.toLowerCase()).trim().stripTags().dasherize().s; + let newText = S(text.toLowerCase()).trim().stripTags().dasherize().s; newText = newText.replace(/([\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\[\\\]\^\`\{\|\}\~])/g, ''); return newText; } -function isValidURL(str) { - var pattern = new RegExp('^(https?:\\/\\/)?' + // protocol +export function isValidURL(str) { + const pattern = new RegExp('^(https?:\\/\\/)?' + // protocol '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path @@ -165,12 +170,12 @@ function isValidURL(str) { } //parse meta -function parseMeta(md, edit, view, toc, tocAffix) { - var lang = null; - var dir = null; - var breaks = true; +export function parseMeta(md, edit, view, toc, tocAffix) { + let lang = null; + let dir = null; + let breaks = true; if (md && md.meta) { - var meta = md.meta; + const meta = md.meta; lang = meta.lang; dir = meta.dir; breaks = meta.breaks; @@ -210,13 +215,13 @@ function parseMeta(md, edit, view, toc, tocAffix) { window.viewAjaxCallback = null; //regex for extra tags -var spaceregex = /\s*/; -var notinhtmltagregex = /(?![^<]*>|[^<>]*<\/)/; -var coloregex = /\[color=([#|\(|\)|\s|\,|\w]*?)\]/; +const spaceregex = /\s*/; +const notinhtmltagregex = /(?![^<]*>|[^<>]*<\/)/; +let coloregex = /\[color=([#|\(|\)|\s|\,|\w]*?)\]/; coloregex = new RegExp(coloregex.source + notinhtmltagregex.source, "g"); -var nameregex = /\[name=(.*?)\]/; -var timeregex = /\[time=([:|,|+|-|\(|\)|\s|\w]*?)\]/; -var nameandtimeregex = new RegExp(nameregex.source + spaceregex.source + timeregex.source + notinhtmltagregex.source, "g"); +let nameregex = /\[name=(.*?)\]/; +let timeregex = /\[time=([:|,|+|-|\(|\)|\s|\w]*?)\]/; +const nameandtimeregex = new RegExp(nameregex.source + spaceregex.source + timeregex.source + notinhtmltagregex.source, "g"); nameregex = new RegExp(nameregex.source + notinhtmltagregex.source, "g"); timeregex = new RegExp(timeregex.source + notinhtmltagregex.source, "g"); @@ -231,35 +236,36 @@ function replaceExtraTags(html) { if (typeof mermaid !== 'undefined' && mermaid) mermaid.startOnLoad = false; //dynamic event or object binding here -function finishView(view) { +export function finishView(view) { //todo list - var lis = view.find('li.raw').removeClass("raw").sortByDepth().toArray(); - for (var i = 0; i < lis.length; i++) { - var li = lis[i]; - var html = $(li).clone()[0].innerHTML; - var p = $(li).children('p'); + const lis = view.find('li.raw').removeClass("raw").sortByDepth().toArray(); + + for (let li of lis) { + let html = $(li).clone()[0].innerHTML; + const p = $(li).children('p'); if (p.length == 1) { html = p.html(); li = p[0]; } html = replaceExtraTags(html); li.innerHTML = html; - var disabled = 'disabled'; + let disabled = 'disabled'; if(typeof editor !== 'undefined' && havePermission()) disabled = ''; if (/^\s*\[[x ]\]\s*/.test(html)) { - li.innerHTML = html.replace(/^\s*\[ \]\s*/, '') - .replace(/^\s*\[x\]\s*/, ''); - lis[i].setAttribute('class', 'task-list-item'); + li.innerHTML = html.replace(/^\s*\[ \]\s*/, ``) + .replace(/^\s*\[x\]\s*/, ``); + li.setAttribute('class', 'task-list-item'); } if (typeof editor !== 'undefined' && havePermission()) $(li).find('input').change(toggleTodoEvent); //color tag in list will convert it to tag icon with color - var tag_color = $(li).closest('ul').find(".color"); - tag_color.each(function (key, value) { + const tag_color = $(li).closest('ul').find(".color"); + tag_color.each((key, value) => { $(value).addClass('fa fa-tag').css('color', $(value).attr('data-color')); }); } + //youtube view.find("div.youtube.raw").removeClass("raw") .click(function () { @@ -270,41 +276,41 @@ function finishView(view) { .click(function () { imgPlayiframe(this, '//player.vimeo.com/video/'); }) - .each(function (key, value) { + .each((key, value) => { $.ajax({ type: 'GET', - url: '//vimeo.com/api/v2/video/' + $(value).attr('data-videoid') + '.json', + url: `//vimeo.com/api/v2/video/${$(value).attr('data-videoid')}.json`, jsonp: 'callback', dataType: 'jsonp', - success: function (data) { - var thumbnail_src = data[0].thumbnail_large; - var image = ''; + success(data) { + const thumbnail_src = data[0].thumbnail_large; + const image = ``; $(value).prepend(image); if(viewAjaxCallback) viewAjaxCallback(); } }); }); //gist - view.find("code[data-gist-id]").each(function (key, value) { + view.find("code[data-gist-id]").each((key, value) => { if ($(value).children().length == 0) $(value).gist(viewAjaxCallback); }); //sequence diagram - var sequences = view.find("div.sequence-diagram.raw").removeClass("raw"); - sequences.each(function (key, value) { + const sequences = view.find("div.sequence-diagram.raw").removeClass("raw"); + sequences.each((key, value) => { try { var $value = $(value); - var $ele = $(value).parent().parent(); + const $ele = $(value).parent().parent(); - var sequence = $value; + const sequence = $value; sequence.sequenceDiagram({ theme: 'simple' }); $ele.addClass('sequence-diagram'); $value.children().unwrap().unwrap(); - var svg = $ele.find('> svg'); - svg[0].setAttribute('viewBox', '0 0 ' + svg.attr('width') + ' ' + svg.attr('height')); + const svg = $ele.find('> svg'); + svg[0].setAttribute('viewBox', `0 0 ${svg.attr('width')} ${svg.attr('height')}`); svg[0].setAttribute('preserveAspectRatio', 'xMidYMid meet'); } catch (err) { $value.unwrap(); @@ -312,13 +318,13 @@ function finishView(view) { } }); //flowchart - var flow = view.find("div.flow-chart.raw").removeClass("raw"); - flow.each(function (key, value) { + const flow = view.find("div.flow-chart.raw").removeClass("raw"); + flow.each((key, value) => { try { var $value = $(value); - var $ele = $(value).parent().parent(); + const $ele = $(value).parent().parent(); - var chart = flowchart.parse($value.text()); + const chart = flowchart.parse($value.text()); $value.html(''); chart.drawSVG(value, { 'line-width': 2, @@ -335,14 +341,14 @@ function finishView(view) { } }); //graphviz - var Viz = require("viz.js"); - var graphvizs = view.find("div.graphviz.raw").removeClass("raw"); - graphvizs.each(function (key, value) { + const Viz = require("viz.js"); + const graphvizs = view.find("div.graphviz.raw").removeClass("raw"); + graphvizs.each((key, value) => { try { var $value = $(value); - var $ele = $(value).parent().parent(); + const $ele = $(value).parent().parent(); - var graphviz = Viz($value.text()); + const graphviz = Viz($value.text()); if (!graphviz) throw Error('viz.js output empty graph'); $value.html(graphviz); @@ -354,14 +360,14 @@ function finishView(view) { } }); //mermaid - var mermaids = view.find("div.mermaid.raw").removeClass("raw"); - mermaids.each(function (key, value) { + const mermaids = view.find("div.mermaid.raw").removeClass("raw"); + mermaids.each((key, value) => { try { var $value = $(value); - var $ele = $(value).closest('pre'); + const $ele = $(value).closest('pre'); - var mermaidError = null; - mermaid.parseError = function (err, hash) { + let mermaidError = null; + mermaid.parseError = (err, hash) => { mermaidError = err; }; @@ -379,44 +385,44 @@ function finishView(view) { } }); //image href new window(emoji not included) - var images = view.find("img.raw[src]").removeClass("raw"); - images.each(function (key, value) { + const images = view.find("img.raw[src]").removeClass("raw"); + images.each((key, value) => { // if it's already wrapped by link, then ignore - var $value = $(value); - $value[0].onload = function (e) { + const $value = $(value); + $value[0].onload = e => { if(viewAjaxCallback) viewAjaxCallback(); }; }); //blockquote - var blockquote = view.find("blockquote.raw").removeClass("raw"); - var blockquote_p = blockquote.find("p"); - blockquote_p.each(function (key, value) { - var html = $(value).html(); + const blockquote = view.find("blockquote.raw").removeClass("raw"); + const blockquote_p = blockquote.find("p"); + blockquote_p.each((key, value) => { + let html = $(value).html(); html = replaceExtraTags(html); $(value).html(html); }); //color tag in blockquote will change its left border color - var blockquote_color = blockquote.find(".color"); - blockquote_color.each(function (key, value) { + const blockquote_color = blockquote.find(".color"); + blockquote_color.each((key, value) => { $(value).closest("blockquote").css('border-left-color', $(value).attr('data-color')); }); //slideshare view.find("div.slideshare.raw").removeClass("raw") - .each(function (key, value) { + .each((key, value) => { $.ajax({ type: 'GET', - url: '//www.slideshare.net/api/oembed/2?url=http://www.slideshare.net/' + $(value).attr('data-slideshareid') + '&format=json', + url: `//www.slideshare.net/api/oembed/2?url=http://www.slideshare.net/${$(value).attr('data-slideshareid')}&format=json`, jsonp: 'callback', dataType: 'jsonp', - success: function (data) { - var $html = $(data.html); - var iframe = $html.closest('iframe'); - var caption = $html.closest('div'); - var inner = $('
    ').append(iframe); - var height = iframe.attr('height'); - var width = iframe.attr('width'); - var ratio = (height / width) * 100; - inner.css('padding-bottom', ratio + '%'); + success(data) { + const $html = $(data.html); + const iframe = $html.closest('iframe'); + const caption = $html.closest('div'); + const inner = $('
    ').append(iframe); + const height = iframe.attr('height'); + const width = iframe.attr('width'); + const ratio = (height / width) * 100; + inner.css('padding-bottom', `${ratio}%`); $(value).html(inner).append(caption); if(viewAjaxCallback) viewAjaxCallback(); } @@ -424,31 +430,31 @@ function finishView(view) { }); //speakerdeck view.find("div.speakerdeck.raw").removeClass("raw") - .each(function (key, value) { - var url = 'https://speakerdeck.com/oembed.json?url=https%3A%2F%2Fspeakerdeck.com%2F' + encodeURIComponent($(value).attr('data-speakerdeckid')); + .each((key, value) => { + const url = `https://speakerdeck.com/oembed.json?url=https%3A%2F%2Fspeakerdeck.com%2F${encodeURIComponent($(value).attr('data-speakerdeckid'))}`; //use yql because speakerdeck not support jsonp $.ajax({ url: 'https://query.yahooapis.com/v1/public/yql', data: { - q: "select * from json where url ='" + url + "'", + q: `select * from json where url ='${url}'`, format: "json" }, dataType: "jsonp", - success: function (data) { + success(data) { if (!data.query || !data.query.results) return; - var json = data.query.results.json; - var html = json.html; + const json = data.query.results.json; + const html = json.html; var ratio = json.height / json.width; $(value).html(html); - var iframe = $(value).children('iframe'); - var src = iframe.attr('src'); + const iframe = $(value).children('iframe'); + const src = iframe.attr('src'); if (src.indexOf('//') == 0) - iframe.attr('src', 'https:' + src); - var inner = $('
    ').append(iframe); - var height = iframe.attr('height'); - var width = iframe.attr('width'); + iframe.attr('src', `https:${src}`); + const inner = $('
    ').append(iframe); + const height = iframe.attr('height'); + const width = iframe.attr('width'); var ratio = (height / width) * 100; - inner.css('padding-bottom', ratio + '%'); + inner.css('padding-bottom', `${ratio}%`); $(value).html(inner); if(viewAjaxCallback) viewAjaxCallback(); } @@ -457,8 +463,8 @@ function finishView(view) { //pdf view.find("div.pdf.raw").removeClass("raw") .each(function (key, value) { - var url = $(value).attr('data-pdfurl'); - var inner = $('
    '); + const url = $(value).attr('data-pdfurl'); + const inner = $('
    '); $(this).append(inner); PDFObject.embed(url, inner, { height: '400px' @@ -466,12 +472,12 @@ function finishView(view) { }); //syntax highlighting view.find("code.raw").removeClass("raw") - .each(function (key, value) { - var langDiv = $(value); + .each((key, value) => { + const langDiv = $(value); if (langDiv.length > 0) { - var reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim(); - var codeDiv = langDiv.find('.code'); - var code = ""; + const reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim(); + const codeDiv = langDiv.find('.code'); + let code = ""; if (codeDiv.length > 0) code = codeDiv.html(); else code = langDiv.html(); if (!reallang) { @@ -490,8 +496,8 @@ function finishView(view) { }; } else { code = S(code).unescapeHTML().s; - var languages = hljs.listLanguages(); - if (languages.indexOf(reallang) == -1) { + const languages = hljs.listLanguages(); + if (!languages.includes(reallang)) { var result = hljs.highlightAuto(code); } else { var result = hljs.highlight(reallang, code); @@ -502,7 +508,7 @@ function finishView(view) { } }); //mathjax - var mathjaxdivs = view.find('span.mathjax.raw').removeClass("raw").toArray(); + const mathjaxdivs = view.find('span.mathjax.raw').removeClass("raw").toArray(); try { if (mathjaxdivs.length > 1) { MathJax.Hub.Queue(["Typeset", MathJax.Hub, mathjaxdivs]); @@ -519,16 +525,16 @@ function finishView(view) { } //only static transform should be here -function postProcess(code) { - var result = $('
    ' + code + '
    '); +export function postProcess(code) { + const result = $(`
    ${code}
    `); //link should open in new window or tab result.find('a:not([href^="#"]):not([target])').attr('target', '_blank'); //update continue line numbers - var linenumberdivs = result.find('.gutter.linenumber').toArray(); - for (var i = 0; i < linenumberdivs.length; i++) { + const linenumberdivs = result.find('.gutter.linenumber').toArray(); + for (let i = 0; i < linenumberdivs.length; i++) { if ($(linenumberdivs[i]).hasClass('continue')) { - var startnumber = linenumberdivs[i - 1] ? parseInt($(linenumberdivs[i - 1]).find('> span').last().attr('data-linenumber')) : 0; - $(linenumberdivs[i]).find('> span').each(function(key, value) { + const startnumber = linenumberdivs[i - 1] ? parseInt($(linenumberdivs[i - 1]).find('> span').last().attr('data-linenumber')) : 0; + $(linenumberdivs[i]).find('> span').each((key, value) => { $(value).attr('data-linenumber', startnumber + key + 1); }); } @@ -538,8 +544,8 @@ function postProcess(code) { window.postProcess = postProcess; function generateCleanHTML(view) { - var src = view.clone(); - var eles = src.find('*'); + const src = view.clone(); + const eles = src.find('*'); //remove syncscroll parts eles.removeClass('part'); src.find('*[class=""]').removeAttr('class'); @@ -550,24 +556,24 @@ function generateCleanHTML(view) { //disable todo list src.find("input.task-list-item-checkbox").attr('disabled', ''); //replace emoji image path - src.find("img.emoji").each(function (key, value) { - var name = $(value).attr('alt'); + src.find("img.emoji").each((key, value) => { + let name = $(value).attr('alt'); name = name.substr(1); name = name.slice(0, name.length - 1); - $(value).attr('src', 'https://www.tortue.me/emoji/' + name + '.png'); + $(value).attr('src', `https://www.tortue.me/emoji/${name}.png`); }); //replace video to iframe - src.find("div[data-videoid]").each(function (key, value) { - var id = $(value).attr('data-videoid'); - var style = $(value).attr('style'); - var url = null; + src.find("div[data-videoid]").each((key, value) => { + const id = $(value).attr('data-videoid'); + const style = $(value).attr('style'); + let url = null; if ($(value).hasClass('youtube')) { url = 'https://www.youtube.com/embed/'; } else if ($(value).hasClass('vimeo')) { url = 'https://player.vimeo.com/video/'; } if (url) { - var iframe = $(''); + const iframe = $(''); iframe.attr('src', url + id); iframe.attr('style', style); $(value).html(iframe); @@ -576,45 +582,44 @@ function generateCleanHTML(view) { return src; } -function exportToRawHTML(view) { - var filename = renderFilename(ui.area.markdown) + '.html'; - var src = generateCleanHTML(view); +export function exportToRawHTML(view) { + const filename = `${renderFilename(ui.area.markdown)}.html`; + const src = generateCleanHTML(view); $(src).find('a.anchor').remove(); - var html = src[0].outerHTML; - var blob = new Blob([html], { + const html = src[0].outerHTML; + const blob = new Blob([html], { type: "text/html;charset=utf-8" }); saveAs(blob, filename); } -var common = require('./common.js'); //extract markdown body to html and compile to template -function exportToHTML(view) { - var title = renderTitle(ui.area.markdown); - var filename = renderFilename(ui.area.markdown) + '.html'; - var src = generateCleanHTML(view); +export function exportToHTML(view) { + const title = renderTitle(ui.area.markdown); + const filename = `${renderFilename(ui.area.markdown)}.html`; + const src = generateCleanHTML(view); //generate toc - var toc = $('#ui-toc').clone(); + const toc = $('#ui-toc').clone(); toc.find('*').removeClass('active').find("a[href^='#'][smoothhashscroll]").removeAttr('smoothhashscroll'); - var tocAffix = $('#ui-toc-affix').clone(); + const tocAffix = $('#ui-toc-affix').clone(); tocAffix.find('*').removeClass('active').find("a[href^='#'][smoothhashscroll]").removeAttr('smoothhashscroll'); //generate html via template - $.get(serverurl + '/build/html.min.css', function (css) { - $.get(serverurl + '/views/html.hbs', function (data) { - var template = Handlebars.compile(data); - var context = { + $.get(`${serverurl}/build/html.min.css`, css => { + $.get(`${serverurl}/views/html.hbs`, data => { + const template = Handlebars.compile(data); + const context = { url: serverurl, - title: title, - css: css, + title, + css, html: src[0].outerHTML, 'ui-toc': toc.html(), 'ui-toc-affix': tocAffix.html(), - lang: (md && md.meta && md.meta.lang) ? 'lang="' + md.meta.lang + '"' : null, - dir: (md && md.meta && md.meta.dir) ? 'dir="' + md.meta.dir + '"' : null + lang: (md && md.meta && md.meta.lang) ? `lang="${md.meta.lang}"` : null, + dir: (md && md.meta && md.meta.dir) ? `dir="${md.meta.dir}"` : null }; - var html = template(context); + const html = template(context); // console.log(html); - var blob = new Blob([html], { + const blob = new Blob([html], { type: "text/html;charset=utf-8" }); saveAs(blob, filename); @@ -624,17 +629,16 @@ function exportToHTML(view) { //jQuery sortByDepth $.fn.sortByDepth = function () { - var ar = this.map(function () { + const ar = this.map(function () { return { length: $(this).parents().length, elt: this } - }).get(), - result = [], - i = ar.length; - ar.sort(function (a, b) { - return a.length - b.length; - }); + }).get(); + + const result = []; + let i = ar.length; + ar.sort((a, b) => a.length - b.length); while (i--) { result.push(ar[i].elt); } @@ -642,16 +646,16 @@ $.fn.sortByDepth = function () { }; function toggleTodoEvent(e) { - var startline = $(this).closest('li').attr('data-startline') - 1; - var line = editor.getLine(startline); - var matches = line.match(/^[>\s]*[\-\+\*]\s\[([x ])\]/); + const startline = $(this).closest('li').attr('data-startline') - 1; + const line = editor.getLine(startline); + const matches = line.match(/^[>\s]*[\-\+\*]\s\[([x ])\]/); if (matches && matches.length >= 2) { - var checked = null; + let checked = null; if (matches[1] == 'x') checked = true; else if (matches[1] == ' ') checked = false; - var replacements = matches[0].match(/(^[>\s]*[\-\+\*]\s\[)([x ])(\])/); + const replacements = matches[0].match(/(^[>\s]*[\-\+\*]\s\[)([x ])(\])/); editor.replaceRange(checked ? ' ' : 'x', { line: startline, ch: replacements[1].length @@ -667,11 +671,11 @@ function removeHash() { history.pushState("", document.title, window.location.pathname + window.location.search); } -var tocExpand = false; +let tocExpand = false; function checkExpandToggle() { - var toc = $('.ui-toc-dropdown .toc'); - var toggle = $('.expand-toggle'); + const toc = $('.ui-toc-dropdown .toc'); + const toggle = $('.expand-toggle'); if (!tocExpand) { toc.removeClass('expand'); toggle.text('Expand all'); @@ -682,8 +686,8 @@ function checkExpandToggle() { } //toc -function generateToc(id) { - var target = $('#' + id); +export function generateToc(id) { + const target = $(`#${id}`); target.html(''); new Toc('doc', { 'level': 3, @@ -695,25 +699,25 @@ function generateToc(id) { }); if (target.text() == 'undefined') target.html(''); - var tocMenu = $('
    Expand all'); - var backtotop = $('Back to top'); - var gotobottom = $('Go to bottom'); + const tocMenu = $('
    Expand all'); + const backtotop = $('Back to top'); + const gotobottom = $('Go to bottom'); checkExpandToggle(); - toggle.click(function (e) { + toggle.click(e => { e.preventDefault(); e.stopPropagation(); tocExpand = !tocExpand; checkExpandToggle(); }); - backtotop.click(function (e) { + backtotop.click(e => { e.preventDefault(); e.stopPropagation(); if (scrollToTop) scrollToTop(); removeHash(); }); - gotobottom.click(function (e) { + gotobottom.click(e => { e.preventDefault(); e.stopPropagation(); if (scrollToBottom) @@ -725,18 +729,18 @@ function generateToc(id) { } //smooth all hash trigger scrolling -function smoothHashScroll() { - var hashElements = $("a[href^='#']:not([smoothhashscroll])").toArray(); - for (var i = 0; i < hashElements.length; i++) { - var element = hashElements[i]; - var $element = $(element); - var hash = element.hash; +export function smoothHashScroll() { + const hashElements = $("a[href^='#']:not([smoothhashscroll])").toArray(); + + for (const element of hashElements) { + const $element = $(element); + const hash = element.hash; if (hash) { $element.on('click', function (e) { // store hash - var hash = decodeURIComponent(this.hash); + const hash = decodeURIComponent(this.hash); // escape special characters in jquery selector - var $hash = $(hash.replace(/(:|\.|\[|\]|,)/g, "\\$1")); + const $hash = $(hash.replace(/(:|\.|\[|\]|,)/g, "\\$1")); // return if no element been selected if ($hash.length <= 0) return; // prevent default anchor click behavior @@ -744,7 +748,7 @@ function smoothHashScroll() { // animate $('body, html').stop(true, true).animate({ scrollTop: $hash.offset().top - }, 100, "linear", function () { + }, 100, "linear", () => { // when done, add hash to url // (default click behaviour) window.location.hash = hash; @@ -757,29 +761,29 @@ function smoothHashScroll() { function imgPlayiframe(element, src) { if (!$(element).attr("data-videoid")) return; - var iframe = $(""); - $(iframe).attr("src", src + $(element).attr("data-videoid") + '?autoplay=1'); + const iframe = $(""); + $(iframe).attr("src", `${src + $(element).attr("data-videoid")}?autoplay=1`); $(element).find('img').css('visibility', 'hidden'); $(element).append(iframe); } -var anchorForId = function (id) { - var anchor = document.createElement("a"); +const anchorForId = id => { + const anchor = document.createElement("a"); anchor.className = "anchor hidden-xs"; - anchor.href = "#" + id; + anchor.href = `#${id}`; anchor.innerHTML = ""; anchor.title = id; return anchor; }; -var linkifyAnchors = function (level, containingElement) { - var headers = containingElement.getElementsByTagName("h" + level); - for (var h = 0; h < headers.length; h++) { - var header = headers[h]; +const linkifyAnchors = (level, containingElement) => { + const headers = containingElement.getElementsByTagName(`h${level}`); + + for (const header of headers) { if (header.getElementsByClassName("anchor").length == 0) { if (typeof header.id == "undefined" || header.id == "") { //to escape characters not allow in css and humanize - var id = slugifyWithUTF8(getHeaderContent(header)); + const id = slugifyWithUTF8(getHeaderContent(header)); header.id = id; } header.insertBefore(anchorForId(header.id), header.firstChild); @@ -787,49 +791,49 @@ var linkifyAnchors = function (level, containingElement) { } }; -function autoLinkify(view) { - var contentBlock = view[0]; +export function autoLinkify(view) { + const contentBlock = view[0]; if (!contentBlock) { return; } - for (var level = 1; level <= 6; level++) { + for (let level = 1; level <= 6; level++) { linkifyAnchors(level, contentBlock); } } function getHeaderContent(header) { - var headerHTML = $(header).clone(); + const headerHTML = $(header).clone(); headerHTML.find('.MathJax_Preview').remove(); headerHTML.find('.MathJax').remove(); return headerHTML[0].innerHTML; } -function deduplicatedHeaderId(view) { - var headers = view.find(':header.raw').removeClass('raw').toArray(); - for (var i = 0; i < headers.length; i++) { - var id = $(headers[i]).attr('id'); +export function deduplicatedHeaderId(view) { + const headers = view.find(':header.raw').removeClass('raw').toArray(); + for (let i = 0; i < headers.length; i++) { + const id = $(headers[i]).attr('id'); if (!id) continue; - var duplicatedHeaders = view.find(':header[id="' + id + '"]').toArray(); - for (var j = 0; j < duplicatedHeaders.length; j++) { + const duplicatedHeaders = view.find(`:header[id="${id}"]`).toArray(); + for (let j = 0; j < duplicatedHeaders.length; j++) { if (duplicatedHeaders[j] != headers[i]) { - var newId = id + j; - var $duplicatedHeader = $(duplicatedHeaders[j]); + const newId = id + j; + const $duplicatedHeader = $(duplicatedHeaders[j]); $duplicatedHeader.attr('id', newId); - var $headerLink = $duplicatedHeader.find('> .header-link'); - $headerLink.attr('href', '#' + newId); + const $headerLink = $duplicatedHeader.find('> .header-link'); + $headerLink.attr('href', `#${newId}`); $headerLink.attr('title', newId); } } } } -function renderTOC(view) { - var tocs = view.find('.toc').toArray(); - for (var i = 0; i < tocs.length; i++) { - var toc = $(tocs[i]); - var id = 'toc' + i; +export function renderTOC(view) { + const tocs = view.find('.toc').toArray(); + for (let i = 0; i < tocs.length; i++) { + const toc = $(tocs[i]); + const id = `toc${i}`; toc.attr('id', id); - var target = $('#' + id); + const target = $(`#${id}`); target.html(''); new Toc('doc', { 'level': 3, @@ -844,8 +848,8 @@ function renderTOC(view) { } } -function scrollToHash() { - var hash = location.hash; +export function scrollToHash() { + const hash = location.hash; location.hash = ""; location.hash = hash; } @@ -855,39 +859,39 @@ function highlightRender(code, lang) { return; code = S(code).escapeHTML().s if (lang == 'sequence') { - return '
    ' + code + '
    '; + return `
    ${code}
    `; } else if (lang == 'flow') { - return '
    ' + code + '
    '; + return `
    ${code}
    `; } else if (lang == 'graphviz') { - return '
    ' + code + '
    '; + return `
    ${code}
    `; } else if (lang == 'mermaid') { - return '
    ' + code + '
    '; + return `
    ${code}
    `; } - var result = { + const result = { value: code }; - var showlinenumbers = /\=$|\=\d+$|\=\+$/.test(lang); + const showlinenumbers = /\=$|\=\d+$|\=\+$/.test(lang); if (showlinenumbers) { - var startnumber = 1; - var matches = lang.match(/\=(\d+)$/); + let startnumber = 1; + const matches = lang.match(/\=(\d+)$/); if (matches) startnumber = parseInt(matches[1]); - var lines = result.value.split('\n'); - var linenumbers = []; - for (var i = 0; i < lines.length - 1; i++) { - linenumbers[i] = ""; + const lines = result.value.split('\n'); + const linenumbers = []; + for (let i = 0; i < lines.length - 1; i++) { + linenumbers[i] = ``; } - var continuelinenumber = /\=\+$/.test(lang); - var linegutter = "
    " + linenumbers.join('\n') + "
    "; - result.value = "
    " + linegutter + "
    " + result.value + "
    "; + const continuelinenumber = /\=\+$/.test(lang); + const linegutter = `
    ${linenumbers.join('\n')}
    `; + result.value = `
    ${linegutter}
    ${result.value}
    `; } return result.value; } -var markdownit = require('markdown-it'); -var markdownitContainer = require('markdown-it-container'); +import markdownit from 'markdown-it'; +import markdownitContainer from 'markdown-it-container'; -var md = markdownit('default', { +export let md = markdownit('default', { html: true, breaks: true, langPrefix: "", @@ -923,19 +927,17 @@ emojify.setConfig({ elements: ['script', 'textarea', 'a', 'pre', 'code', 'svg'], classes: ['no-emojify'] }, - img_dir: serverurl + '/build/emojify.js/dist/images/basic', + img_dir: `${serverurl}/build/emojify.js/dist/images/basic`, ignore_emoticons: true }); -md.renderer.rules.emoji = function(token, idx) { - return emojify.replace(':' + token[idx].markup + ':'); -}; +md.renderer.rules.emoji = (token, idx) => emojify.replace(`:${token[idx].markup}:`); 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()); - return self.renderToken.apply(self, arguments); + tokens[idx].attrJoin('class', `alert-${tokens[idx].info.trim()}`); + return self.renderToken(...arguments); } md.use(markdownitContainer, 'success', { render: renderContainer }); md.use(markdownitContainer, 'info', { render: renderContainer }); @@ -944,25 +946,25 @@ md.use(markdownitContainer, 'danger', { render: renderContainer }); md.renderer.rules.image = function (tokens, idx, options, env, self) { tokens[idx].attrJoin('class', 'raw'); - 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'); - return self.renderToken.apply(self, arguments); + return self.renderToken(...arguments); }; md.renderer.rules.blockquote_open = function (tokens, idx, options, env, self) { tokens[idx].attrJoin('class', 'raw'); - 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'); - 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]; @@ -979,110 +981,99 @@ md.renderer.rules.fence = function (tokens, idx, options, env, self) { } if (highlighted.indexOf('' - + highlighted - + '\n'; + return `
    ${highlighted}
    \n`; }; /* Defined regex markdown it plugins */ -var Plugin = require('markdown-it-regexp'); +import Plugin from 'markdown-it-regexp'; //youtube -var youtubePlugin = new Plugin( +const youtubePlugin = new Plugin( // regexp to match /{%youtube\s*([\d\D]*?)\s*%}/, - // this function will be called when something matches - function (match, utils) { - var videoid = match[1]; + (match, utils) => { + const videoid = match[1]; if (!videoid) return; - var div = $('
    '); + const div = $('
    '); div.attr('data-videoid', videoid); - var thumbnail_src = '//img.youtube.com/vi/' + videoid + '/hqdefault.jpg'; - var image = ''; + const thumbnail_src = `//img.youtube.com/vi/${videoid}/hqdefault.jpg`; + const image = ``; div.append(image); - var icon = ''; + const icon = ''; div.append(icon); return div[0].outerHTML; } ); //vimeo -var vimeoPlugin = new Plugin( +const vimeoPlugin = new Plugin( // regexp to match /{%vimeo\s*([\d\D]*?)\s*%}/, - // this function will be called when something matches - function (match, utils) { - var videoid = match[1]; + (match, utils) => { + const videoid = match[1]; if (!videoid) return; - var div = $('
    '); + const div = $('
    '); div.attr('data-videoid', videoid); - var icon = ''; + const icon = ''; div.append(icon); return div[0].outerHTML; } ); //gist -var gistPlugin = new Plugin( +const gistPlugin = new Plugin( // regexp to match /{%gist\s*([\d\D]*?)\s*%}/, - // this function will be called when something matches - function (match, utils) { - var gistid = match[1]; - var code = ''; + (match, utils) => { + const gistid = match[1]; + const code = ``; return code; } ); //TOC -var tocPlugin = new Plugin( +const tocPlugin = new Plugin( // regexp to match /^\[TOC\]$/i, - // this function will be called when something matches - function (match, utils) { - return '
    '; - } + (match, utils) => '
    ' ); //slideshare -var slidesharePlugin = new Plugin( +const slidesharePlugin = new Plugin( // regexp to match /{%slideshare\s*([\d\D]*?)\s*%}/, - // this function will be called when something matches - function (match, utils) { - var slideshareid = match[1]; - var div = $('
    '); + (match, utils) => { + const slideshareid = match[1]; + const div = $('
    '); div.attr('data-slideshareid', slideshareid); return div[0].outerHTML; } ); //speakerdeck -var speakerdeckPlugin = new Plugin( +const speakerdeckPlugin = new Plugin( // regexp to match /{%speakerdeck\s*([\d\D]*?)\s*%}/, - // this function will be called when something matches - function (match, utils) { - var speakerdeckid = match[1]; - var div = $('
    '); + (match, utils) => { + const speakerdeckid = match[1]; + const div = $('
    '); div.attr('data-speakerdeckid', speakerdeckid); return div[0].outerHTML; } ); //pdf -var pdfPlugin = new Plugin( +const pdfPlugin = new Plugin( // regexp to match /{%pdf\s*([\d\D]*?)\s*%}/, - // this function will be called when something matches - function (match, utils) { - var pdfurl = match[1]; + (match, utils) => { + const pdfurl = match[1]; if (!isValidURL(pdfurl)) return match[0]; - var div = $('
    '); + const div = $('
    '); div.attr('data-pdfurl', pdfurl); return div[0].outerHTML; } @@ -1090,8 +1081,8 @@ var pdfPlugin = new Plugin( //yaml meta, from https://github.com/eugeneware/remarkable-meta function get(state, line) { - var pos = state.bMarks[line]; - var max = state.eMarks[line]; + const pos = state.bMarks[line]; + const max = state.eMarks[line]; return state.src.substr(pos, max - pos); } @@ -1100,9 +1091,9 @@ function meta(state, start, end, silent) { if (state.tShift[start] < 0) return false; if (!get(state, start).match(/^---$/)) return false; - var data = []; + const data = []; for (var line = start + 1; line < end; line++) { - var str = get(state, line); + const str = get(state, line); if (str.match(/^(\.{3}|-{3})$/)) break; if (state.tShift[line] < 0) break; data.push(str); @@ -1138,24 +1129,6 @@ md.use(slidesharePlugin); md.use(speakerdeckPlugin); md.use(pdfPlugin); -module.exports = { - md: md, - updateLastChange: updateLastChange, - postProcess: postProcess, - finishView: finishView, - autoLinkify: autoLinkify, - deduplicatedHeaderId: deduplicatedHeaderId, - renderTOC: renderTOC, - renderTitle: renderTitle, - renderFilename: renderFilename, - renderTags: renderTags, - isValidURL: isValidURL, - generateToc: generateToc, - smoothHashScroll: smoothHashScroll, - scrollToHash: scrollToHash, - updateLastChangeUser: updateLastChangeUser, - updateOwner: updateOwner, - parseMeta: parseMeta, - exportToHTML: exportToHTML, - exportToRawHTML: exportToRawHTML +export default { + md }; diff --git a/public/js/index.js b/public/js/index.js index 381f051..7406c9a 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -30,26 +30,27 @@ import { version } from './common'; -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'; import { clearMap, From 71aece74292e9764e6dc20ebe84f211099d6076d Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Thu, 5 Jan 2017 18:10:55 +0800 Subject: [PATCH 10/71] Convert cover.js to es6 --- public/js/cover.js | 249 +++++++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 124 deletions(-) diff --git a/public/js/cover.js b/public/js/cover.js index b888684..ecb385e 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -3,30 +3,30 @@ 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; -var loginStateChangeEvent = common.loginStateChangeEvent; +import { + checkIfAuth, + clearLoginState, + getLoginState, + resetCheckAuth, + setloginStateChangeEvent +} from './common'; -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 historyModule from './history'; +const parseStorageToHistory = historyModule.parseStorageToHistory; +const parseHistory = historyModule.parseHistory; +const getStorageHistory = historyModule.getStorageHistory; +const getHistory = historyModule.getHistory; +const saveHistory = historyModule.saveHistory; +const removeHistory = historyModule.removeHistory; +const postHistoryToServer = historyModule.postHistoryToServer; +const deleteServerHistory = historyModule.deleteServerHistory; +const parseServerToHistory = historyModule.parseServerToHistory; +const saveStorageHistoryToServer = historyModule.saveStorageHistoryToServer; +const clearDuplicatedHistory = historyModule.clearDuplicatedHistory; -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'; import Cover from './views/Cover'; import Vue from 'vue'; @@ -36,13 +36,13 @@ new Vue({ render: (h) => h(Cover) }) -var options = { +const options = { valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'], item: '
  • \ \ \
    \ -
    \ +
    \
    \
    \

    \ @@ -64,15 +64,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(); @@ -83,7 +84,7 @@ function pageInit() { $(".ui-history").click(); parseServerToHistory(historyList, parseHistoryCallback); }, - function () { + () => { $('.ui-signin').show(); $('.ui-or').show(); $('.ui-welcome').hide(); @@ -100,14 +101,14 @@ $(".masthead-nav li").click(function () { $(this).addClass("active"); }); -$(".ui-home").click(function () { +$(".ui-home").click(() => { if (!$("#home").is(':visible')) { $(".section:visible").hide(); $("#home").fadeIn(); } }); -$(".ui-history").click(function () { +$(".ui-history").click(() => { if (!$("#history").is(':visible')) { $(".section:visible").hide(); $("#history").fadeIn(); @@ -120,7 +121,7 @@ function checkHistoryList() { $(".ui-import-from-browser").hide(); } else if ($("#history-list").children().length == 0) { $(".ui-nohistory").slideDown(); - getStorageHistory(function (data) { + getStorageHistory(data => { if (data && data.length > 0 && getLoginState() && historyList.items.length == 0) { $(".ui-import-from-browser").slideDown(); } @@ -130,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]); @@ -169,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'); @@ -187,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("" + tags[j] + ""); + labels.push(`${tags[j]}`); } tagsEl.html(labels.join(' ')); } @@ -206,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(' ' + value.text + '
    ' + value.time); + $('.ui-delete-modal-item').html(` ${value.text}
    ${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; @@ -228,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'); @@ -239,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; @@ -260,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()); } } @@ -272,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(); @@ -287,7 +288,7 @@ function deleteHistory() { deleteId = null; clearHistory = false; }); - }, function () { + }, () => { if (clearHistory) { saveHistory([]); historyList.clear(); @@ -295,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(); @@ -308,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); @@ -347,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'); @@ -366,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'); @@ -378,16 +379,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 }; @@ -397,7 +398,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 @@ -405,17 +406,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; } @@ -428,6 +429,6 @@ $(".ui-use-tags").on('change', function () { checkHistoryList(); }); -$('.search').keyup(function () { +$('.search').keyup(() => { checkHistoryList(); }); From fce08cc164bb1ecc6b986fe6630381b630a1508c Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Thu, 5 Jan 2017 20:56:16 +0800 Subject: [PATCH 11/71] Convert history.js to es6 --- public/js/cover.js | 27 +++--- public/js/history.js | 204 +++++++++++++++++++------------------------ public/js/index.js | 13 +-- 3 files changed, 112 insertions(+), 132 deletions(-) diff --git a/public/js/cover.js b/public/js/cover.js index ecb385e..677d82e 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -11,20 +11,21 @@ import { setloginStateChangeEvent } from './common'; -import historyModule from './history'; -const parseStorageToHistory = historyModule.parseStorageToHistory; -const parseHistory = historyModule.parseHistory; -const getStorageHistory = historyModule.getStorageHistory; -const getHistory = historyModule.getHistory; -const saveHistory = historyModule.saveHistory; -const removeHistory = historyModule.removeHistory; -const postHistoryToServer = historyModule.postHistoryToServer; -const deleteServerHistory = historyModule.deleteServerHistory; -const parseServerToHistory = historyModule.parseServerToHistory; -const saveStorageHistoryToServer = historyModule.saveStorageHistoryToServer; -const clearDuplicatedHistory = historyModule.clearDuplicatedHistory; +import { + clearDuplicatedHistory, + deleteServerHistory, + getHistory, + getStorageHistory, + parseHistory, + parseServerToHistory, + parseStorageToHistory, + postHistoryToServer, + removeHistory, + saveHistory, + saveStorageHistoryToServer +} from './history'; -import {saveAs} from 'file-saver'; +import { saveAs } from 'file-saver'; import List from 'list.js'; import S from 'string'; diff --git a/public/js/history.js b/public/js/history.js index 6972f24..f120168 100644 --- a/public/js/history.js +++ b/public/js/history.js @@ -1,10 +1,9 @@ -var store = require('store'); -var S = require('string'); - -var common = require('./common'); -var checkIfAuth = common.checkIfAuth; -var urlpath = common.urlpath; -var getLoginState = common.getLoginState; +import store from 'store'; +import S from 'string'; +import { + checkIfAuth, + urlpath +} from './common'; window.migrateHistoryFromTempCallback = null; @@ -12,22 +11,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 +39,12 @@ function migrateHistoryFromTemp() { } } -function saveHistory(notehistory) { +export function saveHistory(notehistory) { checkIfAuth( - function () { + () => { saveHistoryToServer(notehistory); }, - function () { + () => { saveHistoryToStorage(notehistory); } ); @@ -65,7 +64,7 @@ function saveHistoryToCookie(notehistory) { } function saveHistoryToServer(notehistory) { - $.post(serverurl + '/history', { + $.post(`${serverurl}/history`, { history: JSON.stringify(notehistory) }); } @@ -75,37 +74,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 +122,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 +170,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 +187,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 +203,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 +211,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 +242,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 +269,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 +283,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 +329,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 +346,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 -} diff --git a/public/js/index.js b/public/js/index.js index 7406c9a..660f73e 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -59,12 +59,13 @@ import { 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; From c2a8911b9c7872ea0d085020aa17e82162130f3d Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Fri, 13 Jan 2017 22:46:38 +0800 Subject: [PATCH 12/71] Move config variable to lib/config --- public/js/common.js | 25 +------------------------ public/js/lib/config/index.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 24 deletions(-) create mode 100644 public/js/lib/config/index.js diff --git a/public/js/common.js b/public/js/common.js index 6d54b45..9a60122 100644 --- a/public/js/common.js +++ b/public/js/common.js @@ -1,21 +1,4 @@ -// import config from './config'; - -import { - domain, // domain name - urlpath, // sub url path, like: www.example.com/ - debug, - GOOGLE_API_KEY, - GOOGLE_CLIENT_ID, - DROPBOX_APP_KEY -} from './config'; - -//common -export const port = window.location.port; -window.serverurl = `${window.location.protocol}//${domain ? domain : window.location.hostname}${port ? ':' + port : ''}${urlpath ? '/' + urlpath : ''}`; -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'; +import { serverurl } from './lib/config'; let checkAuth = false; let profile = null; @@ -101,12 +84,6 @@ export function checkIfAuth(yesCallback, noCallback) { } export default { - domain, - urlpath, - debug, - GOOGLE_API_KEY, - GOOGLE_CLIENT_ID, - DROPBOX_APP_KEY, checkAuth, profile, lastLoginState, diff --git a/public/js/lib/config/index.js b/public/js/lib/config/index.js new file mode 100644 index 0000000..bffbadd --- /dev/null +++ b/public/js/lib/config/index.js @@ -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; +export const urlpath = config.urlpath; +export const debug = config.debug; + +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'; From 0fca629c34b83617b2d72e42aa0edb66fd2e71f6 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Fri, 13 Jan 2017 22:51:44 +0800 Subject: [PATCH 13/71] Rename common.js to login.js --- public/js/cover.js | 2 +- public/js/extra.js | 2 +- public/js/history.js | 8 ++++++-- public/js/index.js | 7 +++++-- public/js/{common.js => lib/common/login.js} | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) rename public/js/{common.js => lib/common/login.js} (98%) diff --git a/public/js/cover.js b/public/js/cover.js index 677d82e..bc04923 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -9,7 +9,7 @@ import { getLoginState, resetCheckAuth, setloginStateChangeEvent -} from './common'; +} from './lib/common/login'; import { clearDuplicatedHistory, diff --git a/public/js/extra.js b/public/js/extra.js index 6cfb5b0..b651d9e 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -11,7 +11,7 @@ import PDFObject from 'pdfobject'; import S from 'string'; import { saveAs } from 'file-saver'; -require('./common'); +require('./lib/common/login'); require('../vendor/md-toc'); var Viz = require("viz.js"); diff --git a/public/js/history.js b/public/js/history.js index f120168..34b2cba 100644 --- a/public/js/history.js +++ b/public/js/history.js @@ -1,9 +1,13 @@ import store from 'store'; import S from 'string'; + +import { + checkIfAuth +} from './lib/common/login'; + import { - checkIfAuth, urlpath -} from './common'; +} from './lib/config'; window.migrateHistoryFromTempCallback = null; diff --git a/public/js/index.js b/public/js/index.js index 660f73e..3bf42ad 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -19,7 +19,10 @@ var List = require('list.js'); import { checkLoginStateChanged, - setloginStateChangeEvent, + setloginStateChangeEvent +} from './lib/common/login'; + +import { debug, DROPBOX_APP_KEY, GOOGLE_API_KEY, @@ -28,7 +31,7 @@ import { noteurl, urlpath, version -} from './common'; +} from './lib/config'; import { autoLinkify, diff --git a/public/js/common.js b/public/js/lib/common/login.js similarity index 98% rename from public/js/common.js rename to public/js/lib/common/login.js index 9a60122..12cc41f 100644 --- a/public/js/common.js +++ b/public/js/lib/common/login.js @@ -1,4 +1,4 @@ -import { serverurl } from './lib/config'; +import { serverurl } from '../config'; let checkAuth = false; let profile = null; From 2408ff4ba96c929a575b34e85d5cff0a01789ca4 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Fri, 13 Jan 2017 23:12:17 +0800 Subject: [PATCH 14/71] Add default value for config --- public/js/lib/config/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/js/lib/config/index.js b/public/js/lib/config/index.js index bffbadd..2b73679 100644 --- a/public/js/lib/config/index.js +++ b/public/js/lib/config/index.js @@ -2,13 +2,13 @@ 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 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; -export const urlpath = config.urlpath; -export const debug = config.debug; +export const domain = config.domain || ''; // domain name +export const urlpath = config.urlpath || ''; // sub url path, like: www.example.com/ +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 : ''}`; From a541569d7edbe827cae69c666079d5d1ded6790c Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Fri, 13 Jan 2017 23:12:27 +0800 Subject: [PATCH 15/71] Remove old config.js.example --- public/js/config.js.example | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 public/js/config.js.example diff --git a/public/js/config.js.example b/public/js/config.js.example deleted file mode 100644 index c5de388..0000000 --- a/public/js/config.js.example +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - domain: '', // domain name - urlpath: '', // sub url path, like: www.example.com/ - - // settings - debug: false, - - GOOGLE_API_KEY: '', - GOOGLE_CLIENT_ID: '', - DROPBOX_APP_KEY: '' -}; From 1ed19966394b9735c348ec0116ec0e939c363ce6 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Fri, 13 Jan 2017 23:37:16 +0800 Subject: [PATCH 16/71] Remove config.js from setup files --- .gitignore | 1 - bin/heroku | 2 -- bin/setup | 4 ---- 3 files changed, 7 deletions(-) diff --git a/.gitignore b/.gitignore index f48b3c6..ab83c14 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,6 @@ backups/ # ignore config files config.json -public/js/config.js .sequelizerc # ignore webpack build diff --git a/bin/heroku b/bin/heroku index e801003..1228b28 100755 --- a/bin/heroku +++ b/bin/heroku @@ -28,8 +28,6 @@ EOF EOF - cp public/js/config.js.example public/js/config.js - # build app npm run build fi diff --git a/bin/setup b/bin/setup index e24d4de..6724b2d 100755 --- a/bin/setup +++ b/bin/setup @@ -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 From b4bed37d64d59a70db3f0373894cf6ac611c1630 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 14 Jan 2017 14:17:20 +0800 Subject: [PATCH 17/71] Add google apiKey & dropbox appKey to config.json --- config.json.example | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.json.example b/config.json.example index e5e3fc5..e980566 100644 --- a/config.json.example +++ b/config.json.example @@ -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" }, "imgur": { "clientID": "change this" From 98c0cfc6a7dbf19a7996ff37968605ec946c97e1 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 14 Jan 2017 15:24:31 +0800 Subject: [PATCH 18/71] Update README --- README.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index cc05872..f6532d5 100644 --- a/README.md +++ b/README.md @@ -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/` | - Environment variables (will overwrite other server configs) --- @@ -148,7 +138,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 | @@ -196,7 +186,7 @@ Third-party integration api key settings | ------- | --------- | ----------- | | facebook, twitter, github, gitlab, dropbox, google | 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 --- From 77994508e66bc9fa1bde547d83e50d92aa5e1d88 Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Sat, 14 Jan 2017 15:27:24 +0800 Subject: [PATCH 19/71] Update README.md for npm script --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 92557cf..e2ab06a 100644 --- a/README.md +++ b/README.md @@ -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 From 04292240d6a589c537afb8e9838dcc0f062d0f2c Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 14 Jan 2017 15:47:13 +0800 Subject: [PATCH 20/71] Minor style update --- .eslintrc | 5 ++--- public/js/lib/common/login.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.eslintrc b/.eslintrc index 53a6dcb..bd14731 100644 --- a/.eslintrc +++ b/.eslintrc @@ -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", diff --git a/public/js/lib/common/login.js b/public/js/lib/common/login.js index 12cc41f..f1a03c7 100644 --- a/public/js/lib/common/login.js +++ b/public/js/lib/common/login.js @@ -32,7 +32,7 @@ export function setLoginState(bool, id) { export function checkLoginStateChanged() { if (getLoginState() != lastLoginState || getUserId() != lastUserId) { - if(loginStateChangeEvent) { + if (loginStateChangeEvent) { loginStateChangeEvent(); } return true; From 0f833f099f61b93e76a5f32175580fc2c0b9dc1a Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 14 Jan 2017 19:05:54 +0800 Subject: [PATCH 21/71] Update server google/dropbox config check --- lib/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/config.js b/lib/config.js index 53497f1..c0a7fff 100644 --- a/lib/config.js +++ b/lib/config.js @@ -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) || 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) || false; var imgur = process.env.HMD_IMGUR_CLIENTID || config.imgur || false; var email = process.env.HMD_EMAIL ? (process.env.HMD_EMAIL === 'true') : !!config.email; From a9a38c3d75b1cf467bb3b4484abfc09dcbcea107 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sun, 15 Jan 2017 11:58:00 +0800 Subject: [PATCH 22/71] Recover config change in 0f833f0 --- lib/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/config.js b/lib/config.js index 84f6b3d..3816017 100644 --- a/lib/config.js +++ b/lib/config.js @@ -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 && config.dropbox.clientID && config.dropbox.clientSecret) || 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 && config.google.clientID && config.google.clientSecret) || 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 || From 26d8942852f8d216d03138a6c3c1d350e6bc903e Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 21 Jan 2017 12:24:58 +0800 Subject: [PATCH 23/71] Revert experimental vue for now --- .editorconfig | 4 ---- package.json | 3 --- public/js/components/HelloWorld.vue | 21 --------------------- public/js/cover.js | 8 -------- public/js/views/Cover.vue | 15 --------------- public/views/index.ejs | 2 -- webpackBaseConfig.js | 8 +------- 7 files changed, 1 insertion(+), 60 deletions(-) delete mode 100644 public/js/components/HelloWorld.vue delete mode 100644 public/js/views/Cover.vue diff --git a/.editorconfig b/.editorconfig index b3e3025..619c178 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,10 +7,6 @@ indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true -[*.vue] -indent_style = space -indent_size = 2 - [*.md] trim_trailing_whitespace = false diff --git a/package.json b/package.json index e22f9e7..1ed81c9 100644 --- a/package.json +++ b/package.json @@ -116,8 +116,6 @@ "velocity-animate": "^1.4.0", "visibilityjs": "^1.2.4", "viz.js": "^1.4.1", - "vue": "^2.1.6", - "vue-loader": "^10.0.2", "winston": "^2.3.0", "xss": "^0.3.3" }, @@ -164,7 +162,6 @@ "script-loader": "^0.7.0", "style-loader": "^0.13.1", "url-loader": "^0.5.7", - "vue-template-compiler": "^2.1.6", "webpack": "^1.14.0" } } diff --git a/public/js/components/HelloWorld.vue b/public/js/components/HelloWorld.vue deleted file mode 100644 index d8e3007..0000000 --- a/public/js/components/HelloWorld.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/public/js/cover.js b/public/js/cover.js index 79b168d..830564e 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -29,14 +29,6 @@ import { saveAs } from 'file-saver'; import List from 'list.js'; import S from 'string'; -import Cover from './views/Cover'; -import Vue from 'vue'; - -new Vue({ - el: '#cover-app', - render: (h) => h(Cover) -}) - const options = { valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'], item: '
  • \ diff --git a/public/js/views/Cover.vue b/public/js/views/Cover.vue deleted file mode 100644 index 767d087..0000000 --- a/public/js/views/Cover.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/public/views/index.ejs b/public/views/index.ejs index d258857..b94daf5 100644 --- a/public/views/index.ejs +++ b/public/views/index.ejs @@ -30,8 +30,6 @@
    -
    -

    diff --git a/webpackBaseConfig.js b/webpackBaseConfig.js index e618bff..210001b 100644 --- a/webpackBaseConfig.js +++ b/webpackBaseConfig.js @@ -338,7 +338,7 @@ module.exports = { path.resolve(__dirname, 'src'), path.resolve(__dirname, 'node_modules') ], - extensions: ["", ".js", ".vue"], + extensions: ["", ".js"], alias: { codemirror: path.join(__dirname, 'node_modules/codemirror/codemirror.min.js'), inlineAttachment: path.join(__dirname, 'public/vendor/inlineAttachment/inline-attachment.js'), @@ -372,12 +372,6 @@ module.exports = { loaders: [{ test: /\.json$/, loader: 'json-loader' - }, { - test: /\.vue$/, - loader: 'vue', - options: { - // vue-loader options go here - } }, { test: /\.js$/, loader: 'babel', From e98278492e3c80816d54e1a6841548409c8a4d80 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 21 Jan 2017 12:50:02 +0800 Subject: [PATCH 24/71] Fix meta error not clear on before rendering --- public/js/index.js | 1 + public/js/pretty.js | 1 + 2 files changed, 2 insertions(+) diff --git a/public/js/index.js b/public/js/index.js index a018e51..6e55fa1 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -3445,6 +3445,7 @@ function updateViewInner() { var value = editor.getValue(); var lastMeta = md.meta; md.meta = {}; + delete md.metaError; var rendered = md.render(value); if (md.meta.type && md.meta.type === 'slide') { var slideOptions = { diff --git a/public/js/pretty.js b/public/js/pretty.js index c1a471a..b946d42 100644 --- a/public/js/pretty.js +++ b/public/js/pretty.js @@ -22,6 +22,7 @@ var markdown = $("#doc.markdown-body"); var text = markdown.text(); var lastMeta = md.meta; md.meta = {}; +delete md.metaError; var rendered = md.render(text); if (md.meta.type && md.meta.type === 'slide') { var slideOptions = { From 5e1d022e13a56786f40216c5485554d9e8b13c05 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 21 Jan 2017 12:52:26 +0800 Subject: [PATCH 25/71] Add screenshot on index page --- public/css/cover.css | 6 ++++++ public/screenshot.png | Bin 0 -> 238635 bytes public/views/index.ejs | 1 + 3 files changed, 7 insertions(+) create mode 100644 public/screenshot.png diff --git a/public/css/cover.css b/public/css/cover.css index a1527bf..6e191d2 100644 --- a/public/css/cover.css +++ b/public/css/cover.css @@ -354,6 +354,12 @@ input { color: white; } +.screenshot { + margin: 30px auto; + width: 100%; + border-radius: 3px; +} + select { color: black; } diff --git a/public/screenshot.png b/public/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e1e774315ddbf023b79b51939abef71b768f3f9a GIT binary patch literal 238635 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 z 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 __('Explore all features') %>


    +
    From 6e8ff3de234471375836ba907e86bf39804c308e Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 21 Jan 2017 12:53:18 +0800 Subject: [PATCH 26/71] Fix redundant parameter to removeColumn in db migration scripts --- lib/migrations/20161009040430-support-delete-note.js | 2 +- lib/migrations/20161201050312-support-email-signin.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/migrations/20161009040430-support-delete-note.js b/lib/migrations/20161009040430-support-delete-note.js index f478b6f..92ff6f7 100644 --- a/lib/migrations/20161009040430-support-delete-note.js +++ b/lib/migrations/20161009040430-support-delete-note.js @@ -6,6 +6,6 @@ module.exports = { }, down: function (queryInterface, Sequelize) { - queryInterface.removeColumn('Notes', 'deletedAt', Sequelize.DATE); + queryInterface.removeColumn('Notes', 'deletedAt'); } }; diff --git a/lib/migrations/20161201050312-support-email-signin.js b/lib/migrations/20161201050312-support-email-signin.js index bdea7c8..b5aaf77 100644 --- a/lib/migrations/20161201050312-support-email-signin.js +++ b/lib/migrations/20161201050312-support-email-signin.js @@ -7,7 +7,7 @@ module.exports = { }, down: function (queryInterface, Sequelize) { - queryInterface.removeColumn('Users', 'email', Sequelize.TEXT); - queryInterface.removeColumn('Users', 'password', Sequelize.TEXT); + queryInterface.removeColumn('Users', 'email'); + queryInterface.removeColumn('Users', 'password'); } }; From 93d6fe6d7cf7d49b3dcea8ffaad4d3d51beed965 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Sat, 21 Jan 2017 12:53:29 +0800 Subject: [PATCH 27/71] Revert useless linebreak --- public/views/index.ejs | 1 + 1 file changed, 1 insertion(+) diff --git a/public/views/index.ejs b/public/views/index.ejs index b94daf5..2513990 100644 --- a/public/views/index.ejs +++ b/public/views/index.ejs @@ -30,6 +30,7 @@
    +

    From 09a7bcbdef237c1443bbbfc29010e7106cffd739 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 21 Jan 2017 13:08:29 +0800 Subject: [PATCH 28/71] Refactor templates and rearrange its path --- public/views/error.ejs | 6 +- public/views/hackmd.ejs | 12 +- public/views/{ => hackmd}/body.ejs | 8 +- public/views/{ => hackmd}/foot.ejs | 4 +- public/views/{ => hackmd}/footer.ejs | 0 public/views/{ => hackmd}/head.ejs | 6 +- public/views/{ => hackmd}/header.ejs | 0 public/views/index.ejs | 216 +------------------ public/views/index/body.ejs | 175 +++++++++++++++ public/views/index/foot.ejs | 13 ++ public/views/index/footer.ejs | 0 public/views/index/head.ejs | 22 ++ public/views/index/header.ejs | 0 public/views/pretty.ejs | 14 +- public/views/{ => shared}/disqus.ejs | 0 public/views/{ => shared}/ga.ejs | 0 public/views/{ => shared}/help-modal.ejs | 0 public/views/{ => shared}/polyfill.ejs | 0 public/views/{ => shared}/refresh-modal.ejs | 0 public/views/{ => shared}/revision-modal.ejs | 0 public/views/{ => shared}/signin-modal.ejs | 0 public/views/slide.ejs | 14 +- 22 files changed, 247 insertions(+), 243 deletions(-) rename public/views/{ => hackmd}/body.ejs (99%) rename public/views/{ => hackmd}/foot.ejs (97%) rename public/views/{ => hackmd}/footer.ejs (100%) rename public/views/{ => hackmd}/head.ejs (93%) rename public/views/{ => hackmd}/header.ejs (100%) create mode 100644 public/views/index/body.ejs create mode 100644 public/views/index/foot.ejs create mode 100644 public/views/index/footer.ejs create mode 100644 public/views/index/head.ejs create mode 100644 public/views/index/header.ejs rename public/views/{ => shared}/disqus.ejs (100%) rename public/views/{ => shared}/ga.ejs (100%) rename public/views/{ => shared}/help-modal.ejs (100%) rename public/views/{ => shared}/polyfill.ejs (100%) rename public/views/{ => shared}/refresh-modal.ejs (100%) rename public/views/{ => shared}/revision-modal.ejs (100%) rename public/views/{ => shared}/signin-modal.ejs (100%) diff --git a/public/views/error.ejs b/public/views/error.ejs index 402b5eb..a40ed39 100644 --- a/public/views/error.ejs +++ b/public/views/error.ejs @@ -2,18 +2,18 @@ - <%- include head %> + <%- include hackmd/head %> - <%- include header %> + <%- include hackmd/header %>

    <%- code %> <%- detail %> <%- msg %>

    - <%- include footer %> + <%- include hackmd/footer %> \ No newline at end of file diff --git a/public/views/hackmd.ejs b/public/views/hackmd.ejs index c5778fc..49084a6 100644 --- a/public/views/hackmd.ejs +++ b/public/views/hackmd.ejs @@ -2,14 +2,14 @@ - <%- include head %> + <%- include hackmd/head %> - <%- include header %> - <%- include body %> - <%- include footer %> - <%- include foot %> + <%- include hackmd/header %> + <%- include hackmd/body %> + <%- include hackmd/footer %> + <%- include hackmd/foot %> - \ No newline at end of file + diff --git a/public/views/body.ejs b/public/views/hackmd/body.ejs similarity index 99% rename from public/views/body.ejs rename to public/views/hackmd/body.ejs index 5ad1733..d8a3f10 100644 --- a/public/views/body.ejs +++ b/public/views/hackmd/body.ejs @@ -244,7 +244,7 @@
    -<%- include refresh-modal %> -<%- include signin-modal %> -<%- include help-modal %> -<%- include revision-modal %> +<%- include ../shared/refresh-modal %> +<%- include ../shared/signin-modal %> +<%- include ../shared/help-modal %> +<%- include ../shared/revision-modal %> diff --git a/public/views/foot.ejs b/public/views/hackmd/foot.ejs similarity index 97% rename from public/views/foot.ejs rename to public/views/hackmd/foot.ejs index c1df65c..178b550 100644 --- a/public/views/foot.ejs +++ b/public/views/hackmd/foot.ejs @@ -20,9 +20,9 @@ -<%- include build/index-scripts %> +<%- include ../build/index-scripts %> <% } else { %> -<%- include build/index-pack-scripts %> +<%- include ../build/index-pack-scripts %> <% } %> diff --git a/public/views/footer.ejs b/public/views/hackmd/footer.ejs similarity index 100% rename from public/views/footer.ejs rename to public/views/hackmd/footer.ejs diff --git a/public/views/head.ejs b/public/views/hackmd/head.ejs similarity index 93% rename from public/views/head.ejs rename to public/views/hackmd/head.ejs index 218847f..d066399 100644 --- a/public/views/head.ejs +++ b/public/views/hackmd/head.ejs @@ -14,9 +14,9 @@ -<%- include build/index-header %> +<%- include ../build/index-header %> <% } else { %> -<%- include build/index-pack-header %> +<%- include ../build/index-pack-header %> <% } %> -<%- include polyfill %> \ No newline at end of file +<%- include ../shared/polyfill %> \ No newline at end of file diff --git a/public/views/header.ejs b/public/views/hackmd/header.ejs similarity index 100% rename from public/views/header.ejs rename to public/views/hackmd/header.ejs diff --git a/public/views/index.ejs b/public/views/index.ejs index 4bcea0e..5732db4 100644 --- a/public/views/index.ejs +++ b/public/views/index.ejs @@ -2,220 +2,14 @@ - - - - - - - - - HackMD - <%= __('Collaborative markdown notes') %> - - - <% if(useCDN) { %> - - - - - - <%- include build/cover-header %> - <% } else { %> - <%- include build/cover-pack-header %> - <% } %> - <%- include polyfill %> + <%- include index/head %> -
    -
    -
    - -
    -
    -

    - -
    -
    - -
    style="display:none;"<% } %>> -
    -

    HackMD

    -

    - <%= __('Best way to write and share your knowledge in markdown.') %> -

    - <% if (infoMessage && infoMessage.length > 0) { %> -
    <%= infoMessage %>
    - <% } %> - <% if (errorMessage && errorMessage.length > 0) { %> -
    <%= errorMessage %>
    - <% } %> - <% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %> - - <%= __('or') %> - <% } %> - - -
    -
    - -
    style="display:none;"<% } %>> - -
    -
    -
    - -
    -
    - -
    - - <%= __('Title') %> - - - <%= __('Time') %> - - - -
    - - -
      -
    -
      -
      - -
      -
      - -

      - © 2017 HackMD | <%= __('Releases') %> -

      - -
      -
      -
      -
      -
      - - - <%- include signin-modal %> - - <% if(useCDN) { %> - - - - - - - - - <%- include build/cover-scripts %> - <% } else { %> - <%- include build/cover-pack-scripts %> - <% } %> + <%- include index/header %> + <%- include index/body %> + <%- include index/footer %> + <%- include index/foot %> diff --git a/public/views/index/body.ejs b/public/views/index/body.ejs new file mode 100644 index 0000000..b807245 --- /dev/null +++ b/public/views/index/body.ejs @@ -0,0 +1,175 @@ +
      +
      +
      + +
      +
      +

      + +
      +
      + +
      style="display:none;"<% } %>> +
      +

      HackMD

      +

      + <%= __('Best way to write and share your knowledge in markdown.') %> +

      + <% if (infoMessage && infoMessage.length > 0) { %> +
      <%= infoMessage %>
      + <% } %> + <% if (errorMessage && errorMessage.length > 0) { %> +
      <%= errorMessage %>
      + <% } %> + <% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %> + + <%= __('or') %> + <% } %> + + +
      +
      + +
      style="display:none;"<% } %>> + +
      +
      +
      + +
      +
      + +
      + + <%= __('Title') %> + + + <%= __('Time') %> + + + +
      + + +
        +
      +
        +
        + +
        +
        + +

        + © 2017 HackMD | <%= __('Releases') %> +

        + +
        +
        +
        +
        +
        + + +<%- include ../shared/signin-modal %> \ No newline at end of file diff --git a/public/views/index/foot.ejs b/public/views/index/foot.ejs new file mode 100644 index 0000000..293c669 --- /dev/null +++ b/public/views/index/foot.ejs @@ -0,0 +1,13 @@ +<% if(useCDN) { %> + + + + + + + + +<%- include ../build/cover-scripts %> +<% } else { %> +<%- include ../build/cover-pack-scripts %> +<% } %> \ No newline at end of file diff --git a/public/views/index/footer.ejs b/public/views/index/footer.ejs new file mode 100644 index 0000000..e69de29 diff --git a/public/views/index/head.ejs b/public/views/index/head.ejs new file mode 100644 index 0000000..bbd1456 --- /dev/null +++ b/public/views/index/head.ejs @@ -0,0 +1,22 @@ + + + + + + + + +HackMD - <%= __('Collaborative markdown notes') %> + + +<% if(useCDN) { %> + + + + + +<%- include ../build/cover-header %> +<% } else { %> +<%- include ../build/cover-pack-header %> +<% } %> +<%- include ../shared/polyfill %> \ No newline at end of file diff --git a/public/views/index/header.ejs b/public/views/index/header.ejs new file mode 100644 index 0000000..e69de29 diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs index ced65ed..de5b8ad 100644 --- a/public/views/pretty.ejs +++ b/public/views/pretty.ejs @@ -23,12 +23,12 @@ - <%- include build/pretty-header %> + <%- include ../build/pretty-header %> <% } else { %> - <%- include build/pretty-pack-header %> + <%- include ../build/pretty-pack-header %> <% } %> - <%- include polyfill %> + <%- include ../shared/polyfill %> @@ -66,7 +66,7 @@ <% if(typeof disqus !== 'undefined' && disqus) { %>
        - <%- include disqus %> + <%- include ../shared/disqus %>
        <% } %> @@ -90,10 +90,10 @@ -<%- include build/pretty-scripts %> +<%- include ../build/pretty-scripts %> <% } else { %> -<%- include build/pretty-pack-scripts %> +<%- include ../build/pretty-pack-scripts %> <% } %> -<%- include ga %> +<%- include ../shared/ga %> diff --git a/public/views/disqus.ejs b/public/views/shared/disqus.ejs similarity index 100% rename from public/views/disqus.ejs rename to public/views/shared/disqus.ejs diff --git a/public/views/ga.ejs b/public/views/shared/ga.ejs similarity index 100% rename from public/views/ga.ejs rename to public/views/shared/ga.ejs diff --git a/public/views/help-modal.ejs b/public/views/shared/help-modal.ejs similarity index 100% rename from public/views/help-modal.ejs rename to public/views/shared/help-modal.ejs diff --git a/public/views/polyfill.ejs b/public/views/shared/polyfill.ejs similarity index 100% rename from public/views/polyfill.ejs rename to public/views/shared/polyfill.ejs diff --git a/public/views/refresh-modal.ejs b/public/views/shared/refresh-modal.ejs similarity index 100% rename from public/views/refresh-modal.ejs rename to public/views/shared/refresh-modal.ejs diff --git a/public/views/revision-modal.ejs b/public/views/shared/revision-modal.ejs similarity index 100% rename from public/views/revision-modal.ejs rename to public/views/shared/revision-modal.ejs diff --git a/public/views/signin-modal.ejs b/public/views/shared/signin-modal.ejs similarity index 100% rename from public/views/signin-modal.ejs rename to public/views/shared/signin-modal.ejs diff --git a/public/views/slide.ejs b/public/views/slide.ejs index b0323a0..eb1453f 100644 --- a/public/views/slide.ejs +++ b/public/views/slide.ejs @@ -23,10 +23,10 @@ - <%- include build/slide-header %> + <%- include ../build/slide-header %> <% } else { %> - <%- include build/slide-pack-header %> + <%- include ../build/slide-pack-header %> <% } %> @@ -45,7 +45,7 @@ document.getElementsByTagName( 'head' )[0].appendChild( link ); - <%- include polyfill %> + <%- include ../shared/polyfill %>
        @@ -79,7 +79,7 @@
        <% if(typeof disqus !== 'undefined' && disqus) { %>
        - <%- include disqus %> + <%- include ../shared/disqus %>
        <% } %>
        @@ -104,13 +104,13 @@ - <%- include build/slide-scripts %> + <%- include ../build/slide-scripts %> <% } else { %> - <%- include build/slide-pack-scripts %> + <%- include ../build/slide-pack-scripts %> <% } %> -<%- include ga %> +<%- include ../shared/ga %> From a669c201beb3755703e87984268cbd08145e9ac6 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 21 Jan 2017 13:40:08 +0800 Subject: [PATCH 29/71] Fix template partial path --- public/views/pretty.ejs | 14 +++++++------- public/views/slide.ejs | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs index de5b8ad..a6913f6 100644 --- a/public/views/pretty.ejs +++ b/public/views/pretty.ejs @@ -23,12 +23,12 @@ - <%- include ../build/pretty-header %> + <%- include build/pretty-header %> <% } else { %> - <%- include ../build/pretty-pack-header %> + <%- include build/pretty-pack-header %> <% } %> - <%- include ../shared/polyfill %> + <%- include shared/polyfill %> @@ -66,7 +66,7 @@ <% if(typeof disqus !== 'undefined' && disqus) { %>
        - <%- include ../shared/disqus %> + <%- include shared/disqus %>
        <% } %> @@ -90,10 +90,10 @@ -<%- include ../build/pretty-scripts %> +<%- include build/pretty-scripts %> <% } else { %> -<%- include ../build/pretty-pack-scripts %> +<%- include build/pretty-pack-scripts %> <% } %> -<%- include ../shared/ga %> +<%- include shared/ga %> diff --git a/public/views/slide.ejs b/public/views/slide.ejs index eb1453f..ffbfdce 100644 --- a/public/views/slide.ejs +++ b/public/views/slide.ejs @@ -23,10 +23,10 @@ - <%- include ../build/slide-header %> + <%- include build/slide-header %> <% } else { %> - <%- include ../build/slide-pack-header %> + <%- include build/slide-pack-header %> <% } %> @@ -45,7 +45,7 @@ document.getElementsByTagName( 'head' )[0].appendChild( link ); - <%- include ../shared/polyfill %> + <%- include shared/polyfill %>
        @@ -79,7 +79,7 @@
        <% if(typeof disqus !== 'undefined' && disqus) { %>
        - <%- include ../shared/disqus %> + <%- include shared/disqus %>
        <% } %>
        @@ -104,13 +104,13 @@ - <%- include ../build/slide-scripts %> + <%- include build/slide-scripts %> <% } else { %> - <%- include ../build/slide-pack-scripts %> + <%- include build/slide-pack-scripts %> <% } %> -<%- include ../shared/ga %> +<%- include shared/ga %> From fc00fa74341a43b2f99b085aa52fee57f40082ff Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 21 Jan 2017 14:24:51 +0800 Subject: [PATCH 30/71] Add link to features on profile dropdown --- public/views/index/body.ejs | 1 + 1 file changed, 1 insertion(+) diff --git a/public/views/index/body.ejs b/public/views/index/body.ejs index b807245..584d67e 100644 --- a/public/views/index/body.ejs +++ b/public/views/index/body.ejs @@ -26,6 +26,7 @@ From 9ea66e8820eda8fb14b176477808a4ba1f213a35 Mon Sep 17 00:00:00 2001 From: Sheogorath Date: Sat, 21 Jan 2017 19:18:56 +0100 Subject: [PATCH 31/71] Add documentation for new permissions --- public/docs/features.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/docs/features.md b/public/docs/features.md index 1c25bfe..1e9d48f 100644 --- a/public/docs/features.md +++ b/public/docs/features.md @@ -49,7 +49,9 @@ There are four possible options: **Freely**: Anyone can edit this note. **Editable**: A signed-in user can edit this note. - **Locked**: Only the owner can edit this note. + **Limited**: People have to sign-in to view and edit this note. + **Locked**: Anyone can view this note but only the owner can edit it. + **Protected**: People have to sign-in to view this note but only owner can edit. **Private**: Only the owner can view and edit this note. **Only the owner of the note can change the note's permissions.** From 9122ccd1b8dc4d6a41aaa0794e80b5e06f2484d5 Mon Sep 17 00:00:00 2001 From: Sheogorath Date: Mon, 23 Jan 2017 06:11:20 +0100 Subject: [PATCH 32/71] Add fail fast option Fail the script if a command inside it fails to prevent a install with exitcode 0 even when commands in it are failing. --- bin/setup | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/setup b/bin/setup index 6724b2d..3f143cd 100755 --- a/bin/setup +++ b/bin/setup @@ -1,5 +1,7 @@ #!/bin/bash +set -e + # run command at repo root CURRENT_PATH=$PWD if [ -d .git ]; then From 3df5507589e09b9ec75fb1f8e0c750c6590fc003 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Thu, 2 Feb 2017 23:27:34 +0800 Subject: [PATCH 33/71] Upgrade viz.js to fix manual workaround and get smaller file size --- package.json | 2 +- public/js/extra.js | 33 ++++++++++++--------------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 1ed81c9..1c04318 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "validator": "^6.2.0", "velocity-animate": "^1.4.0", "visibilityjs": "^1.2.4", - "viz.js": "^1.4.1", + "viz.js": "^1.7.0", "winston": "^2.3.0", "xss": "^0.3.3" }, diff --git a/public/js/extra.js b/public/js/extra.js index b651d9e..b0a4bdc 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -345,30 +345,21 @@ export function finishView(view) { }); //graphviz var graphvizs = view.find("div.graphviz.raw").removeClass("raw"); - function parseGraphviz(key, value) { - var $value = $(value); - var $ele = $(value).parent().parent(); - - var graphviz = Viz($value.text()); - if (!graphviz) throw Error('viz.js output empty graph'); - $value.html(graphviz); - - $ele.addClass('graphviz'); - $value.children().unwrap().unwrap(); - } graphvizs.each(function (key, value) { try { - parseGraphviz(key, value); + var $value = $(value); + var $ele = $(value).parent().parent(); + + var graphviz = Viz($value.text()); + if (!graphviz) throw Error('viz.js output empty graph'); + $value.html(graphviz); + + $ele.addClass('graphviz'); + $value.children().unwrap().unwrap(); } catch (err) { - // workaround for graphviz not recover from error - try { - parseGraphviz(key, value); - } catch (err) { - var $value = $(value); - $value.unwrap(); - $value.parent().append('
        ' + err + '
        '); - console.warn(err); - } + $value.unwrap(); + $value.parent().append('
        ' + err + '
        '); + console.warn(err); } }); //mermaid From 4dbafe62a3cd0d0c5a19248e25e7262c5aec1bea Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Thu, 2 Feb 2017 23:28:05 +0800 Subject: [PATCH 34/71] Upgrade mermaid to support class diagram --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c04318..f31c9da 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "markdown-it-sup": "^1.0.0", "markdown-pdf": "^7.0.0", "mathjax": "~2.7.0", - "mermaid": "~6.0.0", + "mermaid": "~7.0.0", "meta-marked": "^0.4.2", "method-override": "^2.3.7", "moment": "^2.17.1", From d5008b7aeb339f98751d9e0c78946e306c010b3f Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Thu, 2 Feb 2017 23:37:20 +0800 Subject: [PATCH 35/71] Update viz.js and mermaid CDN links --- public/views/hackmd/foot.ejs | 4 ++-- public/views/pretty.ejs | 4 ++-- public/views/slide.ejs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/public/views/hackmd/foot.ejs b/public/views/hackmd/foot.ejs index 178b550..5d46937 100644 --- a/public/views/hackmd/foot.ejs +++ b/public/views/hackmd/foot.ejs @@ -11,14 +11,14 @@ - + - + <%- include ../build/index-scripts %> <% } else { %> diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs index a6913f6..15f853a 100644 --- a/public/views/pretty.ejs +++ b/public/views/pretty.ejs @@ -84,12 +84,12 @@ - + - + <%- include build/pretty-scripts %> <% } else { %> diff --git a/public/views/slide.ejs b/public/views/slide.ejs index ffbfdce..3799b2e 100644 --- a/public/views/slide.ejs +++ b/public/views/slide.ejs @@ -98,12 +98,12 @@ - + - + <%- include build/slide-scripts %> <% } else { %> From 6c87262bd9d80f2fe409241d2e2084bc99b44b5b Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Thu, 2 Feb 2017 23:40:55 +0800 Subject: [PATCH 36/71] Fix to use minified CDN file source in mermaid --- public/views/hackmd/foot.ejs | 2 +- public/views/pretty.ejs | 2 +- public/views/slide.ejs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/views/hackmd/foot.ejs b/public/views/hackmd/foot.ejs index 5d46937..445b021 100644 --- a/public/views/hackmd/foot.ejs +++ b/public/views/hackmd/foot.ejs @@ -11,7 +11,7 @@ - + diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs index 15f853a..64b65c7 100644 --- a/public/views/pretty.ejs +++ b/public/views/pretty.ejs @@ -84,7 +84,7 @@ - + diff --git a/public/views/slide.ejs b/public/views/slide.ejs index 3799b2e..a3e2d1d 100644 --- a/public/views/slide.ejs +++ b/public/views/slide.ejs @@ -98,7 +98,7 @@ - + From e67a6ad3685289437e510906eeffb0d764ba4a37 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 00:07:08 +0800 Subject: [PATCH 37/71] Fix missing type declaration --- public/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index 39f28fb..56f4fd3 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2675,7 +2675,7 @@ editor.on('update', function () { }); // clear tooltip which described element has been removed $('[id^="tooltip"]').each(function (index, element) { - $ele = $(element); + var $ele = $(element); if ($('[aria-describedby="' + $ele.attr('id') + '"]').length <= 0) $ele.remove(); }); }); From 5a212b933548ccc5ef1cd45d8b86d7d86c8f7b9e Mon Sep 17 00:00:00 2001 From: NV Date: Fri, 3 Feb 2017 17:35:16 +0900 Subject: [PATCH 38/71] Removed UTF-8 BOM in download function --- public/js/cover.js | 2 +- public/js/extra.js | 4 ++-- public/js/index.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/public/js/cover.js b/public/js/cover.js index 830564e..bc6e73f 100644 --- a/public/js/cover.js +++ b/public/js/cover.js @@ -325,7 +325,7 @@ $(".ui-save-history").click(() => { 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')}`, true); }); }); diff --git a/public/js/extra.js b/public/js/extra.js index b651d9e..a657c31 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -612,7 +612,7 @@ export function exportToRawHTML(view) { const blob = new Blob([html], { type: "text/html;charset=utf-8" }); - saveAs(blob, filename); + saveAs(blob, filename, true); } //extract markdown body to html and compile to template @@ -644,7 +644,7 @@ export function exportToHTML(view) { const blob = new Blob([html], { type: "text/html;charset=utf-8" }); - saveAs(blob, filename); + saveAs(blob, filename, true); }); }); } diff --git a/public/js/index.js b/public/js/index.js index 39f28fb..176f0da 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1542,7 +1542,7 @@ ui.toolbar.download.markdown.click(function (e) { var blob = new Blob([markdown], { type: "text/markdown;charset=utf-8" }); - saveAs(blob, filename); + saveAs(blob, filename, true); }); //html ui.toolbar.download.html.click(function (e) { @@ -1922,7 +1922,7 @@ $('#revisionModalDownload').click(function () { var blob = new Blob([revision.content], { type: "text/markdown;charset=utf-8" }); - saveAs(blob, filename); + saveAs(blob, filename, true); }); $('#revisionModalRevert').click(function () { if (!revision) return; From 92ad67b813c3b940f619983c7daee7cdf21c3f4e Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 21:39:08 +0800 Subject: [PATCH 39/71] Update to remove history cache to lower application coupling --- app.js | 6 +- lib/history.js | 147 ++++++++++++++++-------------------------------- lib/realtime.js | 25 ++++---- 3 files changed, 64 insertions(+), 114 deletions(-) diff --git a/app.js b/app.js index ba0b67d..ee82fab 100644 --- a/app.js +++ b/app.js @@ -26,7 +26,6 @@ var validator = require('validator'); var config = require("./lib/config.js"); var logger = require("./lib/logger.js"); var auth = require("./lib/auth.js"); -var history = require("./lib/history.js"); var response = require("./lib/response.js"); var models = require("./lib/models"); @@ -443,6 +442,7 @@ app.get('/logout', function (req, res) { req.logout(); res.redirect(config.serverurl + '/'); }); +var history = require("./lib/history.js"); //get history app.get('/history', history.historyGet); //post history @@ -608,7 +608,7 @@ function startListen() { // sync db then start listen models.sequelize.sync().then(function () { // check if realtime is ready - if (history.isReady() && realtime.isReady()) { + if (realtime.isReady()) { models.Revision.checkAllNotesRevision(function (err, notes) { if (err) throw new Error(err); if (!notes || notes.length <= 0) return startListen(); @@ -639,7 +639,7 @@ function handleTermSignals() { }, 0); }); var checkCleanTimer = setInterval(function () { - if (history.isReady() && realtime.isReady()) { + if (realtime.isReady()) { models.Revision.checkAllNotesRevision(function (err, notes) { if (err) return logger.error(err); if (!notes || notes.length <= 0) { diff --git a/lib/history.js b/lib/history.js index 2723422..e7fb308 100644 --- a/lib/history.js +++ b/lib/history.js @@ -1,7 +1,6 @@ //history //external modules var async = require('async'); -var moment = require('moment'); //core var config = require("./config.js"); @@ -14,45 +13,32 @@ var History = { historyGet: historyGet, historyPost: historyPost, historyDelete: historyDelete, - isReady: isReady, 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 getHistory(userid, callback) { + models.User.findOne({ + where: { + id: userid } - }, function (err) { - if (err) return logger.error('history updater error', err); + }).then(function (user) { + if (!user) + return callback(null, null); + var history = {}; + if (user.history) + history = parseHistoryToObject(JSON.parse(user.history)); + if (config.debug) + logger.info('read history success: ' + user.id); + return callback(null, history); + }).catch(function (err) { + logger.error('read history failed: ' + err); + return callback(err, null); }); - // 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) { +function setHistory(userid, history, callback) { models.User.update({ - history: JSON.stringify(history) + history: JSON.stringify(parseHistoryToArray(history)) }, { where: { id: userid @@ -60,72 +46,27 @@ function finishUpdateHistory(userid, history, callback) { }).then(function (count) { return callback(null, count); }).catch(function (err) { + logger.error('set history failed: ' + 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) { - if (caches[userid]) { - return callback(null, caches[userid].history); - } else { - models.User.findOne({ - where: { - id: userid - } - }).then(function (user) { - if (!user) - return callback(null, null); - var history = []; - if (user.history) - history = JSON.parse(user.history); - if (config.debug) - logger.info('read history success: ' + user.id); - setHistory(userid, history); - return callback(null, history); - }).catch(function (err) { - logger.error('read history failed: ' + err); - return callback(err, null); - }); - } -} - -function setHistory(userid, history) { - 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) { +function updateHistory(userid, noteId, document, time) { if (userid && noteId && typeof document !== 'undefined') { getHistory(userid, function (err, history) { if (err || !history) return; - if (!caches[userid].history[noteId]) { - caches[userid].history[noteId] = {}; + if (!history[noteId]) { + history[noteId] = {}; } - var noteHistory = caches[userid].history[noteId]; + var noteHistory = history[noteId]; var noteInfo = models.Note.parseNoteInfo(document); noteHistory.id = noteId; noteHistory.text = noteInfo.title; - noteHistory.time = moment().valueOf(); + noteHistory.time = time || Date.now(); 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); } if (Array.isArray(history)) { - setHistory(req.user.id, history); - caches[req.user.id].isDirty = true; - res.end(); + setHistory(req.user.id, history, function (err, count) { + if (err) return response.errorInternalError(res); + res.end(); + }); } else { return response.errorBadRequest(res); } @@ -186,11 +128,13 @@ function historyPost(req, res) { getHistory(req.user.id, function (err, history) { if (err) return response.errorInternalError(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') { - caches[req.user.id].history[noteId].pinned = (req.body.pinned === 'true'); - caches[req.user.id].isDirty = true; - res.end(); + history[noteId].pinned = (req.body.pinned === 'true'); + setHistory(req.user.id, history, function (err, count) { + if (err) return response.errorInternalError(res); + res.end(); + }); } else { return response.errorBadRequest(res); } @@ -205,16 +149,19 @@ function historyDelete(req, res) { if (req.isAuthenticated()) { var noteId = req.params.noteId; if (!noteId) { - setHistory(req.user.id, []); - caches[req.user.id].isDirty = true; - res.end(); + setHistory(req.user.id, [], function (err, count) { + if (err) return response.errorInternalError(res); + res.end(); + }); } else { getHistory(req.user.id, function (err, history) { if (err) return response.errorInternalError(res); if (!history) return response.errorNotFound(res); - delete caches[req.user.id].history[noteId]; - caches[req.user.id].isDirty = true; - res.end(); + delete history[noteId]; + setHistory(req.user.id, history, function (err, count) { + if (err) return response.errorInternalError(res); + res.end(); + }); }); } } else { diff --git a/lib/realtime.js b/lib/realtime.js index fadea4f..def8f21 100644 --- a/lib/realtime.js +++ b/lib/realtime.js @@ -122,6 +122,12 @@ function updateNote(note, callback) { } }).then(function (_note) { 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.lastchangeuserId != note.lastchangeuser) { models.User.findOne({ @@ -405,10 +411,7 @@ function finishConnection(socket, note, user) { note.server.setColor(socket, user.color); // update user note history - setTimeout(function () { - var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id); - if (note.server) history.updateHistory(user.userid, noteId, note.server.document); - }, 0); + updateHistory(user.userid, note); emitOnlineUsers(socket); emitRefresh(socket); @@ -497,6 +500,7 @@ function startConnection(socket) { lastchangeuserprofile: lastchangeuserprofile, socks: [], users: {}, + tempUsers: {}, createtime: moment(createtime).valueOf(), updatetime: moment(updatetime).valueOf(), server: server, @@ -687,15 +691,14 @@ function operationCallback(socket, operation) { return logger.error('operation callback failed: ' + err); }); } - // update user note history - setTimeout(function() { - var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id); - if (note.server) history.updateHistory(userId, noteId, note.server.document); - }, 0); - + note.tempUsers[userId] = Date.now(); } // save 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) { @@ -925,4 +928,4 @@ function connection(socket) { }); } -module.exports = realtime; +module.exports = realtime; \ No newline at end of file From ef0ac7768d5dbd6a99c4126a1ed8b091f004d3bf Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 21:47:38 +0800 Subject: [PATCH 40/71] Update realtime to use timer to avoid memory leaks on busy tick --- lib/realtime.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/realtime.js b/lib/realtime.js index def8f21..c1db688 100644 --- a/lib/realtime.js +++ b/lib/realtime.js @@ -354,9 +354,12 @@ function clearSocketQueue(queue, socket) { } function connectNextSocket() { - isConnectionBusy = false; - if (connectionSocketQueue.length > 0) - startConnection(connectionSocketQueue[0]); + setTimeout(function () { + isConnectionBusy = false; + if (connectionSocketQueue.length > 0) { + startConnection(connectionSocketQueue[0]); + } + }, 1); } function interruptConnection(socket, note, user) { @@ -693,8 +696,11 @@ function operationCallback(socket, operation) { } note.tempUsers[userId] = Date.now(); } - // save authorship - note.authorship = models.Note.updateAuthorshipByOperation(operation, userId, note.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); + }); +} function updateHistory(userId, note, time) { var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id); From 8cfbfa43520a298637b6f4e3137e4dea9d09e34d Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 21:48:36 +0800 Subject: [PATCH 41/71] Update to add biggerphoto on parsing user profile --- lib/models/user.js | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/models/user.js b/lib/models/user.js index 7d27242..aee4204 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -79,39 +79,54 @@ module.exports = function (sequelize, DataTypes) { if (profile) { profile = { name: profile.displayName || profile.username, - photo: User.parsePhotoByProfile(profile) + photo: User.parsePhotoByProfile(profile), + biggerphoto: User.parsePhotoByProfile(profile, true) } } return profile; }, - parsePhotoByProfile: function (profile) { + parsePhotoByProfile: function (profile, bigger) { var photo = null; switch (profile.provider) { 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; 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; 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; case "gitlab": - photo = profile.avatarUrl.replace(/(\?s=)\d*$/i, '$196'); + photo = profile.avatarUrl; + if (bigger) photo.replace(/(\?s=)\d*$/i, '$1400'); + else photo.replace(/(\?s=)\d*$/i, '$196'); break; case "dropbox": //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; case "google": - photo = profile.photos[0].value.replace(/(\?sz=)\d*$/i, '$196'); + photo = profile.photos[0].value; + if (bigger) photo.replace(/(\?sz=)\d*$/i, '$1400'); + else photo.replace(/(\?sz=)\d*$/i, '$196'); break; case "ldap": //no image api provided, //use gravatar if email exists, //otherwise generate a letter avatar 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 { photo = letterAvatars(profile.username); } @@ -123,7 +138,8 @@ module.exports = function (sequelize, DataTypes) { var photoUrl = 'https://www.gravatar.com/avatar/' + md5(email); return { name: email.substring(0, email.lastIndexOf("@")), - photo: photoUrl += '?s=96' + photo: photoUrl += '?s=96', + biggerphoto: photoUrl += '?s=400' }; } } From 0a3baec5b6bf6340fb7dfee3dce18807b01acfa6 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 21:59:26 +0800 Subject: [PATCH 42/71] Fix missing type declaration in text complete strategy --- public/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index dd26d37..9b42e79 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -3953,7 +3953,7 @@ $(editor.getInputField()) match: /(?:^|\n|\s)(\>.*|\s|)((\^|)\[(\^|)\](\[\]|\(\)|\:|)\s*\w*)$/, search: function (term, callback) { var line = editor.getLine(editor.getCursor().line); - quote = line.match(this.match)[1].trim(); + var quote = line.match(this.match)[1].trim(); var list = []; if (quote.indexOf('>') == 0) { $.map(supportExtraTags, function (extratag) { From 7863eec3660c7d78f9cfd5b3eee0585975faac6e Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 22:01:30 +0800 Subject: [PATCH 43/71] Fix "[object HTMLCollection] is not iterable!" error in some browsers --- public/js/extra.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/js/extra.js b/public/js/extra.js index 39812fd..1623566 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -792,7 +792,8 @@ const anchorForId = id => { const linkifyAnchors = (level, containingElement) => { const headers = containingElement.getElementsByTagName(`h${level}`); - for (const header of headers) { + for (let i = 0, l = headers.length; i < l; i++) { + let header = headers[i]; if (header.getElementsByClassName("anchor").length == 0) { if (typeof header.id == "undefined" || header.id == "") { //to escape characters not allow in css and humanize From 1a617ddf2ee44e116a97e1bc0168af22a87d2102 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 22:02:12 +0800 Subject: [PATCH 44/71] Fix duplicated headers anchor link not been updated properly --- public/js/extra.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/extra.js b/public/js/extra.js index 1623566..a3e840d 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -833,7 +833,7 @@ export function deduplicatedHeaderId(view) { const newId = id + j; const $duplicatedHeader = $(duplicatedHeaders[j]); $duplicatedHeader.attr('id', newId); - const $headerLink = $duplicatedHeader.find('> .header-link'); + const $headerLink = $duplicatedHeader.find(`> a.anchor[href="#${id}"]`); $headerLink.attr('href', `#${newId}`); $headerLink.attr('title', newId); } From 5ce5d4cd849f764cc563fc4cb1f3288ebb14a2a4 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 22:04:43 +0800 Subject: [PATCH 45/71] Update to use babel-polyfill to support ES6 features in old browsers --- package.json | 1 + webpackBaseConfig.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/package.json b/package.json index f31c9da..74de2c8 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,7 @@ "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", diff --git a/webpackBaseConfig.js b/webpackBaseConfig.js index 210001b..419149c 100644 --- a/webpackBaseConfig.js +++ b/webpackBaseConfig.js @@ -158,6 +158,7 @@ module.exports = { "bootstrap" ], cover: [ + "babel-polyfill", path.join(__dirname, 'public/js/cover.js') ], "cover-styles-pack": [ @@ -168,6 +169,7 @@ module.exports = { path.join(__dirname, 'node_modules/select2/select2-bootstrap.css'), ], "cover-pack": [ + "babel-polyfill", "bootstrap-validator", "script!listPagnation", "expose?select2!select2", @@ -176,6 +178,7 @@ module.exports = { path.join(__dirname, 'public/js/cover.js') ], index: [ + "babel-polyfill", "script!jquery-ui-resizable", "script!js-url", "expose?filterXSS!xss", @@ -221,6 +224,7 @@ module.exports = { path.join(__dirname, 'node_modules/octicons/octicons/octicons.css') ], "index-pack": [ + "babel-polyfill", "expose?Spinner!spin.js", "script!jquery-ui-resizable", "bootstrap-validator", @@ -251,6 +255,7 @@ module.exports = { path.join(__dirname, 'public/js/index.js') ], pretty: [ + "babel-polyfill", "expose?filterXSS!xss", "flowchart.js", "js-sequence-diagrams", @@ -270,6 +275,7 @@ module.exports = { path.join(__dirname, 'node_modules/octicons/octicons/octicons.css') ], "pretty-pack": [ + "babel-polyfill", "expose?jsyaml!js-yaml", "script!mermaid", "expose?moment!moment", @@ -285,6 +291,7 @@ module.exports = { path.join(__dirname, 'public/js/pretty.js') ], slide: [ + "babel-polyfill", "bootstrap-tooltip", "expose?filterXSS!xss", "flowchart.js", @@ -304,6 +311,7 @@ module.exports = { path.join(__dirname, 'node_modules/octicons/octicons/octicons.css') ], "slide-pack": [ + "babel-polyfill", "expose?jQuery!expose?$!jquery", "velocity-animate", "imports?$=jquery!jquery-mousewheel", From 15bf2b6da859f2ab73fab5838689291830005c66 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 3 Feb 2017 22:05:09 +0800 Subject: [PATCH 46/71] Update webpack config to use parallel uglify plugin to speed up production build --- package.json | 3 ++- webpack.production.js | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 74de2c8..d5e8e55 100644 --- a/package.json +++ b/package.json @@ -163,6 +163,7 @@ "script-loader": "^0.7.0", "style-loader": "^0.13.1", "url-loader": "^0.5.7", - "webpack": "^1.14.0" + "webpack": "^1.14.0", + "webpack-parallel-uglify-plugin": "^0.2.0" } } diff --git a/webpack.production.js b/webpack.production.js index b28c34a..7c690d2 100644 --- a/webpack.production.js +++ b/webpack.production.js @@ -3,6 +3,7 @@ var webpack = require('webpack'); var path = require('path'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); +var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); module.exports = [Object.assign({}, baseConfig, { plugins: baseConfig.plugins.concat([ @@ -11,12 +12,14 @@ module.exports = [Object.assign({}, baseConfig, { 'NODE_ENV': JSON.stringify('production') } }), - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false - }, - mangle: false, - sourceMap: false + new ParallelUglifyPlugin({ + uglifyJS: { + compress: { + warnings: false + }, + mangle: false, + sourceMap: false + } }), new ExtractTextPlugin("[name].[hash].css") ]), From 0e6d1bbd6d301e6ccf43c8e71cead7c6c71f2dac Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Sat, 4 Feb 2017 13:31:37 +0800 Subject: [PATCH 47/71] Change database config development to sqlite, test to memory --- config.json.example | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/config.json.example b/config.json.example index 80662b0..9ee00c0 100644 --- a/config.json.example +++ b/config.json.example @@ -2,18 +2,13 @@ "test": { "db": { "dialect": "sqlite", - "storage": "./db.hackmd.sqlite" + "storage": ":memory:" } }, "development": { - "domain": "localhost", "db": { - "username": "", - "password": "", - "database": "hackmd", - "host": "localhost", - "port": "3306", - "dialect": "mysql" + "dialect": "sqlite", + "storage": "./db.hackmd.sqlite" } }, "production": { From 373f32aab73e9bb4938dad97449abadb751aa337 Mon Sep 17 00:00:00 2001 From: Jun SAKATA Date: Mon, 6 Feb 2017 17:41:46 +0900 Subject: [PATCH 48/71] Add additional comment about Prerequisite to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3025f84..83255d4 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ Prerequisite - Node.js 4.x or up (test up to 6.7.0) - Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8` - npm +- gcc/make + - `yum groupinstall 'Development Tools'` for RHEL, `sudo apt-get install build-essential` for Debian Get started --- From c49a0849b2ed8187917ba4023b356e64a1b9a2c9 Mon Sep 17 00:00:00 2001 From: Jun SAKATA Date: Mon, 6 Feb 2017 17:48:08 +0900 Subject: [PATCH 49/71] add sudo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83255d4..2f25193 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Prerequisite - Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8` - npm - gcc/make - - `yum groupinstall 'Development Tools'` for RHEL, `sudo apt-get install build-essential` for Debian + - `sudo yum groupinstall 'Development Tools'` for RHEL, `sudo apt-get install build-essential` for Debian Get started --- From bbbf64aae465ed46505f4945080fa2d72e8d0b2b Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Tue, 7 Feb 2017 21:17:05 +0800 Subject: [PATCH 50/71] Fix HMD_LDAP_TLS_CA not passing correctly and update README.md --- README.md | 12 ++++++------ lib/config.js | 13 +++++++++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3025f84..198f2fb 100644 --- a/README.md +++ b/README.md @@ -130,15 +130,15 @@ Environment variables (will overwrite other server configs) | HMD_DROPBOX_CLIENTSECRET | no example | Dropbox API client secret | | HMD_GOOGLE_CLIENTID | no example | Google API client id | | 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_BINDCREDENTIALS | no example | bindCredentials for LDAP access | -| 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_SEARCHFILTER | (uid={{username}}) | LDAP filter to search with | +| 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_SEARCHFILTER | `(uid={{username}})` | LDAP filter 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_PROVIDERNAME | My institution | Optional name to be displayed at login form indicating the LDAP provider | +| 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_IMGUR_CLIENTID | no example | Imgur API client id | | 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`) | diff --git a/lib/config.js b/lib/config.js index 3816017..e765d73 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,4 +1,5 @@ // external modules +var fs = require('fs'); var path = require('path'); // configs @@ -123,9 +124,17 @@ if (process.env.HMD_LDAP_SEARCHATTRIBUTES) ldap.searchAttributes = process.env.HMD_LDAP_SEARCHATTRIBUTES; if (process.env.HMD_LDAP_TLS_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) { ldap.providerName = process.env.HMD_LDAP_PROVIDERNAME; From 1cc27e1794afbe9f23bfb13cd098eeba554b1086 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Tue, 7 Feb 2017 22:31:38 +0800 Subject: [PATCH 51/71] Fix ldap config not initialize properly --- lib/config.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/config.js b/lib/config.js index e765d73..c037382 100644 --- a/lib/config.js +++ b/lib/config.js @@ -96,7 +96,7 @@ var google = (process.env.HMD_GOOGLE_CLIENTID && process.env.HMD_GOOGLE_CLIENTSE clientID: process.env.HMD_GOOGLE_CLIENTID, clientSecret: process.env.HMD_GOOGLE_CLIENTSECRET } : (config.google && config.google.clientID && config.google.clientSecret && config.google) || false; -var ldap = config.ldap || ( +var ldap = config.ldap || (( process.env.HMD_LDAP_URL || process.env.HMD_LDAP_BINDDN || process.env.HMD_LDAP_BINDCREDENTIALS || @@ -104,10 +104,9 @@ var ldap = config.ldap || ( process.env.HMD_LDAP_SEARCHBASE || process.env.HMD_LDAP_SEARCHFILTER || process.env.HMD_LDAP_SEARCHATTRIBUTES || + process.env.HMD_LDAP_TLS_CA || process.env.HMD_LDAP_PROVIDERNAME -) || false; -if (ldap == true) - ldap = {}; +) ? {} : false); if (process.env.HMD_LDAP_URL) ldap.url = process.env.HMD_LDAP_URL; if (process.env.HMD_LDAP_BINDDN) From 2ab57effbdec0d09e53d351cef47860c7a1f3618 Mon Sep 17 00:00:00 2001 From: Jun SAKATA Date: Wed, 8 Feb 2017 15:30:31 +0900 Subject: [PATCH 52/71] add reference to packages, instead of writing down solutions for specific os --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 2f25193..743d812 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,7 @@ Prerequisite - Node.js 4.x or up (test up to 6.7.0) - Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8` -- npm -- gcc/make - - `sudo yum groupinstall 'Development Tools'` for RHEL, `sudo apt-get install build-essential` for Debian +- npm (and its dependencies, especially [uWebSockets](https://github.com/uWebSockets/uWebSockets#nodejs-developers), [node-gyp](https://github.com/nodejs/node-gyp#installation)) Get started --- From a6f4c94eb22361fa2e1255df94705af5bf48a8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Joda=20St=C3=B6=C3=9Fer?= Date: Thu, 9 Feb 2017 03:34:58 +0100 Subject: [PATCH 53/71] typo in German translation fixed --- locales/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/de.json b/locales/de.json index 4d8ba05..41d8977 100644 --- a/locales/de.json +++ b/locales/de.json @@ -47,7 +47,7 @@ "View": "Anzeigen", "Both": "Beides", "Help": "Hilfe", - "Upload Image": "Foto hochloaden", + "Upload Image": "Foto hochladen", "Menu": "Menü", "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", From a0d16eec2340aacb8cfaa83070500395bfd50672 Mon Sep 17 00:00:00 2001 From: NV Date: Thu, 9 Feb 2017 11:41:41 +0900 Subject: [PATCH 54/71] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c81948a..ebe19f6 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ Environment variables (will overwrite other server configs) | 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_FREEURL | `true` or `false` | set to allow new note by accessing not exist note url | +| HMD_DEFAULT_PERMISSION | `freely`, `editable`, `limited`, `locked` or `private` | when creates new note, uses this permission (only applied when logged in) | | HMD_DB_URL | `mysql://localhost:3306/database` | set the db url | | HMD_FACEBOOK_CLIENTID | no example | Facebook API client id | | HMD_FACEBOOK_CLIENTSECRET | no example | Facebook API client secret | @@ -164,6 +165,7 @@ Application settings `config.json` | 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`) | | allowfreeurl | `true` or `false` | set to allow new note by accessing not exist note url | +| defaultpermission | `freely`, `editable`, `limited`, `locked` or `private` | when creates new note, uses this permission (only applied when logged in) | | 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/) | | sslkeypath | `./cert/client.key` | ssl key path (only need when you set usessl) | From 90c83ebd5b5610652c9bc8ae81299e85fe7056ef Mon Sep 17 00:00:00 2001 From: NV Date: Thu, 9 Feb 2017 14:07:36 +0900 Subject: [PATCH 55/71] Fix image path problem when using filesystem backend --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index ee82fab..67a6254 100644 --- a/app.js +++ b/app.js @@ -502,7 +502,7 @@ app.post('/uploadimage', function (req, res) { switch (config.imageUploadType) { case 'filesystem': 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; From 0a7adaf35d07efa658c040e789967acdc2eb32ff Mon Sep 17 00:00:00 2001 From: NV Date: Thu, 9 Feb 2017 13:24:40 +0900 Subject: [PATCH 56/71] Add default permission config --- lib/config.js | 4 ++++ lib/models/note.js | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/config.js b/lib/config.js index c037382..052a5d0 100644 --- a/lib/config.js +++ b/lib/config.js @@ -24,6 +24,9 @@ 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 defaultpermission = process.env.HMD_DEFAULT_PERMISSION || config.defaultpermission || 'editable'; +defaultpermission = (!allowanonymous && defaultpermission == 'freely') ? 'editable' : defaultpermission; + // db var dburl = config.dburl || process.env.HMD_DB_URL || process.env.DATABASE_URL; var db = config.db || {}; @@ -173,6 +176,7 @@ module.exports = { usecdn: usecdn, allowanonymous: allowanonymous, allowfreeurl: allowfreeurl, + defaultpermission: defaultpermission, dburl: dburl, db: db, sslkeypath: path.join(cwd, sslkeypath), diff --git a/lib/models/note.js b/lib/models/note.js index 8611297..8b38d3f 100644 --- a/lib/models/note.js +++ b/lib/models/note.js @@ -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.ownerId) { - note.permission = "editable"; + note.permission = config.defaultpermission; } else { note.permission = "freely"; } From 5375fe57790152bf97958bb54cef922f03b2b40e Mon Sep 17 00:00:00 2001 From: NV Date: Fri, 10 Feb 2017 11:46:10 +0900 Subject: [PATCH 57/71] Add validation to defaultpermission in config --- lib/config.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/config.js b/lib/config.js index 052a5d0..bdc2cbd 100644 --- a/lib/config.js +++ b/lib/config.js @@ -24,8 +24,13 @@ 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 defaultpermission = process.env.HMD_DEFAULT_PERMISSION || config.defaultpermission || 'editable'; -defaultpermission = (!allowanonymous && defaultpermission == 'freely') ? 'editable' : defaultpermission; +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 var dburl = config.dburl || process.env.HMD_DB_URL || process.env.DATABASE_URL; From 00d1543a1017a231761ac20aaa49627e5744d923 Mon Sep 17 00:00:00 2001 From: NV Date: Fri, 10 Feb 2017 11:49:45 +0900 Subject: [PATCH 58/71] simplified description --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ebe19f6..7991117 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ Environment variables (will overwrite other server configs) | 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_FREEURL | `true` or `false` | set to allow new note by accessing not exist note url | -| HMD_DEFAULT_PERMISSION | `freely`, `editable`, `limited`, `locked` or `private` | when creates new note, uses this permission (only applied when logged in) | +| 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_FACEBOOK_CLIENTID | no example | Facebook API client id | | HMD_FACEBOOK_CLIENTSECRET | no example | Facebook API client secret | @@ -165,7 +165,7 @@ Application settings `config.json` | 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`) | | allowfreeurl | `true` or `false` | set to allow new note by accessing not exist note url | -| defaultpermission | `freely`, `editable`, `limited`, `locked` or `private` | when creates new note, uses this permission (only applied when logged in) | +| 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 | | 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) | From 99a2cbc60461de724167c525cfc89d35c3480cec Mon Sep 17 00:00:00 2001 From: Max Wu Date: Sat, 11 Feb 2017 00:11:21 +0800 Subject: [PATCH 59/71] Update google drive picker to enable setOwnedByMe to show shared files and folders --- public/js/google-drive-picker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/js/google-drive-picker.js b/public/js/google-drive-picker.js index e653653..94aa77f 100644 --- a/public/js/google-drive-picker.js +++ b/public/js/google-drive-picker.js @@ -52,6 +52,7 @@ var view = new google.picker.DocsView(); view.setMimeTypes("text/markdown,text/html"); view.setIncludeFolders(true); + view.setOwnedByMe(true); this.picker = new google.picker.PickerBuilder(). enableFeature(google.picker.Feature.NAV_HIDDEN). addView(view). @@ -115,4 +116,4 @@ }, callback ? callback : function() {}); } }; -}()); \ No newline at end of file +}()); From 6dc70000f0cbda32087e53915ece89af2b9df703 Mon Sep 17 00:00:00 2001 From: Stratos Gerakakis Date: Fri, 10 Feb 2017 18:02:15 +0100 Subject: [PATCH 60/71] Fixed Greek mispellings and translations There were various misspellings and some translations that were not clear enough. --- locales/el.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/locales/el.json b/locales/el.json index ea68aac..8f65dfa 100644 --- a/locales/el.json +++ b/locales/el.json @@ -1,7 +1,7 @@ { "Collaborative markdown notes": "Συνεργατικές σημειώσεις 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": "Εισαγωγή", "History": "Ιστορία", "New guest note": "Νέα σημείωση επισκέπτη", @@ -54,9 +54,9 @@ "Refresh to update.": "Ανανεώστε για ενημέρωση", "New version available!": "Νέα διαθέσιμη έκδοση ", "See releases notes here": "Δείτε τις κυκλοφορίες της σημείωσης εδώ", - "Refresh to enjoy new features.": "Ανανεώστε για να δείτε τις κανούργίες λειτουργίες", + "Refresh to enjoy new features.": "Ανανεώστε για να δείτε τις κανούργιες λειτουργίες", "Your user state has changed.": "Η κατάσταση χρήστη έχει αλλάξει.", - "Refresh to load new user state.": "Ανανεώστε για να φορτωσετε την νέα κατάσταση χρήστη.", + "Refresh to load new user state.": "Ανανεώστε για να φορτώσετε την νέα κατάσταση χρήστη.", "Refresh": "Ανανέωση", "Contacts": "Επαφές", "Report an issue": "Αναφέρετε ένα θέμα", @@ -73,32 +73,32 @@ "Ordered List": "Αριθμημένη λίστα", "Todo List": "Todo List", "Blockquote": "Παράγραφος", - "Bold font": "Εντονη γραμματόσειρά", - "Italics font": "Italics γραμματόσειρά", - "Strikethrough": "Διακριτή διαγραφή", + "Bold font": "Εντονη γραμματοσειρά", + "Italics font": "Πλάγια γραμματοσειρά", + "Strikethrough": "Διαγραμένη γραμματοσειρά", "Inserted text": "Εισαγμένο κείμενο", - "Marked text": "Επιλεγμένο κέιμενο", + "Marked text": "Επιλεγμένο κείμενο", "Link": "Σύνδεσμος", "Image": "Εικόνα", "Code": "Κώδικας", "Externals": "Εξωτερικά", - "This is a alert area.": "Αυτή είνια μια περιοχή ειδοποίησης", + "This is a alert area.": "Αυτή είναι μια περιοχή ειδοποίησης", "Revert": "Επαναστροφή", "Import from clipboard": "Εισαγωγή από πρόχειρο", - "Paste your markdown or webpage here...": "Επικολλήστε το markdown ή την ιστοσελίδα σας εδώ...", + "Paste your markdown or webpage here...": "Επικολλήστε markdown ή την ιστοσελίδα σας εδώ...", "Clear": "Καθαρισμός", "This note is locked": "Η σημείωση είναι κλειδωμένη", - "Sorry, only owner can edit this note.": "Συγνώμη, μόνο ο ιδικτήτης μπορεί να επεξεργαστεί αυτη την σημείωση.", + "Sorry, only owner can edit this note.": "Συγνώμη, μόνο ο ιδιοκτήτης μπορεί να επεξεργαστεί αυτη την σημείωση.", "OK": "Εντάξει", "Reach the limit": "Φτάσατε το όριο", "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", "Paste your gist url here...": "Κάντε επικκόληση του gist url εδώ...", - "Import from Snippet": "Εισαγωγή απο Snippet", + "Import from Snippet": "Εισαγωγή από Snippet", "Select From Available Projects": "Eπιλογή από διαθέσιμα Projects", "Select From Available Snippets": "Eπιλογή από διαθέσιμα Snippets", "OR": "Ή", "Export to Snippet": "Eξαγωγή σε Snippet", "Select Visibility Level": "Επιλέξτε επίπεδο ορατότητας" -} \ No newline at end of file +} From d29aff6505ddb7e49153a5fc2082bc3efe08e512 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 15 Feb 2017 10:22:38 +0100 Subject: [PATCH 61/71] first envs then the config or docker -e will not work --- lib/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config.js b/lib/config.js index bdc2cbd..a14bf97 100644 --- a/lib/config.js +++ b/lib/config.js @@ -33,7 +33,7 @@ var defaultpermission = process.env.HMD_DEFAULT_PERMISSION || config.defaultperm defaultpermission = permissions.indexOf(defaultpermission) != -1 ? defaultpermission : 'editable'; // 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 || {}; // ssl path From 4198d0d56060117e0806389f26eed4e65c4d37a6 Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Wed, 15 Feb 2017 18:14:58 +0800 Subject: [PATCH 62/71] Add travis ci --- .travis.yml | 13 +++++++++++++ Makefile | 3 +++ README.md | 10 ++++++++-- package.json | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 .travis.yml create mode 100644 Makefile diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ed8ab42 --- /dev/null +++ b/.travis.yml @@ -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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b9afabe --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +lint: + @./node_modules/.bin/eslint . +.PHONY: lint diff --git a/README.md b/README.md index 7991117..05b13f8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ 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. Inspired by Hackpad, with more focus on speed and flexibility. @@ -48,7 +50,7 @@ Browsers Requirement Prerequisite --- -- Node.js 4.x or up (test up to 6.7.0) +- Node.js 6.x or up (test up to 6.7.0) - Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8` - npm (and its dependencies, especially [uWebSockets](https://github.com/uWebSockets/uWebSockets#nodejs-developers), [node-gyp](https://github.com/nodejs/node-gyp#installation)) @@ -222,3 +224,7 @@ Additionally, now can show other clients' selections. See more at [http://operational-transformation.github.io/](http://operational-transformation.github.io/) **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 diff --git a/package.json b/package.json index d5e8e55..ad629d1 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "app.js", "license": "MIT", "scripts": { + "test": "make lint", "dev": "webpack --config webpack.config.js --progress --colors --watch", "build": "webpack --config webpack.production.js --progress --colors", "postinstall": "bin/heroku", @@ -150,6 +151,7 @@ "copy-webpack-plugin": "^4.0.1", "css-loader": "^0.26.1", "ejs-loader": "^0.3.0", + "eslint": "^3.15.0", "exports-loader": "^0.6.3", "expose-loader": "^0.7.1", "extract-text-webpack-plugin": "^1.0.1", From 327ab411ac93a34459e025f30b7792f5d886554a Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Wed, 15 Feb 2017 19:16:36 +0800 Subject: [PATCH 63/71] Add Makefile .editorconfig --- .editorconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.editorconfig b/.editorconfig index 619c178..ff999c4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,3 +13,5 @@ trim_trailing_whitespace = false [{.travis.yml,npm-shrinkwrap.json,package.json}] indent_style = space indent_size = 2 +[Makefile] +indent_style = tab From af783b2746c86c33558604654403bfc31798b273 Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Wed, 15 Feb 2017 19:17:51 +0800 Subject: [PATCH 64/71] Update node dependency up to 6.x in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad629d1..2a40bf0 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "xss": "^0.3.3" }, "engines": { - "node": ">=4.x" + "node": ">=6.x" }, "bugs": "https://github.com/hackmdio/hackmd/issues", "keywords": [ From c48ba0ad48d5daa3663aeb929967fa9fc0e8c4dc Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Wed, 15 Feb 2017 22:09:09 +0800 Subject: [PATCH 65/71] Test up to 7.5.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 05b13f8..2afeba2 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Browsers Requirement Prerequisite --- -- Node.js 6.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` - npm (and its dependencies, especially [uWebSockets](https://github.com/uWebSockets/uWebSockets#nodejs-developers), [node-gyp](https://github.com/nodejs/node-gyp#installation)) From 40dfffd4f47a72549fb52d39a25c630551e761fc Mon Sep 17 00:00:00 2001 From: bananaappletw Date: Thu, 16 Feb 2017 12:27:17 +0800 Subject: [PATCH 66/71] Using package.json to test lint instead Exclude *.min.js from eslint --- .editorconfig | 2 -- .eslintignore | 1 + Makefile | 3 --- package.json | 3 ++- 4 files changed, 3 insertions(+), 6 deletions(-) create mode 100644 .eslintignore delete mode 100644 Makefile diff --git a/.editorconfig b/.editorconfig index ff999c4..619c178 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,5 +13,3 @@ trim_trailing_whitespace = false [{.travis.yml,npm-shrinkwrap.json,package.json}] indent_style = space indent_size = 2 -[Makefile] -indent_style = tab diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..121531a --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +*.min.js diff --git a/Makefile b/Makefile deleted file mode 100644 index b9afabe..0000000 --- a/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -lint: - @./node_modules/.bin/eslint . -.PHONY: lint diff --git a/package.json b/package.json index 2a40bf0..a179d93 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "app.js", "license": "MIT", "scripts": { - "test": "make lint", + "test": "npm run-script lint", + "lint": "eslint .", "dev": "webpack --config webpack.config.js --progress --colors --watch", "build": "webpack --config webpack.production.js --progress --colors", "postinstall": "bin/heroku", From 1ca39d9c8e47ae2ce5a524504beb0aaed221a97c Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Fri, 17 Feb 2017 21:56:35 +0800 Subject: [PATCH 67/71] Update to allow li tag specify value number --- public/js/render.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/js/render.js b/public/js/render.js index a61fc8f..5d6d0aa 100644 --- a/public/js/render.js +++ b/public/js/render.js @@ -9,6 +9,8 @@ var dataUriRegex = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base var whiteList = filterXSS.whiteList; // allow ol specify start number whiteList['ol'] = ['start']; +// allow li specify value number +whiteList['li'] = ['value']; // allow style tag whiteList['style'] = []; // allow kbd tag From 2aee0f267c2154ddf001507a62e4fe548515cd3a Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 18 Feb 2017 20:07:15 +0800 Subject: [PATCH 68/71] Fix user profile photo might not replace to proper size --- lib/models/user.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/models/user.js b/lib/models/user.js index aee4204..dd93bf7 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -105,8 +105,8 @@ module.exports = function (sequelize, DataTypes) { break; case "gitlab": photo = profile.avatarUrl; - if (bigger) photo.replace(/(\?s=)\d*$/i, '$1400'); - else photo.replace(/(\?s=)\d*$/i, '$196'); + if (bigger) photo = photo.replace(/(\?s=)\d*$/i, '$1400'); + else photo = photo.replace(/(\?s=)\d*$/i, '$196'); break; case "dropbox": //no image api provided, use gravatar @@ -116,8 +116,8 @@ module.exports = function (sequelize, DataTypes) { break; case "google": photo = profile.photos[0].value; - if (bigger) photo.replace(/(\?sz=)\d*$/i, '$1400'); - else photo.replace(/(\?sz=)\d*$/i, '$196'); + if (bigger) photo = photo.replace(/(\?sz=)\d*$/i, '$1400'); + else photo = photo.replace(/(\?sz=)\d*$/i, '$196'); break; case "ldap": //no image api provided, From f7149f5a834ea79ec82f04ef2da257fe72f1b330 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 18 Feb 2017 20:10:34 +0800 Subject: [PATCH 69/71] Fix to keep selections on save and restore info --- public/js/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index 9b42e79..3ad79d5 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -408,7 +408,8 @@ window.lastInfo = { cursor: { line: null, ch: null - } + }, + selections: null }, view: { scroll: { @@ -3394,6 +3395,7 @@ function saveInfo() { break; } lastInfo.edit.cursor = editor.getCursor(); + lastInfo.edit.selections = editor.listSelections(); lastInfo.needRestore = true; } @@ -3403,6 +3405,7 @@ function restoreInfo() { var line = lastInfo.edit.cursor.line; var ch = lastInfo.edit.cursor.ch; editor.setCursor(line, ch); + editor.setSelections(lastInfo.edit.selections); switch (currentMode) { case modeType.edit: if (scrollbarStyle == 'native') { From 0aaa59813018847c765624bcd8cfa22e9aa57284 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 18 Feb 2017 20:11:18 +0800 Subject: [PATCH 70/71] Fix not determine OT have pending operations properly --- public/js/index.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index 3ad79d5..f0c476e 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2519,7 +2519,7 @@ var addStyleRule = (function () { }()); function updateAuthorshipInner() { // ignore when ot not synced yet - if (cmClient && Object.keys(cmClient.state).length > 0) return; + if (havePendingOperation()) return; authorMarks = {}; for (var i = 0; i < authorship.length; i++) { var atom = authorship[i]; @@ -2734,12 +2734,16 @@ var EditorClient = ot.EditorClient; var SocketIOAdapter = ot.SocketIOAdapter; var CodeMirrorAdapter = ot.CodeMirrorAdapter; var cmClient = null; +var synchronized_ = null; + +function havePendingOperation() { + return (cmClient && cmClient.state && cmClient.state.hasOwnProperty('outstanding')) ? true : false; +} socket.on('doc', function (obj) { var body = obj.str; 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(); if (setDoc && bodyMismatch) { @@ -2764,16 +2768,17 @@ socket.on('doc', function (obj) { obj.revision, obj.clients, new SocketIOAdapter(socket), new CodeMirrorAdapter(editor) ); + synchronized_ = cmClient.state; } else if (setDoc) { if (bodyMismatch) { cmClient.undoManager.undoStack.length = 0; cmClient.undoManager.redoStack.length = 0; } cmClient.revision = obj.revision; - cmClient.setState(new ot.Client.Synchronized()); + cmClient.setState(synchronized_); cmClient.initializeClientList(); cmClient.initializeClients(obj.clients); - } else if (havePendingOperation) { + } else if (havePendingOperation()) { cmClient.serverReconnect(); } From 0bea4da6238b1f46562b146b32d88fc8d8b9060a Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Sat, 18 Feb 2017 20:11:57 +0800 Subject: [PATCH 71/71] Fix out of sync when deleting on same cursor position on several clients from: https://github.com/aullman/opentok-editor/issues/4 --- public/vendor/ot/codemirror-adapter.js | 4 +++- public/vendor/ot/ot.min.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/public/vendor/ot/codemirror-adapter.js b/public/vendor/ot/codemirror-adapter.js index d858c41..cc23be0 100755 --- a/public/vendor/ot/codemirror-adapter.js +++ b/public/vendor/ot/codemirror-adapter.js @@ -343,7 +343,9 @@ ot.CodeMirrorAdapter = (function (global) { }; CodeMirrorAdapter.prototype.applyOperation = function (operation) { - this.ignoreNextChange = true; + if (!operation.isNoop()) { + this.ignoreNextChange = true; + } CodeMirrorAdapter.applyOperationToCodeMirror(operation, this.cm); }; diff --git a/public/vendor/ot/ot.min.js b/public/vendor/ot/ot.min.js index aba0960..d942cb5 100644 --- a/public/vendor/ot/ot.min.js +++ b/public/vendor/ot/ot.min.js @@ -1 +1 @@ -function hex2rgb(t){if("#"==t[0]&&(t=t.substr(1)),3==t.length){var e=t;t="",e=/^([a-f0-9])([a-f0-9])([a-f0-9])$/i.exec(e).slice(1);for(var n=0;n<3;n++)t+=e[n]+e[n]}var o=/^([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i.exec(t).slice(1);return{red:parseInt(o[0],16),green:parseInt(o[1],16),blue:parseInt(o[2],16)}}if("undefined"==typeof ot)var ot={};if(ot.TextOperation=function(){"use strict";function t(){return this&&this.constructor===t?(this.ops=[],this.baseLength=0,void(this.targetLength=0)):new t}function e(e,n){var o=e.ops,r=t.isRetain;switch(o.length){case 1:return o[0];case 2:return r(o[0])?o[1]:r(o[1])?o[0]:null;case 3:if(r(o[0])&&r(o[2]))return o[1]}return null}function n(t){return o(t.ops[0])?t.ops[0]:0}t.prototype.equals=function(t){if(this.baseLength!==t.baseLength)return!1;if(this.targetLength!==t.targetLength)return!1;if(this.ops.length!==t.ops.length)return!1;for(var e=0;e0},r=t.isInsert=function(t){return"string"==typeof t},i=t.isDelete=function(t){return"number"==typeof t&&t<0};return t.prototype.retain=function(t){if("number"!=typeof t)throw new Error("retain expects an integer");return 0===t?this:(this.baseLength+=t,this.targetLength+=t,o(this.ops[this.ops.length-1])?this.ops[this.ops.length-1]+=t:this.ops.push(t),this)},t.prototype.insert=function(t){if("string"!=typeof t)throw new Error("insert expects a string");if(""===t)return this;this.targetLength+=t.length;var e=this.ops;return r(e[e.length-1])?e[e.length-1]+=t:i(e[e.length-1])?r(e[e.length-2])?e[e.length-2]+=t:(e[e.length]=e[e.length-1],e[e.length-2]=t):e.push(t),this},t.prototype["delete"]=function(t){if("string"==typeof t&&(t=t.length),"number"!=typeof t)throw new Error("delete expects an integer or a string");return 0===t?this:(t>0&&(t=-t),this.baseLength-=t,i(this.ops[this.ops.length-1])?this.ops[this.ops.length-1]+=t:this.ops.push(t),this)},t.prototype.isNoop=function(){return 0===this.ops.length||1===this.ops.length&&o(this.ops[0])},t.prototype.toString=function(){var t=Array.prototype.map||function(t){for(var e=this,n=[],o=0,r=e.length;ot.length)throw new Error("Operation can't retain more characters than are left in the string.");n[i++]=t.slice(s,s+c),s+=c}else r(c)?n[i++]=c:s-=c}if(s!==t.length)throw new Error("The operation didn't operate on the whole string.");return n.join("")},t.prototype.invert=function(e){for(var n=0,i=new t,s=this.ops,a=0,h=s.length;au?(s.retain(u),l-=u,u=h[c++]):l===u?(s.retain(l),l=a[p++],u=h[c++]):(s.retain(l),u-=l,l=a[p++]);else if(r(l)&&i(u))l.length>-u?(l=l.slice(-u),u=h[c++]):l.length===-u?(l=a[p++],u=h[c++]):(u+=l.length,l=a[p++]);else if(r(l)&&o(u))l.length>u?(s.insert(l.slice(0,u)),l=l.slice(u),u=h[c++]):l.length===u?(s.insert(l),l=a[p++],u=h[c++]):(s.insert(l),u-=l.length,l=a[p++]);else{if(!o(l)||!i(u))throw new Error("This shouldn't happen: op1: "+JSON.stringify(l)+", op2: "+JSON.stringify(u));l>-u?(s["delete"](u),l+=u,u=h[c++]):l===-u?(s["delete"](u),l=a[p++],u=h[c++]):(s["delete"](l),u+=l,l=a[p++])}}}return s},t.prototype.shouldBeComposedWith=function(t){if(this.isNoop()||t.isNoop())return!0;var o=n(this),s=n(t),a=e(this),h=e(t);return!(!a||!h)&&(r(a)&&r(h)?o+a.length===s:!(!i(a)||!i(h))&&(s-h===o||o===s))},t.prototype.shouldBeComposedWithInverted=function(t){if(this.isNoop()||t.isNoop())return!0;var o=n(this),s=n(t),a=e(this),h=e(t);return!(!a||!h)&&(r(a)&&r(h)?o+a.length===s||o===s:!(!i(a)||!i(h))&&s-h===o)},t.transform=function(e,n){if(e.baseLength!==n.baseLength)throw new Error("Both operations have to have the same base length");for(var s=new t,a=new t,h=e.ops,p=n.ops,c=0,l=0,u=h[c++],f=p[l++];;){if("undefined"==typeof u&&"undefined"==typeof f)break;if(r(u))s.insert(u),a.retain(u.length),u=h[c++];else if(r(f))s.retain(f.length),a.insert(f),f=p[l++];else{if("undefined"==typeof u)throw new Error("Cannot compose operations: first operation is too short.");if("undefined"==typeof f)throw new Error("Cannot compose operations: first operation is too long.");var d;if(o(u)&&o(f))u>f?(d=f,u-=f,f=p[l++]):u===f?(d=f,u=h[c++],f=p[l++]):(d=u,f-=u,u=h[c++]),s.retain(d),a.retain(d);else if(i(u)&&i(f))-u>-f?(u-=f,f=p[l++]):u===f?(u=h[c++],f=p[l++]):(f-=u,u=h[c++]);else if(i(u)&&o(f))-u>f?(d=f,u+=f,f=p[l++]):-u===f?(d=f,u=h[c++],f=p[l++]):(d=-u,f+=u,u=h[c++]),s["delete"](d);else{if(!o(u)||!i(f))throw new Error("The two operations aren't compatible");u>-f?(d=-f,u+=f,f=p[l++]):u===-f?(d=u,u=h[c++],f=p[l++]):(d=u,f+=u,u=h[c++]),a["delete"](d)}}}return[s,a]},t}(),"object"==typeof module&&(module.exports=ot.TextOperation),"undefined"==typeof ot)var ot={};if(ot.Selection=function(t){"use strict";function e(t,e){this.anchor=t,this.head=e}function n(t){this.ranges=t||[]}var o=t.ot?t.ot.TextOperation:require("./text-operation");return e.fromJSON=function(t){return new e(t.anchor,t.head)},e.prototype.equals=function(t){return this.anchor===t.anchor&&this.head===t.head},e.prototype.isEmpty=function(){return this.anchor===this.head},e.prototype.transform=function(t){function n(e){for(var n=e,r=t.ops,i=0,s=t.ops.length;i=0;r--){var i=o.transform(t[r],e);"function"==typeof i[0].isNoop&&i[0].isNoop()||n.push(i[0]),e=i[1]}return n.reverse()}var n="normal",o="undoing",r="redoing";return t.prototype.add=function(t,e){if(this.state===o)this.redoStack.push(t),this.dontCompose=!0;else if(this.state===r)this.undoStack.push(t),this.dontCompose=!0;else{var n=this.undoStack;!this.dontCompose&&e&&n.length>0?n.push(t.compose(n.pop())):(n.push(t),n.length>this.maxItems&&n.shift()),this.dontCompose=!1,this.redoStack=[]}},t.prototype.transform=function(t){this.undoStack=e(this.undoStack,t),this.redoStack=e(this.redoStack,t)},t.prototype.performUndo=function(t){if(this.state=o,0===this.undoStack.length)throw new Error("undo not possible");t(this.undoStack.pop()),this.state=n},t.prototype.performRedo=function(t){if(this.state=r,0===this.redoStack.length)throw new Error("redo not possible");t(this.redoStack.pop()),this.state=n},t.prototype.canUndo=function(){return 0!==this.undoStack.length},t.prototype.canRedo=function(){return 0!==this.redoStack.length},t.prototype.isUndoing=function(){return this.state===o},t.prototype.isRedoing=function(){return this.state===r},t}(),"object"==typeof module&&(module.exports=ot.UndoManager),"undefined"==typeof ot)var ot={};ot.Client=function(t){"use strict";function e(t){this.revision=t,this.setState(a)}function n(){}function o(t){this.outstanding=t}function r(t,e){this.outstanding=t,this.buffer=e}function i(t,e,n){this.acknowlaged=t,this.client=e,this.revision=n}function s(t,e,n,o){this.acknowlaged=t,this.buffer=e,this.client=n,this.revision=o}e.prototype.setState=function(t){this.state=t},e.prototype.applyClient=function(t){this.setState(this.state.applyClient(this,t))},e.prototype.applyServer=function(t,e){this.setState(this.state.applyServer(this,t,e))},e.prototype.applyOperations=function(t,e){this.setState(this.state.applyOperations(this,t,e))},e.prototype.serverAck=function(t){this.setState(this.state.serverAck(this,t))},e.prototype.serverReconnect=function(){"function"==typeof this.state.resend&&this.state.resend(this)},e.prototype.transformSelection=function(t){return this.state.transformSelection(t)},e.prototype.sendOperation=function(t,e){throw new Error("sendOperation must be defined in child class")},e.prototype.applyOperation=function(t){throw new Error("applyOperation must be defined in child class")},e.Synchronized=n,n.prototype.applyClient=function(t,e){return t.sendOperation(t.revision,e),new o(e)},n.prototype.applyServer=function(t,e,n){if(e-t.revision>1)throw new Error("Invalid revision.");return t.revision=e,t.applyOperation(n),this},n.prototype.serverAck=function(t,e){throw new Error("There is no pending operation.")},n.prototype.transformSelection=function(t){return t};var a=new n;return e.AwaitingConfirm=o,o.prototype.applyClient=function(t,e){return new r(this.outstanding,e)},o.prototype.applyServer=function(t,e,n){if(e-t.revision>1)throw new Error("Invalid revision.");t.revision=e;var r=n.constructor.transform(this.outstanding,n);return t.applyOperation(r[1]),new o(r[0])},o.prototype.serverAck=function(t,e){return e-t.revision>1?new i(this.outstanding,t,e).getOperations():(t.revision=e,a)},o.prototype.transformSelection=function(t){return t.transform(this.outstanding)},o.prototype.resend=function(t){t.sendOperation(t.revision,this.outstanding)},e.AwaitingWithBuffer=r,r.prototype.applyClient=function(t,e){var n=this.buffer.compose(e);return new r(this.outstanding,n)},r.prototype.applyServer=function(t,e,n){if(e-t.revision>1)throw new Error("Invalid revision.");t.revision=e;var o=n.constructor.transform,i=o(this.outstanding,n),s=o(this.buffer,i[1]);return t.applyOperation(s[1]),new r(i[0],s[0])},r.prototype.serverAck=function(t,e){return e-t.revision>1?new s(this.outstanding,this.buffer,t,e).getOperations():(t.revision=e,t.sendOperation(t.revision,this.buffer),new o(this.buffer))},r.prototype.transformSelection=function(t){return t.transform(this.outstanding).transform(this.buffer)},r.prototype.resend=function(t){t.sendOperation(t.revision,this.outstanding)},e.Stale=i,i.prototype.applyClient=function(t,e){return new s(this.acknowlaged,e,t,this.revision)},i.prototype.applyServer=function(t,e,n){throw new Error("Ignored server-side change.")},i.prototype.applyOperations=function(t,e,n){for(var o=this.acknowlaged.constructor.transform,r=0;re.line?1:t.che.ch?1:0}function o(t,e){return n(t,e)<=0}function r(t,e){return o(t,e)?t:e}function i(t,e){return o(t,e)?e:t}function s(t){return t.indexFromPos({line:t.lastLine(),ch:0})+t.getLine(t.lastLine()).length}function a(t,e){var n=t[e];t[e]=function(){n.apply(t,arguments)}}var h=ot.TextOperation,p=ot.Selection;e.prototype.detach=function(){this.cm.off("changes",this.onChanges),this.cm.off("change",this.onChange),this.cm.off("cursorActivity",this.onCursorActivity),this.cm.off("focus",this.onFocus),this.cm.off("blur",this.onBlur)},e.operationFromCodeMirrorChanges=function(t,e){function n(t){return t[t.length-1]}function r(t){if(0===t.length)return 0;for(var e=0,n=0;n=0;u--){var f=t[u];l=i(l,f);var d=l(f.from),g=a-d-r(f.text);p=(new h).retain(d)["delete"](r(f.removed)).insert(f.text.join("\n")).retain(g).compose(p),c=c.compose((new h).retain(d)["delete"](r(f.text)).insert(f.removed.join("\n")).retain(g)),a+=r(f.removed)-r(f.text)}return[p,c]},e.operationFromCodeMirrorChange=e.operationFromCodeMirrorChanges,e.applyOperationToCodeMirror=function(t,e){e.operation(function(){for(var n=t.ops,o=0,r=0,i=n.length;r0&&(this.majorRevision+=n.length,this.minorRevision=0);var o=t.events;if(o){for(e=0;e1&&(t-=1),6*t<1?i+6*(o-i)*t:2*t<1?o:3*t<2?i+6*(o-i)*(2/3-t):i};return r(s(t+1/3),s(t),s(t-1/3))}function s(t){for(var e=1,n=0;n0&&n.shouldBeComposedWithInverted(h(this.undoManager.undoStack).wrapped)),s=new t(this.selection,o);this.undoManager.add(new d(n,s),i),this.applyClient(e)},o.prototype.updateSelection=function(){this.selection=this.editorAdapter.getSelection()},o.prototype.onSelectionChange=function(){var t=this.selection;this.updateSelection(),t&&this.selection.equals(t)||this.sendSelection(this.selection)},o.prototype.onBlur=function(){this.selection=null,this.sendSelection(null)},o.prototype.sendSelection=function(t){this.state instanceof c.AwaitingWithBuffer||this.serverAdapter.sendSelection(t)},o.prototype.sendOperation=function(t,e){this.serverAdapter.sendOperation(t,e.toJSON(),this.selection)},o.prototype.getOperations=function(t,e){this.serverAdapter.getOperations(t,e)},o.prototype.applyOperation=function(t){this.editorAdapter.applyOperation(t),this.updateSelection(),this.undoManager.transform(new d(t,null))},o}(); \ No newline at end of file +function hex2rgb(t){if("#"==t[0]&&(t=t.substr(1)),3==t.length){var e=t;t="",e=/^([a-f0-9])([a-f0-9])([a-f0-9])$/i.exec(e).slice(1);for(var n=0;n<3;n++)t+=e[n]+e[n]}var o=/^([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i.exec(t).slice(1);return{red:parseInt(o[0],16),green:parseInt(o[1],16),blue:parseInt(o[2],16)}}if("undefined"==typeof ot)var ot={};if(ot.TextOperation=function(){"use strict";function t(){return this&&this.constructor===t?(this.ops=[],this.baseLength=0,void(this.targetLength=0)):new t}function e(e,n){var o=e.ops,r=t.isRetain;switch(o.length){case 1:return o[0];case 2:return r(o[0])?o[1]:r(o[1])?o[0]:null;case 3:if(r(o[0])&&r(o[2]))return o[1]}return null}function n(t){return o(t.ops[0])?t.ops[0]:0}t.prototype.equals=function(t){if(this.baseLength!==t.baseLength)return!1;if(this.targetLength!==t.targetLength)return!1;if(this.ops.length!==t.ops.length)return!1;for(var e=0;e0},r=t.isInsert=function(t){return"string"==typeof t},i=t.isDelete=function(t){return"number"==typeof t&&t<0};return t.prototype.retain=function(t){if("number"!=typeof t)throw new Error("retain expects an integer");return 0===t?this:(this.baseLength+=t,this.targetLength+=t,o(this.ops[this.ops.length-1])?this.ops[this.ops.length-1]+=t:this.ops.push(t),this)},t.prototype.insert=function(t){if("string"!=typeof t)throw new Error("insert expects a string");if(""===t)return this;this.targetLength+=t.length;var e=this.ops;return r(e[e.length-1])?e[e.length-1]+=t:i(e[e.length-1])?r(e[e.length-2])?e[e.length-2]+=t:(e[e.length]=e[e.length-1],e[e.length-2]=t):e.push(t),this},t.prototype["delete"]=function(t){if("string"==typeof t&&(t=t.length),"number"!=typeof t)throw new Error("delete expects an integer or a string");return 0===t?this:(t>0&&(t=-t),this.baseLength-=t,i(this.ops[this.ops.length-1])?this.ops[this.ops.length-1]+=t:this.ops.push(t),this)},t.prototype.isNoop=function(){return 0===this.ops.length||1===this.ops.length&&o(this.ops[0])},t.prototype.toString=function(){var t=Array.prototype.map||function(t){for(var e=this,n=[],o=0,r=e.length;ot.length)throw new Error("Operation can't retain more characters than are left in the string.");n[i++]=t.slice(s,s+c),s+=c}else r(c)?n[i++]=c:s-=c}if(s!==t.length)throw new Error("The operation didn't operate on the whole string.");return n.join("")},t.prototype.invert=function(e){for(var n=0,i=new t,s=this.ops,a=0,h=s.length;au?(s.retain(u),l-=u,u=h[c++]):l===u?(s.retain(l),l=a[p++],u=h[c++]):(s.retain(l),u-=l,l=a[p++]);else if(r(l)&&i(u))l.length>-u?(l=l.slice(-u),u=h[c++]):l.length===-u?(l=a[p++],u=h[c++]):(u+=l.length,l=a[p++]);else if(r(l)&&o(u))l.length>u?(s.insert(l.slice(0,u)),l=l.slice(u),u=h[c++]):l.length===u?(s.insert(l),l=a[p++],u=h[c++]):(s.insert(l),u-=l.length,l=a[p++]);else{if(!o(l)||!i(u))throw new Error("This shouldn't happen: op1: "+JSON.stringify(l)+", op2: "+JSON.stringify(u));l>-u?(s["delete"](u),l+=u,u=h[c++]):l===-u?(s["delete"](u),l=a[p++],u=h[c++]):(s["delete"](l),u+=l,l=a[p++])}}}return s},t.prototype.shouldBeComposedWith=function(t){if(this.isNoop()||t.isNoop())return!0;var o=n(this),s=n(t),a=e(this),h=e(t);return!(!a||!h)&&(r(a)&&r(h)?o+a.length===s:!(!i(a)||!i(h))&&(s-h===o||o===s))},t.prototype.shouldBeComposedWithInverted=function(t){if(this.isNoop()||t.isNoop())return!0;var o=n(this),s=n(t),a=e(this),h=e(t);return!(!a||!h)&&(r(a)&&r(h)?o+a.length===s||o===s:!(!i(a)||!i(h))&&s-h===o)},t.transform=function(e,n){if(e.baseLength!==n.baseLength)throw new Error("Both operations have to have the same base length");for(var s=new t,a=new t,h=e.ops,p=n.ops,c=0,l=0,u=h[c++],f=p[l++];;){if("undefined"==typeof u&&"undefined"==typeof f)break;if(r(u))s.insert(u),a.retain(u.length),u=h[c++];else if(r(f))s.retain(f.length),a.insert(f),f=p[l++];else{if("undefined"==typeof u)throw new Error("Cannot compose operations: first operation is too short.");if("undefined"==typeof f)throw new Error("Cannot compose operations: first operation is too long.");var d;if(o(u)&&o(f))u>f?(d=f,u-=f,f=p[l++]):u===f?(d=f,u=h[c++],f=p[l++]):(d=u,f-=u,u=h[c++]),s.retain(d),a.retain(d);else if(i(u)&&i(f))-u>-f?(u-=f,f=p[l++]):u===f?(u=h[c++],f=p[l++]):(f-=u,u=h[c++]);else if(i(u)&&o(f))-u>f?(d=f,u+=f,f=p[l++]):-u===f?(d=f,u=h[c++],f=p[l++]):(d=-u,f+=u,u=h[c++]),s["delete"](d);else{if(!o(u)||!i(f))throw new Error("The two operations aren't compatible");u>-f?(d=-f,u+=f,f=p[l++]):u===-f?(d=u,u=h[c++],f=p[l++]):(d=u,f+=u,u=h[c++]),a["delete"](d)}}}return[s,a]},t}(),"object"==typeof module&&(module.exports=ot.TextOperation),"undefined"==typeof ot)var ot={};if(ot.Selection=function(t){"use strict";function e(t,e){this.anchor=t,this.head=e}function n(t){this.ranges=t||[]}var o=t.ot?t.ot.TextOperation:require("./text-operation");return e.fromJSON=function(t){return new e(t.anchor,t.head)},e.prototype.equals=function(t){return this.anchor===t.anchor&&this.head===t.head},e.prototype.isEmpty=function(){return this.anchor===this.head},e.prototype.transform=function(t){function n(e){for(var n=e,r=t.ops,i=0,s=t.ops.length;i=0;r--){var i=o.transform(t[r],e);"function"==typeof i[0].isNoop&&i[0].isNoop()||n.push(i[0]),e=i[1]}return n.reverse()}var n="normal",o="undoing",r="redoing";return t.prototype.add=function(t,e){if(this.state===o)this.redoStack.push(t),this.dontCompose=!0;else if(this.state===r)this.undoStack.push(t),this.dontCompose=!0;else{var n=this.undoStack;!this.dontCompose&&e&&n.length>0?n.push(t.compose(n.pop())):(n.push(t),n.length>this.maxItems&&n.shift()),this.dontCompose=!1,this.redoStack=[]}},t.prototype.transform=function(t){this.undoStack=e(this.undoStack,t),this.redoStack=e(this.redoStack,t)},t.prototype.performUndo=function(t){if(this.state=o,0===this.undoStack.length)throw new Error("undo not possible");t(this.undoStack.pop()),this.state=n},t.prototype.performRedo=function(t){if(this.state=r,0===this.redoStack.length)throw new Error("redo not possible");t(this.redoStack.pop()),this.state=n},t.prototype.canUndo=function(){return 0!==this.undoStack.length},t.prototype.canRedo=function(){return 0!==this.redoStack.length},t.prototype.isUndoing=function(){return this.state===o},t.prototype.isRedoing=function(){return this.state===r},t}(),"object"==typeof module&&(module.exports=ot.UndoManager),"undefined"==typeof ot)var ot={};ot.Client=function(t){"use strict";function e(t){this.revision=t,this.setState(a)}function n(){}function o(t){this.outstanding=t}function r(t,e){this.outstanding=t,this.buffer=e}function i(t,e,n){this.acknowlaged=t,this.client=e,this.revision=n}function s(t,e,n,o){this.acknowlaged=t,this.buffer=e,this.client=n,this.revision=o}e.prototype.setState=function(t){this.state=t},e.prototype.applyClient=function(t){this.setState(this.state.applyClient(this,t))},e.prototype.applyServer=function(t,e){this.setState(this.state.applyServer(this,t,e))},e.prototype.applyOperations=function(t,e){this.setState(this.state.applyOperations(this,t,e))},e.prototype.serverAck=function(t){this.setState(this.state.serverAck(this,t))},e.prototype.serverReconnect=function(){"function"==typeof this.state.resend&&this.state.resend(this)},e.prototype.transformSelection=function(t){return this.state.transformSelection(t)},e.prototype.sendOperation=function(t,e){throw new Error("sendOperation must be defined in child class")},e.prototype.applyOperation=function(t){throw new Error("applyOperation must be defined in child class")},e.Synchronized=n,n.prototype.applyClient=function(t,e){return t.sendOperation(t.revision,e),new o(e)},n.prototype.applyServer=function(t,e,n){if(e-t.revision>1)throw new Error("Invalid revision.");return t.revision=e,t.applyOperation(n),this},n.prototype.serverAck=function(t,e){throw new Error("There is no pending operation.")},n.prototype.transformSelection=function(t){return t};var a=new n;return e.AwaitingConfirm=o,o.prototype.applyClient=function(t,e){return new r(this.outstanding,e)},o.prototype.applyServer=function(t,e,n){if(e-t.revision>1)throw new Error("Invalid revision.");t.revision=e;var r=n.constructor.transform(this.outstanding,n);return t.applyOperation(r[1]),new o(r[0])},o.prototype.serverAck=function(t,e){return e-t.revision>1?new i(this.outstanding,t,e).getOperations():(t.revision=e,a)},o.prototype.transformSelection=function(t){return t.transform(this.outstanding)},o.prototype.resend=function(t){t.sendOperation(t.revision,this.outstanding)},e.AwaitingWithBuffer=r,r.prototype.applyClient=function(t,e){var n=this.buffer.compose(e);return new r(this.outstanding,n)},r.prototype.applyServer=function(t,e,n){if(e-t.revision>1)throw new Error("Invalid revision.");t.revision=e;var o=n.constructor.transform,i=o(this.outstanding,n),s=o(this.buffer,i[1]);return t.applyOperation(s[1]),new r(i[0],s[0])},r.prototype.serverAck=function(t,e){return e-t.revision>1?new s(this.outstanding,this.buffer,t,e).getOperations():(t.revision=e,t.sendOperation(t.revision,this.buffer),new o(this.buffer))},r.prototype.transformSelection=function(t){return t.transform(this.outstanding).transform(this.buffer)},r.prototype.resend=function(t){t.sendOperation(t.revision,this.outstanding)},e.Stale=i,i.prototype.applyClient=function(t,e){return new s(this.acknowlaged,e,t,this.revision)},i.prototype.applyServer=function(t,e,n){throw new Error("Ignored server-side change.")},i.prototype.applyOperations=function(t,e,n){for(var o=this.acknowlaged.constructor.transform,r=0;re.line?1:t.che.ch?1:0}function o(t,e){return n(t,e)<=0}function r(t,e){return o(t,e)?t:e}function i(t,e){return o(t,e)?e:t}function s(t){return t.indexFromPos({line:t.lastLine(),ch:0})+t.getLine(t.lastLine()).length}function a(t,e){var n=t[e];t[e]=function(){n.apply(t,arguments)}}var h=ot.TextOperation,p=ot.Selection;e.prototype.detach=function(){this.cm.off("changes",this.onChanges),this.cm.off("change",this.onChange),this.cm.off("cursorActivity",this.onCursorActivity),this.cm.off("focus",this.onFocus),this.cm.off("blur",this.onBlur)},e.operationFromCodeMirrorChanges=function(t,e){function n(t){return t[t.length-1]}function r(t){if(0===t.length)return 0;for(var e=0,n=0;n=0;u--){var f=t[u];l=i(l,f);var d=l(f.from),g=a-d-r(f.text);p=(new h).retain(d)["delete"](r(f.removed)).insert(f.text.join("\n")).retain(g).compose(p),c=c.compose((new h).retain(d)["delete"](r(f.text)).insert(f.removed.join("\n")).retain(g)),a+=r(f.removed)-r(f.text)}return[p,c]},e.operationFromCodeMirrorChange=e.operationFromCodeMirrorChanges,e.applyOperationToCodeMirror=function(t,e){e.operation(function(){for(var n=t.ops,o=0,r=0,i=n.length;r0&&(this.majorRevision+=n.length,this.minorRevision=0);var o=t.events;if(o){for(e=0;e1&&(t-=1),6*t<1?i+6*(o-i)*t:2*t<1?o:3*t<2?i+6*(o-i)*(2/3-t):i};return r(s(t+1/3),s(t),s(t-1/3))}function s(t){for(var e=1,n=0;n0&&n.shouldBeComposedWithInverted(h(this.undoManager.undoStack).wrapped)),s=new t(this.selection,o);this.undoManager.add(new d(n,s),i),this.applyClient(e)},o.prototype.updateSelection=function(){this.selection=this.editorAdapter.getSelection()},o.prototype.onSelectionChange=function(){var t=this.selection;this.updateSelection(),t&&this.selection.equals(t)||this.sendSelection(this.selection)},o.prototype.onBlur=function(){this.selection=null,this.sendSelection(null)},o.prototype.sendSelection=function(t){this.state instanceof c.AwaitingWithBuffer||this.serverAdapter.sendSelection(t)},o.prototype.sendOperation=function(t,e){this.serverAdapter.sendOperation(t,e.toJSON(),this.selection)},o.prototype.getOperations=function(t,e){this.serverAdapter.getOperations(t,e)},o.prototype.applyOperation=function(t){this.editorAdapter.applyOperation(t),this.updateSelection(),this.undoManager.transform(new d(t,null))},o}(); \ No newline at end of file