diff options
-rw-r--r-- | .eslintignore | 3 | ||||
-rw-r--r-- | .eslintrc.js | 21 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | config.json.example | 2 | ||||
-rw-r--r-- | lib/config/default.js | 1 | ||||
-rw-r--r-- | lib/config/environment.js | 1 | ||||
-rw-r--r-- | lib/config/index.js | 6 | ||||
-rw-r--r-- | lib/logger.js | 28 | ||||
-rw-r--r-- | lib/models/index.js | 1 | ||||
-rw-r--r-- | lib/models/user.js | 2 | ||||
-rw-r--r-- | lib/realtime.js | 3 | ||||
-rw-r--r-- | lib/web/imageRouter/filesystem.js | 2 | ||||
-rw-r--r-- | package.json | 42 | ||||
-rw-r--r-- | public/.eslintrc.js | 28 | ||||
-rw-r--r-- | public/docs/features.md | 4 | ||||
-rw-r--r-- | public/docs/slide-example.md | 1 | ||||
-rw-r--r-- | public/docs/yaml-metadata.md | 39 | ||||
-rw-r--r-- | public/js/history.js | 1 | ||||
-rw-r--r-- | public/js/index.js | 4 | ||||
-rw-r--r-- | public/js/lib/editor/index.js | 8 | ||||
-rw-r--r-- | public/js/lib/editor/ui-elements.js | 2 |
21 files changed, 129 insertions, 76 deletions
diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..2c3d6b04 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +lib/ot +public/vendor +public/build diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..b826a37b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + "root": true, + "extends": "standard", + "env": { + "node": true + }, + "rules": { + // at some point all of these should return to their default "error" state + // but right now, this is not a good choice, because too many places are + // wrong. + "import/first": ["warn"], + "indent": ["warn"], + "no-multiple-empty-lines": ["warn"], + "no-multi-spaces": ["warn"], + "object-curly-spacing": ["warn"], + "one-var": ["warn"], + "quotes": ["warn"], + "semi": ["warn"], + "space-infix-ops": ["warn"] + } +}; @@ -1,8 +1,6 @@ CodiMD === -[![Standard - JavaScript Style Guide][standardjs-image]][standardjs-url] - [![#CodiMD on matrix.org][matrix.org-image]][matrix.org-url] [![build status][travis-image]][travis-url] [![version][github-version-badge]][github-release-page] @@ -179,6 +177,7 @@ There are some config settings you need to change in the files below. | `CMD_HOST` | `localhost` | host to listen on | | `CMD_PORT` | `80` | web app port | | `CMD_PATH` | `/var/run/codimd.sock` | path to UNIX domain socket to listen on (if specified, `CMD_HOST` and `CMD_PORT` are ignored) | +| `CMD_LOGLEVEL` | `info` | Defines what kind of logs are provided to stdout. | | `CMD_ALLOW_ORIGIN` | `localhost, codimd.org` | domain name whitelist (use comma to separate) | | `CMD_PROTOCOL_USESSL` | `true` or `false` | set to use SSL protocol for resources path (only applied when domain is set) | | `CMD_URL_ADDPORT` | `true` or `false` | set to add port on callback URL (ports `80` or `443` won't be applied) (only applied when domain is set) | @@ -274,6 +273,7 @@ There are some config settings you need to change in the files below. | `host` | `localhost` | host to listen on | | `port` | `80` | web app port | | `path` | `/var/run/codimd.sock` | path to UNIX domain socket to listen on (if specified, `host` and `port` are ignored) | +| `loglevel` | `info` | Defines what kind of logs are provided to stdout. | | `allowOrigin` | `['localhost']` | domain name whitelist | | `useSSL` | `true` or `false` | set to use SSL server (if `true`, will auto turn on `protocolUseSSL`) | | `hsts` | `{"enable": true, "maxAgeSeconds": 31536000, "includeSubdomains": true, "preload": true}` | [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) options to use with HTTPS (default is the example value, max age is a year) | @@ -371,7 +371,5 @@ See more at [http://operational-transformation.github.io/](http://operational-tr [travis-url]: https://travis-ci.org/hackmdio/codimd [github-version-badge]: https://img.shields.io/github/release/hackmdio/codimd.svg [github-release-page]: https://github.com/hackmdio/codimd/releases -[standardjs-image]: https://cdn.rawgit.com/feross/standard/master/badge.svg -[standardjs-url]: https://github.com/feross/standard [poeditor-image]: https://img.shields.io/badge/POEditor-translate-blue.svg [poeditor-url]: https://poeditor.com/join/project/1OpGjF2Jir diff --git a/config.json.example b/config.json.example index 16c95509..8965add2 100644 --- a/config.json.example +++ b/config.json.example @@ -6,6 +6,7 @@ } }, "development": { + "loglevel": "debug", "hsts": { "enable": false }, @@ -16,6 +17,7 @@ }, "production": { "domain": "localhost", + "loglevel": "info" "hsts": { "enable": true, "maxAgeSeconds": "31536000", diff --git a/lib/config/default.js b/lib/config/default.js index 15f11aaa..71375b98 100644 --- a/lib/config/default.js +++ b/lib/config/default.js @@ -7,6 +7,7 @@ module.exports = { urlPath: '', host: '0.0.0.0', port: 3000, + loglevel: 'info', urlAddPort: false, allowOrigin: ['localhost'], useSSL: false, diff --git a/lib/config/environment.js b/lib/config/environment.js index 0c7c9a4f..4220e54d 100644 --- a/lib/config/environment.js +++ b/lib/config/environment.js @@ -9,6 +9,7 @@ module.exports = { host: process.env.CMD_HOST, port: toIntegerConfig(process.env.CMD_PORT), path: process.env.CMD_PATH, + loglevel: process.env.CMD_LOGLEVEL, urlAddPort: toBooleanConfig(process.env.CMD_URL_ADDPORT), useSSL: toBooleanConfig(process.env.CMD_USESSL), hsts: { diff --git a/lib/config/index.js b/lib/config/index.js index 4e1fa50d..c1005b0b 100644 --- a/lib/config/index.js +++ b/lib/config/index.js @@ -45,6 +45,12 @@ merge(config, require('./hackmdEnvironment')) merge(config, require('./environment')) merge(config, require('./dockerSecret')) +if (['debug', 'verbose', 'info', 'warn', 'error'].includes(config.loglevel)) { + logger.level = config.loglevel +} else { + logger.error('Selected loglevel %s doesn\'t exist, using default level \'debug\'. Available options: debug, verbose, info, warn, error', config.loglevel) +} + // load LDAP CA if (config.ldap.tlsca) { let ca = config.ldap.tlsca.split(',') diff --git a/lib/logger.js b/lib/logger.js index f8b3895c..c70b81b8 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -1,23 +1,19 @@ 'use strict' -const winston = require('winston') +const {createLogger, format, transports} = require('winston') -class Logger extends winston.Logger { - // Implement stream.writable.write interface - write (chunk) { - this.info(chunk) - } -} - -module.exports = new Logger({ +module.exports = createLogger({ + level: 'debug', + format: format.combine( + format.uncolorize(), + format.timestamp(), + format.align(), + format.splat(), + format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`) + ), transports: [ - new winston.transports.Console({ - level: 'debug', - handleExceptions: true, - json: false, - colorize: false, - timestamp: true + new transports.Console({ + handleExceptions: true }) ], - emitErrs: true, exitOnError: false }) diff --git a/lib/models/index.js b/lib/models/index.js index 0a44ca87..ef70475e 100644 --- a/lib/models/index.js +++ b/lib/models/index.js @@ -25,6 +25,7 @@ if (config.dbURL) { // https://github.com/sequelize/sequelize/issues/6485 function stripNullByte (value) { value = '' + value + // eslint-disable-next-line no-control-regex return value ? value.replace(/\u0000/g, '') : value } sequelize.stripNullByte = stripNullByte diff --git a/lib/models/user.js b/lib/models/user.js index 1bd8c745..2ebf6d06 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -50,7 +50,7 @@ module.exports = function (sequelize, DataTypes) { }, { instanceMethods: { verifyPassword: function (attempt) { - if (scrypt.verifyKdfSync(new Buffer(this.password, 'hex'), attempt)) { + if (scrypt.verifyKdfSync(Buffer.from(this.password, 'hex'), attempt)) { return this } else { return false diff --git a/lib/realtime.js b/lib/realtime.js index 8541bafa..d04ffdc2 100644 --- a/lib/realtime.js +++ b/lib/realtime.js @@ -242,6 +242,7 @@ function getStatus (callback) { } }) models.User.count().then(function (regcount) { + // eslint-disable-next-line standard/no-callback-literal return callback ? callback({ onlineNotes: Object.keys(notes).length, onlineUsers: Object.keys(users).length, @@ -283,7 +284,7 @@ function extractNoteIdFromSocket (socket) { if (!referer) { return false } - var hostUrl = url.parse(referer) + var hostUrl = url.URL.parse(referer) var noteId = config.urlPath ? hostUrl.pathname.slice(config.urlPath.length + 1, hostUrl.pathname.length).split('/')[1] : hostUrl.pathname.split('/')[1] return noteId } else { diff --git a/lib/web/imageRouter/filesystem.js b/lib/web/imageRouter/filesystem.js index 8c432b0c..a2f8700d 100644 --- a/lib/web/imageRouter/filesystem.js +++ b/lib/web/imageRouter/filesystem.js @@ -16,5 +16,5 @@ exports.uploadImage = function (imagePath, callback) { return } - callback(null, url.resolve(config.serverURL + '/uploads/', path.basename(imagePath))) + callback(null, url.URL.resolve(config.serverURL + '/uploads/', path.basename(imagePath))) } diff --git a/package.json b/package.json index 304a526d..bba1e36f 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,10 @@ "main": "app.js", "license": "AGPL-3.0", "scripts": { - "test": "npm run-script standard && npm run-script jsonlint", + "test": "npm run-script eslint && npm run-script jsonlint", + "eslint": "node_modules/.bin/eslint lib public app.js", "jsonlint": "find . -not -path './node_modules/*' -type f -name '*.json' -o -type f -name '*.json.example' | while read json; do echo $json ; jq . $json; done", - "standard": "node ./node_modules/standard/bin/cmd.js", + "standard": "echo 'standard is no longer being used, use `npm run eslint` instead!' && exit 1", "dev": "webpack --config webpack.dev.js --progress --colors --watch", "build": "webpack --config webpack.prod.js --progress --colors --bail", "postinstall": "bin/heroku", @@ -129,7 +130,7 @@ "velocity-animate": "^1.4.0", "visibilityjs": "^1.2.4", "viz.js": "^1.7.0", - "winston": "^2.3.0", + "winston": "^3.1.0", "ws": "^6.0.0", "xss": "^1.0.3" }, @@ -169,6 +170,12 @@ "css-loader": "^1.0.0", "doctoc": "^1.3.0", "ejs-loader": "^0.3.1", + "eslint": "^5.9.0", + "eslint-config-standard": "^12.0.0", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-node": "^8.0.0", + "eslint-plugin-promise": "^4.0.1", + "eslint-plugin-standard": "^4.0.0", "exports-loader": "^0.7.0", "expose-loader": "^0.7.5", "file-loader": "^2.0.0", @@ -180,7 +187,6 @@ "mini-css-extract-plugin": "^0.4.1", "optimize-css-assets-webpack-plugin": "^5.0.0", "script-loader": "^0.7.2", - "standard": "^9.0.1", "string-loader": "^0.0.1", "style-loader": "^0.21.0", "uglifyjs-webpack-plugin": "^1.2.7", @@ -190,34 +196,6 @@ "webpack-merge": "^4.1.4", "webpack-parallel-uglify-plugin": "^1.1.0" }, - "standard": { - "globals": [ - "$", - "CodeMirror", - "Cookies", - "moment", - "editor", - "ui", - "Spinner", - "modeType", - "Idle", - "serverurl", - "key", - "gapi", - "Dropbox", - "FilePicker", - "ot", - "MediaUploader", - "hex2rgb", - "num_loaded", - "Visibility", - "inlineAttachment" - ], - "ignore": [ - "lib/ot", - "public/vendor" - ] - }, "optionalDependencies": { "bufferutil": "^4.0.0", "utf-8-validate": "^5.0.1" diff --git a/public/.eslintrc.js b/public/.eslintrc.js new file mode 100644 index 00000000..dc37b3cb --- /dev/null +++ b/public/.eslintrc.js @@ -0,0 +1,28 @@ +// this config file is used in concert with the root .eslintrc.js in the root dir. +module.exports = { + "env": { + "browser": true + }, + "globals": { + "$": false, + "CodeMirror": false, + "Cookies": false, + "moment": false, + "editor": false, + "ui": false, + "Spinner": false, + "modeType": false, + "Idle": false, + "serverurl": false, + "key": false, + "gapi": false, + "Dropbox": false, + "FilePicker": false, + "ot": false, + "MediaUploader": false, + "hex2rgb": false, + "num_loaded": false, + "Visibility": false, + "inlineAttachment": false + } +}; diff --git a/public/docs/features.md b/public/docs/features.md index 31c08d2e..a4ffb633 100644 --- a/public/docs/features.md +++ b/public/docs/features.md @@ -72,9 +72,11 @@ Notes can be embedded as follows: ## [Slide Mode](./slide-example): You can use a special syntax to organize your note into slides. -After that, you can use the **Slide Mode** <i class="fa fa-tv"></i> to make a presentation. +After that, you can use the **[Slide Mode](./slide-example)** <i class="fa fa-tv"></i> to make a presentation. Visit the above link for details. +To switch the editor into slide mode, set the [document type](./yaml-metadata#type) to `slide`. + View === ## Table of Contents: diff --git a/public/docs/slide-example.md b/public/docs/slide-example.md index 5503cbd7..49503669 100644 --- a/public/docs/slide-example.md +++ b/public/docs/slide-example.md @@ -1,4 +1,5 @@ --- +type: slide slideOptions: transition: slide --- diff --git a/public/docs/yaml-metadata.md b/public/docs/yaml-metadata.md index 888345f7..839616a8 100644 --- a/public/docs/yaml-metadata.md +++ b/public/docs/yaml-metadata.md @@ -25,7 +25,7 @@ This option will set the note title which prior than content title. > default: not set **Example** -```xml +```yml title: meta title ``` @@ -36,7 +36,7 @@ This option will set the note description. > default: not set **Example** -```xml +```yml description: meta description ``` @@ -47,7 +47,7 @@ This option will set the tags which prior than content tags. > default: not set **Example** -```xml +```yml tags: features, cool, updated ``` @@ -62,7 +62,7 @@ So you can prevent any search engine index your note by set `noindex, nofollow`. > default: not set **Example** -```xml +```yml robots: noindex, nofollow ``` @@ -75,13 +75,13 @@ https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes > default: not set (which will be en) **Example** -```xml +```yml langs: ja-jp ``` dir --- -This option provide to describe the direction of the text in this note. +This option specifies the direction of the text in this note. You can only use whether `rtl` or `ltr`. Look more at here: http://www.w3.org/International/questions/qa-html-dir @@ -89,7 +89,7 @@ http://www.w3.org/International/questions/qa-html-dir > default: not set (which will be ltr) **Example** -```xml +```yml dir: rtl ``` @@ -102,35 +102,46 @@ You can only use whether `true` or `false`. > default: not set (which will be true) **Example** -```xml +```yml breaks: false ``` GA --- -This option allow you to enable Google Analytics with your ID. +This option allows you to enable Google Analytics with your ID. > default: not set (which won't enable) **Example** -```xml +```yml GA: UA-12345667-8 ``` disqus --- -This option allow you to enable Disqus with your shortname. +This option allows you to enable Disqus with your shortname. > default: not set (which won't enable) **Example** -```xml +```yml disqus: codimd ``` +type +--- +This option allows you to switch the document view to the slide preview, to simplify live editing of presentations. + +> default: not set + +**Example:** +```yml +type: slide +``` + slideOptions --- -This option allow you provide custom options to slide mode. +This option allows you to provide custom options to slide mode. Please below document for more details: https://github.com/hakimel/reveal.js/#configuration @@ -142,7 +153,7 @@ https://github.com/hakimel/reveal.js/tree/master/css/theme > default: not set (which use default slide options) **Example** -```xml +```yml slideOptions: transition: fade theme: white diff --git a/public/js/history.js b/public/js/history.js index b4c26b42..6007bef4 100644 --- a/public/js/history.js +++ b/public/js/history.js @@ -218,6 +218,7 @@ export function getStorageHistory (callback) { if (typeof data === 'string') { data = JSON.parse(data) } callback(data) } + // eslint-disable-next-line standard/no-callback-literal callback([]) } diff --git a/public/js/index.js b/public/js/index.js index 98c3b6d2..0c575961 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2511,7 +2511,9 @@ function buildCursor (user) { // editor actions function removeNullByte (cm, change) { var str = change.text.join('\n') + // eslint-disable-next-line no-control-regex if (/\u0000/g.test(str) && change.update) { + // eslint-disable-next-line no-control-regex change.update(change.from, change.to, str.replace(/\u0000/g, '').split('\n')) } } @@ -3046,7 +3048,7 @@ function checkInCode () { function checkAbove (method) { var cursor = editor.getCursor() var text = [] - for (var i = 0; i < cursor.line; i++) { // contain current line + for (var i = 0; i < cursor.line; i++) { // contain current line text.push(editor.getLine(i)) } text = text.join('\n') + '\n' + editor.getLine(cursor.line).slice(0, cursor.ch) diff --git a/public/js/lib/editor/index.js b/public/js/lib/editor/index.js index 0537e927..f05d01b8 100644 --- a/public/js/lib/editor/index.js +++ b/public/js/lib/editor/index.js @@ -492,7 +492,7 @@ export default class Editor { clearInterval(spellcheckTimer) } }, - 100, + 100 ) } } @@ -514,7 +514,7 @@ export default class Editor { } setOverrideBrowserKeymap () { var overrideBrowserKeymap = $( - '.ui-preferences-override-browser-keymap label > input[type="checkbox"]', + '.ui-preferences-override-browser-keymap label > input[type="checkbox"]' ) if (overrideBrowserKeymap.is(':checked')) { Cookies.set('preferences-override-browser-keymap', true, { @@ -529,10 +529,10 @@ export default class Editor { setPreferences () { var overrideBrowserKeymap = $( - '.ui-preferences-override-browser-keymap label > input[type="checkbox"]', + '.ui-preferences-override-browser-keymap label > input[type="checkbox"]' ) var cookieOverrideBrowserKeymap = Cookies.get( - 'preferences-override-browser-keymap', + 'preferences-override-browser-keymap' ) if (cookieOverrideBrowserKeymap && cookieOverrideBrowserKeymap === 'true') { overrideBrowserKeymap.prop('checked', true) diff --git a/public/js/lib/editor/ui-elements.js b/public/js/lib/editor/ui-elements.js index ca06d30c..29a37782 100644 --- a/public/js/lib/editor/ui-elements.js +++ b/public/js/lib/editor/ui-elements.js @@ -67,7 +67,7 @@ export const getUIElements = () => ({ codemirrorScroll: $('.ui-edit-area .CodeMirror .CodeMirror-scroll'), codemirrorSizer: $('.ui-edit-area .CodeMirror .CodeMirror-sizer'), codemirrorSizerInner: $( - '.ui-edit-area .CodeMirror .CodeMirror-sizer > div', + '.ui-edit-area .CodeMirror .CodeMirror-sizer > div' ), markdown: $('.ui-view-area .markdown-body'), resize: { |