diff --git a/client/.eslintrc.js b/client/.eslintrc.js index 5de6f54c..b9dd09d7 100644 --- a/client/.eslintrc.js +++ b/client/.eslintrc.js @@ -94,5 +94,7 @@ module.exports = { ], }, ], + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', }, }; diff --git a/client/src/components/ContentBlock.vue b/client/src/components/ContentBlock.vue index 222dc243..04289339 100644 --- a/client/src/components/ContentBlock.vue +++ b/client/src/components/ContentBlock.vue @@ -126,9 +126,12 @@ import type { Modal } from '@/plugins/modal.types'; import { PAGE_LOAD_TIMEOUT } from '@/consts/navigation.consts'; -import { getSelectionHandler } from '@/directives/highlight'; +import { getSelectionHandler, SelectionHandlerOptions } from '@/helpers/highlight'; import { graphql } from '@/__generated__'; import log from 'loglevel'; +import highlightSidebar from '@/helpers/highlight-sidebar'; +import { doUpdateHighlight } from '@/graphql/mutations'; +import { AddHighlightArgument } from '@/__generated__/graphql'; export interface Props { contentBlock: ExtendedContentBlockNode; @@ -255,11 +258,11 @@ graphql(` selectionLength contentUuid startPosition + color note { text } text - color contentBlock { id } @@ -312,6 +315,16 @@ const { mutate: doCreateHighlight } = useMutation( }) ); +let selectionHandler: (event: Event) => void; + +const createHighlight = (highlight: AddHighlightArgument) => { + return doCreateHighlight({ + input: { + highlight: highlight, + }, + }); +}; + onMounted(() => { log.debug('onMounted ContentBlock called'); @@ -329,17 +342,38 @@ onMounted(() => { }, PAGE_LOAD_TIMEOUT); } + const options: SelectionHandlerOptions = { + el: element, + contentBlock: props.contentBlock, + onChangeColor: (newHighlight: AddHighlightArgument) => { + createHighlight(newHighlight); + }, + onCreateNote: (newHighlight: AddHighlightArgument) => { + // we also open the sidebar when clicking on the note icon + createHighlight(newHighlight).then( + ({ + data: { + addHighlight: { highlight }, + }, + }) => { + highlightSidebar.open({ + highlight, + onUpdateText: (text: string) => { + doUpdateHighlight({ + input: { + note: text, + id: highlight.id, + }, + }); + }, + }); + } + ); + }, + }; + selectionHandler = getSelectionHandler(options); // add the listener from highlights - element.addEventListener( - 'mouseup', - getSelectionHandler(element, props.contentBlock, (newHighlight) => { - doCreateHighlight({ - input: { - highlight: newHighlight, - }, - }); - }) - ); + element.addEventListener('mouseup', selectionHandler); } }); @@ -347,8 +381,7 @@ onUnmounted(() => { const element = contentBlockDiv.value; if (element !== null) { - console.log('unmounting'); - element.removeEventListener('mouseup', getSelectionHandler(element, props.contentBlock)); + element.removeEventListener('mouseup', selectionHandler); } }); diff --git a/client/src/components/highlights/HighlightPopover.vue b/client/src/components/highlights/HighlightPopover.vue index 4706f269..acfcdd64 100644 --- a/client/src/components/highlights/HighlightPopover.vue +++ b/client/src/components/highlights/HighlightPopover.vue @@ -17,7 +17,7 @@
diff --git a/client/src/directives/highlight.ts b/client/src/helpers/highlight.ts similarity index 86% rename from client/src/directives/highlight.ts rename to client/src/helpers/highlight.ts index 9cc53f00..afa32357 100644 --- a/client/src/directives/highlight.ts +++ b/client/src/helpers/highlight.ts @@ -1,10 +1,7 @@ -import { DirectiveBinding } from 'vue'; import * as rangy from 'rangy'; import 'rangy/lib/rangy-textrange'; import log from 'loglevel'; -import Mark from 'mark.js'; import { ContentBlockNode } from '@/__generated__/graphql'; -import ContentBlock from '@/components/ContentBlock.vue'; import popover from '@/helpers/popover'; // todo: we need to get the following information for a highlight: @@ -119,8 +116,16 @@ const getSiblings = (element: HTMLElement): Element[] => { return children; }; +export interface SelectionHandlerOptions { + el: HTMLElement; + contentBlock: ContentBlockNode; + onChangeColor?: (highlight: any) => void; + onCreateNote?: (highlight: any) => void; +} + export const getSelectionHandler = - (el: HTMLElement, contentBlock: ContentBlockNode, onUpdateHighlight: (highlight: any) => void = () => {}) => + ({ el, contentBlock, onChangeColor, onCreateNote }: SelectionHandlerOptions) => + // (el: HTMLElement, contentBlock: ContentBlockNode, onUpdateHighlight: (highlight: any) => void = () => {}) => (_e: Event) => { const rect = el.getBoundingClientRect(); if (isInsideViewport(rect.top) || isInsideViewport(rect.bottom)) { @@ -167,24 +172,25 @@ export const getSelectionHandler = const positionOfContentBlock = el.getBoundingClientRect(); const positionOfSelection = startAncestor?.getBoundingClientRect(); const offsetTop = positionOfSelection.top - positionOfContentBlock.top; - popover - .show({ - wrapper: el, - offsetTop, - onChooseColor: (color: string) => { - console.log('chosenColor', color); - highlightedText.color = color; - onUpdateHighlight(highlightedText); - }, - }) - .then(() => { - console.log('confirmed here'); - }) - .catch(() => { - console.log('canceled'); - }); - // todo: how do we save this? maybe we need to move away from the directive and do this inside the mounted - // and unmounted hooks of the ContentBlock + const onChooseColor = (color: string) => { + console.log('chosenColor', color); + highlightedText.color = color; + if (onChangeColor) { + onChangeColor(highlightedText); + } + }; + const onNote = () => { + highlightedText.color = 'alpha'; + if (onCreateNote) { + onCreateNote(highlightedText); + } + }; + popover.show({ + wrapper: el, + offsetTop, + onChooseColor, + onNote, + }); } } } diff --git a/client/src/helpers/popover.ts b/client/src/helpers/popover.ts index 73b68a32..299ee943 100644 --- a/client/src/helpers/popover.ts +++ b/client/src/helpers/popover.ts @@ -9,10 +9,11 @@ interface Options { onChooseColor: (color: string) => void; // we don't use the id as a param here, because the calling component knows already which entity it is onDelete?: () => void; + onNote?: () => void; } export default { - show({ wrapper, offsetTop, onChooseColor, onDelete }: Options) { + show({ wrapper, offsetTop, onChooseColor, onDelete, onNote }: Options) { const mountEl = document.createElement('div'); wrapper.appendChild(mountEl); @@ -46,6 +47,11 @@ export default { cleanUp(); _resolve(); }, + onNote() { + if (onNote) { + onNote(); + } + }, onClose() { cleanUp(); _reject(); @@ -63,7 +69,7 @@ export default { setTimeout(() => { document.addEventListener('click', clickOutsideElementListener); - }, 1); // do not triger ont the same event that created the popover + }, 1); // do not trigger on the same event that created the popover return promise; }, };