mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Handle contextmenu for spelling
This commit is contained in:
parent
abcc2cc11b
commit
e6ffaaa489
3 changed files with 91 additions and 8 deletions
|
@ -20,6 +20,7 @@ define [
|
|||
EditSession = ace.require('ace/edit_session').EditSession
|
||||
ModeList = ace.require('ace/ext/modelist')
|
||||
Vim = ace.require('ace/keyboard/vim').Vim
|
||||
Range = ace.require('ace/range').Range
|
||||
|
||||
# set the path for ace workers if using a CDN (from editor.pug)
|
||||
if window.aceWorkerPath != ""
|
||||
|
@ -363,18 +364,22 @@ define [
|
|||
session.setScrollTop(session.getScrollTop() + 1)
|
||||
session.setScrollTop(session.getScrollTop() - 1)
|
||||
|
||||
onSessionChange = (e) ->
|
||||
onSessionChangeForSpellCheck = (e) ->
|
||||
spellCheckManager.onSessionChange()
|
||||
e.oldSession?.getDocument().off "change", spellCheckManager.onChange
|
||||
e.session.getDocument().on "change", spellCheckManager.onChange
|
||||
e.oldSession?.off "changeScrollTop", spellCheckManager.onScroll
|
||||
e.session.on "changeScrollTop", spellCheckManager.onScroll
|
||||
|
||||
attachToSpellCheck = () ->
|
||||
initSpellCheck = () ->
|
||||
spellCheckManager.init()
|
||||
editor.on 'changeSession', onSessionChange
|
||||
onSessionChange({ session: editor.getSession() }) # Force initial setup
|
||||
editor.on 'changeSession', onSessionChangeForSpellCheck
|
||||
onSessionChangeForSpellCheck({ session: editor.getSession() }) # Force initial setup
|
||||
editor.on 'nativecontextmenu', spellCheckManager.onContextMenu
|
||||
|
||||
detachFromSpellCheck = () ->
|
||||
editor.off 'changeSession', onSessionChange
|
||||
tearDownSpellCheck = () ->
|
||||
editor.off 'changeSession', onSessionChangeForSpellCheck
|
||||
editor.off 'nativecontextmenu', spellCheckManager.onContextMenu
|
||||
|
||||
attachToAce = (sharejs_doc) ->
|
||||
lines = sharejs_doc.getSnapshot().split("\n")
|
||||
|
@ -421,7 +426,7 @@ define [
|
|||
editor.initing = false
|
||||
# now ready to edit document
|
||||
editor.setReadOnly(scope.readOnly) # respect the readOnly setting, normally false
|
||||
attachToSpellCheck()
|
||||
initSpellCheck()
|
||||
|
||||
resetScrollMargins()
|
||||
|
||||
|
@ -483,7 +488,7 @@ define [
|
|||
|
||||
scope.$on '$destroy', () ->
|
||||
if scope.sharejsDoc?
|
||||
detachFromSpellCheck()
|
||||
tearDownSpellCheck()
|
||||
detachFromAce(scope.sharejsDoc)
|
||||
session = editor.getSession()
|
||||
session?.destroy()
|
||||
|
@ -608,3 +613,24 @@ define [
|
|||
@wordManager = new HighlightedWordManager(@editor)
|
||||
getLines: () -> @editor.getValue().split('\n')
|
||||
normalizeChangeEvent: (e) -> e
|
||||
getCoordsFromContextMenuEvent: (e) ->
|
||||
e.domEvent.stopPropagation()
|
||||
return {
|
||||
x: e.domEvent.clientX,
|
||||
y: e.domEvent.clientY
|
||||
}
|
||||
preventContextMenuEventDefault: (e) ->
|
||||
e.domEvent.preventDefault()
|
||||
getHighlightFromCoords: (coords) ->
|
||||
position = @editor.renderer.screenToTextCoordinates(coords.x, coords.y)
|
||||
@wordManager.findHighlightWithinRange({
|
||||
start: position
|
||||
end: position
|
||||
})
|
||||
selectHighlightedWord: (highlight) ->
|
||||
@editor.getSession().getSelection().setSelectionRange(
|
||||
new Range(
|
||||
highlight.row, highlight.column,
|
||||
highlight.row, highlight.column + highlight.word.length
|
||||
)
|
||||
)
|
||||
|
|
|
@ -51,3 +51,20 @@ define [
|
|||
row = @highlights.rows[row]
|
||||
for highlight in (row || []).slice()
|
||||
@removeHighlight highlight
|
||||
|
||||
findHighlightWithinRange: (range) ->
|
||||
rows = @highlights.rows.slice(range.start.row, range.end.row + 1)
|
||||
for row in rows
|
||||
for highlight in (row || [])
|
||||
if @_doesHighlightOverlapRange(highlight, range.start, range.end)
|
||||
return highlight
|
||||
return null
|
||||
|
||||
_doesHighlightOverlapRange: (highlight, start, end) ->
|
||||
highlightIsAllBeforeRange =
|
||||
highlight.row < start.row or
|
||||
(highlight.row == start.row and highlight.column + highlight.word.length <= start.column)
|
||||
highlightIsAllAfterRange =
|
||||
highlight.row > end.row or
|
||||
(highlight.row == end.row and highlight.column >= end.column)
|
||||
!(highlightIsAllBeforeRange or highlightIsAllAfterRange)
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
define [], () ->
|
||||
class SpellCheckManager
|
||||
constructor: (@$scope, @cache, @$http, @$q, @adapter) ->
|
||||
@$scope.spellMenu = {
|
||||
open: false
|
||||
top: '0px'
|
||||
left: '0px'
|
||||
suggestions: []
|
||||
}
|
||||
@inProgressRequest = null
|
||||
@updatedLines = []
|
||||
|
||||
|
@ -30,6 +36,40 @@ define [], () ->
|
|||
|
||||
@runSpellCheckSoon(200) if @isSpellCheckEnabled()
|
||||
|
||||
onContextMenu: (e) =>
|
||||
@closeContextMenu()
|
||||
@openContextMenu(e)
|
||||
|
||||
onScroll: () => @closeContextMenu()
|
||||
|
||||
openContextMenu: (e) ->
|
||||
coords = @adapter.getCoordsFromContextMenuEvent(e)
|
||||
highlight = @adapter.getHighlightFromCoords(coords)
|
||||
if highlight
|
||||
@adapter.preventContextMenuEventDefault(e)
|
||||
@adapter.selectHighlightedWord(highlight)
|
||||
@$scope.$apply () =>
|
||||
@$scope.spellMenu = {
|
||||
open: true
|
||||
top: coords.y + 'px'
|
||||
left: coords.x + 'px'
|
||||
suggestions: highlight.suggestions
|
||||
}
|
||||
@setUpClickOffContextMenuListener()
|
||||
return false
|
||||
|
||||
setUpClickOffContextMenuListener: () ->
|
||||
$(document).one 'click', (e) =>
|
||||
@closeContextMenu() if e.which != 3 # Ignore if right click
|
||||
return true
|
||||
|
||||
closeContextMenu: () ->
|
||||
# This is triggered on scroll, so for performance only apply setting when
|
||||
# it changes
|
||||
if @$scope?.spellMenu and @$scope.spellMenu.open != false
|
||||
@$scope.$apply () =>
|
||||
@$scope.spellMenu.open = false
|
||||
|
||||
runFullCheck: () ->
|
||||
@adapter.wordManager.reset()
|
||||
@runSpellCheck() if @isSpellCheckEnabled()
|
||||
|
|
Loading…
Reference in a new issue