Handle choosing a color and clicking on the note icon differently

Resolves MS-869 and MS870 #Complete
This commit is contained in:
Ramon Wenger 2024-02-01 16:31:52 +01:00
parent f69af1e4cf
commit 837fcc81be
5 changed files with 86 additions and 39 deletions

View File

@ -94,5 +94,7 @@ module.exports = {
], ],
}, },
], ],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
}, },
}; };

View File

@ -126,9 +126,12 @@ import type { Modal } from '@/plugins/modal.types';
import { PAGE_LOAD_TIMEOUT } from '@/consts/navigation.consts'; import { PAGE_LOAD_TIMEOUT } from '@/consts/navigation.consts';
import { getSelectionHandler } from '@/directives/highlight'; import { getSelectionHandler, SelectionHandlerOptions } from '@/helpers/highlight';
import { graphql } from '@/__generated__'; import { graphql } from '@/__generated__';
import log from 'loglevel'; import log from 'loglevel';
import highlightSidebar from '@/helpers/highlight-sidebar';
import { doUpdateHighlight } from '@/graphql/mutations';
import { AddHighlightArgument } from '@/__generated__/graphql';
export interface Props { export interface Props {
contentBlock: ExtendedContentBlockNode; contentBlock: ExtendedContentBlockNode;
@ -255,11 +258,11 @@ graphql(`
selectionLength selectionLength
contentUuid contentUuid
startPosition startPosition
color
note { note {
text text
} }
text text
color
contentBlock { contentBlock {
id id
} }
@ -312,6 +315,16 @@ const { mutate: doCreateHighlight } = useMutation(
}) })
); );
let selectionHandler: (event: Event) => void;
const createHighlight = (highlight: AddHighlightArgument) => {
return doCreateHighlight({
input: {
highlight: highlight,
},
});
};
onMounted(() => { onMounted(() => {
log.debug('onMounted ContentBlock called'); log.debug('onMounted ContentBlock called');
@ -329,17 +342,38 @@ onMounted(() => {
}, PAGE_LOAD_TIMEOUT); }, PAGE_LOAD_TIMEOUT);
} }
// add the listener from highlights const options: SelectionHandlerOptions = {
element.addEventListener( el: element,
'mouseup', contentBlock: props.contentBlock,
getSelectionHandler(element, props.contentBlock, (newHighlight) => { onChangeColor: (newHighlight: AddHighlightArgument) => {
doCreateHighlight({ 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: { input: {
highlight: newHighlight, note: text,
id: highlight.id,
}, },
}); });
}) },
});
}
); );
},
};
selectionHandler = getSelectionHandler(options);
// add the listener from highlights
element.addEventListener('mouseup', selectionHandler);
} }
}); });
@ -347,8 +381,7 @@ onUnmounted(() => {
const element = contentBlockDiv.value; const element = contentBlockDiv.value;
if (element !== null) { if (element !== null) {
console.log('unmounting'); element.removeEventListener('mouseup', selectionHandler);
element.removeEventListener('mouseup', getSelectionHandler(element, props.contentBlock));
} }
}); });

View File

@ -17,7 +17,7 @@
<section class="highlight-popover__section"> <section class="highlight-popover__section">
<note-icon <note-icon
class="highlight-popover__icon" class="highlight-popover__icon"
@click="$emit('confirm')" @click="$emit('note')"
/> />
</section> </section>
<section class="highlight-popover__section"> <section class="highlight-popover__section">

View File

@ -1,10 +1,7 @@
import { DirectiveBinding } from 'vue';
import * as rangy from 'rangy'; import * as rangy from 'rangy';
import 'rangy/lib/rangy-textrange'; import 'rangy/lib/rangy-textrange';
import log from 'loglevel'; import log from 'loglevel';
import Mark from 'mark.js';
import { ContentBlockNode } from '@/__generated__/graphql'; import { ContentBlockNode } from '@/__generated__/graphql';
import ContentBlock from '@/components/ContentBlock.vue';
import popover from '@/helpers/popover'; import popover from '@/helpers/popover';
// todo: we need to get the following information for a highlight: // todo: we need to get the following information for a highlight:
@ -119,8 +116,16 @@ const getSiblings = (element: HTMLElement): Element[] => {
return children; return children;
}; };
export interface SelectionHandlerOptions {
el: HTMLElement;
contentBlock: ContentBlockNode;
onChangeColor?: (highlight: any) => void;
onCreateNote?: (highlight: any) => void;
}
export const getSelectionHandler = 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) => { (_e: Event) => {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
if (isInsideViewport(rect.top) || isInsideViewport(rect.bottom)) { if (isInsideViewport(rect.top) || isInsideViewport(rect.bottom)) {
@ -167,24 +172,25 @@ export const getSelectionHandler =
const positionOfContentBlock = el.getBoundingClientRect(); const positionOfContentBlock = el.getBoundingClientRect();
const positionOfSelection = startAncestor?.getBoundingClientRect(); const positionOfSelection = startAncestor?.getBoundingClientRect();
const offsetTop = positionOfSelection.top - positionOfContentBlock.top; const offsetTop = positionOfSelection.top - positionOfContentBlock.top;
popover const onChooseColor = (color: string) => {
.show({
wrapper: el,
offsetTop,
onChooseColor: (color: string) => {
console.log('chosenColor', color); console.log('chosenColor', color);
highlightedText.color = color; highlightedText.color = color;
onUpdateHighlight(highlightedText); if (onChangeColor) {
}, onChangeColor(highlightedText);
}) }
.then(() => { };
console.log('confirmed here'); const onNote = () => {
}) highlightedText.color = 'alpha';
.catch(() => { if (onCreateNote) {
console.log('canceled'); onCreateNote(highlightedText);
}
};
popover.show({
wrapper: el,
offsetTop,
onChooseColor,
onNote,
}); });
// 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
} }
} }
} }

View File

@ -9,10 +9,11 @@ interface Options {
onChooseColor: (color: string) => void; onChooseColor: (color: string) => void;
// we don't use the id as a param here, because the calling component knows already which entity it is // we don't use the id as a param here, because the calling component knows already which entity it is
onDelete?: () => void; onDelete?: () => void;
onNote?: () => void;
} }
export default { export default {
show({ wrapper, offsetTop, onChooseColor, onDelete }: Options) { show({ wrapper, offsetTop, onChooseColor, onDelete, onNote }: Options) {
const mountEl = document.createElement('div'); const mountEl = document.createElement('div');
wrapper.appendChild(mountEl); wrapper.appendChild(mountEl);
@ -46,6 +47,11 @@ export default {
cleanUp(); cleanUp();
_resolve(); _resolve();
}, },
onNote() {
if (onNote) {
onNote();
}
},
onClose() { onClose() {
cleanUp(); cleanUp();
_reject(); _reject();
@ -63,7 +69,7 @@ export default {
setTimeout(() => { setTimeout(() => {
document.addEventListener('click', clickOutsideElementListener); 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; return promise;
}, },
}; };