github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/cmd/deck/static/spyglass/lens.ts (about) 1 import {Message, Response, isResponse, isTransitMessage} from './common'; 2 3 export interface Spyglass { 4 /** 5 * Replaces the lens display with a new server-rendered page. 6 * The returned promise will be resolved once the page has been updated. 7 * 8 * @param data Some data to pass back to the server. JSON encoding is 9 * recommended, but not required. 10 */ 11 updatePage(data: string): Promise<void>; 12 /** 13 * Requests that the server re-render the lens with the provided data, and 14 * returns a promise that will resolve with that HTML as a string. 15 * 16 * This is equivalent to updatePage(), except that the displayed content is 17 * not automatically changed. 18 * @param data Some data to pass back to the server. JSON encoding is 19 * recommended, but not required. 20 */ 21 requestPage(data: string): Promise<string>; 22 /** 23 * Sends a request to the server-side lens backend with the provided data, and 24 * returns a promise that will resolve with the response as a string. 25 * 26 * @param data Some data to pass back to the server. JSON encoding is 27 * recommended, but not required. 28 */ 29 request(data: string): Promise<string>; 30 /** 31 * Inform Spyglass that the lens content has updated. This should be called whenever 32 * the visible content changes, so Spyglass can ensure that all content is visible. 33 */ 34 contentUpdated(): void; 35 } 36 37 class SpyglassImpl implements Spyglass { 38 private pendingRequests = new Map<number, (v: Response) => void>(); 39 private messageId = 0; 40 41 constructor() { 42 window.addEventListener('message', (e) => this.handleMessage(e)); 43 } 44 45 async updatePage(data: string): Promise<void> { 46 await this.postMessage({type: 'updatePage', data}); 47 this.contentUpdated(); 48 } 49 async requestPage(data: string): Promise<string> { 50 const result = await this.postMessage({type: 'requestPage', data}); 51 return result.data; 52 } 53 async request(data: string): Promise<string> { 54 const result = await this.postMessage({type: 'request', data}); 55 return result.data; 56 } 57 contentUpdated(): void { 58 // .then() to suppress complaints about unhandled promises (we just don't care here). 59 this.postMessage({type: 'contentUpdated', height: document.body.offsetHeight}).then(); 60 } 61 62 private postMessage(message: Message): Promise<Response> { 63 return new Promise<Response>((resolve, reject) => { 64 const id = ++this.messageId; 65 this.pendingRequests.set(id, resolve); 66 window.parent.postMessage({id, message}, document.location.origin); 67 }); 68 } 69 70 private handleMessage(e: MessageEvent) { 71 if (e.origin !== document.location.origin) { 72 console.warn(`Got MessageEvent from unexpected origin ${e.origin}; expected ${document.location.origin}`, e); 73 return; 74 } 75 const data = e.data; 76 if (isTransitMessage(data)) { 77 if (isResponse(data.message)) { 78 if (this.pendingRequests.has(data.id)) { 79 this.pendingRequests.get(data.id)!(data.message); 80 this.pendingRequests.delete(data.id); 81 } 82 } 83 } 84 } 85 } 86 87 const spyglass = new SpyglassImpl(); 88 89 window.addEventListener('load', () => { 90 spyglass.contentUpdated(); 91 }); 92 93 (window as any).spyglass = spyglass;