@atlaskit/modal-dialog
Version:
A modal dialog displays content that requires user interaction, in a layer above the page.
116 lines (114 loc) • 3.22 kB
JavaScript
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
/**
* Set a `style` property on a `HTMLElement`
*
* @returns a `cleanup` function to restore the `style` property to it's original state
*/
function setStyle(el, {
property,
rule,
priority = ''
}) {
const originalValue = el.style.getPropertyValue(property);
const originalPriority = el.style.getPropertyPriority(property);
el.style.setProperty(property, rule, priority);
return function cleanup() {
el.style.setProperty(property, originalValue, originalPriority);
};
}
function hasSameOrigin(href1, href2) {
let url1;
let url2;
try {
url1 = new URL(href1);
url2 = new URL(href2);
} catch {
// failed to parse a href
return false;
}
// https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
return url1.protocol === url2.protocol && url1.host === url2.host && url1.port === url2.port;
}
function isIframeOnAnotherDomain(iframe) {
/**
* iframe with contents defined inline. Runs on the current origin.
* `<iframe srcdoc="<!doctype html><body>Hello</body>" />`
*/
if (iframe.srcdoc) {
return false;
}
/**
* iframe with contents defined inline. Runs on the current origin.
* `<iframe src={`data:text/html;charset=utf-8,${encodeURI('<!doctype html><body>Hello</body>')}`} />`
*/
if (iframe.src.startsWith('data:')) {
return false;
}
return !hasSameOrigin(window.location.href, iframe.src);
}
const registry = new Map();
function applyFix(watchForEndOfInteraction) {
const iframes = Array.from(document.querySelectorAll('iframe')).filter(isIframeOnAnotherDomain);
const cleanups = iframes.map(iframe => {
let entry = registry.get(iframe);
if (!entry) {
entry = {
reset: setStyle(iframe, {
property: 'pointer-events',
rule: 'none',
priority: 'important'
}),
count: 1
};
registry.set(iframe, entry);
} else {
// pointer-events:none already applied to the iframe
// increment how many things requested the fix
entry.count++;
}
return function cleanup() {
entry.count--;
if (entry.count < 1) {
entry.reset();
registry.delete(iframe);
}
};
});
function stop() {
cleanupWatcher();
combine(...cleanups)();
}
const cleanupWatcher = watchForEndOfInteraction({
stop
});
}
export function makeFixForAdapter({
watchForInteractionStart,
watchForInteractionEnd
}) {
let registrationCount = 0;
let stopWatchingInteractionStart = null;
function start() {
applyFix(watchForInteractionEnd);
}
function registerUsage() {
if (registrationCount === 0) {
stopWatchingInteractionStart = watchForInteractionStart({
start
});
}
registrationCount++;
return function unregisterUsage() {
var _stopWatchingInteract;
registrationCount--;
if (registrationCount !== 0) {
return;
}
(_stopWatchingInteract = stopWatchingInteractionStart) === null || _stopWatchingInteract === void 0 ? void 0 : _stopWatchingInteract();
stopWatchingInteractionStart = null;
};
}
return {
registerUsage
};
}