popostmate
Version:
A powerful, simple, promise-based postMessage library
9 lines (8 loc) • 6.08 kB
JavaScript
/**
popostmate - A powerful, simple, promise-based postMessage library
@version v2.0.0
@link https://github.com/vpopolin/postmate
@author Jacob Kelley <jakie8@gmail.com>
@license MIT
**/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Postmate=t()}(this,function(){"use strict";var l="application/x-postmate-v1+json",r=0,g=0;var i={handshake:1,"handshake-reply":1,call:1,emit:1,reply:1,request:1},c=function(e,t){return("string"!=typeof t||e.origin===t)&&(!!e.data&&(("object"!=typeof e.data||"postmate"in e.data)&&(e.data.type===l&&!!i[e.data.postmate])))},u=function(t){return["debug","error"].forEach(function(e){void 0!==t[e]&&"function"==typeof t[e]||(t[e]=function(){})}),t},m=function(){function e(e){var a=this;this.parent=e.parent,this.frame=e.frame,this.child=e.child,this.childOrigin=e.childOrigin,this.childId=e.childId,this.logger=e.logger,this.events={},this.logger.debug("Parent: Registering API"),this.logger.debug("Parent: Awaiting messages..."),this.listener=function(e){if(!c(e,a.childOrigin))return!1;var t=((e||{}).data||{}).value||{},i=t.data,n=t.name;"emit"===e.data.postmate&&e.data.childId===a.childId&&(a.logger.debug("Parent: Received event emission: "+n),n in a.events&&a.events[n].forEach(function(e){e.call(a,i)}))},this.parent.addEventListener("message",this.listener,!1),this.logger.debug("Parent: Awaiting event emissions from Child")}var t=e.prototype;return t.get=function(e){var a=this;return new h.Promise(function(i){var n=++r;a.parent.addEventListener("message",function e(t){t.data.uid===n&&"reply"===t.data.postmate&&t.data.childId===a.childId&&(a.parent.removeEventListener("message",e,!1),i(t.data.value))},!1),a.child.postMessage({postmate:"request",type:l,property:e,uid:n},a.childOrigin)})},t.call=function(e,t){this.child.postMessage({postmate:"call",type:l,property:e,data:t},this.childOrigin)},t.on=function(e,t){this.events[e]||(this.events[e]=[]),this.events[e].push(t)},t.destroy=function(){this.logger.debug("Parent: Destroying Postmate instance"),window.removeEventListener("message",this.listener,!1),this.frame.parentNode.removeChild(this.frame)},e}(),d=function(){function e(e){var s=this;this.model=e.model,this.parent=e.parent,this.parentOrigin=e.parentOrigin,this.child=e.child,this.childId=e.childId,this.logger=e.logger,this.logger.debug("Child: Registering API"),this.logger.debug("Child: Awaiting messages..."),this.child.addEventListener("message",function(t){if(c(t,s.parentOrigin)){s.logger.debug("Child: Received request",t.data);var e,i,n,a=t.data,r=a.property,d=a.uid,o=a.data;if("call"!==t.data.postmate)(e=s.model,i=r,n="function"==typeof e[i]?e[i]():e[i],h.Promise.resolve(n)).then(function(e){return t.source.postMessage({property:r,postmate:"reply",type:l,childId:s.childId,uid:d,value:e},t.origin)});else r in s.model&&"function"==typeof s.model[r]&&s.model[r](o)}})}return e.prototype.emit=function(e,t){this.logger.debug('Child: Emitting Event "'+e+'"',t),this.parent.postMessage({postmate:"emit",type:l,childId:this.childId,value:{name:e,data:t}},this.parentOrigin)},e}(),h=function(){function h(e){var t=e.container,i=void 0===t?void 0!==i?i:document.body:t,n=e.model,a=e.url,r=e.name,d=e.classListArray,o=void 0===d?[]:d,s=e.logger,h=void 0===s?{}:s;return this.parent=window,this.frame=document.createElement("iframe"),this.frame.name=r||"",0<o.length&&this.frame.classList.add.apply(this.frame.classList,o),i.appendChild(this.frame),this.child=this.frame.contentWindow||this.frame.contentDocument.parentWindow,this.model=n||{},this.childId=++g,this.logger=u(h),this.sendHandshake(a)}return h.prototype.sendHandshake=function(a){var r,d=this,o=function(e){var t=document.createElement("a");t.href=e;var i=4<t.protocol.length?t.protocol:window.location.protocol,n=t.host.length?"80"===t.port||"443"===t.port?t.hostname:t.host:window.location.host;return t.origin||i+"//"+n}(a),s=0;return new h.Promise(function(i,n){d.parent.addEventListener("message",function e(t){return!!c(t,o)&&t.data.childId===d.childId&&("handshake-reply"===t.data.postmate?(clearInterval(r),d.logger.debug("Parent: Received handshake reply from Child"),d.parent.removeEventListener("message",e,!1),d.childOrigin=t.origin,d.logger.debug("Parent: Saving Child origin",d.childOrigin),i(new m(d))):(d.logger.error("Parent: Failed handshake"),n("Failed handshake")))},!1);var e=function(){if(++s>h.maxHandshakeRequests)return clearInterval(r),d.logger.error("Parent: Handshake Timeout Reached"),n("Handshake Timeout Reached");d.logger.debug("Parent: Sending handshake attempt "+s,{childOrigin:o}),d.child.postMessage({postmate:"handshake",type:l,model:d.model,childId:d.childId},o)},t=function(){e(),r=setInterval(e,500)};d.frame.attachEvent?d.frame.attachEvent("onload",t):d.frame.addEventListener("load",t),d.logger.debug("Parent: Loading frame",{url:a}),d.frame.src=a})},h}();return h.maxHandshakeRequests=5,h.Promise=function(){try{return window?window.Promise:Promise}catch(e){return null}}(),h.Model=function(){function e(e,t){return void 0===t&&(t={}),this.child=window,this.model=e,this.parent=this.child.parent,this.logger=u(t),this.sendHandshakeReply()}return e.prototype.sendHandshakeReply=function(){var r=this;return new h.Promise(function(n,a){r.child.addEventListener("message",function e(t){if(t.data.postmate){if("handshake"!==t.data.postmate)return r.logger.error("Child : Handshake Reply Failed"),a("Handshake Reply Failed");r.logger.debug("Child: Received handshake from Parent"),r.child.removeEventListener("message",e,!1),r.logger.debug("Child: Sending handshake reply to Parent"),t.source.postMessage({postmate:"handshake-reply",type:l,childId:t.data.childId},t.origin),r.childId=t.data.childId,r.parentOrigin=t.origin;var i=t.data.model;return i&&(Object.keys(i).forEach(function(e){r.model[e]=i[e]}),r.logger.debug("Child: Inherited and extended model from Parent")),r.logger.debug("Child: Saving Parent origin",r.parentOrigin),n(new d(r))}},!1)})},e}(),h});