1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5'use strict'; 6 7/** 8 * @constructor 9 */ 10function MessageWindowImpl() { 11 /** 12 * Used to prevent multiple responses due to the closeWindow handler. 13 * 14 * @type {boolean} 15 * @private 16 */ 17 this.sentReply_ = false; 18 19 window.addEventListener('message', this.onMessage_.bind(this), false); 20}; 21 22/** 23 * @param {Window} parentWindow The id of the window that showed the message. 24 * @param {string} messageId The identifier of the message, as supplied by the 25 * parent. 26 * @param {number} result 0 if window was closed without pressing a button; 27 * otherwise the index of the button pressed (e.g., 1 = primary). 28 * @private 29 */ 30MessageWindowImpl.prototype.sendReply_ = function( 31 parentWindow, messageId, result) { 32 // Only forward the first reply that we receive. 33 if (!this.sentReply_) { 34 var message = { 35 command: 'messageWindowResult', 36 id: messageId, 37 result: result 38 }; 39 parentWindow.postMessage(message, '*'); 40 this.sentReply_ = true; 41 } else { 42 // Make sure that the reply we're ignoring is from the window close. 43 base.debug.assert(result == 0); 44 } 45}; 46 47/** 48 * Size the window to its content vertically. 49 * @private 50 */ 51MessageWindowImpl.prototype.updateSize_ = function() { 52 var borderY = window.outerHeight - window.innerHeight; 53 window.resizeTo(window.outerWidth, document.body.clientHeight + borderY); 54}; 55 56/** 57 * Initializes the button with the label and the click handler. 58 * Hides the button if the label is null or undefined. 59 * 60 * @param{HTMLElement} button 61 * @param{?string} label 62 * @param{Function} clickHandler 63 * @private 64 */ 65MessageWindowImpl.prototype.initButton_ = 66 function(button, label, clickHandler) { 67 if (label) { 68 button.innerText = label; 69 button.addEventListener('click', clickHandler, false); 70 } 71 button.hidden = !Boolean(label); 72}; 73 74/** 75 * Event-handler callback, invoked when the parent window supplies the 76 * message content. 77 * 78 * @param{Event} event 79 * @private 80 */ 81MessageWindowImpl.prototype.onMessage_ = function(event) { 82 switch (event.data['command']) { 83 case 'show': 84 // Validate the message. 85 var messageId = /** @type {number} */ (event.data['id']); 86 var title = /** @type {string} */ (event.data['title']); 87 var message = /** @type {string} */ (event.data['message']); 88 var infobox = /** @type {string} */ (event.data['infobox']); 89 var buttonLabel = /** @type {string} */ (event.data['buttonLabel']); 90 /** @type {string} */ 91 var cancelButtonLabel = (event.data['cancelButtonLabel']); 92 var showSpinner = /** @type {boolean} */ (event.data['showSpinner']); 93 if (typeof(messageId) != 'number' || 94 typeof(title) != 'string' || 95 typeof(message) != 'string' || 96 typeof(infobox) != 'string' || 97 typeof(buttonLabel) != 'string' || 98 typeof(showSpinner) != 'boolean') { 99 console.log('Bad show message:', event.data); 100 break; 101 } 102 103 // Set the dialog text. 104 var button = document.getElementById('button-primary'); 105 var cancelButton = document.getElementById('button-secondary'); 106 var messageDiv = document.getElementById('message'); 107 var infoboxDiv = document.getElementById('infobox'); 108 109 document.getElementById('title').innerText = title; 110 document.querySelector('title').innerText = title; 111 messageDiv.innerHTML = message; 112 113 if (showSpinner) { 114 messageDiv.classList.add('waiting'); 115 messageDiv.classList.add('prominent'); 116 } 117 if (infobox != '') { 118 infoboxDiv.innerText = infobox; 119 } else { 120 infoboxDiv.hidden = true; 121 } 122 123 this.initButton_( 124 button, 125 buttonLabel, 126 this.sendReply_.bind(this, event.source, messageId, 1)); 127 128 this.initButton_( 129 cancelButton, 130 cancelButtonLabel, 131 this.sendReply_.bind(this, event.source, messageId, 0)); 132 133 var buttonToFocus = (cancelButtonLabel) ? cancelButton : button; 134 buttonToFocus.focus(); 135 136 // Add a close handler in case the window is closed without clicking one 137 // of the buttons. This will send a 0 as the result. 138 // Note that when a button is pressed, this will result in sendReply_ 139 // being called multiple times (once for the button, once for close). 140 chrome.app.window.current().onClosed.addListener( 141 this.sendReply_.bind(this, event.source, messageId, 0)); 142 143 this.updateSize_(); 144 chrome.app.window.current().show(); 145 break; 146 147 case 'update_message': 148 var message = /** @type {string} */ (event.data['message']); 149 if (typeof(message) != 'string') { 150 console.log('Bad update_message message:', event.data); 151 break; 152 } 153 154 var messageDiv = document.getElementById('message'); 155 messageDiv.innerText = message; 156 157 this.updateSize_(); 158 break; 159 160 default: 161 console.error('Unexpected message:', event.data); 162 } 163}; 164 165var messageWindow = new MessageWindowImpl(); 166