mirror of https://github.com/status-im/codimd.git
Merge pull request #1355 from hackmdio/feature/multilang-spellcheck
Multilanguage spellchecker
This commit is contained in:
commit
4eb6bac62a
|
@ -24,7 +24,8 @@ exports.getConfig = (req, res) => {
|
||||||
DROPBOX_APP_KEY: config.dropbox.appKey,
|
DROPBOX_APP_KEY: config.dropbox.appKey,
|
||||||
allowedUploadMimeTypes: config.allowedUploadMimeTypes,
|
allowedUploadMimeTypes: config.allowedUploadMimeTypes,
|
||||||
defaultUseHardbreak: config.defaultUseHardbreak,
|
defaultUseHardbreak: config.defaultUseHardbreak,
|
||||||
linkifyHeaderStyle: config.linkifyHeaderStyle
|
linkifyHeaderStyle: config.linkifyHeaderStyle,
|
||||||
|
useCDN: config.useCDN
|
||||||
}
|
}
|
||||||
res.set({
|
res.set({
|
||||||
'Cache-Control': 'private', // only cache by client
|
'Cache-Control': 'private', // only cache by client
|
||||||
|
|
|
@ -165,6 +165,9 @@
|
||||||
"babel-runtime": "~6.26.0",
|
"babel-runtime": "~6.26.0",
|
||||||
"copy-webpack-plugin": "~4.5.2",
|
"copy-webpack-plugin": "~4.5.2",
|
||||||
"css-loader": "~1.0.0",
|
"css-loader": "~1.0.0",
|
||||||
|
"dictionary-de": "^2.0.3",
|
||||||
|
"dictionary-de-at": "^2.0.3",
|
||||||
|
"dictionary-de-ch": "^2.0.3",
|
||||||
"doctoc": "~1.4.0",
|
"doctoc": "~1.4.0",
|
||||||
"ejs-loader": "~0.3.1",
|
"ejs-loader": "~0.3.1",
|
||||||
"exports-loader": "~0.7.0",
|
"exports-loader": "~0.7.0",
|
||||||
|
@ -188,6 +191,7 @@
|
||||||
"standard": "~13.1.0",
|
"standard": "~13.1.0",
|
||||||
"string-loader": "~0.0.1",
|
"string-loader": "~0.0.1",
|
||||||
"style-loader": "~0.23.1",
|
"style-loader": "~0.23.1",
|
||||||
|
"typo-js": "^1.0.3",
|
||||||
"uglifyjs-webpack-plugin": "~1.2.7",
|
"uglifyjs-webpack-plugin": "~1.2.7",
|
||||||
"url-loader": "~1.0.1",
|
"url-loader": "~1.0.1",
|
||||||
"webpack": "~4.39.0",
|
"webpack": "~4.39.0",
|
||||||
|
|
|
@ -11,3 +11,5 @@ window.defaultUseHardbreak = <%- defaultUseHardbreak %>
|
||||||
window.linkifyHeaderStyle = '<%- linkifyHeaderStyle %>'
|
window.linkifyHeaderStyle = '<%- linkifyHeaderStyle %>'
|
||||||
|
|
||||||
window.DROPBOX_APP_KEY = '<%- DROPBOX_APP_KEY %>'
|
window.DROPBOX_APP_KEY = '<%- DROPBOX_APP_KEY %>'
|
||||||
|
|
||||||
|
window.USE_CDN = <%- useCDN %>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import config from './config'
|
||||||
import statusBarTemplate from './statusbar.html'
|
import statusBarTemplate from './statusbar.html'
|
||||||
import toolBarTemplate from './toolbar.html'
|
import toolBarTemplate from './toolbar.html'
|
||||||
import './markdown-lint'
|
import './markdown-lint'
|
||||||
|
import CodeMirrorSpellChecker, { supportLanguages, supportLanguageCodes } from './spellcheck'
|
||||||
import { initTableEditor } from './table-editor'
|
import { initTableEditor } from './table-editor'
|
||||||
import { availableThemes } from './constants'
|
import { availableThemes } from './constants'
|
||||||
|
|
||||||
|
@ -541,21 +542,69 @@ export default class Editor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setSpellcheck () {
|
setSpellcheckLang (lang) {
|
||||||
var cookieSpellcheck = Cookies.get('spellcheck')
|
if (lang === 'disabled') {
|
||||||
if (cookieSpellcheck) {
|
this.statusIndicators.find('.spellcheck-lang').text('')
|
||||||
var mode = null
|
this.activateSpellcheckListItem(false)
|
||||||
if (cookieSpellcheck === 'true' || cookieSpellcheck === true) {
|
return
|
||||||
mode = 'spell-checker'
|
|
||||||
} else {
|
|
||||||
mode = defaultEditorMode
|
|
||||||
}
|
|
||||||
if (mode && mode !== this.editor.getOption('mode')) {
|
|
||||||
this.editor.setOption('mode', mode)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var spellcheckToggle = this.statusSpellcheck.find('.ui-spellcheck-toggle')
|
if (!supportLanguageCodes.includes(lang)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const langName = this.statusIndicators.find(`.status-spellcheck li[value="${lang}"]`).text()
|
||||||
|
this.statusIndicators.find('.spellcheck-lang').text(langName)
|
||||||
|
|
||||||
|
this.spellchecker.setDictLang(lang)
|
||||||
|
this.activateSpellcheckListItem(lang)
|
||||||
|
}
|
||||||
|
|
||||||
|
getExistingSpellcheckLang () {
|
||||||
|
const cookieSpellcheck = Cookies.get('spellcheck')
|
||||||
|
|
||||||
|
if (cookieSpellcheck) {
|
||||||
|
return cookieSpellcheck === 'false' ? undefined : cookieSpellcheck
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activateSpellcheckListItem (lang) {
|
||||||
|
this.statusIndicators.find('.status-spellcheck li').removeClass('active')
|
||||||
|
|
||||||
|
if (lang) {
|
||||||
|
this.statusIndicators.find(`.status-spellcheck li[value="${lang}"]`).addClass('active')
|
||||||
|
} else {
|
||||||
|
this.statusIndicators.find(`.status-spellcheck li[value="disabled"]`).addClass('active')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setSpellcheck () {
|
||||||
|
this.statusSpellcheck.find('ul.dropdown-menu').append(supportLanguages.map(lang => {
|
||||||
|
return $(`<li value="${lang.value}"><a>${lang.name}</a></li>`)
|
||||||
|
}))
|
||||||
|
|
||||||
|
const cookieSpellcheck = Cookies.get('spellcheck')
|
||||||
|
if (cookieSpellcheck) {
|
||||||
|
let mode = null
|
||||||
|
let lang = 'en_US'
|
||||||
|
|
||||||
|
if (cookieSpellcheck === 'false' || !cookieSpellcheck) {
|
||||||
|
mode = defaultEditorMode
|
||||||
|
this.activateSpellcheckListItem(false)
|
||||||
|
} else {
|
||||||
|
mode = 'spell-checker'
|
||||||
|
if (supportLanguageCodes.includes(cookieSpellcheck)) {
|
||||||
|
lang = cookieSpellcheck
|
||||||
|
}
|
||||||
|
this.setSpellcheckLang(lang)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editor.setOption('mode', mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
const spellcheckToggle = this.statusSpellcheck.find('.ui-spellcheck-toggle')
|
||||||
|
|
||||||
const checkSpellcheck = () => {
|
const checkSpellcheck = () => {
|
||||||
var mode = this.editor.getOption('mode')
|
var mode = this.editor.getOption('mode')
|
||||||
|
@ -566,39 +615,32 @@ export default class Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spellcheckToggle.click(() => {
|
const self = this
|
||||||
var mode = this.editor.getOption('mode')
|
this.statusIndicators.find(`.status-spellcheck li`).click(function () {
|
||||||
if (mode === defaultEditorMode) {
|
const lang = $(this).attr('value')
|
||||||
mode = 'spell-checker'
|
|
||||||
} else {
|
|
||||||
mode = defaultEditorMode
|
|
||||||
}
|
|
||||||
if (mode && mode !== this.editor.getOption('mode')) {
|
|
||||||
this.editor.setOption('mode', mode)
|
|
||||||
}
|
|
||||||
Cookies.set('spellcheck', mode === 'spell-checker', {
|
|
||||||
expires: 365
|
|
||||||
})
|
|
||||||
|
|
||||||
checkSpellcheck()
|
if (lang === 'disabled') {
|
||||||
|
spellcheckToggle.removeClass('active')
|
||||||
|
|
||||||
|
Cookies.set('spellcheck', false, {
|
||||||
|
expires: 365
|
||||||
|
})
|
||||||
|
|
||||||
|
self.editor.setOption('mode', defaultEditorMode)
|
||||||
|
} else {
|
||||||
|
spellcheckToggle.addClass('active')
|
||||||
|
|
||||||
|
Cookies.set('spellcheck', lang, {
|
||||||
|
expires: 365
|
||||||
|
})
|
||||||
|
|
||||||
|
self.editor.setOption('mode', 'spell-checker')
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setSpellcheckLang(lang)
|
||||||
})
|
})
|
||||||
|
|
||||||
checkSpellcheck()
|
checkSpellcheck()
|
||||||
|
|
||||||
// workaround spellcheck might not activate beacuse the ajax loading
|
|
||||||
if (window.num_loaded < 2) {
|
|
||||||
var spellcheckTimer = setInterval(
|
|
||||||
() => {
|
|
||||||
if (window.num_loaded >= 2) {
|
|
||||||
if (this.editor.getOption('mode') === 'spell-checker') {
|
|
||||||
this.editor.setOption('mode', 'spell-checker')
|
|
||||||
}
|
|
||||||
clearInterval(spellcheckTimer)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
100
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLinter (enable) {
|
toggleLinter (enable) {
|
||||||
|
@ -723,6 +765,7 @@ export default class Editor {
|
||||||
placeholder: "← Start by entering a title here\n===\nVisit /features if you don't know what to do.\nHappy hacking :)"
|
placeholder: "← Start by entering a title here\n===\nVisit /features if you don't know what to do.\nHappy hacking :)"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.spellchecker = new CodeMirrorSpellChecker(CodeMirror, this.getExistingSpellcheckLang(), this.editor)
|
||||||
this.tableEditor = initTableEditor(this.editor)
|
this.tableEditor = initTableEditor(this.editor)
|
||||||
|
|
||||||
return this.editor
|
return this.editor
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/* eslint-env browser */
|
||||||
|
|
||||||
|
// Modified from https://github.com/sparksuite/codemirror-spell-checker
|
||||||
|
|
||||||
|
import Typo from 'typo-js'
|
||||||
|
import { serverurl } from '../config'
|
||||||
|
|
||||||
|
export const supportLanguages = [
|
||||||
|
{
|
||||||
|
name: 'English (United States)',
|
||||||
|
value: 'en_US',
|
||||||
|
aff: {
|
||||||
|
url: `${serverurl}/vendor/codemirror-spell-checker/en_US.aff`,
|
||||||
|
cdnUrl: `${serverurl}/vendor/codemirror-spell-checker/en_US.aff`
|
||||||
|
},
|
||||||
|
dic: {
|
||||||
|
url: `${serverurl}/vendor/codemirror-spell-checker/en_US.dic`,
|
||||||
|
cdnUrl: `${serverurl}/vendor/codemirror-spell-checker/en_US.dic`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'German',
|
||||||
|
value: 'de',
|
||||||
|
aff: {
|
||||||
|
url: `${serverurl}/build/dictionary-de/index.aff`,
|
||||||
|
cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de@2.0.3/index.aff`
|
||||||
|
},
|
||||||
|
dic: {
|
||||||
|
url: `${serverurl}/build/dictionary-de/index.dic`,
|
||||||
|
cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de@2.0.3/index.dic`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'German (Austria)',
|
||||||
|
value: 'de_AT',
|
||||||
|
aff: {
|
||||||
|
url: `${serverurl}/build/dictionary-de-at/index.aff`,
|
||||||
|
cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-at@2.0.3/index.aff`
|
||||||
|
},
|
||||||
|
dic: {
|
||||||
|
url: `${serverurl}/build/dictionary-de-at/index.dic`,
|
||||||
|
cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-at@2.0.3/index.dic`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'German (Switzerland)',
|
||||||
|
value: 'de_CH',
|
||||||
|
aff: {
|
||||||
|
url: `${serverurl}/build/dictionary-de-ch/index.aff`,
|
||||||
|
cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-ch@2.0.3/index.aff`
|
||||||
|
},
|
||||||
|
dic: {
|
||||||
|
url: `${serverurl}/build/dictionary-de-ch/index.dic`,
|
||||||
|
cdnUrl: `https://cdn.jsdelivr.net/npm/dictionary-de-ch@2.0.3/index.dic`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const supportLanguageCodes = supportLanguages.map(lang => lang.value)
|
||||||
|
|
||||||
|
function request (url) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const req = new XMLHttpRequest()
|
||||||
|
req.open('GET', url, true)
|
||||||
|
req.onload = () => {
|
||||||
|
if (req.readyState === 4 && req.status === 200) {
|
||||||
|
resolve(req.responseText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.send(null)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runSeriesP (iterables, fn) {
|
||||||
|
const results = []
|
||||||
|
for (const iterable of iterables) {
|
||||||
|
results.push(await fn(iterable))
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapSeriesP (iterables, fn) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
resolve(runSeriesP(iterables, fn))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTypo (lang, affData, dicData) {
|
||||||
|
return new Typo(lang, affData, dicData, { platform: 'any' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const typoMap = new Map()
|
||||||
|
|
||||||
|
let fetching = false
|
||||||
|
async function findOrCreateTypoInstance (lang) {
|
||||||
|
if (!lang) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// find existing typo instance
|
||||||
|
let typo = typoMap.get(lang)
|
||||||
|
if (typo) {
|
||||||
|
return typo
|
||||||
|
}
|
||||||
|
|
||||||
|
let dict = supportLanguages.find(l => l.value === lang)
|
||||||
|
|
||||||
|
if (!dict) {
|
||||||
|
console.error(`Dictionary not found for "${lang}"\n Fallback to default English spellcheck`)
|
||||||
|
dict = supportLanguages[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
let affUrl
|
||||||
|
let dicUrl
|
||||||
|
if (window.USE_CDN) {
|
||||||
|
affUrl = dict.aff.cdnUrl
|
||||||
|
dicUrl = dict.dic.cdnUrl
|
||||||
|
} else {
|
||||||
|
affUrl = dict.aff.url
|
||||||
|
dicUrl = dict.dic.url
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fetching) {
|
||||||
|
return typo
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fetching = true
|
||||||
|
|
||||||
|
const [affData, dicData] = await mapSeriesP([affUrl, dicUrl], request)
|
||||||
|
|
||||||
|
typo = createTypo(lang, affData, dicData)
|
||||||
|
typoMap.set(lang, typo)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
} finally {
|
||||||
|
fetching = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return typo
|
||||||
|
}
|
||||||
|
|
||||||
|
class CodeMirrorSpellChecker {
|
||||||
|
/**
|
||||||
|
* @param {CodeMirror} cm
|
||||||
|
* @param {string} lang
|
||||||
|
*/
|
||||||
|
constructor (cm, lang, editor) {
|
||||||
|
// Verify
|
||||||
|
if (typeof cm !== 'function' || typeof cm.defineMode !== 'function') {
|
||||||
|
console.log(
|
||||||
|
'CodeMirror Spell Checker: You must provide an instance of CodeMirror via the option `codeMirrorInstance`'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.typo = undefined
|
||||||
|
this.defineSpellCheckerMode(cm, lang)
|
||||||
|
this.editor = editor
|
||||||
|
}
|
||||||
|
|
||||||
|
setDictLang (lang) {
|
||||||
|
findOrCreateTypoInstance(lang).then(typo => {
|
||||||
|
this.typo = typo
|
||||||
|
|
||||||
|
// re-enable overlay mode to refresh spellcheck
|
||||||
|
this.editor.setOption('mode', 'gfm')
|
||||||
|
this.editor.setOption('mode', 'spell-checker')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineSpellCheckerMode (cm, lang) {
|
||||||
|
// Load AFF/DIC data async ASAP
|
||||||
|
this.setDictLang(lang)
|
||||||
|
|
||||||
|
cm.defineMode('spell-checker', config => {
|
||||||
|
// Define what separates a word
|
||||||
|
const regexWord = '!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~ '
|
||||||
|
|
||||||
|
// Create the overlay and such
|
||||||
|
const overlay = {
|
||||||
|
token: (stream) => {
|
||||||
|
let ch = stream.peek()
|
||||||
|
let word = ''
|
||||||
|
|
||||||
|
if (regexWord.includes(ch)) {
|
||||||
|
stream.next()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ch = stream.peek()) != null && !regexWord.includes(ch)) {
|
||||||
|
word += ch
|
||||||
|
stream.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.typo && !this.typo.check(word)) {
|
||||||
|
return 'spell-error' // CSS class: cm-spell-error
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mode = cm.getMode(config, config.backdrop || 'text/plain')
|
||||||
|
|
||||||
|
return cm.overlayMode(mode, overlay, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CodeMirrorSpellChecker
|
|
@ -38,8 +38,14 @@
|
||||||
<ul class="dropdown-menu" aria-labelledby="themeLabel" style="overflow: auto;">
|
<ul class="dropdown-menu" aria-labelledby="themeLabel" style="overflow: auto;">
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-spellcheck">
|
<div class="status-spellcheck dropup pull-right">
|
||||||
<a class="ui-spellcheck-toggle" title="Toggle spellcheck"><i class="fa fa-check fa-fw"></i></a>
|
<a class="ui-spellcheck-toggle" title="Toggle spellcheck" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<i class="fa fa-check fa-fw"></i>
|
||||||
|
<span class="spellcheck-lang"></span>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="themeLabel">
|
||||||
|
<li value="disabled"><a>Disabled</a></li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-linter">
|
<div class="status-linter">
|
||||||
<a class="ui-linter-toggle" title="Toggle linter"><i class="fa fa-lightbulb-o fa-fw"></i></a>
|
<a class="ui-linter-toggle" title="Toggle linter"><i class="fa fa-lightbulb-o fa-fw"></i></a>
|
||||||
|
|
|
@ -165,7 +165,22 @@ module.exports = {
|
||||||
context: path.join(__dirname, 'node_modules/reveal.js'),
|
context: path.join(__dirname, 'node_modules/reveal.js'),
|
||||||
from: 'plugin',
|
from: 'plugin',
|
||||||
to: 'reveal.js/plugin'
|
to: 'reveal.js/plugin'
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
context: path.join(__dirname, 'node_modules/dictionary-de'),
|
||||||
|
from: '*',
|
||||||
|
to: 'dictionary-de/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: path.join(__dirname, 'node_modules/dictionary-de-at'),
|
||||||
|
from: '*',
|
||||||
|
to: 'dictionary-de-at/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: path.join(__dirname, 'node_modules/dictionary-de-ch'),
|
||||||
|
from: '*',
|
||||||
|
to: 'dictionary-de-ch/'
|
||||||
|
},
|
||||||
]),
|
]),
|
||||||
new MiniCssExtractPlugin()
|
new MiniCssExtractPlugin()
|
||||||
],
|
],
|
||||||
|
@ -203,7 +218,6 @@ module.exports = {
|
||||||
'script-loader!codemirror',
|
'script-loader!codemirror',
|
||||||
'script-loader!inlineAttachment',
|
'script-loader!inlineAttachment',
|
||||||
'script-loader!jqueryTextcomplete',
|
'script-loader!jqueryTextcomplete',
|
||||||
'script-loader!codemirrorSpellChecker',
|
|
||||||
'script-loader!codemirrorInlineAttachment',
|
'script-loader!codemirrorInlineAttachment',
|
||||||
'script-loader!ot',
|
'script-loader!ot',
|
||||||
'flowchart.js',
|
'flowchart.js',
|
||||||
|
@ -259,7 +273,6 @@ module.exports = {
|
||||||
'script-loader!codemirror',
|
'script-loader!codemirror',
|
||||||
'script-loader!inlineAttachment',
|
'script-loader!inlineAttachment',
|
||||||
'script-loader!jqueryTextcomplete',
|
'script-loader!jqueryTextcomplete',
|
||||||
'script-loader!codemirrorSpellChecker',
|
|
||||||
'script-loader!codemirrorInlineAttachment',
|
'script-loader!codemirrorInlineAttachment',
|
||||||
'script-loader!ot',
|
'script-loader!ot',
|
||||||
'flowchart.js',
|
'flowchart.js',
|
||||||
|
@ -371,7 +384,6 @@ module.exports = {
|
||||||
codemirror: path.join(__dirname, 'node_modules/@hackmd/codemirror/codemirror.min.js'),
|
codemirror: path.join(__dirname, 'node_modules/@hackmd/codemirror/codemirror.min.js'),
|
||||||
inlineAttachment: path.join(__dirname, 'public/vendor/inlineAttachment/inline-attachment.js'),
|
inlineAttachment: path.join(__dirname, 'public/vendor/inlineAttachment/inline-attachment.js'),
|
||||||
jqueryTextcomplete: path.join(__dirname, 'public/vendor/jquery-textcomplete/jquery.textcomplete.js'),
|
jqueryTextcomplete: path.join(__dirname, 'public/vendor/jquery-textcomplete/jquery.textcomplete.js'),
|
||||||
codemirrorSpellChecker: path.join(__dirname, 'public/vendor/codemirror-spell-checker/spell-checker.min.js'),
|
|
||||||
codemirrorInlineAttachment: path.join(__dirname, 'public/vendor/inlineAttachment/codemirror.inline-attachment.js'),
|
codemirrorInlineAttachment: path.join(__dirname, 'public/vendor/inlineAttachment/codemirror.inline-attachment.js'),
|
||||||
ot: path.join(__dirname, 'public/vendor/ot/ot.min.js'),
|
ot: path.join(__dirname, 'public/vendor/ot/ot.min.js'),
|
||||||
mermaid: path.join(__dirname, 'node_modules/mermaid/dist/mermaid.min.js'),
|
mermaid: path.join(__dirname, 'node_modules/mermaid/dist/mermaid.min.js'),
|
||||||
|
|
20
yarn.lock
20
yarn.lock
|
@ -4333,6 +4333,21 @@ diagnostics@^1.1.1:
|
||||||
enabled "1.0.x"
|
enabled "1.0.x"
|
||||||
kuler "1.0.x"
|
kuler "1.0.x"
|
||||||
|
|
||||||
|
dictionary-de-at@^2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/dictionary-de-at/-/dictionary-de-at-2.0.3.tgz#78f31d0cd8ca7c7d5ba48fdefb7a7bd3f05e11ca"
|
||||||
|
integrity sha512-unbay9PPM75yZ0RPnqSD/PADpZj7/vPDVeau2jTsVPFKwhoZGJTBVLD2wCaIkhS6tyVsNOboo1VYjzOCOit2ww==
|
||||||
|
|
||||||
|
dictionary-de-ch@^2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/dictionary-de-ch/-/dictionary-de-ch-2.0.3.tgz#1727413a1eb35eb78e7fe15b5b7a742fd650f0c3"
|
||||||
|
integrity sha512-+eqpz5j8WONSzxmc4avCN4XX/6q5+J6JfWz2AaluZIOVNgXPxUjXBhKS73+nRhM3nE1pGeRMqkyZevTQWgYTTw==
|
||||||
|
|
||||||
|
dictionary-de@^2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/dictionary-de/-/dictionary-de-2.0.3.tgz#df50c749fddbff601f5bd044aef4622a365a15b2"
|
||||||
|
integrity sha512-fbNcCIjDrdNvu7DzMzkOY77vIaGqiDQqf9vtwGud1fcSxVWwX6EdtHcosmgG7AA10u3QgDVkymMaX9mr3elwRw==
|
||||||
|
|
||||||
diff-match-patch@^1.0.0:
|
diff-match-patch@^1.0.0:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.4.tgz#6ac4b55237463761c4daf0dc603eb869124744b1"
|
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.4.tgz#6ac4b55237463761c4daf0dc603eb869124744b1"
|
||||||
|
@ -12495,6 +12510,11 @@ typedarray@^0.0.6, typedarray@~0.0.5:
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||||
|
|
||||||
|
typo-js@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.0.3.tgz#54d8ebc7949f1a7810908b6002c6841526c99d5a"
|
||||||
|
integrity sha1-VNjrx5SfGngQkItgAsaEFSbJnVo=
|
||||||
|
|
||||||
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
||||||
|
|
Loading…
Reference in New Issue