Merge branch 'develop' into feature/support-vega-lite

# Conflicts:
#	package.json
#	public/views/slide.ejs
This commit is contained in:
Max Wu 2019-08-06 22:06:43 +08:00
commit 71ea581796
49 changed files with 1509 additions and 1357 deletions

6
app.js
View File

@ -28,8 +28,8 @@ var csp = require('./lib/csp')
function createHttpServer () {
if (config.useSSL) {
const ca = (function () {
let i, len, results
results = []
let i, len
const results = []
for (i = 0, len = config.sslCAPath.length; i < len; i++) {
results.push(fs.readFileSync(config.sslCAPath[i], 'utf8'))
}
@ -55,7 +55,7 @@ var server = createHttpServer()
// logger
app.use(morgan('combined', {
'stream': logger.stream
stream: logger.stream
}))
// socket io

View File

@ -53,14 +53,14 @@ if (['debug', 'verbose', 'info', 'warn', 'error'].includes(config.loglevel)) {
// load LDAP CA
if (config.ldap.tlsca) {
let ca = config.ldap.tlsca.split(',')
let caContent = []
for (let i of ca) {
if (fs.existsSync(i)) {
caContent.push(fs.readFileSync(i, 'utf8'))
const certificateAuthorities = config.ldap.tlsca.split(',')
const caContent = []
for (const ca of certificateAuthorities) {
if (fs.existsSync(ca)) {
caContent.push(fs.readFileSync(ca, 'utf8'))
}
}
let tlsOptions = {
const tlsOptions = {
ca: caContent
}
config.ldap.tlsOptions = config.ldap.tlsOptions ? Object.assign(config.ldap.tlsOptions, tlsOptions) : tlsOptions
@ -134,10 +134,10 @@ config.isGitlabSnippetsEnable = (!config.gitlab.scope || config.gitlab.scope ===
config.updateI18nFiles = (env === Environment.development)
// merge legacy values
let keys = Object.keys(config)
const keys = Object.keys(config)
const uppercase = /[A-Z]/
for (let i = keys.length; i--;) {
let lowercaseKey = keys[i].toLowerCase()
const lowercaseKey = keys[i].toLowerCase()
// if the config contains uppercase letters
// and a lowercase version of this setting exists
// and the config with uppercase is not set

View File

@ -9,14 +9,6 @@ var logger = require('./logger')
var response = require('./response')
var models = require('./models')
// public
var History = {
historyGet: historyGet,
historyPost: historyPost,
historyDelete: historyDelete,
updateHistory: updateHistory
}
function getHistory (userid, callback) {
models.User.findOne({
where: {
@ -41,7 +33,7 @@ function getHistory (userid, callback) {
continue
}
try {
let id = LZString.decompressFromBase64(history[i].id)
const id = LZString.decompressFromBase64(history[i].id)
if (id && models.Note.checkNoteIdValid(id)) {
history[i].id = models.Note.encodeNoteId(id)
}
@ -200,4 +192,8 @@ function historyDelete (req, res) {
}
}
module.exports = History
// public
exports.historyGet = historyGet
exports.historyPost = historyPost
exports.historyDelete = historyDelete
exports.updateHistory = updateHistory

View File

@ -32,9 +32,9 @@ exports.generateAvatarURL = function (name, email = '', big = true) {
}
name = encodeURIComponent(name)
let hash = crypto.createHash('md5')
const hash = crypto.createHash('md5')
hash.update(email.toLowerCase())
let hexDigest = hash.digest('hex')
const hexDigest = hash.digest('hex')
if (email !== '' && config.allowGravatar) {
photo = 'https://www.gravatar.com/avatar/' + hexDigest

View File

@ -165,15 +165,15 @@ module.exports = function (sequelize, DataTypes) {
}
Note.encodeNoteId = function (id) {
// remove dashes in UUID and encode in url-safe base64
let str = id.replace(/-/g, '')
let hexStr = Buffer.from(str, 'hex')
const str = id.replace(/-/g, '')
const hexStr = Buffer.from(str, 'hex')
return base64url.encode(hexStr)
}
Note.decodeNoteId = function (encodedId) {
// decode from url-safe base64
let id = base64url.toBuffer(encodedId).toString('hex')
const id = base64url.toBuffer(encodedId).toString('hex')
// add dashes between the UUID string parts
let idParts = []
const idParts = []
idParts.push(id.substr(0, 8))
idParts.push(id.substr(8, 4))
idParts.push(id.substr(12, 4))
@ -196,7 +196,7 @@ module.exports = function (sequelize, DataTypes) {
}
}).then(function (note) {
if (note) {
let filePath = path.join(config.docsPath, noteId + '.md')
const filePath = path.join(config.docsPath, noteId + '.md')
if (Note.checkFileExist(filePath)) {
// if doc in filesystem have newer modified time than last change time
// then will update the doc in db
@ -421,20 +421,20 @@ module.exports = function (sequelize, DataTypes) {
if (ot.TextOperation.isRetain(op)) {
index += op
} else if (ot.TextOperation.isInsert(op)) {
let opStart = index
let opEnd = index + op.length
var inserted = false
const opStart = index
const opEnd = index + op.length
let inserted = false
// authorship format: [userId, startPos, endPos, createdAt, updatedAt]
if (authorships.length <= 0) authorships.push([userId, opStart, opEnd, timestamp, timestamp])
else {
for (let j = 0; j < authorships.length; j++) {
let authorship = authorships[j]
const authorship = authorships[j]
if (!inserted) {
let nextAuthorship = authorships[j + 1] || -1
const nextAuthorship = authorships[j + 1] || -1
if ((nextAuthorship !== -1 && nextAuthorship[1] >= opEnd) || j >= authorships.length - 1) {
if (authorship[1] < opStart && authorship[2] > opStart) {
// divide
let postLength = authorship[2] - opStart
const postLength = authorship[2] - opStart
authorship[2] = opStart
authorship[4] = timestamp
authorships.splice(j + 1, 0, [userId, opStart, opEnd, timestamp, timestamp])
@ -460,13 +460,13 @@ module.exports = function (sequelize, DataTypes) {
}
index += op.length
} else if (ot.TextOperation.isDelete(op)) {
let opStart = index
let opEnd = index - op
const opStart = index
const opEnd = index - op
if (operation.length === 1) {
authorships = []
} else if (authorships.length > 0) {
for (let j = 0; j < authorships.length; j++) {
let authorship = authorships[j]
const authorship = authorships[j]
if (authorship[1] >= opStart && authorship[1] <= opEnd && authorship[2] >= opStart && authorship[2] <= opEnd) {
authorships.splice(j, 1)
j -= 1
@ -491,12 +491,12 @@ module.exports = function (sequelize, DataTypes) {
}
// merge
for (let j = 0; j < authorships.length; j++) {
let authorship = authorships[j]
const authorship = authorships[j]
for (let k = j + 1; k < authorships.length; k++) {
let nextAuthorship = authorships[k]
const nextAuthorship = authorships[k]
if (nextAuthorship && authorship[0] === nextAuthorship[0] && authorship[2] === nextAuthorship[1]) {
let minTimestamp = Math.min(authorship[3], nextAuthorship[3])
let maxTimestamp = Math.max(authorship[3], nextAuthorship[3])
const minTimestamp = Math.min(authorship[3], nextAuthorship[3])
const maxTimestamp = Math.max(authorship[3], nextAuthorship[3])
authorships.splice(j, 1, [authorship[0], authorship[1], nextAuthorship[2], minTimestamp, maxTimestamp])
authorships.splice(k, 1)
j -= 1
@ -506,7 +506,7 @@ module.exports = function (sequelize, DataTypes) {
}
// clear
for (let j = 0; j < authorships.length; j++) {
let authorship = authorships[j]
const authorship = authorships[j]
if (!authorship[0]) {
authorships.splice(j, 1)
j -= 1
@ -537,11 +537,11 @@ module.exports = function (sequelize, DataTypes) {
var lengthBias = 0
for (let j = 0; j < patch.length; j++) {
var operation = []
let p = patch[j]
const p = patch[j]
var currIndex = p.start1
var currLength = contentLength - bias
for (let i = 0; i < p.diffs.length; i++) {
let diff = p.diffs[i]
const diff = p.diffs[i]
switch (diff[0]) {
case 0: // retain
if (i === 0) {

View File

@ -744,8 +744,8 @@ function queueForConnect (socket) {
})
return socket.disconnect(true)
}
let note = notes[noteId]
let user = users[socket.id]
const note = notes[noteId]
const user = users[socket.id]
// update user color to author color
if (note.authors[user.userid]) {
user.color = users[socket.id].color = note.authors[user.userid].color
@ -766,7 +766,7 @@ function queueForConnect (socket) {
socketClient.registerEventHandler()
if (config.debug) {
let noteId = socket.noteId
const noteId = socket.noteId
logger.info('SERVER connected a client to [' + noteId + ']:')
logger.info(JSON.stringify(user))
// logger.info(notes);

View File

@ -1,57 +1,62 @@
'use strict'
// response
// external modules
var fs = require('fs')
var path = require('path')
var markdownpdf = require('markdown-pdf')
var shortId = require('shortid')
var querystring = require('querystring')
var request = require('request')
var moment = require('moment')
const fs = require('fs')
const path = require('path')
const markdownpdf = require('markdown-pdf')
const shortId = require('shortid')
const querystring = require('querystring')
const request = require('request')
const moment = require('moment')
// core
var config = require('./config')
var logger = require('./logger')
var models = require('./models')
var utils = require('./utils')
var history = require('./history')
const config = require('./config')
const logger = require('./logger')
const models = require('./models')
const utils = require('./utils')
const history = require('./history')
// public
var response = {
errorForbidden: function (res) {
const { req } = res
if (req.user) {
responseError(res, '403', 'Forbidden', 'oh no.')
} else {
req.flash('error', 'You are not allowed to access this page. Maybe try logging in?')
res.redirect(config.serverURL + '/')
}
},
errorNotFound: function (res) {
responseError(res, '404', 'Not Found', 'oops.')
},
errorBadRequest: function (res) {
responseError(res, '400', 'Bad Request', 'something not right.')
},
errorTooLong: function (res) {
responseError(res, '413', 'Payload Too Large', 'Shorten your note!')
},
errorInternalError: function (res) {
responseError(res, '500', 'Internal Error', 'wtf.')
},
errorServiceUnavailable: function (res) {
res.status(503).send("I'm busy right now, try again later.")
},
newNote: newNote,
showNote: showNote,
showPublishNote: showPublishNote,
showPublishSlide: showPublishSlide,
showIndex: showIndex,
noteActions: noteActions,
publishNoteActions: publishNoteActions,
publishSlideActions: publishSlideActions,
githubActions: githubActions,
gitlabActions: gitlabActions
exports.errorForbidden = errorForbidden
exports.errorNotFound = errorNotFound
exports.errorBadRequest = errorBadRequest
exports.errorTooLong = errorTooLong
exports.errorInternalError = errorInternalError
exports.errorServiceUnavailable = errorServiceUnavailable
exports.newNote = newNote
exports.showNote = showNote
exports.showPublishNote = showPublishNote
exports.showPublishSlide = showPublishSlide
exports.showIndex = showIndex
exports.noteActions = noteActions
exports.publishNoteActions = publishNoteActions
exports.publishSlideActions = publishSlideActions
exports.githubActions = githubActions
exports.gitlabActions = gitlabActions
function errorForbidden (res) {
const { req } = res
if (req.user) {
responseError(res, '403', 'Forbidden', 'oh no.')
} else {
req.flash('error', 'You are not allowed to access this page. Maybe try logging in?')
res.redirect(config.serverURL + '/')
}
}
function errorNotFound (res) {
responseError(res, '404', 'Not Found', 'oops.')
}
function errorBadRequest (res) {
responseError(res, '400', 'Bad Request', 'something not right.')
}
function errorTooLong (res) {
responseError(res, '413', 'Payload Too Large', 'Shorten your note!')
}
function errorInternalError (res) {
responseError(res, '500', 'Internal Error', 'wtf.')
}
function errorServiceUnavailable (res) {
res.status(503).send("I'm busy right now, try again later.")
}
function responseError (res, code, detail, msg) {
@ -117,7 +122,7 @@ function newNote (req, res, next) {
var owner = null
var body = ''
if (req.body && req.body.length > config.documentMaxLength) {
return response.errorTooLong(res)
return errorTooLong(res)
} else if (req.body) {
body = req.body
}
@ -125,7 +130,7 @@ function newNote (req, res, next) {
if (req.isAuthenticated()) {
owner = req.user.id
} else if (!config.allowAnonymous) {
return response.errorForbidden(res)
return errorForbidden(res)
}
models.Note.create({
ownerId: owner,
@ -139,7 +144,7 @@ function newNote (req, res, next) {
return res.redirect(config.serverURL + '/' + models.Note.encodeNoteId(note.id))
}).catch(function (err) {
logger.error(err)
return response.errorInternalError(res)
return errorInternalError(res)
})
}
@ -159,7 +164,7 @@ function findNote (req, res, callback, include) {
models.Note.parseNoteId(id, function (err, _id) {
if (err) {
logger.error(err)
return response.errorInternalError(res)
return errorInternalError(res)
}
models.Note.findOne({
where: {
@ -172,17 +177,17 @@ function findNote (req, res, callback, include) {
req.alias = noteId
return newNote(req, res)
} else {
return response.errorNotFound(res)
return errorNotFound(res)
}
}
if (!checkViewPermission(req, note)) {
return response.errorForbidden(res)
return errorForbidden(res)
} else {
return callback(note)
}
}).catch(function (err) {
logger.error(err)
return response.errorInternalError(res)
return errorInternalError(res)
})
})
}
@ -213,7 +218,7 @@ function showPublishNote (req, res, next) {
}
note.increment('viewcount').then(function (note) {
if (!note) {
return response.errorNotFound(res)
return errorNotFound(res)
}
var body = note.content
var extracted = models.Note.extractMeta(body)
@ -242,7 +247,7 @@ function showPublishNote (req, res, next) {
return renderPublish(data, res)
}).catch(function (err) {
logger.error(err)
return response.errorInternalError(res)
return errorInternalError(res)
})
}, include)
}
@ -319,7 +324,7 @@ function actionPDF (req, res, note) {
markdownpdf().from.string(content).to(path, function () {
if (!fs.existsSync(path)) {
logger.error('PDF seems to not be generated as expected. File doesn\'t exist: ' + path)
return response.errorInternalError(res)
return errorInternalError(res)
}
var stream = fs.createReadStream(path)
var filename = title
@ -354,10 +359,10 @@ function actionRevision (req, res, note) {
models.Revision.getPatchedNoteRevisionByTime(note, time, function (err, content) {
if (err) {
logger.error(err)
return response.errorInternalError(res)
return errorInternalError(res)
}
if (!content) {
return response.errorNotFound(res)
return errorNotFound(res)
}
res.set({
'Access-Control-Allow-Origin': '*', // allow CORS as API
@ -369,13 +374,13 @@ function actionRevision (req, res, note) {
res.send(content)
})
} else {
return response.errorNotFound(res)
return errorNotFound(res)
}
} else {
models.Revision.getNoteRevisions(note, function (err, data) {
if (err) {
logger.error(err)
return response.errorInternalError(res)
return errorInternalError(res)
}
var out = {
revision: data
@ -415,7 +420,7 @@ function noteActions (req, res, next) {
actionPDF(req, res, note)
} else {
logger.error('PDF export failed: Disabled by config. Set "allowPDFExport: true" to enable. Check the documentation for details')
response.errorForbidden(res)
errorForbidden(res)
}
break
case 'gist':
@ -480,7 +485,7 @@ function githubActionGist (req, res, note) {
var code = req.query.code
var state = req.query.state
if (!code || !state) {
return response.errorForbidden(res)
return errorForbidden(res)
} else {
var data = {
client_id: config.github.clientID,
@ -501,17 +506,17 @@ function githubActionGist (req, res, note) {
var title = models.Note.decodeTitle(note.title)
var filename = title.replace('/', ' ') + '.md'
var gist = {
'files': {}
files: {}
}
gist.files[filename] = {
'content': content
content: content
}
var gistUrl = 'https://api.github.com/gists'
request({
url: gistUrl,
headers: {
'User-Agent': 'CodiMD',
'Authorization': 'token ' + accessToken
Authorization: 'token ' + accessToken
},
method: 'POST',
json: gist
@ -520,14 +525,14 @@ function githubActionGist (req, res, note) {
res.setHeader('referer', '')
res.redirect(body.html_url)
} else {
return response.errorForbidden(res)
return errorForbidden(res)
}
})
} else {
return response.errorForbidden(res)
return errorForbidden(res)
}
} else {
return response.errorForbidden(res)
return errorForbidden(res)
}
})
}
@ -555,7 +560,7 @@ function gitlabActionProjects (req, res, note) {
id: req.user.id
}
}).then(function (user) {
if (!user) { return response.errorNotFound(res) }
if (!user) { return errorNotFound(res) }
var ret = { baseURL: config.gitlab.baseURL, version: config.gitlab.version }
ret.accesstoken = user.accessToken
ret.profileid = user.profileid
@ -572,10 +577,10 @@ function gitlabActionProjects (req, res, note) {
)
}).catch(function (err) {
logger.error('gitlab action projects failed: ' + err)
return response.errorInternalError(res)
return errorInternalError(res)
})
} else {
return response.errorForbidden(res)
return errorForbidden(res)
}
}
@ -593,7 +598,7 @@ function showPublishSlide (req, res, next) {
if ((note.alias && shortid !== note.alias) || (!note.alias && shortid !== note.shortid)) { return res.redirect(config.serverURL + '/p/' + (note.alias || note.shortid)) }
note.increment('viewcount').then(function (note) {
if (!note) {
return response.errorNotFound(res)
return errorNotFound(res)
}
var body = note.content
var extracted = models.Note.extractMeta(body)
@ -624,7 +629,7 @@ function showPublishSlide (req, res, next) {
return renderPublishSlide(data, res)
}).catch(function (err) {
logger.error(err)
return response.errorInternalError(res)
return errorInternalError(res)
})
}, include)
}
@ -635,5 +640,3 @@ function renderPublishSlide (data, res) {
})
res.render('slide.ejs', data)
}
module.exports = response

View File

@ -7,7 +7,7 @@ exports.isSQLite = function isSQLite (sequelize) {
}
exports.getImageMimeType = function getImageMimeType (imagePath) {
var fileExtension = /[^.]+$/.exec(imagePath)
const fileExtension = /[^.]+$/.exec(imagePath)
switch (fileExtension[0]) {
case 'bmp':

View File

@ -6,7 +6,7 @@ const DropboxStrategy = require('passport-dropbox-oauth2').Strategy
const config = require('../../../config')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let dropboxAuth = module.exports = Router()
const dropboxAuth = module.exports = Router()
passport.use(new DropboxStrategy({
apiVersion: '2',

View File

@ -11,7 +11,7 @@ const { setReturnToFromReferer } = require('../utils')
const { urlencodedParser } = require('../../utils')
const response = require('../../../response')
let emailAuth = module.exports = Router()
const emailAuth = module.exports = Router()
passport.use(new LocalStrategy({
usernameField: 'email'

View File

@ -7,7 +7,7 @@ const FacebookStrategy = require('passport-facebook').Strategy
const config = require('../../../config')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let facebookAuth = module.exports = Router()
const facebookAuth = module.exports = Router()
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,

View File

@ -7,7 +7,7 @@ const config = require('../../../config')
const response = require('../../../response')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let githubAuth = module.exports = Router()
const githubAuth = module.exports = Router()
passport.use(new GithubStrategy({
clientID: config.github.clientID,

View File

@ -7,7 +7,7 @@ const config = require('../../../config')
const response = require('../../../response')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let gitlabAuth = module.exports = Router()
const gitlabAuth = module.exports = Router()
passport.use(new GitlabStrategy({
baseURL: config.gitlab.baseURL,

View File

@ -6,7 +6,7 @@ var GoogleStrategy = require('passport-google-oauth20').Strategy
const config = require('../../../config')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let googleAuth = module.exports = Router()
const googleAuth = module.exports = Router()
passport.use(new GoogleStrategy({
clientID: config.google.clientID,

View File

@ -10,7 +10,7 @@ const { setReturnToFromReferer } = require('../utils')
const { urlencodedParser } = require('../../utils')
const response = require('../../../response')
let ldapAuth = module.exports = Router()
const ldapAuth = module.exports = Router()
passport.use(new LDAPStrategy({
server: {

View File

@ -8,11 +8,11 @@ const OAuthStrategy = require('passport-oauth2').Strategy
const config = require('../../../config')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let mattermostAuth = module.exports = Router()
const mattermostAuth = module.exports = Router()
const mattermostClient = new MattermostClient()
let mattermostStrategy = new OAuthStrategy({
const mattermostStrategy = new OAuthStrategy({
authorizationURL: config.mattermost.baseURL + '/oauth/authorize',
tokenURL: config.mattermost.baseURL + '/oauth/access_token',
clientID: config.mattermost.clientID,

View File

@ -6,7 +6,7 @@ const { Strategy, InternalOAuthError } = require('passport-oauth2')
const config = require('../../../config')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let oauth2Auth = module.exports = Router()
const oauth2Auth = module.exports = Router()
class OAuth2CustomStrategy extends Strategy {
constructor (options, verify) {
@ -31,7 +31,7 @@ class OAuth2CustomStrategy extends Strategy {
return done(new Error('Failed to parse user profile'))
}
let profile = parseProfile(json)
const profile = parseProfile(json)
profile.provider = 'oauth2'
done(null, profile)
@ -76,7 +76,7 @@ OAuth2CustomStrategy.prototype.userProfile = function (accessToken, done) {
return done(new Error('Failed to parse user profile'))
}
let profile = parseProfile(json)
const profile = parseProfile(json)
profile.provider = 'oauth2'
done(null, profile)

View File

@ -9,7 +9,7 @@ const logger = require('../../../logger')
const { urlencodedParser } = require('../../utils')
const { setReturnToFromReferer } = require('../utils')
let openIDAuth = module.exports = Router()
const openIDAuth = module.exports = Router()
passport.use(new OpenIDStrategy({
returnURL: config.serverURL + '/auth/openid/callback',

View File

@ -10,7 +10,7 @@ const { urlencodedParser } = require('../../utils')
const fs = require('fs')
const intersection = function (array1, array2) { return array1.filter((n) => array2.includes(n)) }
let samlAuth = module.exports = Router()
const samlAuth = module.exports = Router()
passport.use(new SamlStrategy({
callbackUrl: config.serverURL + '/auth/saml/callback',

View File

@ -7,7 +7,7 @@ const TwitterStrategy = require('passport-twitter').Strategy
const config = require('../../../config')
const { setReturnToFromReferer, passportGeneralCallback } = require('../utils')
let twitterAuth = module.exports = Router()
const twitterAuth = module.exports = Router()
passport.use(new TwitterStrategy({
consumerKey: config.twitter.consumerKey,

View File

@ -32,16 +32,16 @@ exports.uploadImage = function (imagePath, callback) {
return
}
let key = path.join('uploads', path.basename(imagePath))
let protocol = config.minio.secure ? 'https' : 'http'
const key = path.join('uploads', path.basename(imagePath))
const protocol = config.minio.secure ? 'https' : 'http'
minioClient.putObject(config.s3bucket, key, buffer, buffer.size, getImageMimeType(imagePath), function (err, data) {
if (err) {
callback(new Error(err), null)
return
}
let hidePort = [80, 443].includes(config.minio.port)
let urlPort = hidePort ? '' : `:${config.minio.port}`
const hidePort = [80, 443].includes(config.minio.port)
const urlPort = hidePort ? '' : `:${config.minio.port}`
callback(null, `${protocol}://${config.minio.endPoint}${urlPort}/${config.s3bucket}/${key}`)
})
})

View File

@ -26,7 +26,7 @@ exports.uploadImage = function (imagePath, callback) {
callback(new Error(err), null)
return
}
let params = {
const params = {
Bucket: config.s3bucket,
Key: path.join('uploads', path.basename(imagePath)),
Body: buffer

View File

@ -69,8 +69,7 @@ UserRouter.get('/me/delete/:token?', function (req, res) {
// export the data of the authenticated user
UserRouter.get('/me/export', function (req, res) {
if (req.isAuthenticated()) {
// let output = fs.createWriteStream(__dirname + '/example.zip');
let archive = archiver('zip', {
const archive = archiver('zip', {
zlib: { level: 3 } // Sets the compression level.
})
res.setHeader('Content-Type', 'application/zip')
@ -90,14 +89,14 @@ UserRouter.get('/me/export', function (req, res) {
ownerId: user.id
}
}).then(function (notes) {
let filenames = {}
const filenames = {}
async.each(notes, function (note, callback) {
let basename = note.title.replace(/\//g, '-') // Prevent subdirectories
const basename = note.title.replace(/\//g, '-') // Prevent subdirectories
let filename
let suffix = ''
let suffix = 0
do {
let seperator = typeof suffix === 'number' ? '-' : ''
filename = basename + seperator + suffix + '.md'
const separator = suffix === 0 ? '' : '-'
filename = basename + separator + suffix + '.md'
suffix++
} while (filenames[filename])
filenames[filename] = true

View File

@ -13,7 +13,7 @@ process.on('message', function (data) {
}
switch (data.msg) {
case 'create patch':
if (!data.hasOwnProperty('lastDoc') || !data.hasOwnProperty('currDoc')) {
if (!Object.hasOwnProperty.call(data, 'lastDoc') || !Object.hasOwnProperty.call(data, 'currDoc')) {
return logger.error('dmp worker error: not enough data on create patch')
}
try {
@ -33,7 +33,7 @@ process.on('message', function (data) {
}
break
case 'get revision':
if (!data.hasOwnProperty('revisions') || !data.hasOwnProperty('count')) {
if (!Object.hasOwnProperty.call(data, 'revisions') || !Object.hasOwnProperty.call(data, 'count')) {
return logger.error('dmp worker error: not enough data on get revision')
}
try {
@ -77,12 +77,12 @@ function getRevision (revisions, count) {
if (count <= Math.round(revisions.length / 2)) {
// start from top to target
for (let i = 0; i < count; i++) {
let revision = revisions[i]
const revision = revisions[i]
if (i === 0) {
startContent = revision.content || revision.lastContent
}
if (i !== count - 1) {
let patch = dmp.patch_fromText(revision.patch)
const patch = dmp.patch_fromText(revision.patch)
applyPatches = applyPatches.concat(patch)
}
lastPatch = revision.patch
@ -99,13 +99,13 @@ function getRevision (revisions, count) {
// start from bottom to target
var l = revisions.length - 1
for (var i = l; i >= count - 1; i--) {
let revision = revisions[i]
const revision = revisions[i]
if (i === l) {
startContent = revision.lastContent
authorship = revision.authorship
}
if (revision.patch) {
let patch = dmp.patch_fromText(revision.patch)
const patch = dmp.patch_fromText(revision.patch)
applyPatches = applyPatches.concat(patch)
}
lastPatch = revision.patch

View File

@ -30,62 +30,61 @@
},
"dependencies": {
"@hackmd/codemirror": "~5.46.2",
"@hackmd/diff-match-patch": "~1.1.1",
"@hackmd/diff-match-patch": "~1.1.3",
"@hackmd/idle-js": "~1.0.1",
"@hackmd/imgur": "~0.4.1",
"@hackmd/js-sequence-diagrams": "~0.0.1-alpha.3",
"@hackmd/lz-string": "~1.4.4",
"@hackmd/meta-marked": "~0.4.4",
"@passport-next/passport-openid": "~1.0.0",
"archiver": "~2.1.1",
"async": "~2.1.4",
"aws-sdk": "~2.345.0",
"azure-storage": "~2.10.2",
"archiver": "~3.1.1",
"async": "~3.1.0",
"aws-sdk": "~2.503.0",
"azure-storage": "~2.10.3",
"babel-polyfill": "~6.26.0",
"base64url": "~3.0.0",
"body-parser": "~1.18.3",
"base64url": "~3.0.1",
"body-parser": "~1.19.0",
"bootstrap": "~3.4.0",
"bootstrap-validator": "~0.11.8",
"chance": "~1.0.4",
"chance": "~1.0.18",
"cheerio": "~0.22.0",
"compression": "~1.7.4",
"connect-flash": "~0.1.1",
"connect-session-sequelize": "~6.0.0",
"cookie": "~0.3.1",
"cookie-parser": "~1.4.3",
"cookie": "~0.4.0",
"cookie-parser": "~1.4.4",
"deep-freeze": "~0.0.1",
"ejs": "~2.5.5",
"ejs": "~2.6.2",
"emojify.js": "~1.1.0",
"express": "~4.16.4",
"express-session": "~1.16.1",
"file-saver": "~1.3.3",
"flowchart.js": "~1.12.0",
"fork-awesome": "~1.1.3",
"express": "~4.17.1",
"express-session": "~1.16.2",
"file-saver": "~2.0.2",
"flowchart.js": "~1.12.2",
"fork-awesome": "~1.1.7",
"formidable": "~1.2.1",
"gist-embed": "~2.6.0",
"graceful-fs": "~4.1.11",
"handlebars": "~4.0.13",
"helmet": "~3.13.0",
"highlight.js": "~9.12.0",
"graceful-fs": "~4.2.1",
"handlebars": "~4.1.2",
"helmet": "~3.20.0",
"highlight.js": "~9.15.9",
"i18n": "~0.8.3",
"ionicons": "~2.0.1",
"isomorphic-fetch": "~2.2.1",
"jquery": "~3.1.1",
"jquery": "~3.4.1",
"jquery-mousewheel": "~3.1.13",
"jquery-ui": "~1.12.1",
"js-cookie": "~2.1.3",
"js-cookie": "~2.2.0",
"js-yaml": "~3.13.1",
"jsdom-nogyp": "~0.8.3",
"keymaster": "~1.6.2",
"list.js": "~1.5.0",
"lodash": "~4.17.11",
"lodash": "~4.17.15",
"lutim": "~1.0.2",
"markdown-it": "~8.2.2",
"markdown-it": "~9.0.1",
"markdown-it-abbr": "~1.0.4",
"markdown-it-container": "~2.0.0",
"markdown-it-deflist": "~2.0.1",
"markdown-it-emoji": "~1.3.0",
"markdown-it-footnote": "~3.0.1",
"markdown-it-deflist": "~2.0.3",
"markdown-it-emoji": "~1.4.0",
"markdown-it-footnote": "~3.0.2",
"markdown-it-imsize": "~2.0.1",
"markdown-it-ins": "~2.0.0",
"markdown-it-mark": "~2.0.0",
@ -94,15 +93,15 @@
"markdown-it-sub": "~1.0.0",
"markdown-it-sup": "~1.0.0",
"markdown-pdf": "~9.0.0",
"mathjax": "~2.7.0",
"mattermost-redux": "~5.9.0",
"mathjax": "~2.7.5",
"mattermost-redux": "~5.13.0",
"mermaid": "~8.2.3",
"method-override": "~2.3.7",
"method-override": "~3.0.0",
"minimist": "~1.2.0",
"minio": "~6.0.0",
"minio": "~7.0.10",
"moment": "~2.24.0",
"morgan": "~1.9.1",
"mysql": "~2.16.0",
"mysql": "~2.17.1",
"passport": "~0.4.0",
"passport-dropbox-oauth2": "~1.1.0",
"passport-facebook": "~2.1.1",
@ -115,12 +114,12 @@
"passport-saml": "~1.0.0",
"passport-twitter": "~1.0.4",
"passport.socketio": "~3.7.0",
"pdfobject": "~2.0.201604172",
"pdfobject": "~2.1.1",
"pg": "~6.1.2",
"pg-hstore": "~2.3.2",
"plantuml-encoder": "^1.2.5",
"prismjs": "~1.6.0",
"randomcolor": "~0.5.3",
"prismjs": "~1.17.1",
"randomcolor": "~0.5.4",
"raphael": "~2.2.8",
"readline-sync": "~1.4.7",
"request": "~2.88.0",
@ -128,27 +127,27 @@
"scrypt": "~6.0.3",
"select2": "~3.5.2-browserify",
"sequelize": "5.3.5",
"shortid": "~2.2.8",
"socket.io": "~2.1.1",
"socket.io-client": "~2.1.1",
"spin.js": "~2.3.2",
"sqlite3": "~4.0.1",
"shortid": "~2.2.14",
"socket.io": "~2.2.0",
"socket.io-client": "~2.2.0",
"spin.js": "~4.0.0",
"sqlite3": "~4.0.9",
"store": "~2.0.12",
"tedious": "~6.1.0",
"tedious": "~6.2.0",
"toobusy-js": "~0.5.1",
"turndown": "~5.0.1",
"uuid": "~3.1.0",
"validator": "~10.4.0",
"turndown": "~5.0.3",
"uuid": "~3.3.2",
"validator": "~11.1.0",
"vega": "~5.4.0",
"vega-embed": "~4.2.2",
"vega-lite": "~3.4.0",
"velocity-animate": "~1.4.0",
"visibilityjs": "~1.2.4",
"viz.js": "~1.7.0",
"winston": "~3.1.0",
"ws": "~6.0.0",
"velocity-animate": "~1.5.2",
"visibilityjs": "~2.0.2",
"viz.js": "~2.1.2",
"winston": "~3.2.1",
"ws": "~7.1.1",
"wurl": "~2.5.3",
"xss": "~1.0.3"
"xss": "~1.0.6"
},
"devDependencies": {
"acorn": "~6.1.1",
@ -179,14 +178,14 @@
"script-loader": "~0.7.2",
"sequelize-cli": "~5.4.0",
"sinon": "~7.3.2",
"standard": "~12.0.1",
"standard": "~13.1.0",
"string-loader": "~0.0.1",
"style-loader": "~0.21.0",
"style-loader": "~0.23.1",
"uglifyjs-webpack-plugin": "~1.2.7",
"url-loader": "~1.0.1",
"webpack": "~4.30.0",
"webpack-cli": "~3.3.0",
"webpack-merge": "~4.1.4",
"webpack": "~4.39.0",
"webpack-cli": "~3.3.6",
"webpack-merge": "~4.2.1",
"webpack-parallel-uglify-plugin": "~1.1.0"
},
"optionalDependencies": {
@ -210,7 +209,8 @@
"ignore": [
"/public/build",
"/public/vendor",
"/lib/ot"
"/lib/ot",
"webpack.*"
]
},
"nyc": {

View File

@ -10,7 +10,6 @@ module.exports = {
"moment": false,
"editor": false,
"ui": false,
"Spinner": false,
"modeType": false,
"serverurl": false,
"key": false,

View File

@ -350,7 +350,7 @@ export function finishView (view) {
$value.html('')
chart.drawSVG(value, {
'line-width': 2,
'fill': 'none',
fill: 'none',
'font-size': '16px',
'font-family': "'Andale Mono', monospace"
})
@ -773,12 +773,12 @@ export function generateToc (id) {
target.html('')
/* eslint-disable no-unused-vars */
var toc = new window.Toc('doc', {
'level': 3,
'top': -1,
'class': 'toc',
'ulClass': 'nav',
'targetId': id,
'process': getHeaderContent
level: 3,
top: -1,
class: 'toc',
ulClass: 'nav',
targetId: id,
process: getHeaderContent
})
/* eslint-enable no-unused-vars */
if (target.text() === 'undefined') { target.html('') }
@ -861,7 +861,7 @@ const linkifyAnchors = (level, containingElement) => {
const headers = containingElement.getElementsByTagName(`h${level}`)
for (let i = 0, l = headers.length; i < l; i++) {
let header = headers[i]
const 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
@ -920,12 +920,12 @@ export function renderTOC (view) {
const target = $(`#${id}`)
target.html('')
/* eslint-disable no-unused-vars */
let TOC = new window.Toc('doc', {
'level': 3,
'top': -1,
'class': 'toc',
'targetId': id,
'process': getHeaderContent
const TOC = new window.Toc('doc', {
level: 3,
top: -1,
class: 'toc',
targetId: id,
process: getHeaderContent
})
/* eslint-enable no-unused-vars */
if (target.text() === 'undefined') { target.html('') }
@ -975,7 +975,7 @@ function highlightRender (code, lang) {
return result.value
}
export let md = markdownit('default', {
export const md = markdownit('default', {
html: true,
breaks: true,
langPrefix: '',
@ -1044,7 +1044,7 @@ md.use(markdownitContainer, 'spoiler', {
}
})
let defaultImageRender = md.renderer.rules.image
const defaultImageRender = md.renderer.rules.image
md.renderer.rules.image = function (tokens, idx, options, env, self) {
tokens[idx].attrJoin('class', 'raw')
return defaultImageRender(...arguments)
@ -1089,26 +1089,26 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => {
}
const makePlantumlURL = (umlCode) => {
let format = 'svg'
let code = plantumlEncoder.encode(umlCode)
const format = 'svg'
const code = plantumlEncoder.encode(umlCode)
return `${plantumlServer}/${format}/${code}`
}
// https://github.com/qjebbs/vscode-plantuml/tree/master/src/markdown-it-plantuml
md.renderer.rules.plantuml = (tokens, idx) => {
let token = tokens[idx]
const token = tokens[idx]
if (token.type !== 'plantuml') {
return tokens[idx].content
}
let url = makePlantumlURL(token.content)
const url = makePlantumlURL(token.content)
return `<img src="${url}" />`
}
// https://github.com/qjebbs/vscode-plantuml/tree/master/src/markdown-it-plantuml
md.core.ruler.push('plantuml', (state) => {
let blockTokens = state.tokens
for (let blockToken of blockTokens) {
const blockTokens = state.tokens
for (const blockToken of blockTokens) {
if (blockToken.type === 'fence' && blockToken.info === 'plantuml') {
blockToken.type = 'plantuml'
}

View File

@ -144,7 +144,7 @@ export function writeHistory (title, tags) {
}
function writeHistoryToStorage (title, tags) {
let data = store.get('notehistory')
const data = store.get('notehistory')
let notehistory
if (data && typeof data === 'string') {
notehistory = JSON.parse(data)
@ -260,7 +260,7 @@ function parseToHistory (list, notehistory, callback) {
for (let i = 0; i < notehistory.length; i++) {
// migrate LZString encoded id to base64url encoded id
try {
let id = LZString.decompressFromBase64(notehistory[i].id)
const id = LZString.decompressFromBase64(notehistory[i].id)
if (id && checkNoteIdValid(id)) {
notehistory[i].id = encodeNoteId(id)
}

View File

@ -1,5 +1,5 @@
/* eslint-env browser, jquery */
/* global CodeMirror, Cookies, moment, Spinner, serverurl,
/* global CodeMirror, Cookies, moment, serverurl,
key, Dropbox, ot, hex2rgb, Visibility, inlineAttachment */
import TurndownService from 'turndown'
@ -17,6 +17,8 @@ import List from 'list.js'
import Idle from '@hackmd/idle-js'
import { Spinner } from 'spin.js'
import {
checkLoginStateChanged,
setloginStateChangeEvent
@ -83,6 +85,7 @@ require('../css/index.css')
require('../css/extra.css')
require('../css/slide-preview.css')
require('../css/site.css')
require('spin.js/spin.css')
require('highlight.js/styles/github-gist.css')
@ -260,7 +263,7 @@ let visibleMD = false
let visibleLG = false
const isTouchDevice = 'ontouchstart' in document.documentElement
let currentStatus = statusType.offline
let lastInfo = {
const lastInfo = {
needRestore: false,
cursor: null,
scroll: null,
@ -286,14 +289,14 @@ let lastInfo = {
let personalInfo = {}
let onlineUsers = []
const fileTypes = {
'pl': 'perl',
'cgi': 'perl',
'js': 'javascript',
'php': 'php',
'sh': 'bash',
'rb': 'ruby',
'html': 'html',
'py': 'python'
pl: 'perl',
cgi: 'perl',
js: 'javascript',
php: 'php',
sh: 'bash',
rb: 'ruby',
html: 'html',
py: 'python'
}
// editor settings
@ -334,9 +337,7 @@ var opts = {
left: '50%' // Left position relative to parent
}
/* eslint-disable no-unused-vars */
var spinner = new Spinner(opts).spin(ui.spinner[0])
/* eslint-enable no-unused-vars */
new Spinner(opts).spin(ui.spinner[0])
// idle
var idle = new Idle({
@ -955,8 +956,8 @@ ui.toolbar.export.dropbox.click(function () {
var options = {
files: [
{
'url': noteurl + '/download',
'filename': filename
url: noteurl + '/download',
filename: filename
}
],
error: function (errorMessage) {
@ -1787,29 +1788,29 @@ var authorMarks = {} // temp variable
var addTextMarkers = [] // temp variable
function updateInfo (data) {
// console.log(data);
if (data.hasOwnProperty('createtime') && window.createtime !== data.createtime) {
if (Object.hasOwnProperty.call(data, 'createtime') && window.createtime !== data.createtime) {
window.createtime = data.createtime
updateLastChange()
}
if (data.hasOwnProperty('updatetime') && window.lastchangetime !== data.updatetime) {
if (Object.hasOwnProperty.call(data, 'updatetime') && window.lastchangetime !== data.updatetime) {
window.lastchangetime = data.updatetime
updateLastChange()
}
if (data.hasOwnProperty('owner') && window.owner !== data.owner) {
if (Object.hasOwnProperty.call(data, 'owner') && window.owner !== data.owner) {
window.owner = data.owner
window.ownerprofile = data.ownerprofile
updateOwner()
}
if (data.hasOwnProperty('lastchangeuser') && window.lastchangeuser !== data.lastchangeuser) {
if (Object.hasOwnProperty.call(data, 'lastchangeuser') && window.lastchangeuser !== data.lastchangeuser) {
window.lastchangeuser = data.lastchangeuser
window.lastchangeuserprofile = data.lastchangeuserprofile
updateLastChangeUser()
updateOwner()
}
if (data.hasOwnProperty('authors') && authors !== data.authors) {
if (Object.hasOwnProperty.call(data, 'authors') && authors !== data.authors) {
authors = data.authors
}
if (data.hasOwnProperty('authorship') && authorship !== data.authorship) {
if (Object.hasOwnProperty.call(data, 'authorship') && authorship !== data.authorship) {
authorship = data.authorship
updateAuthorship()
}
@ -1854,7 +1855,7 @@ function updateAuthorshipInner () {
authorMarks = {}
for (let i = 0; i < authorship.length; i++) {
var atom = authorship[i]
let author = authors[atom[0]]
const author = authors[atom[0]]
if (author) {
var prePos = editor.posFromIndex(atom[1])
var preLine = editor.getLine(prePos.line)
@ -1872,7 +1873,7 @@ function updateAuthorshipInner () {
if (prePos.ch === preLine.length) {
startLine++
} else if (prePos.ch !== 0) {
let mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3])
const mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3])
var _postPos = {
line: prePos.line,
ch: preLine.length
@ -1889,7 +1890,7 @@ function updateAuthorshipInner () {
if (postPos.ch === 0) {
endLine--
} else if (postPos.ch !== postLine.length) {
let mark = initMarkAndCheckGutter(authorMarks[postPos.line], author, atom[3])
const mark = initMarkAndCheckGutter(authorMarks[postPos.line], author, atom[3])
var _prePos = {
line: postPos.line,
ch: 0
@ -1909,7 +1910,7 @@ function updateAuthorshipInner () {
}
}
} else {
let mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3])
const mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3])
if (JSON.stringify(prePos) !== JSON.stringify(postPos)) {
mark.textmarkers.push({
userid: author.userid,
@ -1922,15 +1923,15 @@ function updateAuthorshipInner () {
}
addTextMarkers = []
editor.eachLine(iterateLine)
var allTextMarks = editor.getAllMarks()
const allTextMarks = editor.getAllMarks()
for (let i = 0; i < allTextMarks.length; i++) {
let _textMarker = allTextMarks[i]
var pos = _textMarker.find()
var found = false
const _textMarker = allTextMarks[i]
const pos = _textMarker.find()
let found = false
for (let j = 0; j < addTextMarkers.length; j++) {
let textMarker = addTextMarkers[j]
let author = authors[textMarker.userid]
let className = 'authorship-inline-' + author.color.substr(1)
const textMarker = addTextMarkers[j]
const author = authors[textMarker.userid]
const className = 'authorship-inline-' + author.color.substr(1)
var obj = {
from: textMarker.pos[0],
to: textMarker.pos[1]
@ -1948,12 +1949,12 @@ function updateAuthorshipInner () {
}
}
for (let i = 0; i < addTextMarkers.length; i++) {
let textMarker = addTextMarkers[i]
let author = authors[textMarker.userid]
const textMarker = addTextMarkers[i]
const author = authors[textMarker.userid]
const rgbcolor = hex2rgb(author.color)
const colorString = `rgba(${rgbcolor.red},${rgbcolor.green},${rgbcolor.blue},0.7)`
const styleString = `background-image: linear-gradient(to top, ${colorString} 1px, transparent 1px);`
let className = `authorship-inline-${author.color.substr(1)}`
const className = `authorship-inline-${author.color.substr(1)}`
const rule = `.${className} { ${styleString} }`
addStyleRule(rule)
editor.markText(textMarker.pos[0], textMarker.pos[1], {
@ -1963,11 +1964,11 @@ function updateAuthorshipInner () {
}
}
function iterateLine (line) {
var lineNumber = line.lineNo()
var currMark = authorMarks[lineNumber]
var author = currMark ? authors[currMark.gutter.userid] : null
const lineNumber = line.lineNo()
const currMark = authorMarks[lineNumber]
const author = currMark ? authors[currMark.gutter.userid] : null
if (currMark && author) {
let className = 'authorship-gutter-' + author.color.substr(1)
const className = 'authorship-gutter-' + author.color.substr(1)
const gutters = line.gutterMarkers
if (!gutters || !gutters['authorship-gutters'] ||
!gutters['authorship-gutters'].className ||
@ -1975,7 +1976,7 @@ function iterateLine (line) {
const styleString = `border-left: 3px solid ${author.color}; height: ${defaultTextHeight}px; margin-left: 3px;`
const rule = `.${className} { ${styleString} }`
addStyleRule(rule)
var gutter = $('<div>', {
const gutter = $('<div>', {
class: 'authorship-gutter ' + className,
title: author.name
})
@ -1985,8 +1986,8 @@ function iterateLine (line) {
editor.setGutterMarker(line, 'authorship-gutters', null)
}
if (currMark && currMark.textmarkers.length > 0) {
for (var i = 0; i < currMark.textmarkers.length; i++) {
let textMarker = currMark.textmarkers[i]
for (let i = 0; i < currMark.textmarkers.length; i++) {
const textMarker = currMark.textmarkers[i]
if (textMarker.userid !== currMark.gutter.userid) {
addTextMarkers.push(textMarker)
}
@ -1997,12 +1998,12 @@ editorInstance.on('update', function () {
$('.authorship-gutter:not([data-original-title])').tooltip({
container: '.CodeMirror-lines',
placement: 'right',
delay: { 'show': 500, 'hide': 100 }
delay: { show: 500, hide: 100 }
})
$('.authorship-inline:not([data-original-title])').tooltip({
container: '.CodeMirror-lines',
placement: 'bottom',
delay: { 'show': 500, 'hide': 100 }
delay: { show: 500, hide: 100 }
})
// clear tooltip which described element has been removed
$('[id^="tooltip"]').each(function (index, element) {
@ -2063,7 +2064,7 @@ var cmClient = null
var synchronized_ = null
function havePendingOperation () {
return !!((cmClient && cmClient.state && cmClient.state.hasOwnProperty('outstanding')))
return !!((cmClient && cmClient.state && Object.hasOwnProperty.call(cmClient.state, 'outstanding')))
}
socket.on('doc', function (obj) {
@ -2223,7 +2224,7 @@ function updateOnlineStatus () {
break
}
}
let id = items[i].values().id
const id = items[i].values().id
if (found) {
onlineUserList.get('id', id)[0].values(_onlineUsers[foundindex])
shortOnlineUserList.get('id', id)[0].values(_onlineUsers[foundindex])
@ -2417,19 +2418,19 @@ function buildCursor (user) {
break
}
if ($('div[data-clientid="' + user.id + '"]').length <= 0) {
let cursor = $('<div data-clientid="' + user.id + '" class="CodeMirror-other-cursor" style="display:none;"></div>')
const cursor = $('<div data-clientid="' + user.id + '" class="CodeMirror-other-cursor" style="display:none;"></div>')
cursor.attr('data-line', user.cursor.line)
cursor.attr('data-ch', user.cursor.ch)
cursor.attr('data-offset-left', 0)
cursor.attr('data-offset-top', 0)
let cursorbar = $('<div class="cursorbar">&nbsp;</div>')
const cursorbar = $('<div class="cursorbar">&nbsp;</div>')
cursorbar[0].style.height = defaultTextHeight + 'px'
cursorbar[0].style.borderLeft = '2px solid ' + user.color
var icon = '<i class="fa ' + iconClass + '"></i>'
let cursortag = $('<div class="cursortag">' + icon + '&nbsp;<span class="name">' + user.name + '</span></div>')
const cursortag = $('<div class="cursortag">' + icon + '&nbsp;<span class="name">' + user.name + '</span></div>')
// cursortag[0].style.background = color;
cursortag[0].style.color = user.color
@ -2485,15 +2486,15 @@ function buildCursor (user) {
checkCursorTag(coord, cursortag)
} else {
let cursor = $('div[data-clientid="' + user.id + '"]')
const cursor = $('div[data-clientid="' + user.id + '"]')
cursor.attr('data-line', user.cursor.line)
cursor.attr('data-ch', user.cursor.ch)
let cursorbar = cursor.find('.cursorbar')
const cursorbar = cursor.find('.cursorbar')
cursorbar[0].style.height = defaultTextHeight + 'px'
cursorbar[0].style.borderLeft = '2px solid ' + user.color
let cursortag = cursor.find('.cursortag')
const cursortag = cursor.find('.cursortag')
cursortag.find('i').removeClass().addClass('fa').addClass(iconClass)
cursortag.find('.name').text(user.name)
@ -2502,8 +2503,8 @@ function buildCursor (user) {
cursor[0].style.top = coord.top + 'px'
} else {
cursor.animate({
'left': coord.left,
'top': coord.top
left: coord.left,
top: coord.top
}, {
duration: cursorAnimatePeriod,
queue: false
@ -2712,8 +2713,8 @@ function restoreInfo () {
$(window).scrollLeft(lastInfo.edit.scroll.left)
$(window).scrollTop(lastInfo.edit.scroll.top)
} else {
let left = lastInfo.edit.scroll.left
let top = lastInfo.edit.scroll.top
const left = lastInfo.edit.scroll.left
const top = lastInfo.edit.scroll.top
editor.scrollIntoView()
editor.scrollTo(left, top)
}
@ -2723,8 +2724,8 @@ function restoreInfo () {
$(window).scrollTop(lastInfo.view.scroll.top)
break
case modeType.both:
let left = lastInfo.edit.scroll.left
let top = lastInfo.edit.scroll.top
const left = lastInfo.edit.scroll.left
const top = lastInfo.edit.scroll.top
editor.scrollIntoView()
editor.scrollTo(left, top)
ui.area.view.scrollLeft(lastInfo.view.scroll.left)
@ -2846,8 +2847,8 @@ function partialUpdate (src, tar, des) {
for (let i = 0; i < tar.length; i++) {
// copyAttribute(src[i], des[i], 'data-startline');
// copyAttribute(src[i], des[i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[i])
let rawTar = cloneAndRemoveDataAttr(tar[i])
const rawSrc = cloneAndRemoveDataAttr(src[i])
const rawTar = cloneAndRemoveDataAttr(tar[i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
start = i
break
@ -2859,8 +2860,8 @@ function partialUpdate (src, tar, des) {
for (let i = 0; i < src.length; i++) {
// copyAttribute(src[i], des[i], 'data-startline');
// copyAttribute(src[i], des[i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[i])
let rawTar = cloneAndRemoveDataAttr(tar[i])
const rawSrc = cloneAndRemoveDataAttr(src[i])
const rawTar = cloneAndRemoveDataAttr(tar[i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
start = i
break
@ -2868,12 +2869,12 @@ function partialUpdate (src, tar, des) {
}
// tar end
for (let i = 1; i <= tar.length + 1; i++) {
let srcLength = src.length
let tarLength = tar.length
const srcLength = src.length
const tarLength = tar.length
// copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
// copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
let rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
const rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
const rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
tarEnd = tar.length - i
break
@ -2881,12 +2882,12 @@ function partialUpdate (src, tar, des) {
}
// src end
for (let i = 1; i <= src.length + 1; i++) {
let srcLength = src.length
let tarLength = tar.length
const srcLength = src.length
const tarLength = tar.length
// copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
// copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
let rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
const rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
const rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
srcEnd = src.length - i
break
@ -3317,22 +3318,22 @@ $(editor.getInputField())
'textComplete:show': function (e) {
$(this).data('autocompleting', true)
editor.setOption('extraKeys', {
'Up': function () {
Up: function () {
return false
},
'Right': function () {
Right: function () {
editor.doc.cm.execCommand('goCharRight')
},
'Down': function () {
Down: function () {
return false
},
'Left': function () {
Left: function () {
editor.doc.cm.execCommand('goCharLeft')
},
'Enter': function () {
Enter: function () {
return false
},
'Backspace': function () {
Backspace: function () {
editor.doc.cm.execCommand('delCharBefore')
}
})

View File

@ -1,6 +1,6 @@
import modeType from './modeType'
let state = {
const state = {
syncscroll: true,
currentMode: modeType.view,
nightMode: false

View File

@ -1,4 +1,4 @@
let config = {
const config = {
docmaxlength: null
}

View File

@ -76,8 +76,8 @@ export default class Editor {
},
'Cmd-Left': 'goLineLeftSmart',
'Cmd-Right': 'goLineRight',
'Home': 'goLineLeftSmart',
'End': 'goLineRight',
Home: 'goLineLeftSmart',
End: 'goLineRight',
'Ctrl-C': function (cm) {
if (!isMac && cm.getOption('keyMap').substr(0, 3) === 'vim') {
document.execCommand('copy')
@ -513,6 +513,7 @@ export default class Editor {
this.jumpToAddressBarKeymapValue = null
}
}
setOverrideBrowserKeymap () {
var overrideBrowserKeymap = $(
'.ui-preferences-override-browser-keymap label > input[type="checkbox"]'

View File

@ -4,17 +4,17 @@ export function wrapTextWith (editor, cm, symbol) {
if (!cm.getSelection()) {
return CodeMirror.Pass
} else {
let ranges = cm.listSelections()
const ranges = cm.listSelections()
for (let i = 0; i < ranges.length; i++) {
let range = ranges[i]
const range = ranges[i]
if (!range.empty()) {
const from = range.from()
const to = range.to()
if (symbol !== 'Backspace') {
let selection = cm.getRange(from, to)
let anchorIndex = editor.indexFromPos(ranges[i].anchor)
let headIndex = editor.indexFromPos(ranges[i].head)
const selection = cm.getRange(from, to)
const anchorIndex = editor.indexFromPos(ranges[i].anchor)
const headIndex = editor.indexFromPos(ranges[i].head)
cm.replaceRange(symbol + selection + symbol, from, to, '+input')
if (anchorIndex > headIndex) {
ranges[i].anchor.ch += symbol.length
@ -25,18 +25,18 @@ export function wrapTextWith (editor, cm, symbol) {
}
cm.setSelections(ranges)
} else {
let preEndPos = {
const preEndPos = {
line: to.line,
ch: to.ch + symbol.length
}
let preText = cm.getRange(to, preEndPos)
let preIndex = wrapSymbols.indexOf(preText)
let postEndPos = {
const preText = cm.getRange(to, preEndPos)
const preIndex = wrapSymbols.indexOf(preText)
const postEndPos = {
line: from.line,
ch: from.ch - symbol.length
}
let postText = cm.getRange(postEndPos, from)
let postIndex = wrapSymbols.indexOf(postText)
const postText = cm.getRange(postEndPos, from)
const postIndex = wrapSymbols.indexOf(postText)
// check if surround symbol are list in array and matched
if (preIndex > -1 && postIndex > -1 && preIndex === postIndex) {
cm.replaceRange('', to, preEndPos, '+delete')
@ -49,25 +49,25 @@ export function wrapTextWith (editor, cm, symbol) {
}
export function insertText (cm, text, cursorEnd = 0) {
let cursor = cm.getCursor()
const cursor = cm.getCursor()
cm.replaceSelection(text, cursor, cursor)
cm.focus()
cm.setCursor({ line: cursor.line, ch: cursor.ch + cursorEnd })
}
export function insertLink (cm, isImage) {
let cursor = cm.getCursor()
let ranges = cm.listSelections()
const cursor = cm.getCursor()
const ranges = cm.listSelections()
const linkEnd = '](https://)'
const symbol = (isImage) ? '![' : '['
for (let i = 0; i < ranges.length; i++) {
let range = ranges[i]
const range = ranges[i]
if (!range.empty()) {
const from = range.from()
const to = range.to()
let anchorIndex = editor.indexFromPos(ranges[i].anchor)
let headIndex = editor.indexFromPos(ranges[i].head)
const anchorIndex = editor.indexFromPos(ranges[i].anchor)
const headIndex = editor.indexFromPos(ranges[i].head)
let selection = cm.getRange(from, to)
selection = symbol + selection + linkEnd
cm.replaceRange(selection, from, to)
@ -88,9 +88,9 @@ export function insertLink (cm, isImage) {
}
export function insertHeader (cm) {
let cursor = cm.getCursor()
let startOfLine = { line: cursor.line, ch: 0 }
let startOfLineText = cm.getRange(startOfLine, { line: cursor.line, ch: 1 })
const cursor = cm.getCursor()
const startOfLine = { line: cursor.line, ch: 0 }
const startOfLineText = cm.getRange(startOfLine, { line: cursor.line, ch: 1 })
// See if it is already a header
if (startOfLineText === '#') {
cm.replaceRange('#', startOfLine, startOfLine)
@ -101,11 +101,11 @@ export function insertHeader (cm) {
}
export function insertOnStartOfLines (cm, symbol) {
let cursor = cm.getCursor()
let ranges = cm.listSelections()
const cursor = cm.getCursor()
const ranges = cm.listSelections()
for (let i = 0; i < ranges.length; i++) {
let range = ranges[i]
const range = ranges[i]
if (!range.empty()) {
const from = range.from()
const to = range.to()

View File

@ -174,12 +174,12 @@ const buildMap = _.throttle(buildMapInner, buildMapThrottle)
// Optimizations are required only for big texts.
function buildMapInner (callback) {
if (!viewArea || !markdownArea) return
let i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount, acc, _scrollMap
let i, pos, a, b, acc
offset = viewArea.scrollTop() - viewArea.offset().top
_scrollMap = []
nonEmptyList = []
_lineHeightMap = []
const offset = viewArea.scrollTop() - viewArea.offset().top
const _scrollMap = []
const nonEmptyList = []
const _lineHeightMap = []
viewTop = 0
viewBottom = viewArea[0].scrollHeight - viewArea.height()
@ -200,7 +200,7 @@ function buildMapInner (callback) {
acc += Math.round(h / lineHeight)
}
_lineHeightMap.push(acc)
linesCount = acc
const linesCount = acc
for (i = 0; i < linesCount; i++) {
_scrollMap.push(-1)
@ -350,11 +350,11 @@ export function syncScrollToView (event, preventAnimate) {
}
if (viewScrolling) return
let lineNo, posTo
let posTo
let topDiffPercent, posToNextDiff
const scrollInfo = editor.getScrollInfo()
const textHeight = editor.defaultTextHeight()
lineNo = Math.floor(scrollInfo.top / textHeight)
const lineNo = Math.floor(scrollInfo.top / textHeight)
// if reach the last line, will start lerp to the bottom
const diffToBottom = (scrollInfo.top + scrollInfo.clientHeight) - (scrollInfo.height - textHeight)
if (scrollInfo.height > scrollInfo.clientHeight && diffToBottom > 0) {

View File

@ -26,7 +26,7 @@ function extend () {
for (const source of arguments) {
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (Object.hasOwnProperty.call(source, key)) {
target[key] = source[key]
}
}
@ -74,17 +74,17 @@ const defaultOptions = {
const meta = JSON.parse($('#meta').text())
var options = meta.slideOptions || {}
if (options.hasOwnProperty('spotlight')) {
if (Object.hasOwnProperty.call(options, 'spotlight')) {
defaultOptions.dependencies.push({
src: `${serverurl}/build/reveal.js/plugin/spotlight/spotlight.js`
})
}
if (options.hasOwnProperty('allottedTime') || options.hasOwnProperty('allottedMinutes')) {
if (Object.hasOwnProperty.call(options, 'allottedTime') || Object.hasOwnProperty.call(options, 'allottedMinutes')) {
defaultOptions.dependencies.push({
src: `${serverurl}/build/reveal.js/plugin/elapsed-time-bar/elapsed-time-bar.js`
})
if (options.hasOwnProperty('allottedMinutes')) {
if (Object.hasOwnProperty.call(options, 'allottedMinutes')) {
options.allottedTime = options.allottedMinutes * 60 * 1000
}
}
@ -123,14 +123,14 @@ window.viewAjaxCallback = () => {
function renderSlide (event) {
if (window.location.search.match(/print-pdf/gi)) {
const slides = $('.slides')
let title = document.title
const title = document.title
finishView(slides)
document.title = title
Reveal.layout()
} else {
const markdown = $(event.currentSlide)
if (!markdown.attr('data-rendered')) {
let title = document.title
const title = document.title
finishView(markdown)
markdown.attr('data-rendered', 'true')
document.title = title

View File

@ -1,28 +1,24 @@
import base64url from 'base64url'
let uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
export function checkNoteIdValid (id) {
let result = id.match(uuidRegex)
if (result && result.length === 1) {
return true
} else {
return false
}
const result = id.match(uuidRegex)
return !!(result && result.length === 1)
}
export function encodeNoteId (id) {
// remove dashes in UUID and encode in url-safe base64
let str = id.replace(/-/g, '')
let hexStr = Buffer.from(str, 'hex')
const str = id.replace(/-/g, '')
const hexStr = Buffer.from(str, 'hex')
return base64url.encode(hexStr)
}
export function decodeNoteId (encodedId) {
// decode from url-safe base64
let id = base64url.toBuffer(encodedId).toString('hex')
const id = base64url.toBuffer(encodedId).toString('hex')
// add dashes between the UUID string parts
let idParts = []
const idParts = []
idParts.push(id.substr(0, 8))
idParts.push(id.substr(8, 4))
idParts.push(id.substr(12, 4))

View File

@ -1,10 +1,10 @@
<% if(useCDN) { %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.5.2/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.0/js/bootstrap.min.js" integrity="sha256-kJrlY+s09+QoWjpkOrXXwhxeaoDz9FW5SaxF8I0DibQ=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.pagination.js/0.1.1/list.pagination.min.js" integrity="sha256-WwTza96H3BgcQTfEfxX7MFaFc/dZA0QrPRKDRLdFHJo=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.2/select2.min.js" integrity="sha256-HzzZFiY4t0PIv02Tm8/R3CVvLpcjHhO1z/YAUCp4oQ4=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-url/2.3.0/url.min.js" integrity="sha256-HOZJz4x+1mn1Si84WT5XKXPtOlTytmZLnMb6n1v4+5Q=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.8/validator.min.js" integrity="sha256-LHeY7YoYJ0SSXbCx7sR14Pqna+52moaH3bhv0Mjzd/M=" crossorigin="anonymous" defer></script>
<%- include ../build/cover-scripts %>

View File

@ -13,8 +13,8 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.0/css/bootstrap.min.css" integrity="sha256-H0KfTigpUV+0/5tn2HXC0CPwhhDhWgSawJdnFd0CGCo=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fork-awesome/1.1.3/css/fork-awesome.min.css" integrity="sha256-ZhApazu+kejqTYhMF+1DzNKjIzP7KXu6AzyXcC1gMus=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/4.9.0/bootstrap-social.min.css" integrity="sha256-02JtFTurpwBjQJ6q13iJe82/NF0RbZlJroDegK5g87Y=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.min.css" integrity="sha256-ijlUKKj3hJCiiT2HWo1kqkI79NTEYpzOsw5Rs3k42dI=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2-bootstrap.min.css" integrity="sha256-NAWFcNIZdH+TS1xpWujF/EB/Y8gwBbEOCoaK/eqaer8=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.2/select2.min.css" integrity="sha256-ijlUKKj3hJCiiT2HWo1kqkI79NTEYpzOsw5Rs3k42dI=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.2/select2-bootstrap.min.css" integrity="sha256-NAWFcNIZdH+TS1xpWujF/EB/Y8gwBbEOCoaK/eqaer8=" crossorigin="anonymous" />
<%- include ../build/cover-header %>
<%- include ../shared/polyfill %>
<% } else { %>

View File

@ -16,7 +16,7 @@
<link rel="apple-touch-icon" href="<%- serverURL %>/apple-touch-icon.png">
<% if(useCDN) { %>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fork-awesome/1.1.3/css/fork-awesome.min.css" integrity="sha256-ZhApazu+kejqTYhMF+1DzNKjIzP7KXu6AzyXcC1gMus=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fork-awesome/1.1.7/css/fork-awesome.min.css" integrity="sha256-ZhApazu+kejqTYhMF+1DzNKjIzP7KXu6AzyXcC1gMus=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.7.0/css/reveal.min.css" integrity="sha256-9+Wg2bcNeiOMGXOUNqBdceY2lAH/eCiTDcdzHhHIl48=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
@ -90,20 +90,20 @@
<% if(useCDN) { %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.7.0/lib/js/head.min.js" integrity="sha256-CTcwyen1cxIrm4hlqdxe0y7Hq6B0rpxAKLiXMD3dJv0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.7.0/js/reveal.min.js" integrity="sha256-Xr6ZH+/kc7hDVReZLO5khBknteLqu5oen/xnSraXrVk=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.5.2/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js" integrity="sha256-jnOjDTXIPqall8M0MyTSt98JetJuZ7Yu+1Jm7hLTF7U=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.7.0/js-yaml.min.js" integrity="sha256-8PanqYAVOGlOct+i65R+HqibK3KPsXINnrSfxN+Y/J0=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.13.1/js-yaml.min.js" integrity="sha256-8PanqYAVOGlOct+i65R+HqibK3KPsXINnrSfxN+Y/J0=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/Safe.js" integrity="sha256-0ygBUDksNDXZS4vm5HMNH1a33KUu6QT1cdNTN+ZLF+4=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.2.3/mermaid.min.js" integrity="sha256-4s3fF5e1iWRLtiV7mRev7n17oALqqDHbWrNqF3/r7jU=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js" integrity="sha256-/BfiIkHlHoVihZdc6TFuj7MmJ0TWcWsMXkeDFwhi0zw=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.1.2/handlebars.min.js" integrity="sha256-1O3BtOwnPyyRzOszK6P+gqaRoXHV6JXj8HkjZmPYhCI=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.9/highlight.min.js" integrity="sha256-/BfiIkHlHoVihZdc6TFuj7MmJ0TWcWsMXkeDFwhi0zw=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.7.0/viz.js" integrity="sha256-8t+rndrF+TU4JtelmOH1lDHTMe2ovhO2UbzDArp5lY8=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/2.1.2/viz.js" integrity="sha256-8t+rndrF+TU4JtelmOH1lDHTMe2ovhO2UbzDArp5lY8=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/abcjs/3.1.1/abcjs_basic-min.js" integrity="sha256-Sq1r2XXWXQoShQKsS0Wrf5r7fRkErd9Fat9vHYeU68s=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vega/5.4.0/vega.min.js" integrity="sha256-PrkRj4B3I5V9yHBLdO3jyyqNUwSKS1CXXIh3VrnFPEU=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vega-lite/3.4.0/vega-lite.min.js" integrity="sha256-ro+FWr16NboXJ5rSwInNli1P16ObUXnWUJMgKc8KnHI=" crossorigin="anonymous" defer></script>

View File

@ -43,7 +43,7 @@ describe('Content security policies', function () {
// beginnging Tests
it('Disable CDN', function () {
let testconfig = defaultConfig
const testconfig = defaultConfig
testconfig.useCDN = false
mock('../lib/config', testconfig)
csp = mock.reRequire('../lib/csp')
@ -57,7 +57,7 @@ describe('Content security policies', function () {
})
it('Disable Google Analytics', function () {
let testconfig = defaultConfig
const testconfig = defaultConfig
testconfig.csp.addGoogleAnalytics = false
mock('../lib/config', testconfig)
csp = mock.reRequire('../lib/csp')
@ -66,7 +66,7 @@ describe('Content security policies', function () {
})
it('Disable Disqus', function () {
let testconfig = defaultConfig
const testconfig = defaultConfig
testconfig.csp.addDisqus = false
mock('../lib/config', testconfig)
csp = mock.reRequire('../lib/csp')
@ -79,7 +79,7 @@ describe('Content security policies', function () {
})
it('Set ReportURI', function () {
let testconfig = defaultConfig
const testconfig = defaultConfig
testconfig.csp.reportURI = 'https://example.com/reportURI'
mock('../lib/config', testconfig)
csp = mock.reRequire('../lib/csp')
@ -88,7 +88,7 @@ describe('Content security policies', function () {
})
it('Set own directives', function () {
let testconfig = defaultConfig
const testconfig = defaultConfig
mock('../lib/config', defaultConfig)
csp = mock.reRequire('../lib/csp')
const unextendedCSP = csp.computeDirectives()

View File

@ -9,7 +9,7 @@ describe('generateAvatarURL() gravatar enabled', function () {
let avatars
beforeEach(function () {
// Reset config to make sure we don't influence other tests
let testconfig = {
const testconfig = {
allowGravatar: true,
serverURL: 'http://localhost:3000',
port: 3000
@ -32,7 +32,7 @@ describe('generateAvatarURL() gravatar disabled', function () {
let avatars
beforeEach(function () {
// Reset config to make sure we don't influence other tests
let testconfig = {
const testconfig = {
allowGravatar: false,
serverURL: 'http://localhost:3000',
port: 3000

View File

@ -49,8 +49,8 @@ describe('cleanDanglingUser', function () {
connected: {}
}
}
let user1Socket = makeMockSocket()
let user2Socket = makeMockSocket()
const user1Socket = makeMockSocket()
const user2Socket = makeMockSocket()
user1Socket.rooms.push('room1')

View File

@ -124,7 +124,7 @@ describe('realtime#connection', function () {
const emitRefreshStub = sinon.stub(realtime, 'emitRefresh')
const failConnectionSpy = sinon.spy(realtime, 'failConnection')
let note = {
const note = {
id: noteId,
authors: [
{

View File

@ -57,7 +57,7 @@ describe('realtime#update note is dirty timer', function () {
socks: []
}
let note2 = {
const note2 = {
server: {
isDirty: true
},
@ -79,7 +79,7 @@ describe('realtime#update note is dirty timer', function () {
callback(null, note)
})
let note = {
const note = {
server: {
isDirty: true
},
@ -109,7 +109,7 @@ describe('realtime#update note is dirty timer', function () {
})
}
let note = {
const note = {
server: {
isDirty: true
},

View File

@ -35,7 +35,7 @@ describe('realtime#extractNoteIdFromSocket', function () {
})
it('return false if query not set and referer not set', function () {
let noteId = realtime.extractNoteIdFromSocket(makeMockSocket({
const noteId = realtime.extractNoteIdFromSocket(makeMockSocket({
otherHeader: 1
}, {
otherQuery: 1

View File

@ -274,7 +274,7 @@ describe('realtime#socket event', function () {
onlineUsersFunc()
assert(clientSocket.emit.called)
assert(clientSocket.emit.lastCall.args[0] === 'online users')
let returnUserList = clientSocket.emit.lastCall.args[1].users
const returnUserList = clientSocket.emit.lastCall.args[1].users
assert(returnUserList.length === 2)
assert(returnUserList[0].id === 10)
assert(returnUserList[1].id === 20)
@ -444,8 +444,8 @@ describe('realtime#socket event', function () {
})
describe('permission', function () {
let ownerId = 'user1_id'
let otherSignInUserId = 'user2_id'
const ownerId = 'user1_id'
const otherSignInUserId = 'user2_id'
let otherClient
let checkViewPermissionSpy
let permissionFunc

View File

@ -53,7 +53,7 @@ describe('realtime#updateNote', function () {
const callback = sinon.stub()
const note = {
tempUsers: {
'user1': Date.now()
user1: Date.now()
}
}
realtime.updateNote(note, callback)

View File

@ -238,7 +238,6 @@ module.exports = {
],
'index-pack': [
'babel-polyfill',
'expose-loader?Spinner!spin.js',
'script-loader!jquery-ui-resizable',
'bootstrap-validator',
'expose-loader?jsyaml!js-yaml',

2070
yarn.lock

File diff suppressed because it is too large Load Diff