diff --git a/src/compiler/compile/render-dom/wrappers/Element/index.ts b/src/compiler/compile/render-dom/wrappers/Element/index.ts index 488dc01504d0..bcf90471c48d 100644 --- a/src/compiler/compile/render-dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render-dom/wrappers/Element/index.ts @@ -481,15 +481,8 @@ export default class ElementWrapper extends Wrapper { group.events.forEach(name => { if (name === 'resize') { // special case - const resize_listener = block.get_unique_name(`${this.var}_resize_listener`); - block.add_variable(resize_listener); - - block.builders.mount.add_line( - `${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));` - ); - - block.builders.destroy.add_line( - `${resize_listener}.cancel();` + block.event_listeners.push( + `@listen_resize_with_iframe(${this.var}, ${callee}.bind(${this.var}))` ); } else { block.event_listeners.push( diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index f65d07117ce9..48ca115946c7 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -70,7 +70,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); } @@ -215,35 +215,57 @@ 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 it 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) { + try { + if (typeof window === 'undefined' || !window.parent || window.parent.document) { + crossorigin = false; + } + } 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.type = 'text/html'; + return crossorigin; +} - let win; +export function listen_resize_with_iframe(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'; + } + + 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};` + ); + + let unsubscribe: () => void; - if (/Trident/.test(navigator.userAgent)) { - element.appendChild(object); - object.data = 'about:blank'; + 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(); }; } diff --git a/test/js/samples/bind-width-height/expected.js b/test/js/samples/bind-width-height/expected.js index 2ef190588f3e..8851538551b1 100644 --- a/test/js/samples/bind-width-height/expected.js +++ b/test/js/samples/bind-width-height/expected.js @@ -2,28 +2,28 @@ import { SvelteComponent, add_render_callback, - add_resize_listener, detach, element, init, insert, + listen_resize_with_iframe, noop, safe_not_equal } from "svelte/internal"; function create_fragment(ctx) { - var div, div_resize_listener; + var div, dispose; return { c() { div = element("div"); div.textContent = "some content"; add_render_callback(() => ctx.div_resize_handler.call(div)); + dispose = listen_resize_with_iframe(div, ctx.div_resize_handler.bind(div)); }, m(target, anchor) { insert(target, div, anchor); - div_resize_listener = add_resize_listener(div, ctx.div_resize_handler.bind(div)); }, p: noop, @@ -35,7 +35,7 @@ function create_fragment(ctx) { detach(div); } - div_resize_listener.cancel(); + dispose(); } }; }