Commit 845bc4b9 authored by Christos's avatar Christos

Merge branch 'spellchecker' into 'master'

Spellchecker

See merge request wax/wax!232
parents e2d2bd28 c3210d13
......@@ -15,6 +15,7 @@ class ContainerEditor extends SubstanceContainerEditor {
this.context.editorSession.onUpdate('document', this.checkChange, this)
this.change = {}
this.focus = this.focus.bind(this)
this.spellchecker = false
}
render($$) {
......@@ -24,22 +25,23 @@ class ContainerEditor extends SubstanceContainerEditor {
}
didUpdate() {
if (this.props.spellcheck) {
if (this.props.spellcheck && !this.spellchecker) {
loadTypo('en_US').then(typo => {
window.typo = typo
})
const spellCheck = new SpellCheckManager(this.context.editorSession)
// spellCheck.runGlobalCheck()
spellCheck.runGlobalCheck()
this.spellchecker = true
} else if (!this.props.spellcheck) {
if (window.typo) window.typo = null
this.spellchecker = false
}
}
didMount() {
super.didMount()
// load spellCheck
loadTypo(
'en_US',
'https://rawgit.com/kofifus/Typo.js/master/typo/dictionaries/en_US/en_US.aff',
'https://rawgit.com/kofifus/Typo.js/master/typo/dictionaries/en_US/en_US.dic',
).then(typo => {
window.typo = typo
})
if (this.isEmpty() && this.props.editing === 'full') {
this.createText()
......
......@@ -16,10 +16,12 @@ class SaveCommand extends Command {
}
execute(params) {
params.surface.context.editor.emit('hightLightSave')
const editorSession = params.editorSession
const dirty = params.editorSession.hasUnsavedChanges()
editorSession.save()
setTimeout(() => {
params.surface.context.editor.emit('hightLightSave')
})
// if (dirty)
return {
......
import { forEach } from 'lodash'
import { Command } from 'substance'
/**
Used for edit tools or property annotations (e.g. EditLinkTool)
@class
*/
class SpellCheckCommand extends Command {
getCommandState(params) {
let markFound = undefined
let state = params.selectionState
let markers = state.markers
let markers = []
if (!params.editorSession.markersManager) return
let Allmarkers =
params.editorSession.markersManager._markers._documentMarkers
const selection = params.editorSession.getSelection()
const marker = this.filterMarkers(markers)
if (!markers) return
if (markers.length === 0 && markers[0].end.offset >= selection.end.offset) {
forEach(Allmarkers, marker => {
markers.push(...marker)
})
if (markers.length === 0) {
return {
disabled: true,
}
}
markers = markers.filter(function(m) {
return m.type === 'spell-error'
})
if (
markers.length > 0 &&
selection &&
markers[0].end.offset >= selection.end.offset
) {
forEach(markers, marker => {
if (
selection.start &&
selection.start.path[0] === marker.start.path[0] &&
selection.start.offset <= marker.end.offset &&
selection.start.offset >= marker.start.offset
) {
markFound = marker
return false
}
})
if (markFound) {
return {
disabled: false,
active: false,
active: true,
mode: null,
node: markers[0],
node: markFound,
}
} else {
return {
......@@ -38,9 +46,6 @@ class SpellCheckCommand extends Command {
}
}
}
filterMarkers(markers) {
// console.log(markers)
}
}
export default SpellCheckCommand
import { debounce, isString } from 'lodash'
import { debounce, isString, forEach, chunk } from 'lodash'
class SpellCheckManager {
constructor(editorSession, options) {
options = options || {}
let wait = options.wait || 750
this.editorSession = editorSession
// TODO: MarkersManager is basically a TextPropertyManager
......@@ -13,6 +12,7 @@ class SpellCheckManager {
this._schedule = {}
this._scheduleCheck = debounce(this._runSpellCheck.bind(this), wait)
editorSession.onFinalize('document', this._onDocumentChange, this)
}
......@@ -26,17 +26,20 @@ class SpellCheckManager {
runGlobalCheck() {
let paths = Object.keys(this.textPropertyManager._textProperties)
paths.forEach(p => {
this._runSpellCheck(p)
const editor = this.editorSession._context.editorSession.editor
editor.emit('displayNotification', () => {
return `Scanning the document for erros. Please Wait`
})
// console.log(chunk(paths, '3')[0])
setTimeout(() => {
chunk(paths, '20')[0].forEach((p, index) => {
this._runSpellCheck(p)
})
}, 2000)
}
_onDocumentChange(change, info) {
if (info.spellcheck) return
// Note: instead of analyzing the model, we consider
// all existing TextPropertyComponents instead
// as this reflects what is presented to the user
if (!window.typo) return
const textProperties = this.textPropertyManager._textProperties
if (!change.updated) return
Object.keys(change.updated).forEach(pathStr => {
......@@ -45,20 +48,39 @@ class SpellCheckManager {
}
_runSpellCheck(pathStr) {
// console.log('Running spell-checker on', pathStr)
let path = pathStr.split(',')
let text = this.editorSession.getDocument().get(path)
let lang = this.editorSession.getLanguage()
if (!text || !isString(text)) return
if (!window.typo) return
text = text.split(' ')
window.typo.suggest(text[0], null, all => {
const obj = { suggestions: all, path }
var data = []
data.push(obj)
this._addSpellErrors(path, data, text[0])
})
let startlength = 0
const separators = [
' ',
'-',
'/',
':',
'\\.',
'\\,',
'\\;',
'\\+',
'\\',
'\\[',
'\\]',
'\\',
'\\',
'\\',
'\\',
'\\(',
'\\)',
'\\*',
'\\?',
]
const textArray = text.split(new RegExp(separators.join('|'), 'g'))
const data = typo.checkMultiple(textArray, path)
this._addSpellErrors(path, data)
return
}
/*
......@@ -66,7 +88,7 @@ class SpellCheckManager {
Removes all spell errors on the given path first.
*/
_addSpellErrors(path, data, text) {
_addSpellErrors(path, data) {
const editorSession = this.editorSession
const markersManager = editorSession.markersManager
// NOTE: we have one set of markers for each text property
......@@ -77,18 +99,20 @@ class SpellCheckManager {
type: 'spell-error',
start: {
path: path,
offset: 0,
offset: m.start,
},
end: {
offset: text.length,
offset: m.start + m.word.length,
},
suggestions: m.suggestions,
}
})
this.editorSession._selectionState.markers = markers
markersManager.setMarkers(key, markers)
editorSession.startFlow()
setTimeout(() => {
editorSession.startFlow()
})
}
}
......
SET UTF-8
TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
ICONV 1
ICONV ’ '
NOSUGGEST !
# ordinal numbers
COMPOUNDMIN 1
# only in compounds: 1th, 2th, 3th
ONLYINCOMPOUND c
# compound rules:
# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.)
# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.)
COMPOUNDRULE 2
COMPOUNDRULE n*1t
COMPOUNDRULE n*mp
WORDCHARS 0123456789
PFX A Y 1
PFX A 0 re .
PFX I Y 1
PFX I 0 in .
PFX U Y 1
PFX U 0 un .
PFX C Y 1
PFX C 0 de .
PFX E Y 1
PFX E 0 dis .
PFX F Y 1
PFX F 0 con .
PFX K Y 1
PFX K 0 pro .
SFX V N 2
SFX V e ive e
SFX V 0 ive [^e]
SFX N Y 3
SFX N e ion e
SFX N y ication y
SFX N 0 en [^ey]
SFX X Y 3
SFX X e ions e
SFX X y ications y
SFX X 0 ens [^ey]
SFX H N 2
SFX H y ieth y
SFX H 0 th [^y]
SFX Y Y 1
SFX Y 0 ly .
SFX G Y 2
SFX G e ing e
SFX G 0 ing [^e]
SFX J Y 2
SFX J e ings e
SFX J 0 ings [^e]
SFX D Y 4
SFX D 0 d e
SFX D y ied [^aeiou]y
SFX D 0 ed [^ey]
SFX D 0 ed [aeiou]y
SFX T N 4
SFX T 0 st e
SFX T y iest [^aeiou]y
SFX T 0 est [aeiou]y
SFX T 0 est [^ey]
SFX R Y 4
SFX R 0 r e
SFX R y ier [^aeiou]y
SFX R 0 er [aeiou]y
SFX R 0 er [^ey]
SFX Z Y 4
SFX Z 0 rs e
SFX Z y iers [^aeiou]y
SFX Z 0 ers [aeiou]y
SFX Z 0 ers [^ey]
SFX S Y 4
SFX S y ies [^aeiou]y
SFX S 0 s [aeiou]y
SFX S 0 es [sxzh]
SFX S 0 s [^sxzhy]
SFX P Y 3
SFX P y iness [^aeiou]y
SFX P 0 ness [aeiou]y
SFX P 0 ness [^y]
SFX M Y 1
SFX M 0 's .
SFX B Y 3
SFX B 0 able [^aeiou]
SFX B 0 able ee
SFX B e able [^aeiou]e
SFX L Y 1
SFX L 0 ment .
REP 90
REP a ei
REP ei a
REP a ey
REP ey a
REP ai ie
REP ie ai
REP alot a_lot
REP are air
REP are ear
REP are eir
REP air are
REP air ere
REP ere air
REP ere ear
REP ere eir
REP ear are
REP ear air
REP ear ere
REP eir are
REP eir ere
REP ch te
REP te ch
REP ch ti
REP ti ch
REP ch tu
REP tu ch
REP ch s
REP s ch
REP ch k
REP k ch
REP f ph
REP ph f
REP gh f
REP f gh
REP i igh
REP igh i
REP i uy
REP uy i
REP i ee
REP ee i
REP j di
REP di j
REP j gg
REP gg j
REP j ge
REP ge j
REP s ti
REP ti s
REP s ci
REP ci s
REP k cc
REP cc k
REP k qu
REP qu k
REP kw qu
REP o eau
REP eau o
REP o ew
REP ew o
REP oo ew
REP ew oo
REP ew ui
REP ui ew
REP oo ui
REP ui oo
REP ew u
REP u ew
REP oo u
REP u oo
REP u oe
REP oe u
REP u ieu
REP ieu u
REP ue ew
REP ew ue
REP uff ough
REP oo ieu
REP ieu oo
REP ier ear
REP ear ier
REP ear air
REP air ear
REP w qu
REP qu w
REP z ss
REP ss z
REP shun tion
REP shun sion
REP shun cion
REP size cise
......@@ -8,16 +8,18 @@
* Typo is a JavaScript implementation of a spellchecker using hunspell-style
* dictionaries.
*/
var affPath = require('./dictionairies/en_US.aff')
var dicPath = require('./dictionairies/en_US.dic')
import { forEach } from 'lodash'
;('use strict')
'use strict'
function loadTypo(dicName, affPath, dicPath) {
function loadTypo(dicName) {
return new Promise(function(resolve, reject) {
let xhr_aff = new XMLHttpRequest()
xhr_aff.open('GET', affPath, true)
xhr_aff.onload = function() {
if (xhr_aff.readyState === 4 && xhr_aff.status === 200) {
//console.log('aff loaded');
// console.log('aff loaded')
let xhr_dic = new XMLHttpRequest()
xhr_dic.open('GET', dicPath, true)
xhr_dic.onload = function() {
......@@ -698,6 +700,29 @@ Typo.prototype = {
return false
},
checkMultiple(textArray, path) {
if (!this.loaded) {
throw 'Dictionary not loaded.'
}
var data = []
var startlength = 0
forEach(textArray, (word, index) => {
if (index >= 1) startlength += textArray[index - 1].length + 1
//if not found in dictionairy get suggestions
if (!this.check(word)) {
const obj = {
suggestions: this.suggest(word, null),
path,
start: startlength,
word,
}
data.push(obj)
}
})
return data
},
/**
* Checks whether a word exists in the current dictionary.
*
......@@ -803,7 +828,7 @@ Typo.prototype = {
// calling suggest with no arguments will stop the current search if there is one
if (arguments.length === 0) return
limit = limit || 5
limit = limit || 7
if (self.memoized.hasOwnProperty(word)) {
const memoizedLimit = self.memoized[word]['limit']
......
......@@ -7,8 +7,6 @@ class SpellCheckToggleCommand extends Command {
disabled: false,
active: false,
}
newState.disabled = true
return newState
if (params.surface)
if (params.surface && params.surface.props.spellcheck) {
......
......@@ -313,29 +313,40 @@ figcaption {
//spellCheck
.sc-overlay > .se-active-tools .sc-correction-tool {
background: #eeeeee;
background: $note-blue;
padding-bottom: 10px;
width: 150px;
border: 1px solid #ccc;
border-radius: 4px;
button {
&:disabled {
opacity: 0.4;
opacity: 0.6;
cursor: not-allowed;
}
}
button.suggestion {
font-size: 15px;
display: block;
color: #000;
color: $white;
width: 100%;
text-align: left;
margin-bottom: 5px;
margin-left: 10px;
&:hover {
font-weight: 600;
}
}
.no-suggestions {
margin-left: 10px;
font-size: 15px;
color: #000;
color: $white;
}
.add-to-dictionairy {
border-top: 1px solid #fff;
border-top: 2px solid #fff;
font-size: 15px;
color: #4990e2;
width: 98%;
color: $white;
cursor: not-allowed;
width: 100%;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment