mirror of
				https://github.com/pocoproject/poco.git
				synced 2025-10-30 13:47:10 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			576 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			576 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * File: iframeSizer.contentWindow.js
 | |
|  * Desc: Include this file in any page being loaded into an iframe
 | |
|  *       to force the iframe to resize to the content size.
 | |
|  * Requires: iframeResizer.js on host page.
 | |
|  * Author: David J. Bradshaw - dave@bradshaw.net
 | |
|  * Contributor: Jure Mav - jure.mav@gmail.com
 | |
|  */
 | |
| 
 | |
| ;(function() {
 | |
| 	'use strict';
 | |
| 
 | |
| 	var
 | |
| 		autoResize            = true,
 | |
| 		base                  = 10,
 | |
| 		bodyBackground        = '',
 | |
| 		bodyMargin            = 0,
 | |
| 		bodyMarginStr         = '',
 | |
| 		bodyPadding           = '',
 | |
| 		calculateWidth        = false,
 | |
| 		doubleEventList       = {'resize':1,'click':1},
 | |
| 		eventCancelTimer      = 128,
 | |
| 		height                = 1,
 | |
| 		firstRun              = true,
 | |
| 		heightCalcModeDefault = 'offset',
 | |
| 		heightCalcMode        = heightCalcModeDefault,
 | |
| 		initLock              = true,
 | |
| 		initMsg               = '',
 | |
| 		interval              = 32,
 | |
| 		logging               = false,
 | |
| 		msgID                 = '[iFrameSizer]',  //Must match host page msg ID
 | |
| 		msgIdLen              = msgID.length,
 | |
| 		myID                  = '',
 | |
| 		publicMethods         = false,
 | |
| 		resetRequiredMethods  = {max:1,scroll:1,bodyScroll:1,documentElementScroll:1},
 | |
| 		targetOriginDefault   = '*',
 | |
| 		target                = window.parent,
 | |
| 		tolerance             = 0,
 | |
| 		triggerLocked         = false,
 | |
| 		triggerLockedTimer    = null,
 | |
| 		width                 = 1;
 | |
| 
 | |
| 
 | |
| 	function addEventListener(el,evt,func){
 | |
| 		if ('addEventListener' in window){
 | |
| 			el.addEventListener(evt,func, false);
 | |
| 		} else if ('attachEvent' in window){ //IE
 | |
| 			el.attachEvent('on'+evt,func);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function formatLogMsg(msg){
 | |
| 		return msgID + '[' + myID + ']' + ' ' + msg;
 | |
| 	}
 | |
| 
 | |
| 	function log(msg){
 | |
| 		if (logging && ('object' === typeof window.console)){
 | |
| 			console.log(formatLogMsg(msg));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function warn(msg){
 | |
| 		if ('object' === typeof window.console){
 | |
| 			console.warn(formatLogMsg(msg));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	function init(){
 | |
| 		log('Initialising iFrame');
 | |
| 		readData();
 | |
| 		setMargin();
 | |
| 		setBodyStyle('background',bodyBackground);
 | |
| 		setBodyStyle('padding',bodyPadding);
 | |
| 		injectClearFixIntoBodyElement();
 | |
| 		checkHeightMode();
 | |
| 		stopInfiniteResizingOfIFrame();
 | |
| 		setupPublicMethods();
 | |
| 		startEventListeners();
 | |
| 		sendSize('init','Init message from host page');
 | |
| 	}
 | |
| 
 | |
| 	function readData(){
 | |
| 
 | |
| 		var data = initMsg.substr(msgIdLen).split(':');
 | |
| 
 | |
| 		function strBool(str){
 | |
| 			return 'true' === str ? true : false;
 | |
| 		}
 | |
| 
 | |
| 		myID             = data[0];
 | |
| 		bodyMargin       = (undefined !== data[1]) ? Number(data[1])   : bodyMargin; //For V1 compatibility
 | |
| 		calculateWidth   = (undefined !== data[2]) ? strBool(data[2])  : calculateWidth;
 | |
| 		logging          = (undefined !== data[3]) ? strBool(data[3])  : logging;
 | |
| 		interval         = (undefined !== data[4]) ? Number(data[4])   : interval;
 | |
| 		publicMethods    = (undefined !== data[5]) ? strBool(data[5])  : publicMethods;
 | |
| 		autoResize       = (undefined !== data[6]) ? strBool(data[6])  : autoResize;
 | |
| 		bodyMarginStr    = data[7];
 | |
| 		heightCalcMode   = (undefined !== data[8]) ? data[8]           : heightCalcMode;
 | |
| 		bodyBackground   = data[9];
 | |
| 		bodyPadding      = data[10];
 | |
| 		tolerance        = (undefined !== data[11]) ? Number(data[11]) : tolerance;
 | |
| 	}
 | |
| 
 | |
| 	function chkCSS(attr,value){
 | |
| 		if (-1 !== value.indexOf('-')){
 | |
| 			warn('Negative CSS value ignored for '+attr);
 | |
| 			value='';
 | |
| 		}
 | |
| 		return value;
 | |
| 	}
 | |
| 
 | |
| 	function setBodyStyle(attr,value){
 | |
| 		if ((undefined !== value) && ('' !== value) && ('null' !== value)){
 | |
| 			document.body.style[attr] = value;
 | |
| 			log('Body '+attr+' set to "'+value+'"');
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function setMargin(){
 | |
| 		//If called via V1 script, convert bodyMargin from int to str 
 | |
| 		if (undefined === bodyMarginStr){
 | |
| 			bodyMarginStr = bodyMargin+'px';
 | |
| 		}
 | |
| 		chkCSS('margin',bodyMarginStr);
 | |
| 		setBodyStyle('margin',bodyMarginStr);
 | |
| 	}
 | |
| 
 | |
| 	function stopInfiniteResizingOfIFrame(){
 | |
| 		document.documentElement.style.height = '';
 | |
| 		document.body.style.height = '';
 | |
| 		log('HTML & body height set to "auto"');
 | |
| 	}
 | |
| 
 | |
| 	function initWindowResizeListener(){
 | |
| 		addEventListener(window,'resize', function(){
 | |
| 			sendSize('resize','Window resized');
 | |
| 		});
 | |
| 	}
 | |
| 
 | |
| 	function initWindowClickListener(){
 | |
| 		addEventListener(window,'click', function(){
 | |
| 			sendSize('click','Window clicked');
 | |
| 		});
 | |
| 	}
 | |
| 
 | |
| 	function checkHeightMode(){
 | |
| 		if (heightCalcModeDefault !== heightCalcMode){
 | |
| 			if (!(heightCalcMode in getHeight)){
 | |
| 				warn(heightCalcMode + ' is not a valid option for heightCalculationMethod.');
 | |
| 				heightCalcMode='bodyScroll';
 | |
| 			}
 | |
| 			log('Height calculation method set to "'+heightCalcMode+'"');
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function startEventListeners(){
 | |
| 		if ( true === autoResize ) {
 | |
| 			initWindowResizeListener();
 | |
| 			initWindowClickListener();
 | |
| 			setupMutationObserver();
 | |
| 		}
 | |
| 		else {
 | |
| 			log('Auto Resize disabled');
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function injectClearFixIntoBodyElement(){
 | |
| 		var clearFix = document.createElement('div');
 | |
| 		clearFix.style.clear = 'both';
 | |
| 		clearFix.style.display = 'block'; //Guard against this having been globally redefined in CSS.
 | |
| 		document.body.appendChild(clearFix);
 | |
| 	}
 | |
| 
 | |
| 	function setupPublicMethods(){
 | |
| 		if (publicMethods) {
 | |
| 			log('Enable public methods');
 | |
| 
 | |
| 			window.parentIFrame = {
 | |
| 				close: function closeF(){
 | |
| 					sendSize('close','parentIFrame.close()', 0, 0);
 | |
| 				},
 | |
| 				getId: function getIdF(){
 | |
| 					return myID;
 | |
| 				},
 | |
| 				reset: function resetF(){
 | |
| 					resetIFrame('parentIFrame.size');
 | |
| 				},
 | |
| 				scrollTo: function scrollToF(x,y){
 | |
| 					sendMsg(y,x,'scrollTo'); // X&Y reversed at sendMsg uses hieght/width
 | |
| 				},
 | |
| 				sendMessage: function sendMessageF(msg,targetOrigin){
 | |
| 					sendMsg(0,0,'message',msg,targetOrigin);
 | |
| 				},
 | |
| 				setHeightCalculationMethod: function setHeightCalculationMethodF(heightCalculationMethod){
 | |
| 					heightCalcMode = heightCalculationMethod;
 | |
| 					checkHeightMode();
 | |
| 				},
 | |
| 				setTargetOrigin: function setTargetOriginF(targetOrigin){
 | |
| 					log('Set targetOrigin: '+targetOrigin);
 | |
| 					targetOriginDefault = targetOrigin;
 | |
| 				},
 | |
| 				size: function sizeF(customHeight, customWidth){
 | |
| 					var valString = ''+(customHeight?customHeight:'')+(customWidth?','+customWidth:'');
 | |
| 					lockTrigger();
 | |
| 					sendSize('size','parentIFrame.size('+valString+')', customHeight, customWidth);
 | |
| 				}
 | |
| 			};
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function initInterval(){
 | |
| 		if ( 0 !== interval ){
 | |
| 			log('setInterval: '+interval+'ms');
 | |
| 			setInterval(function(){
 | |
| 				sendSize('interval','setInterval: '+interval);
 | |
| 			},Math.abs(interval));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function setupInjectElementLoadListners(mutations){
 | |
| 		function addLoadListener(element){
 | |
| 			if (element.height === undefined || element.width === undefined || 0 === element.height || 0 === element.width){
 | |
| 				log('Attach listerner to '+element.src);
 | |
| 				addEventListener(element,'load', function imageLoaded(){
 | |
| 					sendSize('imageLoad','Image loaded');
 | |
| 				});
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		mutations.forEach(function (mutation) {
 | |
| 			if (mutation.type === 'attributes' && mutation.attributeName === 'src'){
 | |
| 				addLoadListener(mutation.target);
 | |
| 			} else if (mutation.type === 'childList'){
 | |
| 				var images = mutation.target.querySelectorAll('img');
 | |
| 				Array.prototype.forEach.call(images,function (image) {
 | |
| 					addLoadListener(image);
 | |
| 				});
 | |
| 			}
 | |
| 		});
 | |
| 	}
 | |
| 
 | |
| 	function setupMutationObserver(){
 | |
| 
 | |
| 		var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
 | |
| 
 | |
| 		function createMutationObserver(){
 | |
| 			var
 | |
| 				target = document.querySelector('body'),
 | |
| 
 | |
| 				config = {
 | |
| 					attributes            : true,
 | |
| 					attributeOldValue     : false,
 | |
| 					characterData         : true,
 | |
| 					characterDataOldValue : false,
 | |
| 					childList             : true,
 | |
| 					subtree               : true
 | |
| 				},
 | |
| 
 | |
| 				observer = new MutationObserver(function(mutations) {
 | |
| 					sendSize('mutationObserver','mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type);
 | |
| 					setupInjectElementLoadListners(mutations); //Deal with WebKit asyncing image loading when tags are injected into the page
 | |
| 				});
 | |
| 
 | |
| 			log('Enable MutationObserver');
 | |
| 			observer.observe(target, config);
 | |
| 		}
 | |
| 
 | |
| 		if (MutationObserver){
 | |
| 			if (0 > interval) {
 | |
| 				initInterval();
 | |
| 			} else {
 | |
| 				createMutationObserver();
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			warn('MutationObserver not supported in this browser!');
 | |
| 			initInterval();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	// document.documentElement.offsetHeight is not reliable, so
 | |
| 	// we have to jump through hoops to get a better value.
 | |
| 	function getBodyOffsetHeight(){
 | |
| 		function getComputedBodyStyle(prop) {
 | |
| 			function convertUnitsToPxForIE8(value) {
 | |
| 				var PIXEL = /^\d+(px)?$/i;
 | |
| 
 | |
| 				if (PIXEL.test(value)) {
 | |
| 					return parseInt(value,base);
 | |
| 				}
 | |
| 
 | |
| 				var
 | |
| 					style = el.style.left,
 | |
| 					runtimeStyle = el.runtimeStyle.left;
 | |
| 
 | |
| 				el.runtimeStyle.left = el.currentStyle.left;
 | |
| 				el.style.left = value || 0;
 | |
| 				value = el.style.pixelLeft;
 | |
| 				el.style.left = style;
 | |
| 				el.runtimeStyle.left = runtimeStyle;
 | |
| 
 | |
| 				return value;
 | |
| 			}
 | |
| 
 | |
| 			var
 | |
| 				el = document.body,
 | |
| 				retVal = 0;
 | |
| 
 | |
| 			if (('defaultView' in document) && ('getComputedStyle' in document.defaultView)) {
 | |
| 				retVal = document.defaultView.getComputedStyle(el, null);
 | |
| 				retVal = (null !== retVal) ? retVal[prop] : 0;
 | |
| 			} else {//IE8
 | |
| 				retVal =  convertUnitsToPxForIE8(el.currentStyle[prop]);
 | |
| 			}
 | |
| 
 | |
| 			return parseInt(retVal,base);
 | |
| 		}
 | |
| 
 | |
| 		return  document.body.offsetHeight +
 | |
| 				getComputedBodyStyle('marginTop') +
 | |
| 				getComputedBodyStyle('marginBottom');
 | |
| 	}
 | |
| 
 | |
| 	function getBodyScrollHeight(){
 | |
| 		return document.body.scrollHeight;
 | |
| 	}
 | |
| 
 | |
| 	function getDEOffsetHeight(){
 | |
| 		return document.documentElement.offsetHeight;
 | |
| 	}
 | |
| 
 | |
| 	function getDEScrollHeight(){
 | |
| 		return document.documentElement.scrollHeight;
 | |
| 	}
 | |
| 
 | |
| 	//From https://github.com/guardian/iframe-messenger
 | |
| 	function getLowestElementHeight() {
 | |
| 		var
 | |
| 			allElements       = document.querySelectorAll('body *'),
 | |
| 			allElementsLength = allElements.length,
 | |
| 			maxBottomVal      = 0,
 | |
| 			timer             = new Date().getTime();
 | |
| 
 | |
| 		for (var i = 0; i < allElementsLength; i++) {
 | |
| 			if (allElements[i].getBoundingClientRect().bottom > maxBottomVal) {
 | |
| 				maxBottomVal = allElements[i].getBoundingClientRect().bottom;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		timer = new Date().getTime() - timer;
 | |
| 
 | |
| 		log('Parsed '+allElementsLength+' HTML elements');
 | |
| 		log('LowestElement bottom position calculated in ' + timer + 'ms');
 | |
| 
 | |
| 		return maxBottomVal;
 | |
| 	}
 | |
| 
 | |
| 	function getAllHeights(){
 | |
| 		return [
 | |
| 			getBodyOffsetHeight(),
 | |
| 			getBodyScrollHeight(),
 | |
| 			getDEOffsetHeight(),
 | |
| 			getDEScrollHeight()
 | |
| 		];
 | |
| 	}
 | |
| 
 | |
| 	function getMaxHeight(){
 | |
| 		return Math.max.apply(null,getAllHeights());
 | |
| 	}
 | |
| 
 | |
| 	function getMinHeight(){
 | |
| 		return Math.min.apply(null,getAllHeights());
 | |
| 	}
 | |
| 
 | |
| 	function getBestHeight(){
 | |
| 		return Math.max(getBodyOffsetHeight(),getLowestElementHeight());
 | |
| 	}
 | |
| 
 | |
| 	var getHeight = {
 | |
| 		offset                : getBodyOffsetHeight, //Backward compatability
 | |
| 		bodyOffset            : getBodyOffsetHeight,
 | |
| 		bodyScroll            : getBodyScrollHeight,
 | |
| 		documentElementOffset : getDEOffsetHeight,
 | |
| 		scroll                : getDEScrollHeight, //Backward compatability
 | |
| 		documentElementScroll : getDEScrollHeight,
 | |
| 		max                   : getMaxHeight,
 | |
| 		min                   : getMinHeight,
 | |
| 		grow                  : getMaxHeight,
 | |
| 		lowestElement         : getBestHeight
 | |
| 	};
 | |
| 
 | |
| 	function getWidth(){
 | |
| 		return Math.max(
 | |
| 			document.documentElement.scrollWidth,
 | |
| 			document.body.scrollWidth
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	function sendSize(triggerEvent, triggerEventDesc, customHeight, customWidth){
 | |
| 
 | |
| 		var	currentHeight,currentWidth;
 | |
| 
 | |
| 		function recordTrigger(){
 | |
| 			if (!(triggerEvent in {'reset':1,'resetPage':1,'init':1})){
 | |
| 				log( 'Trigger event: ' + triggerEventDesc );
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		function resizeIFrame(){
 | |
| 			height = currentHeight;
 | |
| 			width  = currentWidth;
 | |
| 
 | |
| 			sendMsg(height,width,triggerEvent);
 | |
| 		}
 | |
| 
 | |
| 		function isDoubleFiredEvent(){
 | |
| 			return  triggerLocked && (triggerEvent in doubleEventList);
 | |
| 		}
 | |
| 
 | |
| 		function isSizeChangeDetected(){
 | |
| 			function checkTolarance(a,b){
 | |
| 				var retVal = Math.abs(a-b) <= tolerance;
 | |
| 				return !retVal;
 | |
| 			}
 | |
| 
 | |
| 			currentHeight = (undefined !== customHeight)  ? customHeight : getHeight[heightCalcMode]();
 | |
| 			currentWidth  = (undefined !== customWidth )  ? customWidth  : getWidth();
 | |
| 
 | |
| 			return	checkTolarance(height,currentHeight) ||
 | |
| 					(calculateWidth && checkTolarance(width,currentWidth));
 | |
| 
 | |
| 			//return	(height !== currentHeight) ||
 | |
| 			//		(calculateWidth && width !== currentWidth);
 | |
| 		}
 | |
| 
 | |
| 		function isForceResizableEvent(){
 | |
| 			return !(triggerEvent in {'init':1,'interval':1,'size':1});
 | |
| 		}
 | |
| 
 | |
| 		function isForceResizableHeightCalcMode(){
 | |
| 			return (heightCalcMode in resetRequiredMethods);
 | |
| 		}
 | |
| 
 | |
| 		function logIgnored(){
 | |
| 			log('No change in size detected');
 | |
| 		}
 | |
| 
 | |
| 		function checkDownSizing(){
 | |
| 			if (isForceResizableEvent() && isForceResizableHeightCalcMode()){
 | |
| 				resetIFrame(triggerEventDesc);
 | |
| 			} else if (!(triggerEvent in {'interval':1})){
 | |
| 				recordTrigger();
 | |
| 				logIgnored();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (!isDoubleFiredEvent()){
 | |
| 			if (isSizeChangeDetected()){
 | |
| 				recordTrigger();
 | |
| 				lockTrigger();
 | |
| 				resizeIFrame();
 | |
| 			} else {
 | |
| 				checkDownSizing();
 | |
| 			}
 | |
| 		} else {
 | |
| 			log('Trigger event cancelled: '+triggerEvent);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	function lockTrigger(){
 | |
| 		if (!triggerLocked){
 | |
| 			triggerLocked = true;
 | |
| 			log('Trigger event lock on');
 | |
| 		}
 | |
| 		clearTimeout(triggerLockedTimer);
 | |
| 		triggerLockedTimer = setTimeout(function(){
 | |
| 			triggerLocked = false;
 | |
| 			log('Trigger event lock off');
 | |
| 			log('--');
 | |
| 		},eventCancelTimer);
 | |
| 	}
 | |
| 
 | |
| 	function triggerReset(triggerEvent){
 | |
| 		height = getHeight[heightCalcMode]();
 | |
| 		width  = getWidth();
 | |
| 
 | |
| 		sendMsg(height,width,triggerEvent);
 | |
| 	}
 | |
| 
 | |
| 	function resetIFrame(triggerEventDesc){
 | |
| 		var hcm = heightCalcMode;
 | |
| 		heightCalcMode = heightCalcModeDefault;
 | |
| 
 | |
| 		log('Reset trigger event: ' + triggerEventDesc);
 | |
| 		lockTrigger();
 | |
| 		triggerReset('reset');
 | |
| 
 | |
| 		heightCalcMode = hcm;
 | |
| 	}
 | |
| 
 | |
| 	function sendMsg(height,width,triggerEvent,msg,targetOrigin){
 | |
| 		function setTargetOrigin(){
 | |
| 			if (undefined === targetOrigin){
 | |
| 				targetOrigin = targetOriginDefault;
 | |
| 			} else {
 | |
| 				log('Message targetOrigin: '+targetOrigin);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		function sendToParent(){
 | |
| 			var
 | |
| 				size  = height + ':' + width,
 | |
| 				message = myID + ':' +  size + ':' + triggerEvent + (undefined !== msg ? ':' + msg : '');
 | |
| 
 | |
| 			log('Sending message to host page (' + message + ')');
 | |
| 			target.postMessage( msgID + message, targetOrigin);
 | |
| 		}
 | |
| 
 | |
| 		setTargetOrigin();
 | |
| 		sendToParent();
 | |
| 	}
 | |
| 
 | |
| 	function receiver(event) {
 | |
| 		function isMessageForUs(){
 | |
| 			return msgID === (''+event.data).substr(0,msgIdLen); //''+ Protects against non-string messages
 | |
| 		}
 | |
| 
 | |
| 		function initFromParent(){
 | |
| 			initMsg = event.data;
 | |
| 			target  = event.source;
 | |
| 
 | |
| 			init();
 | |
| 			firstRun = false;
 | |
| 			setTimeout(function(){ initLock = false;},eventCancelTimer);
 | |
| 		}
 | |
| 
 | |
| 		function resetFromParent(){
 | |
| 			if (!initLock){
 | |
| 				log('Page size reset by host page');
 | |
| 				triggerReset('resetPage');
 | |
| 			} else {
 | |
| 				log('Page reset ignored by init');
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		function getMessageType(){
 | |
| 			return event.data.split(']')[1];
 | |
| 		}
 | |
| 
 | |
| 		function isMiddleTier(){
 | |
| 			return ('iFrameResize' in window);
 | |
| 		}
 | |
| 
 | |
| 		function isInitMsg(){
 | |
| 			//test if this message is from a child below us. This is an ugly test, however, updating
 | |
| 			//the message format would break backwards compatibity.
 | |
| 			return event.data.split(':')[2] in {'true':1,'false':1};
 | |
| 		}
 | |
| 
 | |
| 		if (isMessageForUs()){
 | |
| 			if (firstRun && isInitMsg()){ //Check msg ID
 | |
| 				initFromParent();
 | |
| 			} else if ('reset' === getMessageType()){
 | |
| 				resetFromParent();
 | |
| 			} else if (event.data !== initMsg && !isMiddleTier()){
 | |
| 				warn('Unexpected message ('+event.data+')');
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	addEventListener(window, 'message', receiver);
 | |
| 
 | |
| })();
 | 
