diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 9291f329b6..64d02191fb 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -586,7 +586,7 @@ export default class ElementWrapper extends Wrapper { ); block.chunks.destroy.push( - b`${resize_listener}.cancel();` + b`${resize_listener}();` ); } else { block.event_listeners.push( diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 9ab9a4395f..bf8fc1f5a0 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -57,7 +57,7 @@ export function empty() { return text(''); } -export function listen(node: Node, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions) { +export function listen(node: EventTarget, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions) { node.addEventListener(event, handler, options); return () => node.removeEventListener(event, handler, options); } @@ -234,37 +234,61 @@ export function select_multiple_value(select) { return [].map.call(select.querySelectorAll(':checked'), option => option.__value); } -export function add_resize_listener(element, fn) { - if (getComputedStyle(element).position === 'static') { - element.style.position = 'relative'; +// unfortunately this can't be a constant as that wouldn't be tree-shakeable +// so we cache the result instead +let crossorigin: boolean; + +export function is_crossorigin() { + if (crossorigin === undefined) { + crossorigin = false; + + try { + if (typeof window !== 'undefined' && window.parent) { + void window.parent.document; + } + } catch (error) { + crossorigin = true; + } } - const object = document.createElement('object'); - object.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'); - object.setAttribute('aria-hidden', 'true'); - object.type = 'text/html'; - object.tabIndex = -1; + return crossorigin; +} - let win; +export function add_resize_listener(node: HTMLElement, fn: () => void) { + const computed_style = getComputedStyle(node); + const z_index = (parseInt(computed_style.zIndex) || 0) - 1; - object.onload = () => { - win = object.contentDocument.defaultView; - win.addEventListener('resize', fn); - }; + if (computed_style.position === 'static') { + node.style.position = 'relative'; + } - if (/Trident/.test(navigator.userAgent)) { - element.appendChild(object); - object.data = 'about:blank'; + const iframe = element('iframe'); + iframe.setAttribute('style', + `display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; ` + + `overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: ${z_index};` + ); + iframe.setAttribute('aria-hidden', 'true'); + iframe.tabIndex = -1; + + let unsubscribe: () => void; + + if (is_crossorigin()) { + iframe.src = `data:text/html,`; + unsubscribe = listen(window, 'message', (event: MessageEvent) => { + if (event.source === iframe.contentWindow) fn(); + }); } else { - object.data = 'about:blank'; - element.appendChild(object); + iframe.src = 'about:blank'; + iframe.onload = () => { + unsubscribe = listen(iframe.contentWindow, 'resize', fn); + }; } - return { - cancel: () => { - win && win.removeEventListener && win.removeEventListener('resize', fn); - element.removeChild(object); - } + append(node, iframe); + + return () => { + detach(iframe); + if (unsubscribe) unsubscribe(); }; } @@ -316,4 +340,4 @@ export class HtmlTag { d() { this.n.forEach(detach); } -} \ No newline at end of file +} diff --git a/test/js/samples/bind-width-height/expected.js b/test/js/samples/bind-width-height/expected.js index 5c1888b7db..4848704c4b 100644 --- a/test/js/samples/bind-width-height/expected.js +++ b/test/js/samples/bind-width-height/expected.js @@ -30,7 +30,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(div); - div_resize_listener.cancel(); + div_resize_listener(); } }; } diff --git a/test/js/samples/video-bindings/expected.js b/test/js/samples/video-bindings/expected.js index 3cad17b34d..9c5467e1a0 100644 --- a/test/js/samples/video-bindings/expected.js +++ b/test/js/samples/video-bindings/expected.js @@ -59,7 +59,7 @@ function create_fragment(ctx) { o: noop, d(detaching) { if (detaching) detach(video); - video_resize_listener.cancel(); + video_resize_listener(); run_all(dispose); } }; diff --git a/test/runtime/samples/binding-width-height-a11y/_config.js b/test/runtime/samples/binding-width-height-a11y/_config.js index 5ab4a7ade7..93856bf0f6 100644 --- a/test/runtime/samples/binding-width-height-a11y/_config.js +++ b/test/runtime/samples/binding-width-height-a11y/_config.js @@ -1,8 +1,8 @@ export default { async test({ assert, target }) { - const object = target.querySelector('object'); + const iframe = target.querySelector('iframe'); - assert.equal(object.getAttribute('aria-hidden'), "true"); - assert.equal(object.getAttribute('tabindex'), "-1"); + assert.equal(iframe.getAttribute('aria-hidden'), "true"); + assert.equal(iframe.getAttribute('tabindex'), "-1"); } };