Javascript  |  166行  |  5.04 KB

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * @constructor
 */
function MessageWindowImpl() {
  /**
   * Used to prevent multiple responses due to the closeWindow handler.
   *
   * @type {boolean}
   * @private
   */
  this.sentReply_ = false;

  window.addEventListener('message', this.onMessage_.bind(this), false);
};

/**
 * @param {Window} parentWindow The id of the window that showed the message.
 * @param {string} messageId The identifier of the message, as supplied by the
 *     parent.
 * @param {number} result 0 if window was closed without pressing a button;
 *     otherwise the index of the button pressed (e.g., 1 = primary).
 * @private
 */
MessageWindowImpl.prototype.sendReply_ = function(
    parentWindow, messageId, result) {
  // Only forward the first reply that we receive.
  if (!this.sentReply_) {
    var message = {
      command: 'messageWindowResult',
      id: messageId,
      result: result
    };
    parentWindow.postMessage(message, '*');
    this.sentReply_ = true;
  } else {
    // Make sure that the reply we're ignoring is from the window close.
    base.debug.assert(result == 0);
  }
};

/**
 * Size the window to its content vertically.
 * @private
 */
MessageWindowImpl.prototype.updateSize_ = function() {
  var borderY = window.outerHeight - window.innerHeight;
  window.resizeTo(window.outerWidth, document.body.clientHeight + borderY);
};

/**
 * Initializes the button with the label and the click handler.
 * Hides the button if the label is null or undefined.
 *
 * @param{HTMLElement} button
 * @param{?string} label
 * @param{Function} clickHandler
 * @private
 */
MessageWindowImpl.prototype.initButton_ =
    function(button, label, clickHandler) {
  if (label) {
    button.innerText = label;
    button.addEventListener('click', clickHandler, false);
  }
  button.hidden = !Boolean(label);
};

/**
 * Event-handler callback, invoked when the parent window supplies the
 * message content.
 *
 * @param{Event} event
 * @private
 */
MessageWindowImpl.prototype.onMessage_ = function(event) {
  switch (event.data['command']) {
    case 'show':
      // Validate the message.
      var messageId = /** @type {number} */ (event.data['id']);
      var title = /** @type {string} */ (event.data['title']);
      var message = /** @type {string} */ (event.data['message']);
      var infobox = /** @type {string} */ (event.data['infobox']);
      var buttonLabel = /** @type {string} */ (event.data['buttonLabel']);
      /** @type {string} */
      var cancelButtonLabel = (event.data['cancelButtonLabel']);
      var showSpinner = /** @type {boolean} */ (event.data['showSpinner']);
      if (typeof(messageId) != 'number' ||
          typeof(title) != 'string' ||
          typeof(message) != 'string' ||
          typeof(infobox) != 'string' ||
          typeof(buttonLabel) != 'string' ||
          typeof(showSpinner) != 'boolean') {
        console.log('Bad show message:', event.data);
        break;
      }

      // Set the dialog text.
      var button = document.getElementById('button-primary');
      var cancelButton = document.getElementById('button-secondary');
      var messageDiv = document.getElementById('message');
      var infoboxDiv = document.getElementById('infobox');

      document.getElementById('title').innerText = title;
      document.querySelector('title').innerText = title;
      messageDiv.innerHTML = message;

      if (showSpinner) {
        messageDiv.classList.add('waiting');
        messageDiv.classList.add('prominent');
      }
      if (infobox != '') {
        infoboxDiv.innerText = infobox;
      } else {
        infoboxDiv.hidden = true;
      }

      this.initButton_(
          button,
          buttonLabel,
          this.sendReply_.bind(this, event.source, messageId, 1));

      this.initButton_(
          cancelButton,
          cancelButtonLabel,
          this.sendReply_.bind(this, event.source, messageId, 0));

      var buttonToFocus = (cancelButtonLabel) ? cancelButton : button;
      buttonToFocus.focus();

      // Add a close handler in case the window is closed without clicking one
      // of the buttons. This will send a 0 as the result.
      // Note that when a button is pressed, this will result in sendReply_
      // being called multiple times (once for the button, once for close).
      chrome.app.window.current().onClosed.addListener(
          this.sendReply_.bind(this, event.source, messageId, 0));

      this.updateSize_();
      chrome.app.window.current().show();
      break;

    case 'update_message':
      var message = /** @type {string} */ (event.data['message']);
      if (typeof(message) != 'string') {
        console.log('Bad update_message message:', event.data);
        break;
      }

      var messageDiv = document.getElementById('message');
      messageDiv.innerText = message;

      this.updateSize_();
      break;

    default:
      console.error('Unexpected message:', event.data);
  }
};

var messageWindow = new MessageWindowImpl();