apps/wpcom-block-editor/src/calypso/iframe-bridge-server.js
function handleUpdateImageBlocks( calypsoPort ) {
	calypsoPort.addEventListener( 'message', onUpdateImageBlocks, false );
	calypsoPort.start();

	const imageBlocks = {
		'core/cover': updateSingeImageBlock,
		'core/image': updateSingeImageBlock,
		'core/file': partialRight( updateSingeImageBlock, { url: 'href' } ),
		'core/gallery': updateMultipleImagesBlock,
		'core/media-text': partialRight( updateSingeImageBlock, {
			id: 'mediaId',
			url: 'mediaUrl',
		} ),
		'jetpack/tiled-gallery': updateMultipleImagesBlock,
	};

	/**
	 * Updates all the blocks containing a given edited image.
	 *
	 * @param {Array} blocks Array of block objects for the current post.
	 * @param {Object} image The edited image.
	 * @param {number} image.id The image ID.
	 * @param {string} image.url The new image URL.
	 * @param {string} image.status The new image status. "deleted" or "updated" (default).
	 * @param {number} [image.transientId] The temporary ID assigned to uploading image.
	 */
	function updateImageBlocks( blocks, image ) {
		forEach( blocks, block => {
			if ( imageBlocks[ block.name ] ) {
				imageBlocks[ block.name ]( block, image );
			}
			if ( block.innerBlocks.length ) {
				updateImageBlocks( block.innerBlocks, image );
			}
		} );
	}

	function preloadImage( imageUrl ) {
		return new Promise( ( resolve, reject ) => {
			const preloadedImage = new Image();
			preloadedImage.src = imageUrl;
			preloadedImage.onload = resolve;
			preloadedImage.onerror = reject;
		} );
	}

	function updateSingeImageBlock( block, image, attrNames ) {
		const blockImageId = get( block, 'attributes.id' );
		if ( blockImageId !== image.id && blockImageId !== image.transientId ) {
			return;
		}
		attrNames = { ...attrNames, id: 'id', url: 'url' };

		if ( 'deleted' === image.status ) {
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.id ]: undefined,
				[ attrNames.url ]: undefined,
			} );
			return;
		}

		preloadImage( image.url ).then( () => {
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.id ]: image.id,
				[ attrNames.url ]: image.url,
			} );
		} );
	}

	function updateMultipleImagesBlock( block, image, attrNames ) {
		attrNames = { ...attrNames, id: 'id', url: 'url', images: 'images' };
		const currentImages = get( block, [ 'attributes', attrNames.images ] );
		let updatedImages = [];

		if ( 'deleted' === image.status ) {
			updatedImages = filter( currentImages, currentImage => {
				return currentImage.id !== image.id && currentImage.id !== image.transientId;
			} );
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.images ]: updatedImages,
			} );
			return;
		}

		preloadImage( image.url ).then( () => {
			updatedImages = map( currentImages, currentImage => {
				const currentImageId = parseInt( currentImage.id, 10 );
				if ( currentImageId !== image.id && currentImageId !== image.transientId ) {
					return currentImage;
				}
				return {
					[ attrNames.id ]: image.id,
					[ attrNames.url ]: image.url,
				};
			} );
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.images ]: updatedImages,
			} );
		} );
	}

	// To update the featured image preview we need to manually modify the image in the `core` state.
	// Though, there is no direct mechanism to also invalidate its cache and re-render the preview.
	// As a workaround, we call `receiveEntityRecords`, normally used to update the state after a fetch,
	// which has a handy `invalidateCache` parameter that does exactly what we need.
	function updateFeaturedImagePreview( image ) {
		const currentImageId = select( 'core/editor' ).getEditedPostAttribute( 'featured_media' );
		if ( currentImageId !== image.id ) {
			return;
		}
		preloadImage( image.url ).then( () => {
			const currentImage = select( 'core' ).getMedia( currentImageId );
			const updatedImage = {
				...currentImage,
				media_details: {
					height: image.height,
					width: image.width,
				},
				source_url: image.url,
			};
			dispatch( 'core' ).receiveEntityRecords( 'root', 'media', [ updatedImage ], null, true );
		} );
	}

	function onUpdateImageBlocks( message ) {
		const action = get( message, 'data.action' );
		if ( action !== 'updateImageBlocks' ) {
			return;
		}
		const image = get( message, 'data.payload' );
		updateImageBlocks( select( 'core/editor' ).getBlocks(), image );
		updateFeaturedImagePreview( image );
	}
}
function handleUpdateImageBlocks( calypsoPort ) {
	calypsoPort.addEventListener( 'message', onUpdateImageBlocks, false );
	calypsoPort.start();

	const imageBlocks = {
		'core/cover': updateSingeImageBlock,
		'core/image': updateSingeImageBlock,
		'core/file': partialRight( updateSingeImageBlock, { url: 'href' } ),
		'core/gallery': updateMultipleImagesBlock,
		'core/media-text': partialRight( updateSingeImageBlock, {
			id: 'mediaId',
			url: 'mediaUrl',
		} ),
		'jetpack/tiled-gallery': updateMultipleImagesBlock,
	};

	/**
	 * Updates all the blocks containing a given edited image.
	 *
	 * @param {Array} blocks Array of block objects for the current post.
	 * @param {Object} image The edited image.
	 * @param {number} image.id The image ID.
	 * @param {string} image.url The new image URL.
	 * @param {string} image.status The new image status. "deleted" or "updated" (default).
	 * @param {number} [image.transientId] The temporary ID assigned to uploading image.
	 */
	function updateImageBlocks( blocks, image ) {
		forEach( blocks, block => {
			if ( imageBlocks[ block.name ] ) {
				imageBlocks[ block.name ]( block, image );
			}
			if ( block.innerBlocks.length ) {
				updateImageBlocks( block.innerBlocks, image );
			}
		} );
	}

	function preloadImage( imageUrl ) {
		return new Promise( ( resolve, reject ) => {
			const preloadedImage = new Image();
			preloadedImage.src = imageUrl;
			preloadedImage.onload = resolve;
			preloadedImage.onerror = reject;
		} );
	}

	function updateSingeImageBlock( block, image, attrNames ) {
		const blockImageId = get( block, 'attributes.id' );
		if ( blockImageId !== image.id && blockImageId !== image.transientId ) {
			return;
		}
		attrNames = { ...attrNames, id: 'id', url: 'url' };

		if ( 'deleted' === image.status ) {
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.id ]: undefined,
				[ attrNames.url ]: undefined,
			} );
			return;
		}

		preloadImage( image.url ).then( () => {
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.id ]: image.id,
				[ attrNames.url ]: image.url,
			} );
		} );
	}

	function updateMultipleImagesBlock( block, image, attrNames ) {
		attrNames = { ...attrNames, id: 'id', url: 'url', images: 'images' };
		const currentImages = get( block, [ 'attributes', attrNames.images ] );
		let updatedImages = [];

		if ( 'deleted' === image.status ) {
			updatedImages = filter( currentImages, currentImage => {
				return currentImage.id !== image.id && currentImage.id !== image.transientId;
			} );
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.images ]: updatedImages,
			} );
			return;
		}

		preloadImage( image.url ).then( () => {
			updatedImages = map( currentImages, currentImage => {
				const currentImageId = parseInt( currentImage.id, 10 );
				if ( currentImageId !== image.id && currentImageId !== image.transientId ) {
					return currentImage;
				}
				return {
					[ attrNames.id ]: image.id,
					[ attrNames.url ]: image.url,
				};
			} );
			dispatch( 'core/editor' ).updateBlockAttributes( block.clientId, {
				[ attrNames.images ]: updatedImages,
			} );
		} );
	}

	// To update the featured image preview we need to manually modify the image in the `core` state.
	// Though, there is no direct mechanism to also invalidate its cache and re-render the preview.
	// As a workaround, we call `receiveEntityRecords`, normally used to update the state after a fetch,
	// which has a handy `invalidateCache` parameter that does exactly what we need.
	function updateFeaturedImagePreview( image ) {
		const currentImageId = select( 'core/editor' ).getEditedPostAttribute( 'featured_media' );
		if ( currentImageId !== image.id ) {
			return;
		}
		preloadImage( image.url ).then( () => {
			const currentImage = select( 'core' ).getMedia( currentImageId );
			const updatedImage = {
				...currentImage,
				media_details: {
					height: image.height,
					width: image.width,
				},
				source_url: image.url,
			};
			dispatch( 'core' ).receiveEntityRecords( 'root', 'media', [ updatedImage ], null, true );
		} );
	}

	function onUpdateImageBlocks( message ) {
		const action = get( message, 'data.action' );
		if ( action !== 'updateImageBlocks' ) {
			return;
		}
		const image = get( message, 'data.payload' );
		updateImageBlocks( select( 'core/editor' ).getBlocks(), image );
		updateFeaturedImagePreview( image );
	}
}
function handleUpdateImageBlocks ( calypsoPort ) { calypsoPort . addEventListener ( 'message' , onUpdateImageBlocks , false ) ; calypsoPort . start ( ) ; const imageBlocks = { 'core/cover' : updateSingeImageBlock , 'core/image' : updateSingeImageBlock , 'core/file' : partialRight ( updateSingeImageBlock , { url : 'href' } ) , 'core/gallery' : updateMultipleImagesBlock , 'core/media-text' : partialRight ( updateSingeImageBlock , { id : 'mediaId' , url : 'mediaUrl' , } ) , 'jetpack/tiled-gallery' : updateMultipleImagesBlock , } ; /**
	 * Updates all the blocks containing a given edited image.
	 *
	 * @param {Array} blocks Array of block objects for the current post.
	 * @param {Object} image The edited image.
	 * @param {number} image.id The image ID.
	 * @param {string} image.url The new image URL.
	 * @param {string} image.status The new image status. "deleted" or "updated" (default).
	 * @param {number} [image.transientId] The temporary ID assigned to uploading image.
	 */ function updateImageBlocks ( blocks , image ) { forEach ( blocks , block => { if ( imageBlocks [ block . name ] ) { imageBlocks [ block . name ] ( block , image ) ; } if ( block . innerBlocks . length ) { updateImageBlocks ( block . innerBlocks , image ) ; } } ) ; } function preloadImage ( imageUrl ) { return new Promise ( ( resolve , reject ) => { const preloadedImage = new Image ( ) ; preloadedImage . src = imageUrl ; preloadedImage . onload = resolve ; preloadedImage . onerror = reject ; } ) ; } function updateSingeImageBlock ( block , image , attrNames ) { const blockImageId = get ( block , 'attributes.id' ) ; if ( blockImageId !== image . id && blockImageId !== image . transientId ) { return ; } attrNames = { ... attrNames , id : 'id' , url : 'url' } ; if ( 'deleted' === image . status ) { dispatch ( 'core/editor' ) . updateBlockAttributes ( block . clientId , { [ attrNames . id ] : undefined , [ attrNames . url ] : undefined , } ) ; return ; } preloadImage ( image . url ) . then ( ( ) => { dispatch ( 'core/editor' ) . updateBlockAttributes ( block . clientId , { [ attrNames . id ] : image . id , [ attrNames . url ] : image . url , } ) ; } ) ; } function updateMultipleImagesBlock ( block , image , attrNames ) { attrNames = { ... attrNames , id : 'id' , url : 'url' , images : 'images' } ; const currentImages = get ( block , [ 'attributes' , attrNames . images ] ) ; let updatedImages = [ ] ; if ( 'deleted' === image . status ) { updatedImages = filter ( currentImages , currentImage => { return currentImage . id !== image . id && currentImage . id !== image . transientId ; } ) ; dispatch ( 'core/editor' ) . updateBlockAttributes ( block . clientId , { [ attrNames . images ] : updatedImages , } ) ; return ; } preloadImage ( image . url ) . then ( ( ) => { updatedImages = map ( currentImages , currentImage => { const currentImageId = parseInt ( currentImage . id , 10 ) ; if ( currentImageId !== image . id && currentImageId !== image . transientId ) { return currentImage ; } return { [ attrNames . id ] : image . id , [ attrNames . url ] : image . url , } ; } ) ; dispatch ( 'core/editor' ) . updateBlockAttributes ( block . clientId , { [ attrNames . images ] : updatedImages , } ) ; } ) ; } // To update the featured image preview we need to manually modify the image in the `core` state. // Though, there is no direct mechanism to also invalidate its cache and re-render the preview. // As a workaround, we call `receiveEntityRecords`, normally used to update the state after a fetch, // which has a handy `invalidateCache` parameter that does exactly what we need. function updateFeaturedImagePreview ( image ) { const currentImageId = select ( 'core/editor' ) . getEditedPostAttribute ( 'featured_media' ) ; if ( currentImageId !== image . id ) { return ; } preloadImage ( image . url ) . then ( ( ) => { const currentImage = select ( 'core' ) . getMedia ( currentImageId ) ; const updatedImage = { ... currentImage , media_details : { height : image . height , width : image . width , } , source_url : image . url , } ; dispatch ( 'core' ) . receiveEntityRecords ( 'root' , 'media' , [ updatedImage ] , null , true ) ; } ) ; } function onUpdateImageBlocks ( message ) { const action = get ( message , 'data.action' ) ; if ( action !== 'updateImageBlocks' ) { return ; } const image = get ( message , 'data.payload' ) ; updateImageBlocks ( select ( 'core/editor' ) . getBlocks ( ) , image ) ; updateFeaturedImagePreview ( image ) ; } }
Listens for image changes or removals happening in the Media Modal,
and updates accordingly all blocks containing them.

@param {MessagePort} calypsoPort Port used for communication with parent frame.
Listens for image changes or removals happening in the Media Modal and updates accordingly all blocks containing them .