message listener which listens for messages from child objects to (this) parent.
handles string-encoded JSON messages with {widgetId: id, height: x} and handles changing child object height from its declared height -
- the child object is marked up as data-widget-id="{widgetId}" in the HTML element
- this ID is passed to the child somehow, typically via iframe URL so it can take it pass it back:
- Like this: <iframe src="http://source.of/child/page?widgetId={widgetId}" data-widget-id="{widgetId}"></iframe>
- Example: <iframe src="http://source.of/child/page?widgetId=chart2" data-widget-id="chart2"></iframe>
handles legaacy "type-id-value" string only messages for example: "height-chart1-430" to set the height of element id="chart1" to 430px
<head>
<script>
(function(global){'use strict';if(!global.console){global.console={}}var con=global.console;var prop,method;var dummy=function(){};var properties=['memory'];var methods=('assert,clear,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn,timeLog,trace').split(',');while(prop=properties.pop()){if(!con[prop]){con[prop]={}}}while(method=methods.pop()){if(!con[method]){con[method]=dummy;}}})(typeof window==='undefined'?this:window);function onMessageHandler(e){if((!e.data.length)){console.log("WidgetMsg: No message");return}if(e.data[0]==="{"){console.log("WidgetMsg: Attempt JSON receiver");try{var msg=JSON.parse(e.data);if(msg.widgetId&&msg.height){var selector="[data-widget-id='"+msg.widgetId+"']";console.log("WidgetMsg: Selector",selector);var element=document.querySelector(selector);if(element){console.log("WidgetMsg: set element height",selector,msg.height);element.height=parseInt(msg.height)}else{console.log("WidgetMsg: Element not found",selector)}}}catch(error){console.log("WidgetMsg: Error",error)}}else if(e.data.indexOf("-")>0){console.log("WidgetMsg: Attempt Legacy \"type-id-value\" encoding ");var p=e.data.split("-");if(p.length!==3){console.log("WidgetMsg: Incorrect msg layout",p)}if(p[0]=="height"){var elementId=p[1];var h=parseInt(p[2]);console.log("WidgetMsg: New Frame Height",elementId,h);var el=document.getElementById(elementId);if(el){el.height=h}else{console.log("WidgetMsg: Cannot find element by ID",elementId)}}}else{console.log("WidgetMsg: Unknown Msg Encoding",e.data)}}if(window.addEventListener){window.addEventListener('message',onMessageHandler,false)}else if(window.attachEvent){window.attachEvent('onmessage',onMessageHandler)}
</script>
</head>
- Markup the iframe with a unique data-widget-id="" value
- Pass this ID into the frame src URL as a query parameter
<iframe src="http://source.of/iframe/page?widgetId=chart2" data-widget-id="chart2"></iframe>
Many iframes can be setup as long as the data-widget-id attribute has a unique value for each and they are called with their respective ID in the URL param
<head>
<script>
function parentPost(attribute,value){if(!URLSearchParams){var self=this||{};try{!function(t,e){if(new t("q=%2B").get("q")!==e||new t({q:e}).get("q")!==e||new t([["q",e]]).get("q")!==e||"q=%0A"!==new t("q=\n").toString()||"q=+%26"!==new t({q:" &"}).toString()||"q=%25zx"!==new t({q:"%zx"}).toString()){throw t}self.URLSearchParams=t}(URLSearchParams,"+")}catch(t){!function(t,a,o){"use strict";var u=t.create,h=t.defineProperty,e=/[!'\(\)~]|%20|%00/g,n=/%(?![0-9a-fA-F]{2})/g,r=/\+/g,i={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"},s={append:function(t,e){p(this._ungap,t,e)},delete:function(t){delete this._ungap[t]},get:function(t){return this.has(t)?this._ungap[t][0]:null},getAll:function(t){return this.has(t)?this._ungap[t].slice(0):[]},has:function(t){return t in this._ungap},set:function(t,e){this._ungap[t]=[a(e)]},forEach:function(e,n){var r=this;for(var i in r._ungap){r._ungap[i].forEach(t,i)}function t(t){e.call(n,t,a(i),r)}},toJSON:function(){return{}},toString:function(){var t=[];for(var e in this._ungap){for(var n=v(e),r=0,i=this._ungap[e];r<i.length;r+=1){t.push(n+"="+v(i[r]))}}return t.join("&")}};for(var c in s){h(f.prototype,c,{configurable:!0,writable:!0,value:s[c]})}function f(t){var e=u(null);switch(h(this,"_ungap",{value:e}),!0){case!t:break;case "string"==typeof t:"?"===t.charAt(0)&&(t=t.slice(1));for(var n=t.split("&"),r=0,i=n.length;r<i;r+=1){var a=(s=n[r]).indexOf("=");-1<a?p(e,g(s.slice(0,a)),g(s.slice(a+1))):s.length&&p(e,g(s),"")}break;case o(t):for(var s,r=0,i=t.length;r<i;r+=1){p(e,(s=t[r])[0],s[1])}break;case "forEach"in t:t.forEach(l,e);break;default:for(var c in t){p(e,c,t[c])}}}function l(t,e){p(this,e,t)}function p(t,e,n){var r=o(n)?n.join(","):n;e in t?t[e].push(r):t[e]=[r]}function g(t){return decodeURIComponent(t.replace(n,"%25").replace(r," "))}function v(t){return encodeURIComponent(t).replace(e,d)}function d(t){return i[t]}self.URLSearchParams=f}(Object,String,Array.isArray)}!function(d){var r=!1;try{r=!!Symbol.iterator}catch(t){}function t(t,e){var n=[];return t.forEach(e,n),r?n[Symbol.iterator]():{next:function(){var t=n.shift();return{done:void 0===t,value:t}}}}"forEach"in d||(d.forEach=function(n,r){var i=this,t=Object.create(null);this.toString().replace(/=[\s\S]*?(?:&|$)/g,"=").split("=").forEach(function(e){!e.length||e in t||(t[e]=i.getAll(e)).forEach(function(t){n.call(r,t,e,i)})})}),"keys"in d||(d.keys=function(){return t(this,function(t,e){this.push(e)})}),"values"in d||(d.values=function(){return t(this,function(t,e){this.push(t)})}),"entries"in d||(d.entries=function(){return t(this,function(t,e){this.push([e,t])})}),!r||Symbol.iterator in d||(d[Symbol.iterator]=d.entries),"sort"in d||(d.sort=function(){for(var t,e,n,r=this.entries(),i=r.next(),a=i.done,s=[],c=Object.create(null);!a;){e=(n=i.value)[0],s.push(e),e in c||(c[e]=[]),c[e].push(n[1]),a=(i=r.next()).done}for(s.sort(),t=0;t<s.length;t+=1){this.delete(s[t])}for(t=0;t<s.length;t+=1){e=s[t],this.append(e,c[e].shift())}}),function(f){function l(t){var e=t.append;t.append=d.append,URLSearchParams.call(t,t._usp.search.slice(1)),t.append=e}function p(t,e){if(!(t instanceof e)){throw new TypeError("'searchParams' accessed on an object that does not implement interface "+e.name)}}function t(e){var n,r,i,t=e.prototype,a=v(t,"searchParams"),s=v(t,"href"),c=v(t,"search");function o(t,e){d.append.call(this,t,e),t=this.toString(),i.set.call(this._usp,t?"?"+t:"")}function u(t){d.delete.call(this,t),t=this.toString(),i.set.call(this._usp,t?"?"+t:"")}function h(t,e){d.set.call(this,t,e),t=this.toString(),i.set.call(this._usp,t?"?"+t:"")}!a&&c&&c.set&&(i=c,r=function(t,e){return t.append=o,t.delete=u,t.set=h,g(t,"_usp",{configurable:!0,writable:!0,value:e})},n=function(t,e){return g(t,"_searchParams",{configurable:!0,writable:!0,value:r(e,t)}),e},f.defineProperties(t,{href:{get:function(){return s.get.call(this)},set:function(t){var e=this._searchParams;s.set.call(this,t),e&&l(e)}},search:{get:function(){return c.get.call(this)},set:function(t){var e=this._searchParams;c.set.call(this,t),e&&l(e)}},searchParams:{get:function(){return p(this,e),this._searchParams||n(this,new URLSearchParams(this.search.slice(1)))},set:function(t){p(this,e),n(this,t)}}}))}var g=f.defineProperty,v=f.getOwnPropertyDescriptor;try{t(HTMLAnchorElement),/^function|object$/.test(typeof URL)&&URL.prototype&&t(URL)}catch(t){}}(Object)}(self.URLSearchParams.prototype,Object)}var params=new URLSearchParams(window.location.search);var widgetId=params.get("widgetId");if(!widgetId){console.log("No Widget ID",params);return}var msg={widgetId:widgetId};msg[attribute]=value;var msgStr=JSON.stringify(msg);parent.postMessage(msgStr,"*")}
</script>
</head>
When the content is ready (E.g. after a chart has plotted) and the content height has been established call the function
var widget_height = document.getElementById("content").offsetHeight
parentPost("height", widget_height)