improve autocomplete working
This commit is contained in:
@@ -65,6 +65,7 @@ export default defineComponent({
|
||||
'update:modelValue',
|
||||
'click',
|
||||
'contextedLinkAutocomplete',
|
||||
'contextedKeypress',
|
||||
],
|
||||
|
||||
data(): CKEditorComponentData {
|
||||
@@ -227,6 +228,9 @@ export default defineComponent({
|
||||
editor.model.document.on('contextedLinkAutocomplete', (_, data) => {
|
||||
this.$emit('contextedLinkAutocomplete', data)
|
||||
})
|
||||
editor.model.document.on('contextedKeypress', (_, eventData) => {
|
||||
this.$emit('contextedKeypress', eventData)
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ export default class ContextedLinkEditing extends Plugin {
|
||||
init() {
|
||||
this._defineSchema() // ADDED
|
||||
this._defineConverters() // ADDED
|
||||
this._addContextedKeyHandler()
|
||||
const twoStepCaretMovementPlugin = this.editor.plugins.get(TwoStepCaretMovement)
|
||||
twoStepCaretMovementPlugin.registerAttribute('contextedLink')
|
||||
inlineHighlight(this.editor, 'contextedLink', 'a', HIGHLIGHT_CLASS)
|
||||
@@ -18,14 +19,6 @@ export default class ContextedLinkEditing extends Plugin {
|
||||
)
|
||||
}
|
||||
afterInit() {
|
||||
// const editor = this.editor
|
||||
// editor.model.document.on('change', (eventInfo, batch) => {
|
||||
// const model = editor.model
|
||||
// const selection = model.document.selection
|
||||
// const collapsed = selection.isCollapsed // should be true
|
||||
// if (!collapsed) return
|
||||
// console.log(eventInfo, batch)
|
||||
// })
|
||||
this._addAutocomplete()
|
||||
}
|
||||
_defineSchema() {
|
||||
@@ -98,9 +91,11 @@ export default class ContextedLinkEditing extends Plugin {
|
||||
const autocompleteText = (inputText as string).match(/(?<=\[\[).*/g)
|
||||
const cursorNodes = [focus.textNode, focus.nodeBefore, focus.nodeAfter]
|
||||
const autocompleteNode: any = cursorNodes.find((node) =>
|
||||
node?.hasAttribute('autocomplete')
|
||||
['contextedLink', 'autocomplete'].some((attribute) =>
|
||||
node?.hasAttribute(attribute)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if (Boolean(autocompleteText) || Boolean(autocompleteNode)) {
|
||||
if (Boolean(autocompleteText) !== Boolean(autocompleteNode)) {
|
||||
editor.execute('autocomplete')
|
||||
@@ -112,35 +107,47 @@ export default class ContextedLinkEditing extends Plugin {
|
||||
}
|
||||
} else {
|
||||
showAutocomplete = true
|
||||
const view = editor.editing.view
|
||||
const viewPosition = view.document.selection.focus
|
||||
const viewNode = viewPosition?.parent.parent
|
||||
const domElement = viewNode
|
||||
? (view.domConverter.mapViewToDom(viewNode) as HTMLElement)
|
||||
: undefined
|
||||
const event: AutocompleteEvent = {
|
||||
position: getNodePosition(
|
||||
editor,
|
||||
editor.model.createPositionFromPath(
|
||||
autocompleteNode.root,
|
||||
autocompleteNode.getPath()
|
||||
)
|
||||
),
|
||||
autocompleteText: autocompleteNode.data,
|
||||
domElement,
|
||||
show: showAutocomplete,
|
||||
}
|
||||
editor.model.document.fire('contextedLinkAutocomplete', event)
|
||||
fireAutocompleteEvent(editor, true, autocompleteNode)
|
||||
}
|
||||
}
|
||||
if (!autocompleteNode && showAutocomplete) {
|
||||
showAutocomplete = false
|
||||
editor.model.document.fire('contextedLinkAutocomplete', {
|
||||
show: showAutocomplete,
|
||||
})
|
||||
fireAutocompleteEvent(editor, false)
|
||||
}
|
||||
})
|
||||
}
|
||||
_addContextedKeyHandler() {
|
||||
const editor = this.editor
|
||||
const viewDocument = editor.editing.view.document
|
||||
viewDocument.on(
|
||||
'keydown',
|
||||
(evt, data) => {
|
||||
const { keyCode } = data
|
||||
const keyCodesCycle = [38, 40] // Up, Down
|
||||
const keyCodesConfirm = [13] // Enter
|
||||
const keyCodesCancel = [27] // Escape
|
||||
if (keyCodesCancel.includes(keyCode)) {
|
||||
fireAutocompleteEvent(editor, false)
|
||||
}
|
||||
const keyCodes = [...keyCodesConfirm, ...keyCodesCycle]
|
||||
const selection = editor.model.document.selection
|
||||
const selectionInContextedLink = ['contextedLink', 'autocomplete'].some(
|
||||
(attribute) => selection.hasAttribute(attribute)
|
||||
)
|
||||
if (selectionInContextedLink && keyCodes.includes(keyCode)) {
|
||||
if (selection.hasAttribute('contextedLink')) {
|
||||
const autocompleteNode = editor.model.document.selection.focus
|
||||
?.textNode as any
|
||||
fireAutocompleteEvent(editor, true, autocompleteNode)
|
||||
}
|
||||
console.log(keyCode)
|
||||
this.editor.model.document.fire('contextedKeypress', { keyCode })
|
||||
data.preventDefault(evt.stop())
|
||||
}
|
||||
},
|
||||
{ priority: 'highest' }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function getNodePosition(editor: any, modelPosition: any) {
|
||||
@@ -150,7 +157,7 @@ function getNodePosition(editor: any, modelPosition: any) {
|
||||
const viewRange = editor.editing.view.createRange(viewPosition)
|
||||
const domConverter = editor.editing.view.domConverter
|
||||
const rangeRects = Rect.getDomRangeRects(
|
||||
domConverter.viewRangeToDom(viewRange)
|
||||
domConverter.viewRangeToDom(viewRange)
|
||||
).pop()
|
||||
return rangeRects
|
||||
} catch (e) {
|
||||
@@ -181,3 +188,32 @@ function getTextAfterCode(range: any, model: any) {
|
||||
}, '')
|
||||
return { text, range: model.createRange(start, range.end) }
|
||||
}
|
||||
|
||||
function fireAutocompleteEvent(editor: any, show: boolean, autocompleteNode?: any) {
|
||||
let event: AutocompleteEvent
|
||||
if (show) {
|
||||
const view = editor.editing.view
|
||||
const viewPosition = view.document.selection.focus
|
||||
const viewNode = viewPosition?.parent.parent
|
||||
const domElement = viewNode
|
||||
? (view.domConverter.mapViewToDom(viewNode) as HTMLElement)
|
||||
: undefined
|
||||
event = {
|
||||
position: getNodePosition(
|
||||
editor,
|
||||
editor.model.createPositionFromPath(
|
||||
autocompleteNode.root,
|
||||
autocompleteNode.getPath()
|
||||
)
|
||||
),
|
||||
autocompleteText: autocompleteNode.data,
|
||||
domElement,
|
||||
show: true,
|
||||
}
|
||||
} else {
|
||||
event = {
|
||||
show: false,
|
||||
}
|
||||
}
|
||||
editor.model.document.fire('contextedLinkAutocomplete', event)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,21 @@ const results = computed<Note[]>(() => {
|
||||
props.autocompleteText ? findNotesByByTitle(props.autocompleteText) : notes.value
|
||||
).filter((note) => note.id !== activeNote.value?.id)
|
||||
})
|
||||
|
||||
const handleKeypress = (event: { [key: string]: number }) => {
|
||||
const keyCode = event.keyCode
|
||||
const keyCodes = {
|
||||
cycle: [38, 40],
|
||||
confirm: [13],
|
||||
}
|
||||
if (keyCodes.cycle.includes(keyCode)) {
|
||||
const direction = keyCode === 38 ? -1 : 1
|
||||
// console.log(direction)
|
||||
} else if (keyCodes.confirm.includes(keyCode)) {
|
||||
// console.log('confirm')
|
||||
}
|
||||
}
|
||||
defineExpose({ handleKeypress })
|
||||
</script>
|
||||
<template>
|
||||
<ul
|
||||
|
||||
@@ -64,9 +64,11 @@ const handleClick = ({ data }: { data: any }) => {
|
||||
if (note) activeNote.value = note
|
||||
}
|
||||
|
||||
const autocompleteRef = ref<InstanceType<typeof Autocomplete> | null>(null)
|
||||
const showAutocomplete = ref(false)
|
||||
const autocompleteStyle = ref({})
|
||||
const autocompleteText = ref('')
|
||||
|
||||
const handleAutocomplete = (event: AutocompleteEvent) => {
|
||||
const position = event.position
|
||||
if (position && editorElement.value) {
|
||||
@@ -82,6 +84,10 @@ const handleAutocomplete = (event: AutocompleteEvent) => {
|
||||
autocompleteText.value = event.autocompleteText || ''
|
||||
showAutocomplete.value = event.show
|
||||
}
|
||||
|
||||
const handleContextedKeypress = (event: any) => {
|
||||
if (autocompleteRef.value) autocompleteRef.value.handleKeypress(event)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="relative" ref="editorElement">
|
||||
@@ -92,9 +98,11 @@ const handleAutocomplete = (event: AutocompleteEvent) => {
|
||||
:config="editorConfig"
|
||||
@click="handleClick"
|
||||
@contexted-link-autocomplete="handleAutocomplete"
|
||||
@contexted-keypress="handleContextedKeypress"
|
||||
></CKEditor>
|
||||
<Autocomplete
|
||||
v-if="showAutocomplete"
|
||||
ref="autocompleteRef"
|
||||
:autocomplete-text="autocompleteText"
|
||||
:style="autocompleteStyle"
|
||||
class="absolute w-[250px]"
|
||||
|
||||
Reference in New Issue
Block a user