summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintignore3
-rw-r--r--.eslintrc.js21
-rw-r--r--README.md6
-rw-r--r--app.js2
-rwxr-xr-xbin/setup10
-rw-r--r--lib/config/default.js1
-rw-r--r--lib/config/environment.js1
-rw-r--r--lib/logger.js10
-rw-r--r--lib/migrations/20150702001020-update-to-0_3_1.js2
-rw-r--r--lib/migrations/20160112220142-note-add-lastchange.js2
-rw-r--r--lib/migrations/20160420180355-note-add-alias.js2
-rw-r--r--lib/migrations/20160515114000-user-add-tokens.js2
-rw-r--r--lib/migrations/20160607060246-support-revision.js2
-rw-r--r--lib/migrations/20160703062241-support-authorship.js2
-rw-r--r--lib/migrations/20161009040430-support-delete-note.js2
-rw-r--r--lib/migrations/20161201050312-support-email-signin.js2
-rw-r--r--lib/models/index.js1
-rw-r--r--lib/models/user.js2
-rw-r--r--lib/realtime.js3
-rw-r--r--lib/response.js2
-rw-r--r--lib/web/auth/oauth2/index.js8
-rw-r--r--lib/web/imageRouter/filesystem.js2
-rw-r--r--locales/nl.json283
-rw-r--r--package.json42
-rw-r--r--public/.eslintrc.js28
-rw-r--r--public/js/history.js1
-rw-r--r--public/js/index.js4
-rw-r--r--public/js/lib/editor/index.js8
-rw-r--r--public/js/lib/editor/ui-elements.js2
29 files changed, 287 insertions, 169 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"]
+ }
+};
diff --git a/README.md b/README.md
index 938ba71d..7ab6dbe9 100644
--- a/README.md
+++ b/README.md
@@ -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]
@@ -187,6 +185,7 @@ There are some config settings you need to change in the files below.
| `CMD_ALLOW_ANONYMOUS` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `CMD_ALLOW_ANONYMOUS_EDITS` | `true` or `false` | if `allowAnonymous` is `true`, allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `CMD_ALLOW_FREEURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
+| `CMD_FORBIDDEN_NODE_IDS` | `'robots.txt'` | disallow creation of notes, even if `CMD_ALLOW_FREEURL` is `true` |
| `CMD_DEFAULT_PERMISSION` | `freely`, `editable`, `limited`, `locked` or `private` | set notes default permission (only applied on signed users) |
| `CMD_DB_URL` | `mysql://localhost:3306/database` | set the database URL |
| `CMD_SESSION_SECRET` | no example | Secret used to sign the session cookie. If non is set, one will randomly generated on startup |
@@ -286,6 +285,7 @@ There are some config settings you need to change in the files below.
| `allowAnonymous` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `allowAnonymousEdits` | `true` or `false` | if `allowAnonymous` is `true`: allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `allowFreeURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
+| `forbiddenNoteIDs` | `['robots.txt']` | disallow creation of notes, even if `allowFreeUrl` is `true` |
| `defaultPermission` | `freely`, `editable`, `limited`, `locked`, `protected` or `private` | set notes default permission (only applied on signed users) |
| `dbURL` | `mysql://localhost:3306/database` | set the db URL; if set, then db config (below) won't be applied |
| `db` | `{ "dialect": "sqlite", "storage": "./db.codimd.sqlite" }` | set the db configs, [see more here](http://sequelize.readthedocs.org/en/latest/api/sequelize/) |
@@ -373,7 +373,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/app.js b/app.js
index 33956ce9..618fba15 100644
--- a/app.js
+++ b/app.js
@@ -53,7 +53,7 @@ if (config.useSSL) {
// logger
app.use(morgan('combined', {
- 'stream': logger
+ 'stream': logger.stream
}))
// socket io
diff --git a/bin/setup b/bin/setup
index 122cb7ae..38aa05a4 100755
--- a/bin/setup
+++ b/bin/setup
@@ -8,11 +8,12 @@ if [ -d .git ]; then
cd "$(git rev-parse --show-toplevel)"
fi
-if ! type npm > /dev/null
+if ! type yarn > /dev/null
then
cat << EOF
-npm is not installed, please install Node.js and npm.
+yarn is not installed, please install Node.js, npm and yarn.
Read more on Node.js official website: https://nodejs.org
+And for yarn package manager at: https://yarnpkg.com/en/
Setup will not be run
EOF
exit 0
@@ -27,8 +28,9 @@ if [ ! -f .sequelizerc ]; then
cp .sequelizerc.example .sequelizerc
fi
-echo "install npm packages"
-BUILD_ASSETS=false npm install
+echo "install packages"
+yarn install --pure-lockfile
+yarn install --production=false --pure-lockfile
cat << EOF
diff --git a/lib/config/default.js b/lib/config/default.js
index 71375b98..d7a8f471 100644
--- a/lib/config/default.js
+++ b/lib/config/default.js
@@ -32,6 +32,7 @@ module.exports = {
allowAnonymous: true,
allowAnonymousEdits: false,
allowFreeURL: false,
+ forbiddenNoteIDs: ['robots.txt', 'favicon.ico', 'api'],
defaultPermission: 'editable',
dbURL: '',
db: {},
diff --git a/lib/config/environment.js b/lib/config/environment.js
index 4220e54d..a57fe0db 100644
--- a/lib/config/environment.js
+++ b/lib/config/environment.js
@@ -28,6 +28,7 @@ module.exports = {
allowAnonymous: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS),
allowAnonymousEdits: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS_EDITS),
allowFreeURL: toBooleanConfig(process.env.CMD_ALLOW_FREEURL),
+ forbiddenNoteIDs: toArrayConfig(process.env.CMD_FORBIDDEN_NOTE_IDS),
defaultPermission: process.env.CMD_DEFAULT_PERMISSION,
dbURL: process.env.CMD_DB_URL,
sessionSecret: process.env.CMD_SESSION_SECRET,
diff --git a/lib/logger.js b/lib/logger.js
index c70b81b8..5ef1860a 100644
--- a/lib/logger.js
+++ b/lib/logger.js
@@ -1,7 +1,7 @@
'use strict'
const {createLogger, format, transports} = require('winston')
-module.exports = createLogger({
+const logger = createLogger({
level: 'debug',
format: format.combine(
format.uncolorize(),
@@ -17,3 +17,11 @@ module.exports = createLogger({
],
exitOnError: false
})
+
+logger.stream = {
+ write: function (message, encoding) {
+ logger.info(message)
+ }
+}
+
+module.exports = logger
diff --git a/lib/migrations/20150702001020-update-to-0_3_1.js b/lib/migrations/20150702001020-update-to-0_3_1.js
index eb18211f..e1a88661 100644
--- a/lib/migrations/20150702001020-update-to-0_3_1.js
+++ b/lib/migrations/20150702001020-update-to-0_3_1.js
@@ -21,7 +21,7 @@ module.exports = {
defaultValue: 0
})
}).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'shortid'" || error.message === 'column "shortid" of relation "Notes" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: shortid' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'shortid'" || error.message === 'column "shortid" of relation "Notes" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
diff --git a/lib/migrations/20160112220142-note-add-lastchange.js b/lib/migrations/20160112220142-note-add-lastchange.js
index 682337c9..87e3ff19 100644
--- a/lib/migrations/20160112220142-note-add-lastchange.js
+++ b/lib/migrations/20160112220142-note-add-lastchange.js
@@ -8,7 +8,7 @@ module.exports = {
type: Sequelize.DATE
})
}).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'lastchangeuserId'" || error.message === 'column "lastchangeuserId" of relation "Notes" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: lastchangeuserId' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'lastchangeuserId'" || error.message === 'column "lastchangeuserId" of relation "Notes" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
diff --git a/lib/migrations/20160420180355-note-add-alias.js b/lib/migrations/20160420180355-note-add-alias.js
index 6cc1337e..45d53e69 100644
--- a/lib/migrations/20160420180355-note-add-alias.js
+++ b/lib/migrations/20160420180355-note-add-alias.js
@@ -8,7 +8,7 @@ module.exports = {
indicesType: 'UNIQUE'
})
}).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'alias'" || error.message === 'column "alias" of relation "Notes" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: alias' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'alias'" || error.message === 'column "alias" of relation "Notes" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
diff --git a/lib/migrations/20160515114000-user-add-tokens.js b/lib/migrations/20160515114000-user-add-tokens.js
index 8bf6d11f..435ae9cb 100644
--- a/lib/migrations/20160515114000-user-add-tokens.js
+++ b/lib/migrations/20160515114000-user-add-tokens.js
@@ -4,7 +4,7 @@ module.exports = {
return queryInterface.addColumn('Users', 'accessToken', Sequelize.STRING).then(function () {
return queryInterface.addColumn('Users', 'refreshToken', Sequelize.STRING)
}).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'accessToken'" || error.message === 'column "accessToken" of relation "Users" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: accessToken' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'accessToken'" || error.message === 'column "accessToken" of relation "Users" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
diff --git a/lib/migrations/20160607060246-support-revision.js b/lib/migrations/20160607060246-support-revision.js
index 465a09fa..547f89b8 100644
--- a/lib/migrations/20160607060246-support-revision.js
+++ b/lib/migrations/20160607060246-support-revision.js
@@ -16,7 +16,7 @@ module.exports = {
updatedAt: Sequelize.DATE
})
}).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'savedAt'" || error.message === 'column "savedAt" of relation "Notes" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: savedAt' | error.message === "ER_DUP_FIELDNAME: Duplicate column name 'savedAt'" || error.message === 'column "savedAt" of relation "Notes" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
diff --git a/lib/migrations/20160703062241-support-authorship.js b/lib/migrations/20160703062241-support-authorship.js
index ccdfeb3e..f452b1a7 100644
--- a/lib/migrations/20160703062241-support-authorship.js
+++ b/lib/migrations/20160703062241-support-authorship.js
@@ -17,7 +17,7 @@ module.exports = {
updatedAt: Sequelize.DATE
})
}).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'authorship'" || error.message === 'column "authorship" of relation "Notes" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: authorship' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'authorship'" || error.message === 'column "authorship" of relation "Notes" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
diff --git a/lib/migrations/20161009040430-support-delete-note.js b/lib/migrations/20161009040430-support-delete-note.js
index 39e6f7fb..56a336ac 100644
--- a/lib/migrations/20161009040430-support-delete-note.js
+++ b/lib/migrations/20161009040430-support-delete-note.js
@@ -2,7 +2,7 @@
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.addColumn('Notes', 'deletedAt', Sequelize.DATE).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'deletedAt'" || error.message === 'column "deletedAt" of relation "Notes" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: deletedAt' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'deletedAt'" || error.message === 'column "deletedAt" of relation "Notes" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
diff --git a/lib/migrations/20161201050312-support-email-signin.js b/lib/migrations/20161201050312-support-email-signin.js
index 0a8a832d..26bc09ea 100644
--- a/lib/migrations/20161201050312-support-email-signin.js
+++ b/lib/migrations/20161201050312-support-email-signin.js
@@ -10,7 +10,7 @@ module.exports = {
}
})
}).catch(function (error) {
- if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'email'" || error.message === 'column "email" of relation "Users" already exists') {
+ if (error.message === 'SQLITE_ERROR: duplicate column name: email' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'email'" || error.message === 'column "email" of relation "Users" already exists') {
console.log('Migration has already run… ignoring.')
} else {
throw error
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/response.js b/lib/response.js
index 671aa120..b94f473a 100644
--- a/lib/response.js
+++ b/lib/response.js
@@ -157,7 +157,7 @@ function findNote (req, res, callback, include) {
include: include || null
}).then(function (note) {
if (!note) {
- if (config.allowFreeURL && noteId) {
+ if (config.allowFreeURL && noteId && !config.forbiddenNoteIDs.includes(noteId)) {
req.alias = noteId
return newNote(req, res)
} else {
diff --git a/lib/web/auth/oauth2/index.js b/lib/web/auth/oauth2/index.js
index f2a3132d..b9160f6e 100644
--- a/lib/web/auth/oauth2/index.js
+++ b/lib/web/auth/oauth2/index.js
@@ -2,13 +2,13 @@
const Router = require('express').Router
const passport = require('passport')
-const OAuth2Strategy = require('passport-oauth2').Strategy
+const { Strategy, InternalOAuthError } = require('passport-oauth2')
const config = require('../../../config')
const {setReturnToFromReferer, passportGeneralCallback} = require('../utils')
let oauth2Auth = module.exports = Router()
-class OAuth2CustomStrategy extends OAuth2Strategy {
+class OAuth2CustomStrategy extends Strategy {
constructor (options, verify) {
options.customHeaders = options.customHeaders || {}
super(options, verify)
@@ -22,7 +22,7 @@ class OAuth2CustomStrategy extends OAuth2Strategy {
var json
if (err) {
- return done(new passport.InternalOAuthError('Failed to fetch user profile', err))
+ return done(new InternalOAuthError('Failed to fetch user profile', err))
}
try {
@@ -67,7 +67,7 @@ OAuth2CustomStrategy.prototype.userProfile = function (accessToken, done) {
var json
if (err) {
- return done(new passport.InternalOAuthError('Failed to fetch user profile', err))
+ return done(new InternalOAuthError('Failed to fetch user profile', err))
}
try {
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/locales/nl.json b/locales/nl.json
index 325c273d..6fd857a7 100644
--- a/locales/nl.json
+++ b/locales/nl.json
@@ -1,106 +1,179 @@
{
- "Collaborative markdown notes": "Samenwerkende markdown notities",
- "Realtime collaborative markdown notes on all platforms.": "Realtime samenwerkende markdown notities.",
- "Best way to write and share your knowledge in markdown.": "De beste manier je kennis te delen en schrijven in markdown.",
- "Intro": "Introductie",
- "History": "Geschiedenis",
- "New guest note": "Nieuwe gast notitie",
- "Collaborate with URL": "Samenwerken met URL",
- "Support charts and MathJax": "Ondersteun grafieken en MathJax",
- "Support slide mode": "Ondersteun slide mode",
- "Sign In": "Log in",
- "Below is the history from browser": "Hier onder staat de browser geschiedenis",
- "Welcome!": "Welkom!",
- "New note": "Nieuwe notitie",
- "or": "of",
- "Sign Out": "Log uit",
- "Explore all features": "Ontdek alle features",
- "Select tags...": "Selecteer tags...",
- "Search keyword...": "Zoeken op keyword...",
- "Sort by title": "Sorteren op titel",
- "Title": "Titel",
- "Sort by time": "Sorteren op tijd",
- "Time": "Tijd",
- "Export history": "Exporteer geschiedenis",
- "Import history": "Importeer geschiedenis",
- "Clear history": "Verwijder geschiedenis",
- "Refresh history": "Ververs geschiedenis",
- "No history": "Geen geschidenis gevonden",
- "Import from browser": "Importeer van browser",
- "Releases": "Releases",
- "Are you sure?": "Weet je het zeker?",
- "Do you really want to delete this note?": "Will je deze notitie echt verwijderen?",
- "All users will lose their connection.": "Alle gebruikers zullen hun verbinding verliezen.",
- "Cancel": "Stoppen",
- "Yes, do it!": "Ja, doe het!",
- "Choose method": "Kies methode",
- "Sign in via %s": "Log in via %s",
- "New": "Nieuw",
- "Publish": "Publiceren",
- "Extra": "Extra",
- "Revision": "Herzien",
- "Slide Mode": "Slide Mode",
- "Export": "Exporteren",
- "Import": "Importeren",
- "Clipboard": "Kladbord",
- "Download": "Downloaden",
- "Raw HTML": "Raw HTML",
- "Edit": "Aanpassen",
- "View": "Bekijken",
- "Both": "Beide",
- "Help": "Help",
- "Upload Image": "Afbeelding uploaden",
- "Menu": "Menu",
- "This page need refresh": "Deze pagina moet herladen worden",
- "You have an incompatible client version.": "Je client is niet compatible.",
- "Refresh to update.": "Ververs om te updaten.",
- "New version available!": "Nieuwe versie beschikbaar!",
- "See releases notes here": "Zie releases hier",
- "Refresh to enjoy new features.": "Ververs om de nieuwe features te zien.",
- "Your user state has changed.": "Je gebruikers-status is veranderd.",
- "Refresh to load new user state.": "Ververs om je nieuwe gebruikers-status te zien.",
- "Refresh": "Ververs",
- "Contacts": "Contacten",
- "Report an issue": "Probleem rapporteren",
- "Send us email": "Stuur ons een mail",
- "Documents": "Documenten",
- "Features": "Features",
- "YAML Metadata": "YAML Metadata",
- "Slide Example": "Slide Voorbeeld",
- "Cheatsheet": "Afkijkblad",
- "Example": "Voorbeeld",
- "Syntax": "Syntax",
- "Header": "Koptekst",
- "Unordered List": "Niet gesorteerde Lijst",
- "Ordered List": "Gesorteerde List",
- "Todo List": "Todo Lijst",
- "Blockquote": "Quote",
- "Bold font": "Bold tekst",
- "Italics font": "Italics tekst",
- "Strikethrough": "Doorstreepte tekst",
- "Inserted text": "Bijgevoegde tekst",
- "Marked text": "Gemarkeerde tekst",
- "Link": "Link",
- "Image": "Afbeelding",
- "Code": "Code",
- "Externals": "Uiterlijkheden",
- "This is a alert area.": "Dit is een waarschuwingsgebied.",
- "Revert": "Terugzetten",
- "Import from clipboard": "Importeren from kladbord",
- "Paste your markdown or webpage here...": "Plak je markdown of webpagina hier...",
- "Clear": "Legen",
- "This note is locked": "Deze notitie zit op slot",
- "Sorry, only owner can edit this note.": "Sorry, alleen de eigenaar kan deze notitie aanpassen.",
- "OK": "OK",
- "Reach the limit": "Limiet bereikt",
- "Sorry, you've reached the max length this note can be.": "Sorry, je notitie heeft de maximale lengte bereikt.",
- "Please reduce the content or divide it to more notes, thank you!": "Verwijder alsjeblieft wat tekst of verdeel het over meerdere notities!",
- "Import from Gist": "Importeren vanaf een Gist",
- "Paste your gist url here...": "Plak je Gist URL hier...",
- "Import from Snippet": "Imporeren vanaf een Snippet",
- "Select From Available Projects": "Selecteer van beschikbare projecten",
- "Select From Available Snippets": "Selecteer van beschikbare Snippets",
- "OR": "OF",
- "Export to Snippet": "Exporteren naar Snippet",
- "Select Visibility Level": "Selecteer zichtbaarheids niveau"
-}
+ "Used in the title of every note that has no title set.": {
+ "Collaborative markdown notes": "Samenwerkende markdown notities"
+ },
+ "Not used right now.": {
+ "Realtime collaborative markdown notes on all platforms.": "Realtime samenwerkende markdown notities.",
+ "Welcome!": "Welkom!"
+ },
+ "Subtitle on the entry page. Used to tell what CodiMD is.": {
+ "Best way to write and share your knowledge in markdown.": "De beste manier je kennis te delen en schrijven in markdown."
+ },
+ "Name of the menu item on the index page. It's the default tab for unauthenticated users.": {
+ "Intro": "Introductie"
+ },
+ "Name of the tab that shows the user's note history. Default page for logged in users": {
+ "History": "Geschiedenis"
+ },
+ "Button on the main page to create a new note as guest": {
+ "New guest note": "Nieuwe gast notitie"
+ },
+ "Little text to illustrate some of our features on the index page. Also links to the share-notes section on the features page": {
+ "Collaborate with URL": "Samenwerken met URL"
+ },
+ "Little text to illustrate the mathjax feature of CodiMD. Also links to the MathJax section of the features page": {
+ "Support charts and MathJax": "Ondersteun grafieken en MathJax"
+ },
+ "Shows that CodiMD has a slide mode feature and links to the Slide-mode section of the features page": {
+ "Support slide mode": "Ondersteun slide mode"
+ },
+ "Login button on the index page": {
+ "Sign In": "Log in"
+ },
+ "Shows up on the history page for non-logged in users": {
+ "Below is the history from browser": "Hier onder staat de browser geschiedenis"
+ },
+ "New note\"-button on the index page for logged in users": {
+ "New note": "Nieuwe notitie"
+ },
+ "Used on the index page for not logged in users to split the \"sign in\" and \"Explore all features\" button.": {
+ "or": "of"
+ },
+ "Log out string on the index page. In the drop-down menu for the user name.": {
+ "Sign Out": "Log uit"
+ },
+ "Text in the button that links to the features page": {
+ "Explore all features": "Ontdek alle features"
+ },
+ "Placeholder text in the search field for tags on the history tab on the index page": {
+ "Select tags...": "Selecteer tags..."
+ },
+ "placeholder text in the search field for keywords on the history tab on the index page": {
+ "Search keyword...": "Zoeken op keyword..."
+ },
+ "Help text for the \"Title\"-button on the history tab on the index page.": {
+ "Sort by title": "Sorteren op titel"
+ },
+ "Text to sort notes by title on the history tab on the index page.": {
+ "Title": "Titel"
+ },
+ "Sort by time": "Sorteren op tijd",
+ "Time": "Tijd",
+ "Export history": "Exporteer geschiedenis",
+ "Import history": "Importeer geschiedenis",
+ "Clear history": "Verwijder geschiedenis",
+ "Refresh history": "Ververs geschiedenis",
+ "No history": "Geen geschidenis gevonden",
+ "Import from browser": "Importeer van browser",
+ "Releases": "Releases",
+ "Are you sure?": "Weet je het zeker?",
+ "Do you really want to delete this note?": "Will je deze notitie echt verwijderen?",
+ "All users will lose their connection.": "Alle gebruikers zullen hun verbinding verliezen.",
+ "Cancel": "Stoppen",
+ "Yes, do it!": "Ja, doe het!",
+ "Choose method": "Kies methode",
+ "Sign in via %s": "Log in via %s",
+ "New": "Nieuw",
+ "Publish": "Publiceren",
+ "Extra": "Extra",
+ "Revision": "Versie",
+ "Slide Mode": "Slide Mode",
+ "Export": "Exporteren",
+ "Import": "Importeren",
+ "Clipboard": "Kladbord",
+ "Download": "Downloaden",
+ "Raw HTML": "Ruwe HTML",
+ "Edit": "Aanpassen",
+ "View": "Bekijken",
+ "Both": "Beide",
+ "Help": "Help",
+ "Upload Image": "Afbeelding uploaden",
+ "Menu": "Menu",
+ "This page need refresh": "Deze pagina moet vernieuwd worden",
+ "You have an incompatible client version.": "Je client is niet compatibel.",
+ "Refresh to update.": "Ververs om te updaten.",
+ "New version available!": "Nieuwe versie beschikbaar!",
+ "See releases notes here": "Bekijk de release notes hier",
+ "Refresh to enjoy new features.": "Ververs om de nieuwe features te zien.",
+ "Your user state has changed.": "Je gebruikers-status is veranderd.",
+ "Refresh to load new user state.": "Ververs om je nieuwe gebruikers-status te zien.",
+ "Refresh": "Ververs",
+ "Contacts": "Contacten",
+ "Report an issue": "Probleem rapporteren",
+ "Meet us on %s": "Ontmoet ons op %s",
+ "Send us email": "Stuur ons een mail",
+ "Documents": "Documenten",
+ "Features": "Features",
+ "YAML Metadata": "YAML Metadata",
+ "Slide Example": "Slide Voorbeeld",
+ "Cheatsheet": "Afkijkblad",
+ "Example": "Voorbeeld",
+ "Syntax": "Syntax",
+ "Header": "Koptekst",
+ "Unordered List": "Niet gesorteerde Lijst",
+ "Ordered List": "Gesorteerde List",
+ "Todo List": "Todo Lijst",
+ "Blockquote": "Citaat",
+ "Bold font": "Bold tekst",
+ "Italics font": "Italics tekst",
+ "Strikethrough": "Doorstreepte tekst",
+ "Inserted text": "Bijgevoegde tekst",
+ "Marked text": "Gemarkeerde tekst",
+ "Link": "Link",
+ "Image": "Afbeelding",
+ "Code": "Code",
+ "Externals": "Uiterlijkheden",
+ "This is a alert area.": "Dit is een waarschuwingsgebied.",
+ "Revert": "Terugzetten",
+ "Import from clipboard": "Importeren from kladbord",
+ "Paste your markdown or webpage here...": "Plak je markdown of webpagina hier...",
+ "Clear": "Legen",
+ "This note is locked": "Deze notitie zit op slot",
+ "Sorry, only owner can edit this note.": "Sorry, alleen de eigenaar kan deze notitie aanpassen.",
+ "OK": "OK",
+ "Reach the limit": "Limiet bereikt",
+ "Sorry, you've reached the max length this note can be.": "Sorry, je notitie heeft de maximale lengte bereikt.",
+ "Please reduce the content or divide it to more notes, thank you!": "Verwijder alsjeblieft wat tekst of verdeel het over meerdere notities!",
+ "Import from Gist": "Importeren vanaf een Gist",
+ "Paste your gist url here...": "Plak je Gist URL hier...",
+ "Import from Snippet": "Imporeren vanaf een Snippet",
+ "Select From Available Projects": "Selecteer van beschikbare projecten",
+ "Select From Available Snippets": "Selecteer van beschikbare Snippets",
+ "OR": "OF",
+ "Used in the drop-down menu in the codimd view. Allows to export notes to GitLab Snippets.": {
+ "Export to Snippet": "Exporteren naar Snippet"
+ },
+ "Used in the GitLab snippet export and import menu in the codimd view.": {
+ "Select Visibility Level": "Selecteer zichtbaarheids niveau"
+ },
+ "Addtional text that shows up by hovering over the night mode button in the codimd view. Should explain what the moon sign at the top does.": {
+ "Night Theme": "Nachtweergave"
+ },
+ "Text at the bottom of the index page. Contains 3 links to github, Matrix and POEditor.\n\nLike: \"Follow us on Github, Matrix and POEditor.": {
+ "Follow us on %s and %s.": "Volg ons op %s en %s."
+ },
+ "Optional text at the bottom of the index page linking to the privacy policy of an instance.": {
+ "Privacy": "Privacy"
+ },
+ "Optional text at the bottom of the index page linking to the Terms of Use document provided by the instance.": {
+ "Terms of Use": "Gebruikersvoorwaarden"
+ },
+ "Used as title of the modal that asks the user that he/she is really sure about deleting his/her account.": {
+ "Do you really want to delete your user account?": "Weet je zeker dat je je account wilt verwijderen?"
+ },
+ "Used in a modal that shows up as soon as the user clicks on the \"Delete user\"-button in the user drop-down menu. Should make clear that everything the user owns or references to the user will be deleted and can not be recovered.": {
+ "This will delete your account, all notes that are owned by you and remove all references to your account from other notes.": "Dit zal je account verwijderen. Alle notities waar je eigenaar van bent worden verwijderd, samen met alle verwijzingen naar je account."
+ },
+ "Used in the user drop-down menu on the index page. Opens a modal that informs the user that his account will be deleted completely and makes sure the user really want that. Then deletes the account including all notes a user owns.": {
+ "Delete user": "Gebruiker verwijderen"
+ },
+ "Used in the user drop-down menu on the index page. Generates an archive of all notes a user owns and downloads them.": {
+ "Export user data": "Gebruikersdata exporteren"
+ },
+ "Used in the sidebar of the help modal. Links to POEditor, our translation platform.": {
+ "Help us translating on %s": "Help ons vertalen op %s"
+ },
+ "Link besides the \"Release\" and possible \"Privacy policies\" at the bottom of the index page that points to the source code of the CodiMD version you are using.": {
+ "Source Code": ""
+ }
+} \ No newline at end of file
diff --git a/package.json b/package.json
index cd875ac6..2cc9415a 100644
--- a/package.json
+++ b/package.json
@@ -5,13 +5,14 @@
"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",
- "start": "node app.js",
+ "start": "sequelize db:migrate && node app.js",
"doctoc": "doctoc --title='# Table of Contents' README.md"
},
"dependencies": {
@@ -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/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: {