UNPKG

@openreplay/tracker-assist

Version:

Tracker plugin for screen assistance through the WebRTC

187 lines (186 loc) 7.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_js_1 = require("./utils.js"); class Mouse { constructor(agentName, onDragCamera) { this.agentName = agentName; this.onDragCamera = onDragCamera; this.position = [0, 0,]; this.isDragging = false; this.pScrEl = document.scrollingElement || document.documentElement; // Is it always correct this.lastScrEl = null; this.resetLastScrEl = () => { this.lastScrEl = null; }; this.handleWScroll = e => { if (e.target !== this.lastScrEl && this.lastScrEl !== 'window') { this.resetLastScrEl(); } }; this.mouse = document.createElement('div'); const agentBubble = document.createElement('div'); const svg = '<svg version="1.1" width="20" height="20" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" xml:space="" viewBox="8.2 4.9 11.6 18.2"><polygon fill="#FFFFFF" points="8.2,20.9 8.2,4.9 19.8,16.5 13,16.5 12.6,16.6 "></polygon><polygon fill="#FFFFFF" points="17.3,21.6 13.7,23.1 9,12 12.7,10.5 "></polygon><rect x="12.5" y="13.6" transform="matrix(0.9221 -0.3871 0.3871 0.9221 -5.7605 6.5909)" width="2" height="8"></rect><polygon points="9.2,7.3 9.2,18.5 12.2,15.6 12.6,15.5 17.4,15.5 "></polygon></svg>'; this.mouse.innerHTML = svg; this.mouse.setAttribute('data-openreplay-hidden', ''); Object.assign(agentBubble.style, { position: 'absolute', padding: '4px 5px', borderRadius: '4px', backgroundColor: '#394EFF', color: 'white', bottom: '-20px', left: '65%', fontSize: '12px', whiteSpace: 'nowrap', }); this.onDragCamera = onDragCamera; const agentNameStr = this.agentName ? this.agentName.length > 10 ? this.agentName.slice(0, 9) + '...' : this.agentName : 'Agent'; agentBubble.innerHTML = `<span>${agentNameStr}</span>`; this.mouse.appendChild(agentBubble); Object.assign(this.mouse.style, { position: 'absolute', zIndex: '999998', pointerEvents: 'none', // adjusting the svg empty space marginTop: '-1px', marginLeft: '-2px', }); } mount() { document.body.appendChild(this.mouse); window.addEventListener('scroll', this.handleWScroll); window.addEventListener('resize', this.resetLastScrEl); } move(pos) { if (this.position[0] !== pos[0] || this.position[1] !== pos[1]) { this.resetLastScrEl(); } this.position = pos; Object.assign(this.mouse.style, { left: `${pos[0] || 0}px`, top: `${pos[1] || 0}px`, }); } getPosition() { return this.position; } click(pos) { const el = document.elementFromPoint(pos[0], pos[1]); if (el instanceof HTMLElement || el instanceof SVGElement) { try { const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true, view: window, clientX: pos[0], clientY: pos[1] }); el.dispatchEvent(clickEvent); } catch (e) { console.error(e); // @ts-ignore el.click && el.click(); } el.focus(); return el; } return null; } startDrag(pos) { this.move(pos); const el = document.elementFromPoint(pos[0], pos[1]); if (el) { const downEvt = new MouseEvent("mousedown", { bubbles: true, cancelable: true, clientX: pos[0], clientY: pos[1], buttons: 1, }); el.dispatchEvent(downEvt); this.isDragging = true; } } drag(pos) { const [x, y, dx, dy] = pos; this.move([x, y]); if (!this.isDragging) return; const el = document.elementFromPoint(x, y); if (el) { const moveEvt = new MouseEvent("mousemove", { bubbles: true, cancelable: true, clientX: x, clientY: y, buttons: 1, }); el.dispatchEvent(moveEvt); if ((0, utils_js_1.hasOpenreplayAttribute)(el, 'draggable') && this.onDragCamera) { this.onDragCamera(dx, dy); } } } stopDrag() { if (!this.isDragging) return; const [x, y] = this.position; const el = document.elementFromPoint(x, y); if (el) { const upEvt = new MouseEvent("mouseup", { bubbles: true, cancelable: true, clientX: x, clientY: y, buttons: 0, }); el.dispatchEvent(upEvt); } this.isDragging = false; } scroll(delta) { // what would be the browser-like logic? const [mouseX, mouseY,] = this.position; const [dX, dY,] = delta; let el = this.lastScrEl; // Scroll the same one if (el instanceof Element) { el.scrollLeft += dX; el.scrollTop += dY; return; // TODO: if not scrolled } if (el === 'window') { window.scroll(this.pScrEl.scrollLeft + dX, this.pScrEl.scrollTop + dY); return; } el = document.elementFromPoint(mouseX - this.pScrEl.scrollLeft, mouseY - this.pScrEl.scrollTop); while (el) { // el.scrollTopMax > 0 // available in firefox if (el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth) { const styles = getComputedStyle(el); if (styles.overflow.indexOf('scroll') >= 0 || styles.overflow.indexOf('auto') >= 0) { // returns true for body in habr.com but it's not scrollable const esl = el.scrollLeft; const est = el.scrollTop; el.scrollLeft += dX; el.scrollTop += dY; if (esl !== el.scrollLeft || est !== el.scrollTop) { // doesn't work if the scroll-behavior is "smooth" this.lastScrEl = el; return; } } } el = el.parentElement; } // If not scrolled window.scroll(this.pScrEl.scrollLeft + dX, this.pScrEl.scrollTop + dY); this.lastScrEl = 'window'; } remove() { if (this.mouse.parentElement) { document.body.removeChild(this.mouse); } window.removeEventListener('scroll', this.handleWScroll); window.removeEventListener('resize', this.resetLastScrEl); } } exports.default = Mouse;