diff --git a/client/src/components/ContentBlock.vue b/client/src/components/ContentBlock.vue
index 47efc129..9d8982be 100644
--- a/client/src/components/ContentBlock.vue
+++ b/client/src/components/ContentBlock.vue
@@ -3,6 +3,7 @@
:class="{ 'hideable-element--greyed-out': isHidden }"
class="content-block__container hideable-element content-list__parent"
ref="wrapper"
+ v-highlight
>
{
+ return position >= TOP_TRESHOLD && position <= BOTTOM_TRESHOLD;
+};
+
+const findClosestAncestor = (node: Node, tag: string): HTMLElement | null => {
+ let currentNode: Node | null = node;
+ while (currentNode && currentNode.nodeName.toLowerCase() !== tag && currentNode.nodeName.toLowerCase() !== 'body') {
+ currentNode = currentNode.parentNode;
+ }
+ if (currentNode) {
+ return currentNode as HTMLElement;
+ }
+ return null;
+};
+const findClosestAncestorWithClass = (node: Node, className: string): HTMLElement | null => {
+ let currentNode: Node | null = node;
+ while (
+ currentNode && // current node exists
+ // current node is not an HTMLElement, so probably a TextNode
+ // or, current node does not contain the class
+ (!(currentNode instanceof HTMLElement) || !currentNode.classList.contains(className)) &&
+ // we have not arrived at the top yet
+ currentNode.nodeName.toLowerCase() !== 'body'
+ ) {
+ // so, we continue looking
+ currentNode = currentNode.parentNode;
+ }
+ if (currentNode instanceof HTMLElement && currentNode.classList.contains(className)) {
+ // make sure we're not up at the body element
+ return currentNode as HTMLElement;
+ }
+ return null;
+};
+
+const findPositionInParent = (element: HTMLElement, className: string = 'content-component'): number => {
+ /*
+ * currently, a content block has the structure
+ * div.content-block__container
+ * div.content-block
+ * div.content-block__visibility
+ * div.content-block__title
+ * div.content-component
+ * div.content-component
+ * [...]
+ * div.content-component
+ *
+ * We only care about the .content-component divs, not the others
+ *
+ */
+
+ if (!element.parentElement) {
+ log.error('element has no parent', element);
+ return -1; // element has no parent, probably somehow ended up at the top. But this should probably never happen in our application
+ }
+ const children = Array.from(element.parentElement.children).filter((child) => child.classList.contains(className));
+ return children.indexOf(element);
+};
+
+const getSelectionHandler = (el: HTMLElement) => (_e: Event) => {
+ const rect = el.getBoundingClientRect();
+ if (isInsideViewport(rect.top) || isInsideViewport(rect.bottom)) {
+ // the listener only does something if the `el` is visible in the viewport, to save resources
+
+ console.log(el);
+ console.log(rect);
+ // now we check if the selection is inside our container
+
+ const selection = rangy.getSelection();
+ if (selection.rangeCount && !selection.isCollapsed) {
+ const range = selection.getRangeAt(0);
+ if (range.intersectsNode(el)) {
+ // the selection is inside our container, so we can do something with it
+ console.log('selection is inside our container');
+ console.log(el);
+ console.log(range.compareNode(el));
+ const { startContainer, endContainer } = range;
+ const startAncestor = findClosestAncestor(startContainer, 'p');
+ const endAncestor = findClosestAncestor(endContainer, 'p');
+ console.log('same?');
+ console.log(startAncestor === endAncestor);
+
+ if (startAncestor === endAncestor) {
+ const parent = findClosestAncestorWithClass(startContainer, 'content-component');
+ console.log(parent);
+ if (parent) {
+ // our selection is wholly inside the container node, we continue with it
+ const position = findPositionInParent(parent);
+ console.log(`selection is inside our container at ${position}`);
+
+ const { start, end } = range.toCharacterRange(parent);
+ console.log(start, end);
+ const instance = new Mark(parent);
+ instance.markRanges([{ start, length: end - start }]);
+ }
+ }
+ }
+ }
+ }
+};
+
+const addListener = (el: HTMLElement, binding: DirectiveBinding, vnode: VNode, prevVnode: VNode) => {
+ log.debug('registering a selection handler');
+ document.addEventListener('selectionchange', getSelectionHandler(el));
+};
+
+const removeListener = (el: HTMLElement, binding: DirectiveBinding, vnode: VNode, prevVnode: VNode) => {
+ log.debug('removing a selection handler');
+ document.removeEventListener('selectionchange', getSelectionHandler(el));
+};
+
+export default {
+ mounted: addListener,
+ unmounted: removeListener,
+};