Skip to content

Commit 4eb6bac

Browse files
authored
Merge pull request #1355 from hackmdio/feature/multilang-spellcheck
Multilanguage spellchecker
2 parents 023161d + dc873e0 commit 4eb6bac

File tree

8 files changed

+342
-43
lines changed

8 files changed

+342
-43
lines changed

lib/status/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ exports.getConfig = (req, res) => {
2424
DROPBOX_APP_KEY: config.dropbox.appKey,
2525
allowedUploadMimeTypes: config.allowedUploadMimeTypes,
2626
defaultUseHardbreak: config.defaultUseHardbreak,
27-
linkifyHeaderStyle: config.linkifyHeaderStyle
27+
linkifyHeaderStyle: config.linkifyHeaderStyle,
28+
useCDN: config.useCDN
2829
}
2930
res.set({
3031
'Cache-Control': 'private', // only cache by client

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@
165165
"babel-runtime": "~6.26.0",
166166
"copy-webpack-plugin": "~4.5.2",
167167
"css-loader": "~1.0.0",
168+
"dictionary-de": "^2.0.3",
169+
"dictionary-de-at": "^2.0.3",
170+
"dictionary-de-ch": "^2.0.3",
168171
"doctoc": "~1.4.0",
169172
"ejs-loader": "~0.3.1",
170173
"exports-loader": "~0.7.0",
@@ -188,6 +191,7 @@
188191
"standard": "~13.1.0",
189192
"string-loader": "~0.0.1",
190193
"style-loader": "~0.23.1",
194+
"typo-js": "^1.0.3",
191195
"uglifyjs-webpack-plugin": "~1.2.7",
192196
"url-loader": "~1.0.1",
193197
"webpack": "~4.39.0",

public/js/lib/common/constant.ejs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ window.defaultUseHardbreak = <%- defaultUseHardbreak %>
1111
window.linkifyHeaderStyle = '<%- linkifyHeaderStyle %>'
1212

1313
window.DROPBOX_APP_KEY = '<%- DROPBOX_APP_KEY %>'
14+
15+
window.USE_CDN = <%- useCDN %>

public/js/lib/editor/index.js

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import config from './config'
77
import statusBarTemplate from './statusbar.html'
88
import toolBarTemplate from './toolbar.html'
99
import './markdown-lint'
10+
import CodeMirrorSpellChecker, { supportLanguages, supportLanguageCodes } from './spellcheck'
1011
import { initTableEditor } from './table-editor'
1112
import { availableThemes } from './constants'
1213

@@ -541,21 +542,69 @@ export default class Editor {
541542
})
542543
}
543544

545+
setSpellcheckLang (lang) {
546+
if (lang === 'disabled') {
547+
this.statusIndicators.find('.spellcheck-lang').text('')
548+
this.activateSpellcheckListItem(false)
549+
return
550+
}
551+
552+
if (!supportLanguageCodes.includes(lang)) {
553+
return
554+
}
555+
556+
const langName = this.statusIndicators.find(`.status-spellcheck li[value="${lang}"]`).text()
557+
this.statusIndicators.find('.spellcheck-lang').text(langName)
558+
559+
this.spellchecker.setDictLang(lang)
560+
this.activateSpellcheckListItem(lang)
561+
}
562+
563+
getExistingSpellcheckLang () {
564+
const cookieSpellcheck = Cookies.get('spellcheck')
565+
566+
if (cookieSpellcheck) {
567+
return cookieSpellcheck === 'false' ? undefined : cookieSpellcheck
568+
} else {
569+
return undefined
570+
}
571+
}
572+
573+
activateSpellcheckListItem (lang) {
574+
this.statusIndicators.find('.status-spellcheck li').removeClass('active')
575+
576+
if (lang) {
577+
this.statusIndicators.find(`.status-spellcheck li[value="${lang}"]`).addClass('active')
578+
} else {
579+
this.statusIndicators.find(`.status-spellcheck li[value="disabled"]`).addClass('active')
580+
}
581+
}
582+
544583
setSpellcheck () {
545-
var cookieSpellcheck = Cookies.get('spellcheck')
584+
this.statusSpellcheck.find('ul.dropdown-menu').append(supportLanguages.map(lang => {
585+
return $(`<li value="${lang.value}"><a>${lang.name}</a></li>`)
586+
}))
587+
588+
const cookieSpellcheck = Cookies.get('spellcheck')
546589
if (cookieSpellcheck) {
547-
var mode = null
548-
if (cookieSpellcheck === 'true' || cookieSpellcheck === true) {
549-
mode = 'spell-checker'
550-
} else {
590+
let mode = null
591+
let lang = 'en_US'
592+
593+
if (cookieSpellcheck === 'false' || !cookieSpellcheck) {
551594
mode = defaultEditorMode
595+
this.activateSpellcheckListItem(false)
596+
} else {
597+
mode = 'spell-checker'
598+
if (supportLanguageCodes.includes(cookieSpellcheck)) {
599+
lang = cookieSpellcheck
600+
}
601+
this.setSpellcheckLang(lang)
552602
}
553-
if (mode && mode !== this.editor.getOption('mode')) {
554-
this.editor.setOption('mode', mode)
555-
}
603+
604+
this.editor.setOption('mode', mode)
556605
}
557606

558-
var spellcheckToggle = this.statusSpellcheck.find('.ui-spellcheck-toggle')
607+
const spellcheckToggle = this.statusSpellcheck.find('.ui-spellcheck-toggle')
559608

560609
const checkSpellcheck = () => {
561610
var mode = this.editor.getOption('mode')
@@ -566,39 +615,32 @@ export default class Editor {
566615
}
567616
}
568617

569-
spellcheckToggle.click(() => {
570-
var mode = this.editor.getOption('mode')
571-
if (mode === defaultEditorMode) {
572-
mode = 'spell-checker'
618+
const self = this
619+
this.statusIndicators.find(`.status-spellcheck li`).click(function () {
620+
const lang = $(this).attr('value')
621+
622+
if (lang === 'disabled') {
623+
spellcheckToggle.removeClass('active')
624+
625+
Cookies.set('spellcheck', false, {
626+
expires: 365
627+
})
628+
629+
self.editor.setOption('mode', defaultEditorMode)
573630
} else {
574-
mode = defaultEditorMode
575-
}
576-
if (mode && mode !== this.editor.getOption('mode')) {
577-
this.editor.setOption('mode', mode)
631+
spellcheckToggle.addClass('active')
632+
633+
Cookies.set('spellcheck', lang, {
634+
expires: 365
635+
})
636+
637+
self.editor.setOption('mode', 'spell-checker')
578638
}
579-
Cookies.set('spellcheck', mode === 'spell-checker', {
580-
expires: 365
581-
})
582639

583-
checkSpellcheck()
640+
self.setSpellcheckLang(lang)
584641
})
585642

586643
checkSpellcheck()
587-
588-
// workaround spellcheck might not activate beacuse the ajax loading
589-
if (window.num_loaded < 2) {
590-
var spellcheckTimer = setInterval(
591-
() => {
592-
if (window.num_loaded >= 2) {
593-
if (this.editor.getOption('mode') === 'spell-checker') {
594-
this.editor.setOption('mode', 'spell-checker')
595-
}
596-
clearInterval(spellcheckTimer)
597-
}
598-
},
599-
100
600-
)
601-
}
602644
}
603645

604646
toggleLinter (enable) {
@@ -723,6 +765,7 @@ export default class Editor {
723765
placeholder: "← Start by entering a title here\n===\nVisit /features if you don't know what to do.\nHappy hacking :)"
724766
})
725767

768+
this.spellchecker = new CodeMirrorSpellChecker(CodeMirror, this.getExistingSpellcheckLang(), this.editor)
726769
this.tableEditor = initTableEditor(this.editor)
727770

728771
return this.editor

0 commit comments

Comments
 (0)