Skip to content

Commit

Permalink
Fix #1412 compatibility with WebComponents
Browse files Browse the repository at this point in the history
  • Loading branch information
mistic100 committed Sep 7, 2024
1 parent cb90113 commit dc681a7
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 41 deletions.
2 changes: 2 additions & 0 deletions packages/core/src/Viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { ViewerDynamics } from './services/ViewerDynamics';
import { ViewerState } from './services/ViewerState';
import {
Animation,
checkClosedShadowDom,
checkStylesheet,
exitFullscreen,
getAbortError,
Expand Down Expand Up @@ -118,6 +119,7 @@ export class Viewer extends TypedEventTarget<ViewerEvents> {
this.container.classList.add('psv-container');
this.parent.appendChild(this.container);

checkClosedShadowDom(this.parent);
checkStylesheet(this.container, 'core');

this.state = new ViewerState();
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/buttons/MenuButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class MenuButton extends AbstractButton {
content: MENU_TEMPLATE(this.viewer.navbar.collapsed, this.viewer.config.lang.menu),
noMargin: true,
clickHandler: (target) => {
const li = target ? getClosest(target as HTMLElement, 'li') : undefined;
const li = target ? getClosest(target as HTMLElement, '.psv-panel-menu-item') : undefined;
const buttonId = li ? li.dataset[BUTTON_DATA] : undefined;

if (buttonId) {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/components/Panel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CAPTURE_EVENTS_CLASS, ICONS, KEY_CODES } from '../data/constants';
import { PSVError } from '../PSVError';
import { toggleClass } from '../utils';
import { getEventTarget, toggleClass } from '../utils';
import type { Viewer } from '../Viewer';
import { HidePanelEvent, KeypressEvent, ShowPanelEvent } from '../events';
import { AbstractComponent } from './AbstractComponent';
Expand Down Expand Up @@ -174,11 +174,11 @@ export class Panel extends AbstractComponent {

if (config.clickHandler) {
this.state.clickHandler = (e) => {
(config as PanelConfig).clickHandler(e.target as HTMLElement);
(config as PanelConfig).clickHandler(getEventTarget(e));
};
this.state.keyHandler = (e) => {
if (e.key === KEY_CODES.Enter) {
(config as PanelConfig).clickHandler(e.target as HTMLElement);
(config as PanelConfig).clickHandler(getEventTarget(e));
}
};
this.content.addEventListener('click', this.state.clickHandler);
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,11 @@ export type ClickData = {
/**
* Original element which received the click
*/
target: HTMLElement;
target?: HTMLElement;
/**
* Original event which triggered the click
*/
originalEvent?: Event;
/**
* List of THREE scenes objects under the mouse
*/
Expand Down
25 changes: 13 additions & 12 deletions packages/core/src/services/EventsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ import {
Animation,
clone,
distance,
getClosest,
getEventTarget,
getMatchingTarget,
getPosition,
getTouchData,
hasParent,
isEmpty,
throttle,
throttle
} from '../utils';
import { PressHandler } from '../utils/PressHandler';
import type { Viewer } from '../Viewer';
Expand Down Expand Up @@ -156,7 +156,7 @@ export class EventsHandler extends AbstractService {
case 'fullscreenchange': this.__onFullscreenChange(); break;
}

if (!getClosest(evt.target as HTMLElement, '.' + CAPTURE_EVENTS_CLASS)) {
if (!getMatchingTarget(evt, '.' + CAPTURE_EVENTS_CLASS)) {
// prettier-ignore
switch (evt.type) {
case 'mousedown': this.__onMouseDown(evt as MouseEvent); break;
Expand Down Expand Up @@ -243,7 +243,7 @@ export class EventsHandler extends AbstractService {
*/
private __onMouseUp(evt: MouseEvent) {
if (this.step.is(Step.CLICK, Step.MOVING)) {
this.__stopMove(evt.clientX, evt.clientY, evt.target, evt.button === 2);
this.__stopMove(evt.clientX, evt.clientY, evt, evt.button === 2);
}
}

Expand Down Expand Up @@ -271,7 +271,7 @@ export class EventsHandler extends AbstractService {
if (!this.data.longtouchTimeout) {
this.data.longtouchTimeout = setTimeout(() => {
const touch = evt.touches[0];
this.__stopMove(touch.clientX, touch.clientY, touch.target, true);
this.__stopMove(touch.clientX, touch.clientY, evt, true);
this.data.longtouchTimeout = null;
}, LONGTOUCH_DELAY);
}
Expand Down Expand Up @@ -301,7 +301,7 @@ export class EventsHandler extends AbstractService {
this.__stopMove(this.data.mouseX, this.data.mouseY);
} else if (evt.touches.length === 0) {
const touch = evt.changedTouches[0];
this.__stopMove(touch.clientX, touch.clientY, touch.target);
this.__stopMove(touch.clientX, touch.clientY, evt);
}
}
}
Expand Down Expand Up @@ -442,7 +442,7 @@ export class EventsHandler extends AbstractService {
* Stops the movement
* @description If the move threshold was not reached a click event is triggered, otherwise an animation is launched to simulate inertia
*/
private __stopMove(clientX: number, clientY: number, target?: EventTarget, rightclick = false) {
private __stopMove(clientX: number, clientY: number, event?: Event, rightclick = false) {
if (this.step.is(Step.MOVING)) {
if (this.config.moveInertia) {
this.__logMouseMove(clientX, clientY);
Expand All @@ -453,7 +453,7 @@ export class EventsHandler extends AbstractService {
}
} else {
if (this.step.is(Step.CLICK) && !this.__moveThresholdReached(clientX, clientY)) {
this.__doClick(clientX, clientY, target, rightclick);
this.__doClick(clientX, clientY, event, rightclick);
}
this.step.remove(Step.CLICK);
if (!this.step.is(Step.INERTIA)) {
Expand Down Expand Up @@ -518,7 +518,7 @@ export class EventsHandler extends AbstractService {
/**
* Triggers an event with all coordinates when a simple click is performed
*/
private __doClick(clientX: number, clientY: number, target: EventTarget, rightclick = false) {
private __doClick(clientX: number, clientY: number, event?: Event, rightclick = false) {
const boundingRect = this.viewer.container.getBoundingClientRect();

const viewerX = clientX - boundingRect.left;
Expand All @@ -532,7 +532,8 @@ export class EventsHandler extends AbstractService {

const data: ClickData = {
rightclick: rightclick,
target: target as HTMLElement,
originalEvent: event,
target: getEventTarget(event),
clientX,
clientY,
viewerX,
Expand Down Expand Up @@ -576,7 +577,7 @@ export class EventsHandler extends AbstractService {
* Trigger events for observed THREE objects
*/
private __handleObjectsEvents(evt: MouseEvent) {
if (!isEmpty(this.state.objectsObservers) && hasParent(evt.target as HTMLElement, this.viewer.container)) {
if (!isEmpty(this.state.objectsObservers) && evt.composedPath().includes(this.viewer.container)) {
const viewerPos = getPosition(this.viewer.container);

const viewerPoint: Point = {
Expand Down
25 changes: 24 additions & 1 deletion packages/core/src/utils/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function hasParent(el: HTMLElement, parent: Element): boolean {
}

/**
* Gets the closest parent (can by itself)
* Gets the closest parent matching the selector (can by itself)
*/
export function getClosest(el: HTMLElement, selector: string): HTMLElement | null {
// When el is document or window, the matches does not exist
Expand All @@ -76,6 +76,29 @@ export function getClosest(el: HTMLElement, selector: string): HTMLElement | nul
return null;
}

/**
* Returns the first element of the event' composedPath
*/
export function getEventTarget(e: Event): HTMLElement | null {
return e?.composedPath()[0] as HTMLElement || null;
}

/**
* Returns the first element of the event's composedPath matching the selector
*/
export function getMatchingTarget(e: Event, selector: string): HTMLElement | null {
if (!e) {
return null;
}
return e.composedPath().find((el) => {
if (!(el instanceof HTMLElement) && !(el instanceof SVGElement)) {
return false;
}

return el.matches(selector);
}) as HTMLElement;
}

/**
* Gets the position of an element in the viewport without reflow
* Will gives the same result as getBoundingClientRect() as soon as there are no CSS transforms
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/utils/psv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,16 @@ export function checkVersion(name: string, version: string, coreVersion: string)
console.error(`PhotoSphereViewer: @photo-sphere-viewer/${name} is in version ${version} but @photo-sphere-viewer/core is in version ${coreVersion}`);
}
}

/**
* Checks if the viewer is not used insude a closed shadow DOM
*/
export function checkClosedShadowDom(el: Node) {
do {
if (el instanceof ShadowRoot && el.mode === 'closed') {
console.error(`PhotoSphereViewer: closed shadow DOM detected, the viewer might not work as expected`);
return;
}
el = el.parentNode;
} while (el);
}
2 changes: 1 addition & 1 deletion packages/gallery-plugin/src/GalleryComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export class GalleryComponent extends AbstractComponent {
// prevent click on drag
const currentMouse = this.isAboveBreakpoint ? (e as MouseEvent).clientX : (e as MouseEvent).clientY;
if (Math.abs(this.state.initMouse - currentMouse) < 10) {
const item = utils.getClosest(e.target as HTMLElement, `[data-${GALLERY_ITEM_DATA_KEY}]`);
const item = utils.getMatchingTarget(e, `.psv-gallery-item`);
if (item) {
this.plugin.__click(item.dataset[GALLERY_ITEM_DATA]);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/map-plugin/src/components/MapComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export class MapComponent extends AbstractComponent {
}

handleEvent(e: Event) {
if (utils.getClosest(e.target as HTMLElement, `.${CONSTANTS.CAPTURE_EVENTS_CLASS}:not(.psv-map)`)) {
if (utils.getMatchingTarget(e, `.${CONSTANTS.CAPTURE_EVENTS_CLASS}:not(.psv-map)`)) {
return;
}
switch (e.type) {
Expand Down Expand Up @@ -213,7 +213,7 @@ export class MapComponent extends AbstractComponent {
if (this.state.mousedown) {
this.__move(event.clientX, event.clientY);
e.stopPropagation();
} else if (e.target === this.canvas) {
} else if (e.composedPath().includes(this.canvas)) {
this.__handleHotspots(event.clientX, event.clientY);
}
break;
Expand Down Expand Up @@ -246,7 +246,7 @@ export class MapComponent extends AbstractComponent {
this.state.mousedown = false;
e.stopPropagation();
}
if (e.target === this.canvas) {
if (e.composedPath().includes(this.canvas)) {
this.__clickHotspot(mouse.clientX, mouse.clientY);
}
break;
Expand Down
2 changes: 1 addition & 1 deletion packages/map-plugin/src/components/MapZoomToolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class MapZoomToolbar extends AbstractComponent {
switch (e.type) {
case 'mousedown':
case 'touchstart': {
const button = utils.getClosest(e.target as HTMLElement, 'svg');
const button = utils.getMatchingTarget(e, 'svg[data-delta]');
const delta: string = button?.dataset['delta'];
if (delta) {
cancelAnimationFrame(this.animation);
Expand Down
22 changes: 14 additions & 8 deletions packages/markers-plugin/src/MarkersPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,23 @@ export class MarkersPlugin extends AbstractConfigurablePlugin<
}
break;

case 'mouseenter':
this.__onEnterMarker(e as MouseEvent, this.__getTargetMarker(e.target as HTMLElement));
case 'mouseenter': {
const marker = this.__getTargetMarker(utils.getEventTarget(e));
this.__onEnterMarker(e as MouseEvent, marker);
break;
}

case 'mouseleave':
this.__onLeaveMarker(this.__getTargetMarker(e.target as HTMLElement));
case 'mouseleave': {
const marker = this.__getTargetMarker(utils.getEventTarget(e));
this.__onLeaveMarker(marker);
break;
}

case 'mousemove':
this.__onHoverMarker(e as MouseEvent, this.__getTargetMarker(e.target as HTMLElement, true));
case 'mousemove': {
const marker = this.__getTargetMarker(utils.getEventTarget(e), true);
this.__onHoverMarker(e as MouseEvent, marker);
break;
}

case 'contextmenu':
e.preventDefault();
Expand Down Expand Up @@ -602,7 +608,7 @@ export class MarkersPlugin extends AbstractConfigurablePlugin<
content: MARKERS_LIST_TEMPLATE(markers, this.viewer.config.lang[MarkersButton.id]),
noMargin: true,
clickHandler: (target) => {
const li = utils.getClosest(target, 'li');
const li = utils.getClosest(target, '.psv-panel-menu-item');
const markerId = li ? li.dataset[MARKER_DATA] : undefined;

if (markerId) {
Expand Down Expand Up @@ -797,7 +803,7 @@ export class MarkersPlugin extends AbstractConfigurablePlugin<
}

// the marker could have been deleted in an event handler
if (this.markers[marker.id]) {
if (this.markers[marker.id] && !e.data.rightclick) {
if (marker.config.tooltip?.trigger === 'click') {
if (marker.tooltip) {
this.hideMarkerTooltip(marker.id);
Expand Down
3 changes: 3 additions & 0 deletions packages/overlays-plugin/src/OverlaysPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ export class OverlaysPlugin extends AbstractConfigurablePlugin<
this.clearOverlays();
}
} else if (e instanceof events.ClickEvent) {
if (e.data.rightclick) {
return false;
}
const overlay = e.data.objects
.map((o) => o.userData[OVERLAY_DATA] as ParsedOverlayConfig['id'])
.filter((o) => !!o)
Expand Down
2 changes: 1 addition & 1 deletion packages/plan-plugin/src/components/PlanComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export class PlanComponent extends AbstractComponent {
}

handleEvent(e: Event) {
if (utils.getClosest(e.target as HTMLElement, `.${CONSTANTS.CAPTURE_EVENTS_CLASS}:not(.psv-plan)`)) {
if (utils.getMatchingTarget(e, `.${CONSTANTS.CAPTURE_EVENTS_CLASS}:not(.psv-plan)`)) {
return;
}
switch (e.type) {
Expand Down
8 changes: 4 additions & 4 deletions packages/settings-plugin/src/SettingsComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class SettingsComponent extends AbstractComponent {
handleEvent(e: Event) {
switch (e.type) {
case 'click':
this.__click(e.target as HTMLElement);
this.__click(e);
break;

case 'transitionend':
Expand All @@ -41,7 +41,7 @@ export class SettingsComponent extends AbstractComponent {
this.plugin.hideSettings();
break;
case CONSTANTS.KEY_CODES.Enter:
this.__click(e.target as HTMLElement);
this.__click(e);
break;
}
}
Expand Down Expand Up @@ -87,8 +87,8 @@ export class SettingsComponent extends AbstractComponent {
/**
* Handle clicks on items
*/
private __click(element: HTMLElement) {
const li = utils.getClosest(element, 'li');
private __click(e: Event) {
const li = utils.getMatchingTarget(e, '.psv-settings-item');
if (!li) {
return;
}
Expand Down
13 changes: 8 additions & 5 deletions packages/virtual-tour-plugin/src/ArrowsRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,28 +96,31 @@ export class ArrowsRenderer extends AbstractComponent {
this.render()
break;
case events.ClickEvent.type: {
const link = this.getTargetLink((e as events.ClickEvent).data.target, true);
if ((e as events.ClickEvent).data.rightclick) {
break;
}
const link = this.__getTargetLink((e as events.ClickEvent).data.target, true);
if (link) {
this.plugin.setCurrentNode(link.nodeId, null, link);
}
break;
}
case 'mouseenter': {
const link = this.getTargetLink(e.target as HTMLElement);
const link = this.__getTargetLink(utils.getEventTarget(e));
if (link) {
this.plugin.__onEnterArrow(link, e as MouseEvent);
}
break;
}
case 'mouseleave': {
const link = this.getTargetLink(e.target as HTMLElement);
const link = this.__getTargetLink(utils.getEventTarget(e));
if (link) {
this.plugin.__onLeaveArrow(link);
}
break;
}
case 'mousemove': {
const link = this.getTargetLink(e.target as HTMLElement, true);
const link = this.__getTargetLink(utils.getEventTarget(e), true);
if (link) {
this.plugin.__onHoverArrow(e as MouseEvent);
}
Expand Down Expand Up @@ -262,7 +265,7 @@ export class ArrowsRenderer extends AbstractComponent {
}
}

private getTargetLink(target: HTMLElement, closest = false): VirtualTourLink {
private __getTargetLink(target: HTMLElement, closest = false): VirtualTourLink {
const target2 = closest ? utils.getClosest(target, '.psv-virtual-tour-link') : target;
return target2 ? (target2 as any)[LINK_DATA] : undefined;
}
Expand Down

0 comments on commit dc681a7

Please sign in to comment.