mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #229 from sharelatex/spelling-cache
add client-side spelling cache to reduce load on server
This commit is contained in:
commit
f2d62e0653
3 changed files with 63 additions and 14 deletions
|
@ -20,6 +20,7 @@ div.full-size(
|
||||||
keybindings="settings.mode",
|
keybindings="settings.mode",
|
||||||
font-size="settings.fontSize",
|
font-size="settings.fontSize",
|
||||||
auto-complete="settings.autoComplete",
|
auto-complete="settings.autoComplete",
|
||||||
|
spell-check="true",
|
||||||
spell-check-language="project.spellCheckLanguage",
|
spell-check-language="project.spellCheckLanguage",
|
||||||
highlights="onlineUserCursorHighlights[editor.open_doc_id]"
|
highlights="onlineUserCursorHighlights[editor.open_doc_id]"
|
||||||
show-print-margin="false",
|
show-print-margin="false",
|
||||||
|
|
|
@ -18,7 +18,7 @@ define [
|
||||||
url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}"
|
url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}"
|
||||||
return url
|
return url
|
||||||
|
|
||||||
App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage) ->
|
App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory) ->
|
||||||
monkeyPatchSearch($rootScope, $compile)
|
monkeyPatchSearch($rootScope, $compile)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -29,6 +29,7 @@ define [
|
||||||
fontSize: "="
|
fontSize: "="
|
||||||
autoComplete: "="
|
autoComplete: "="
|
||||||
sharejsDoc: "="
|
sharejsDoc: "="
|
||||||
|
spellCheck: "="
|
||||||
spellCheckLanguage: "="
|
spellCheckLanguage: "="
|
||||||
highlights: "="
|
highlights: "="
|
||||||
text: "="
|
text: "="
|
||||||
|
@ -55,7 +56,9 @@ define [
|
||||||
scope.name = attrs.aceEditor
|
scope.name = attrs.aceEditor
|
||||||
|
|
||||||
autoCompleteManager = new AutoCompleteManager(scope, editor, element)
|
autoCompleteManager = new AutoCompleteManager(scope, editor, element)
|
||||||
spellCheckManager = new SpellCheckManager(scope, editor, element)
|
if scope.spellCheck # only enable spellcheck when explicitly required
|
||||||
|
spellCheckCache = $cacheFactory("spellCheck-#{scope.name}", {capacity: 1000})
|
||||||
|
spellCheckManager = new SpellCheckManager(scope, editor, element, spellCheckCache)
|
||||||
undoManager = new UndoManager(scope, editor, element)
|
undoManager = new UndoManager(scope, editor, element)
|
||||||
highlightsManager = new HighlightsManager(scope, editor, element)
|
highlightsManager = new HighlightsManager(scope, editor, element)
|
||||||
cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage)
|
cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage)
|
||||||
|
|
|
@ -5,7 +5,7 @@ define [
|
||||||
Range = ace.require("ace/range").Range
|
Range = ace.require("ace/range").Range
|
||||||
|
|
||||||
class SpellCheckManager
|
class SpellCheckManager
|
||||||
constructor: (@$scope, @editor, @element) ->
|
constructor: (@$scope, @editor, @element, @cache) ->
|
||||||
$(document.body).append @element.find(".spell-check-menu")
|
$(document.body).append @element.find(".spell-check-menu")
|
||||||
|
|
||||||
@updatedLines = []
|
@updatedLines = []
|
||||||
|
@ -102,6 +102,8 @@ define [
|
||||||
learnWord: (highlight) ->
|
learnWord: (highlight) ->
|
||||||
@apiRequest "/learn", word: highlight.word
|
@apiRequest "/learn", word: highlight.word
|
||||||
@highlightedWordManager.removeWord highlight.word
|
@highlightedWordManager.removeWord highlight.word
|
||||||
|
language = @$scope.spellCheckLanguage
|
||||||
|
@cache?.put("#{language}:#{highlight.word}", true)
|
||||||
|
|
||||||
getHighlightedWordAtCursor: () ->
|
getHighlightedWordAtCursor: () ->
|
||||||
cursor = @editor.getCursorPosition()
|
cursor = @editor.getCursorPosition()
|
||||||
|
@ -143,24 +145,67 @@ define [
|
||||||
runSpellCheck: (linesToProcess) ->
|
runSpellCheck: (linesToProcess) ->
|
||||||
{words, positions} = @getWords(linesToProcess)
|
{words, positions} = @getWords(linesToProcess)
|
||||||
language = @$scope.spellCheckLanguage
|
language = @$scope.spellCheckLanguage
|
||||||
@apiRequest "/check", {language: language, words: words}, (error, result) =>
|
|
||||||
if error? or !result? or !result.misspellings?
|
|
||||||
return null
|
|
||||||
|
|
||||||
|
highlights = []
|
||||||
|
seen = {}
|
||||||
|
newWords = []
|
||||||
|
newPositions = []
|
||||||
|
|
||||||
|
# iterate through all words, building up a list of
|
||||||
|
# newWords/newPositions not in the cache
|
||||||
|
for word, i in words
|
||||||
|
key = "#{language}:#{word}"
|
||||||
|
seen[key] ?= @cache.get(key) # avoid hitting the cache unnecessarily
|
||||||
|
cached = seen[key]
|
||||||
|
if not cached?
|
||||||
|
newWords.push words[i]
|
||||||
|
newPositions.push positions[i]
|
||||||
|
else if cached is true
|
||||||
|
# word is correct
|
||||||
|
else
|
||||||
|
highlights.push
|
||||||
|
column: positions[i].column
|
||||||
|
row: positions[i].row
|
||||||
|
word: word
|
||||||
|
suggestions: cached
|
||||||
|
words = newWords
|
||||||
|
positions = newPositions
|
||||||
|
|
||||||
|
displayResult = (highlights) =>
|
||||||
if linesToProcess?
|
if linesToProcess?
|
||||||
for shouldProcess, row in linesToProcess
|
for shouldProcess, row in linesToProcess
|
||||||
@highlightedWordManager.clearRows(row, row) if shouldProcess
|
@highlightedWordManager.clearRows(row, row) if shouldProcess
|
||||||
else
|
else
|
||||||
@highlightedWordManager.clearRows()
|
@highlightedWordManager.clearRows()
|
||||||
|
for highlight in highlights
|
||||||
|
@highlightedWordManager.addHighlight highlight
|
||||||
|
|
||||||
|
if not words.length
|
||||||
|
displayResult highlights
|
||||||
|
else
|
||||||
|
@apiRequest "/check", {language: language, words: words}, (error, result) =>
|
||||||
|
if error? or !result? or !result.misspellings?
|
||||||
|
return null
|
||||||
|
mispelled = []
|
||||||
for misspelling in result.misspellings
|
for misspelling in result.misspellings
|
||||||
word = words[misspelling.index]
|
word = words[misspelling.index]
|
||||||
position = positions[misspelling.index]
|
position = positions[misspelling.index]
|
||||||
@highlightedWordManager.addHighlight
|
mispelled[misspelling.index] = true
|
||||||
|
highlights.push
|
||||||
column: position.column
|
column: position.column
|
||||||
row: position.row
|
row: position.row
|
||||||
word: word
|
word: word
|
||||||
suggestions: misspelling.suggestions
|
suggestions: misspelling.suggestions
|
||||||
|
key = "#{language}:#{word}"
|
||||||
|
if not seen[key]
|
||||||
|
@cache.put key, misspelling.suggestions
|
||||||
|
seen[key] = true
|
||||||
|
for word, i in words when not mispelled[i]
|
||||||
|
key = "#{language}:#{word}"
|
||||||
|
if not seen[key]
|
||||||
|
@cache.put(key, true)
|
||||||
|
seen[key] = true
|
||||||
|
displayResult highlights
|
||||||
|
|
||||||
getWords: (linesToProcess) ->
|
getWords: (linesToProcess) ->
|
||||||
lines = @editor.getValue().split("\n")
|
lines = @editor.getValue().split("\n")
|
||||||
|
|
Loading…
Reference in a new issue