mirror of https://github.com/status-im/codimd.git
Bundle our own spellchecker
Signed-off-by: Yukai Huang <yukaihuangtw@gmail.com>
This commit is contained in:
parent
023161d00d
commit
aef2c780c8
|
@ -188,6 +188,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",
|
||||||
|
|
|
@ -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 from './spellcheck'
|
||||||
import { initTableEditor } from './table-editor'
|
import { initTableEditor } from './table-editor'
|
||||||
import { availableThemes } from './constants'
|
import { availableThemes } from './constants'
|
||||||
|
|
||||||
|
@ -723,6 +724,8 @@ 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 :)"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
new CodeMirrorSpellChecker(CodeMirror)
|
||||||
this.tableEditor = initTableEditor(this.editor)
|
this.tableEditor = initTableEditor(this.editor)
|
||||||
|
|
||||||
return this.editor
|
return this.editor
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/* eslint-env browser */
|
||||||
|
|
||||||
|
// Modified from https://github.com/sparksuite/codemirror-spell-checker
|
||||||
|
|
||||||
|
import Typo from 'typo-js'
|
||||||
|
import { serverurl } from '../config'
|
||||||
|
|
||||||
|
const dictionaryDownloadUrls = {
|
||||||
|
en_US: {
|
||||||
|
aff: `${serverurl}/vendor/codemirror-spell-checker/en_US.aff`,
|
||||||
|
dic: `${serverurl}/vendor/codemirror-spell-checker/en_US.dic`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CodeMirrorSpellChecker {
|
||||||
|
/**
|
||||||
|
* @param {CodeMirror} cm
|
||||||
|
* @param {string} lang
|
||||||
|
*/
|
||||||
|
constructor (cm, lang = 'en_US') {
|
||||||
|
// 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.numLoaded = 0
|
||||||
|
this.affLoading = false
|
||||||
|
this.dicLoading = false
|
||||||
|
this.affData = ''
|
||||||
|
this.dicData = ''
|
||||||
|
this.typo = undefined
|
||||||
|
|
||||||
|
this.setupCM.bind(this)(cm, lang)
|
||||||
|
}
|
||||||
|
|
||||||
|
setupCM (cm, lang) {
|
||||||
|
cm.defineMode('spell-checker', config => {
|
||||||
|
// Load AFF/DIC data
|
||||||
|
if (!this.affLoading) {
|
||||||
|
this.affLoading = true
|
||||||
|
|
||||||
|
const xhrAff = new XMLHttpRequest()
|
||||||
|
xhrAff.open('GET', dictionaryDownloadUrls[lang].aff, true)
|
||||||
|
xhrAff.onload = () => {
|
||||||
|
if (xhrAff.readyState === 4 && xhrAff.status === 200) {
|
||||||
|
this.affData = xhrAff.responseText
|
||||||
|
this.numLoaded++
|
||||||
|
|
||||||
|
if (this.numLoaded === 2) {
|
||||||
|
this.typo = new Typo(lang, this.affData, this.dicData, { platform: 'any' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhrAff.send(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.dicLoading) {
|
||||||
|
this.dicLoading = true
|
||||||
|
const xhrDic = new XMLHttpRequest()
|
||||||
|
xhrDic.open('GET', dictionaryDownloadUrls[lang].dic, true)
|
||||||
|
xhrDic.onload = () => {
|
||||||
|
if (xhrDic.readyState === 4 && xhrDic.status === 200) {
|
||||||
|
this.dicData = xhrDic.responseText
|
||||||
|
this.numLoaded++
|
||||||
|
|
||||||
|
if (this.numLoaded === 2) {
|
||||||
|
this.typo = new Typo(lang, this.affData, this.dicData, { platform: 'any' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhrDic.send(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
export default CodeMirrorSpellChecker
|
|
@ -203,7 +203,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 +258,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 +369,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'),
|
||||||
|
|
|
@ -12495,6 +12495,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