UNPKG

joicomponents

Version:

Design patterns to build native web components

165 lines (151 loc) 5.9 kB
<script type="module"> const innerTemplate = ` <style> html { } * { box-sizing: border-box; margin: 0; padding: 0; } body { display: inline-block; } </style> <script>(function(){ var pW = undefined; var pH = undefined; const s = document.styleSheets[0].cssRules[0]; window.addEventListener("message", function(e){ const dim = JSON.parse(e.data); s.style.width = dim.width + "px"; s.style.height = dim.height + "px"; alertSize(); }); function alertSize() { const html = document.children[0]; const body = html.children[1]; //scrollHeight is always as big as offsetHeight. If the offsetHeight of the body is capped at the offsetHeight of the parent, then use scrollHeight let height = body.offsetHeight === html.offsetHeight ? body.scrollHeight : body.offsetHeight; let width = body.offsetWidth === html.offsetWidth ? body.scrollWidth : body.offsetWidth; // debugger; if (pW === width && pH === height) return setTimeout(alertSize, 150); // debugger; pW = width; pH = height; parent.postMessage(JSON.stringify({width, height}), "*"); requestAnimationFrame(alertSize); } document.addEventListener("DOMContentLoaded", alertSize); })();</scrip` + `t>`; const outerTemplate = document.createElement("template"); outerTemplate.innerHTML = ` <style> :host, iframe { box-sizing: border-box; border: none; margin: 0; padding: 0; } :host{ overflow: visible; display: inline-block; } iframe { overflow: hidden; height: 0; /*initial value only, will be overwritten later*/ width: 0; /*initial value only, will be overwritten later*/ } </style> <iframe sandbox="allow-scripts" scrolling="no" frameborder="0"></iframe>`; import {LayoutAttributesMixin} from "https://unpkg.com/joicomponents@1.2.31/src/layout/LayoutAttributesMixin.js"; class OverflowIframe extends LayoutAttributesMixin(HTMLElement) { constructor() { super(); this.attachShadow({mode: "open"}); this.shadowRoot.appendChild(outerTemplate.content.cloneNode(true)); this._iframe = this.shadowRoot.children[1]; window.addEventListener("message", this.onMessage.bind(this)); this._ready = false; this._iframeWidth; this._iframeHeight; } static get observedAttributes() { return ["srcdoc"/*, "_layout-width", "_layout-height"*/]; } attributeChangedCallback(name, oldValue, newValue) { // if (name === "_layout-width" || name === "_layout-height") { // if (!this.hasAttribute("_layout-width") || !this.hasAttribute("_layout-height")) // return console.log(false, name, newValue); // let width = Math.min(window.innerWidth, this.offsetWidth); // let height = Math.min(window.innerHeight, this.offsetHeight); // this.sendMessage(JSON.stringify({width, height})); // } // if (name === "_layout-width" || name === "_layout-width") { // console.log(name, newValue); // this.sendMessage(JSON.stringify({width: newValue})); // } if (name === "srcdoc") { const src = innerTemplate + (newValue || ""); let blob = new Blob([src], {type: "text/html"}); this._iframe.setAttribute("src", URL.createObjectURL(blob)); } } onMessage(e) { if (e.source !== this._iframe.contentWindow) return; // debugger; const dim = JSON.parse(e.data); this._iframe.style.width = dim.width + "px"; this._iframe.style.height = dim.height + "px"; if (!this._ready) //first time only this.observeStrangeCousin(); this._ready = true; } observeStrangeCousin() { const omg = this.parentNode.children[0]; //todo const width = omg.clientWidth; const height = omg.clientHeight; if (this._iframeHeight === height && this._iframeWidth === width) return setTimeout(this.observeStrangeCousin.bind(this), 150); this._iframeHeight = height; this._iframeWidth = width; this._iframe.contentWindow.postMessage(JSON.stringify({width, height}), "*"); requestAnimationFrame(this.observeStrangeCousin.bind(this)); } } customElements.define("overflow-iframe-part2", OverflowIframe); </script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } overflow-iframe-part2 { border: 4px solid orange; } </style> <h1>Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine!</h1> <hr> <div style="width: 100%; height:100%; border: 5px solid red;"> <div id="omg" style="position: absolute; border: none; margin: 0; padding: 0; box-sizing: content-box; height: 100%; width: 100%; visibility: hidden;"></div> <overflow-iframe-part2 auto-layout="w; h" srcdoc="<h1 style='height: 60%; border: 3px solid pink;'>Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! Hello sunshine! </h1>" ></overflow-iframe-part2> <hr> <overflow-iframe-part2 auto-layout="w; h" srcdoc="<span style='padding-right: 2000px; border: 2px solid blue;'>I'm also toooooo long......</span>" ></overflow-iframe-part2> <hr> <overflow-iframe-part2 auto-layout="w; h" srcdoc="<h1 style='height: 100%; border: 5px solid green'>Hello sunshine! </h1>" ></overflow-iframe-part2> </div> <!-- <script>setTimeout(()=> {const h1 = document.querySelector('*'); h1.style.height = '10%'; h1.style.width = '110%';}, 1000);</script> This code is untested. I have only done superficial tests from within devtools in Chrome. The code should only work in Chrome, Safari, Firefox as template does not work in IE and Edge. -->