diff --git a/src/ckeditor/CKEditor.ts b/src/ckeditor/CKEditor.ts index 68eee70..7127cff 100644 --- a/src/ckeditor/CKEditor.ts +++ b/src/ckeditor/CKEditor.ts @@ -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) + }) }, }, diff --git a/src/ckeditor/ContextedPlugin.ts b/src/ckeditor/ContextedPlugin.ts index ec523bd..9c0882e 100644 --- a/src/ckeditor/ContextedPlugin.ts +++ b/src/ckeditor/ContextedPlugin.ts @@ -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) +} diff --git a/src/components/Autocomplete.vue b/src/components/Autocomplete.vue index 430ffdb..1a50257 100644 --- a/src/components/Autocomplete.vue +++ b/src/components/Autocomplete.vue @@ -12,6 +12,21 @@ const results = computed(() => { 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 })