1 import * as DOM from "../services/dom";
2 import Clipboard from "clipboard/dist/clipboard.min";
10 this.container = this.$el;
11 this.pageId = this.$opts.pageId;
15 this.isSelection = false;
16 this.pointerModeLink = true;
17 this.pointerSectionId = '';
19 this.setupListeners();
22 new Clipboard(this.container.querySelector('button'));
26 // Select all contents on input click
27 DOM.onChildEvent(this.container, 'input', 'click', (event, input) => {
29 event.stopPropagation();
32 // Prevent closing pointer when clicked or focused
33 DOM.onEvents(this.container, ['click', 'focus'], event => {
34 event.stopPropagation();
37 // Pointer mode toggle
38 DOM.onChildEvent(this.container, 'span.icon', 'click', (event, icon) => {
39 event.stopPropagation();
40 this.pointerModeLink = !this.pointerModeLink;
41 icon.querySelector('[data-icon="include"]').style.display = (!this.pointerModeLink) ? 'inline' : 'none';
42 icon.querySelector('[data-icon="link"]').style.display = (this.pointerModeLink) ? 'inline' : 'none';
43 this.updateForTarget();
46 // Hide pointer when clicking away
47 DOM.onEvents(document.body, ['click', 'focus'], event => {
48 if (!this.showing || this.isSelection) return;
52 // Show pointer when selecting a single block of tagged content
53 const pageContent = document.querySelector('.page-content');
54 DOM.onEvents(pageContent, ['mouseup', 'keyup'], event => {
55 event.stopPropagation();
56 const targetEl = event.target.closest('[id^="bkmrk"]');
58 this.showPointerAtTarget(targetEl, event.pageX);
64 this.container.style.display = null;
69 * Move and display the pointer at the given element, targeting the given screen x-position if possible.
70 * @param {Element} element
71 * @param {Number} xPosition
73 showPointerAtTarget(element, xPosition) {
74 const selection = window.getSelection();
75 if (selection.toString().length === 0) return;
77 // Show pointer and set link
78 this.pointerSectionId = element.id;
79 this.updateForTarget(element);
81 this.container.style.display = 'block';
82 const targetBounds = element.getBoundingClientRect();
83 const pointerBounds = this.container.getBoundingClientRect();
85 const xTarget = Math.min(Math.max(xPosition, targetBounds.left), targetBounds.right);
86 const xOffset = xTarget - (pointerBounds.width / 2);
87 const yOffset = (targetBounds.top - pointerBounds.height) - 16;
89 this.container.style.left = `${xOffset}px`;
90 this.container.style.top = `${yOffset}px`;
93 this.isSelection = true;
96 this.isSelection = false;
99 const scrollListener = () => {
101 window.removeEventListener('scroll', scrollListener, {passive: true});
103 window.addEventListener('scroll', scrollListener, {passive: true});
107 * Update the pointer inputs/content for the given target element.
108 * @param {?Element} element
110 updateForTarget(element) {
111 let inputText = this.pointerModeLink ? window.baseUrl(`/link/${this.pageId}#${this.pointerSectionId}`) : `{{@${this.pageId}#${this.pointerSectionId}}}`;
112 if (this.pointerModeLink && !inputText.startsWith('http')) {
113 inputText = window.location.protocol + "//" + window.location.host + inputText;
116 this.container.querySelector('input').value = inputText;
118 // Update anchor if present
119 const editAnchor = this.container.querySelector('#pointer-edit');
120 if (editAnchor && element) {
121 const editHref = editAnchor.dataset.editHref;
122 const elementId = element.id;
124 // get the first 50 characters.
125 const queryContent = element.textContent && element.textContent.substring(0, 50);
126 editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`;
131 export default Pointer;