X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/ff3fb2ebb91ccbe186dc82d69b6351bbf82eacb7..refs/pull/4254/head:/resources/js/components/pointer.js diff --git a/resources/js/components/pointer.js b/resources/js/components/pointer.js index a74422ce4..e2e2ceca7 100644 --- a/resources/js/components/pointer.js +++ b/resources/js/components/pointer.js @@ -1,13 +1,13 @@ -import * as DOM from "../services/dom"; -import Clipboard from "clipboard/dist/clipboard.min"; +import * as DOM from '../services/dom'; +import {Component} from './component'; +import {copyTextToClipboard} from '../services/clipboard'; -/** - * @extends Component - */ -class Pointer { +export class Pointer extends Component { setup() { this.container = this.$el; + this.input = this.$refs.input; + this.button = this.$refs.button; this.pageId = this.$opts.pageId; // Instance variables @@ -16,22 +16,18 @@ class Pointer { this.pointerModeLink = true; this.pointerSectionId = ''; - this.init(); this.setupListeners(); } - init() { - // Set up pointer by removing it - this.container.parentNode.removeChild(this.container); - - // Set up clipboard - new Clipboard(this.container.querySelector('button')); - } - setupListeners() { + // Copy on copy button click + this.button.addEventListener('click', () => { + copyTextToClipboard(this.input.value); + }); + // Select all contents on input click - DOM.onChildEvent(this.container, 'input', 'click', (event, input) => { - input.select(); + this.input.addEventListener('click', event => { + this.input.select(); event.stopPropagation(); }); @@ -50,10 +46,9 @@ class Pointer { }); // Hide pointer when clicking away - DOM.onEvents(document.body, ['click', 'focus'], event => { + DOM.onEvents(document.body, ['click', 'focus'], () => { if (!this.showing || this.isSelection) return; - this.container.parentElement.removeChild(this.container); - this.showing = false; + this.hidePointer(); }); // Show pointer when selecting a single block of tagged content @@ -67,6 +62,11 @@ class Pointer { }); } + hidePointer() { + this.container.style.display = null; + this.showing = false; + } + /** * Move and display the pointer at the given element, targeting the given screen x-position if possible. * @param {Element} element @@ -80,23 +80,29 @@ class Pointer { this.pointerSectionId = element.id; this.updateForTarget(element); - element.parentNode.insertBefore(this.container, element); this.container.style.display = 'block'; + const targetBounds = element.getBoundingClientRect(); + const pointerBounds = this.container.getBoundingClientRect(); + + const xTarget = Math.min(Math.max(xPosition, targetBounds.left), targetBounds.right); + const xOffset = xTarget - (pointerBounds.width / 2); + const yOffset = (targetBounds.top - pointerBounds.height) - 16; + + this.container.style.left = `${xOffset}px`; + this.container.style.top = `${yOffset}px`; + this.showing = true; this.isSelection = true; - // Set pointer to sit near mouse-up position - requestAnimationFrame(() => { - const bookMarkBounds = element.getBoundingClientRect(); - const pointerLeftOffset = Math.max((xPosition - bookMarkBounds.left - 164), 0); - const pointerLeftOffsetPercent = (pointerLeftOffset / bookMarkBounds.width) * 100; - - this.container.children[0].style.left = pointerLeftOffsetPercent + '%'; + setTimeout(() => { + this.isSelection = false; + }, 100); - setTimeout(() => { - this.isSelection = false; - }, 100); - }); + const scrollListener = () => { + this.hidePointer(); + window.removeEventListener('scroll', scrollListener, {passive: true}); + }; + window.addEventListener('scroll', scrollListener, {passive: true}); } /** @@ -106,15 +112,15 @@ class Pointer { updateForTarget(element) { let inputText = this.pointerModeLink ? window.baseUrl(`/link/${this.pageId}#${this.pointerSectionId}`) : `{{@${this.pageId}#${this.pointerSectionId}}}`; if (this.pointerModeLink && !inputText.startsWith('http')) { - inputText = window.location.protocol + "//" + window.location.host + inputText; + inputText = `${window.location.protocol}//${window.location.host}${inputText}`; } - this.container.querySelector('input').value = inputText; + this.input.value = inputText; // Update anchor if present const editAnchor = this.container.querySelector('#pointer-edit'); if (editAnchor && element) { - const editHref = editAnchor.dataset.editHref; + const {editHref} = editAnchor.dataset; const elementId = element.id; // get the first 50 characters. @@ -122,6 +128,5 @@ class Pointer { editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`; } } -} -export default Pointer; \ No newline at end of file +}