import './popover.html'; import { Blaze } from 'meteor/blaze'; import { Template } from 'meteor/templating'; import _ from 'underscore'; import { messageBox } from './messageBox'; import { MessageAction } from './MessageAction'; import { isRtl } from '../../../utils/client'; export const popover = { renderedPopover: null, open({ currentTarget, ...config }) { // Popover position must be computed as soon as possible, avoiding DOM changes over currentTarget const data = { targetRect: currentTarget?.getBoundingClientRect(), ...config, }; this.renderedPopover = Blaze.renderWithData(Template.popover, data, document.body); }, close() { if (!this.renderedPopover) { return false; } Blaze.remove(this.renderedPopover); const { activeElement } = this.renderedPopover.dataVar.curValue; if (activeElement) { $(activeElement).removeClass('active'); } }, }; Template.popover.helpers({ hasAction() { return !!this.action; }, }); Template.popover.onRendered(function () { if (this.data.onRendered) { this.data.onRendered(); } $('.rc-popover').click(function (e) { if (e.currentTarget === e.target) { popover.close(); } }); const { offsetVertical = 0, offsetHorizontal = 0 } = this.data; const { activeElement } = this.data; const originalWidth = window.innerWidth; const popoverContent = this.firstNode.children[0]; const position = _.throttle(() => { const direction = typeof this.data.direction === 'function' ? this.data.direction() : this.data.direction; const verticalDirection = /top/.test(direction) ? 'top' : 'bottom'; const rtlDirection = isRtl() ^ /inverted/.test(direction) ? 'left' : 'right'; const rightDirection = /right/.test(direction) ? 'right' : rtlDirection; const horizontalDirection = /left/.test(direction) ? 'left' : rightDirection; const position = typeof this.data.position === 'function' ? this.data.position() : this.data.position; const customCSSProperties = typeof this.data.customCSSProperties === 'function' ? this.data.customCSSProperties() : this.data.customCSSProperties; const mousePosition = typeof this.data.mousePosition === 'function' ? this.data.mousePosition() : this.data.mousePosition || { x: this.data.targetRect[horizontalDirection === 'left' ? 'right' : 'left'], y: this.data.targetRect[verticalDirection], }; const offsetWidth = offsetHorizontal * (horizontalDirection === 'left' ? 1 : -1); const offsetHeight = offsetVertical * (verticalDirection === 'bottom' ? 1 : -1); const leftDiff = window.innerWidth - originalWidth; if (position) { popoverContent.style.top = `${position.top}px`; popoverContent.style.left = `${position.left + leftDiff}px`; } else { const clientHeight = this.data.targetRect.height; const popoverWidth = popoverContent.offsetWidth; const popoverHeight = popoverContent.offsetHeight; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; let top = mousePosition.y - clientHeight + offsetHeight; if (verticalDirection === 'top') { top = mousePosition.y - popoverHeight + offsetHeight; if (top < 0) { top = 10 + offsetHeight; } } if (top + popoverHeight > windowHeight) { top = windowHeight - 10 - popoverHeight - offsetHeight; } let left = mousePosition.x - popoverWidth + offsetWidth; if (horizontalDirection === 'right') { left = mousePosition.x + offsetWidth; } if (left + popoverWidth >= windowWidth) { left = mousePosition.x - popoverWidth + offsetWidth; } if (left <= 0) { left = mousePosition.x + offsetWidth; } popoverContent.style.top = `${top}px`; popoverContent.style.left = `${left + leftDiff}px`; } if (customCSSProperties) { Object.keys(customCSSProperties).forEach(function (property) { popoverContent.style[property] = customCSSProperties[property]; }); } const realTop = Number(popoverContent.style.top.replace('px', '')); if (realTop + popoverContent.offsetHeight > window.innerHeight) { popoverContent.style.overflow = 'scroll'; popoverContent.style.bottom = 0; popoverContent.className = 'rc-popover__content rc-popover__content-scroll'; } if (activeElement) { $(activeElement).addClass('active'); } popoverContent.style.opacity = 1; }, 50); const observer = new MutationObserver(position); observer.observe(popoverContent, { childList: true, subtree: true }); $(window).on('resize', position); position(); this.position = position; this.observer = observer; this.firstNode.style.visibility = 'visible'; }); Template.popover.onDestroyed(function () { if (this.data.onDestroyed) { this.data.onDestroyed(); } $(window).off('resize', this.position); this.observer?.disconnect(); }); Template.popover.events({ 'click .js-action'(e, instance) { !this.action || this.action.call(this, e, instance.data.data); popover.close(); }, 'click .js-close'() { popover.close(); }, 'click [data-type="messagebox-action"]'(event, t) { const { id } = event.currentTarget.dataset; const actions = messageBox.actions.getById(id); actions .filter(({ action }) => !!action) .forEach(({ action }) => { action.call(null, { ...t.data.data, event, }); }); popover.close(); }, 'click [data-type="message-action"]'(e, t) { const button = MessageAction.getButtonById(e.currentTarget.dataset.id); if ((button != null ? button.action : undefined) != null) { e.stopPropagation(); e.preventDefault(); const { tabBar, rid } = t.data.instance; button.action.call(t.data.data, e, { tabBar, rid }); popover.close(); return false; } }, }); Template.popover.helpers({ isSafariIos: /iP(ad|hone|od).+Version\/[\d\.]+.*Safari/i.test(navigator.userAgent), });