blob: 1c45a983812fe367b3d60b4ce06c737c298fc134 [file] [log] [blame]
// Copyright 2013 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.
class CWSContainerClient extends cr.EventTarget {
/**
* @param {WebView} webView Web View tag.
* @param {number} width Width of the CWS widget.
* @param {number} height Height of the CWS widget.
* @param {string} url Share Url for an entry.
* @param {string} target Target (scheme + host + port) of the widget.
* @param {Object<*>} options Options to be sent to the dialog host.
* @param {!CWSWidgetContainerPlatformDelegate} delegate Delegate for
* accessing Chrome platform APIs.
*/
constructor(webView, width, height, url, target, options, delegate) {
super();
/** @private {!CWSWidgetContainerPlatformDelegate} */
this.delegate_ = delegate;
this.webView_ = webView;
this.width_ = width;
this.height_ = height;
this.url_ = url;
this.target_ = target;
this.options_ = options;
this.loaded_ = false;
this.loading_ = false;
this.onMessageBound_ = this.onMessage_.bind(this);
this.onLoadStopBound_ = this.onLoadStop_.bind(this);
this.onLoadAbortBound_ = this.onLoadAbort_.bind(this);
}
/**
* Handles messages from the widget
* @param {Event} event Message event.
* @private
*/
onMessage_(event) {
if (event.origin != this.target_) {
return;
}
const data = event.data;
switch (data['message']) {
case 'widget_loaded':
this.onWidgetLoaded_();
break;
case 'widget_load_failed':
this.onWidgetLoadFailed_();
break;
case 'before_install':
this.sendInstallRequest_(data['item_id']);
break;
case 'after_install':
this.sendInstallDone_(data['item_id']);
break;
default:
console.error('Unexpected message: ' + data['message'], data);
}
}
/**
* Called when receiving 'loadstop' event from the <webview>.
* @param {Event} event Message event.
* @private
*/
onLoadStop_(event) {
if (this.url_ == this.webView_.src && !this.loaded_) {
this.loaded_ = true;
this.postInitializeMessage_();
}
}
/**
* Called when the widget is loaded successfully.
* @private
*/
onWidgetLoaded_() {
cr.dispatchSimpleEvent(this, CWSContainerClient.Events.LOADED);
}
/**
* Called when the widget is failed to load.
* @private
*/
onWidgetLoadFailed_() {
this.sendWidgetLoadFailed_();
}
/**
* Called when receiving the 'loadabort' event from <webview>.
* @param {Event} event Message event.
* @private
*/
onLoadAbort_(event) {
this.sendWidgetLoadFailed_();
}
/**
* Called when the installation is completed from the suggest-app dialog.
*
* @param {boolean} result True if the installation is success, false if
* failed.
* @param {string} itemId Item id to be installed.
*/
onInstallCompleted(result, itemId) {
if (result) {
this.postInstallSuccessMessage_(itemId);
} else {
this.postInstallFailureMessage_(itemId);
}
}
/**
* Send the fail message to the suggest-app dialog.
* @private
*/
sendWidgetLoadFailed_() {
cr.dispatchSimpleEvent(this, CWSContainerClient.Events.LOAD_FAILED);
}
/**
* Send the install request to the suggest-app dialog.
*
* @param {string} itemId Item id to be installed.
* @private
*/
sendInstallRequest_(itemId) {
const event = new Event(CWSContainerClient.Events.REQUEST_INSTALL);
event.itemId = itemId;
this.dispatchEvent(event);
}
/**
* Notifies the suggest-app dialog that the item installation is completed.
*
* @param {string} itemId The installed item ID.
* @private
*/
sendInstallDone_(itemId) {
const event = new Event(CWSContainerClient.Events.INSTALL_DONE);
event.itemId = itemId;
this.dispatchEvent(event);
}
/**
* Send the 'install_failure' message to the widget.
*
* @param {string} itemId Item id to be installed.
* @private
*/
postInstallFailureMessage_(itemId) {
const message = {message: 'install_failure', item_id: itemId, v: 1};
this.postMessage_(message);
}
/**
* Send the 'install_success' message to the widget.
*
* @param {string} itemId Item id to be installed.
* @private
*/
postInstallSuccessMessage_(itemId) {
const message = {message: 'install_success', item_id: itemId, v: 1};
this.postMessage_(message);
}
/**
* Send the 'initialize' message to the widget.
* @private
*/
postInitializeMessage_() {
new Promise((fulfill, reject) => {
this.delegate_.getInstalledItems(
/**
* @param {?Array<!string>} items Installed items.
* Null on error.
*/
items => {
if (!items) {
reject('Failed to retrive installed items.');
return;
}
fulfill(items);
});
})
.then(/**
* @param {!Array<string>} preinstalledExtensionIDs
*/
preinstalledExtensionIDs => {
const message = {
message: 'initialize',
hl: this.delegate_.strings.UI_LOCALE,
width: this.width_,
height: this.height_,
preinstalled_items: preinstalledExtensionIDs,
v: 1
};
if (this.options_) {
Object.keys(this.options_).forEach(key => {
message[key] = this.options_[key];
});
}
this.postMessage_(message);
});
}
/**
* Send a message to the widget. This method shouldn't be called directly,
* should from more specified posting function (eg. postXyzMessage_()).
*
* @param {Object} message Message object to be posted.
* @private
*/
postMessage_(message) {
if (!this.webView_.contentWindow) {
return;
}
this.webView_.contentWindow.postMessage(message, this.target_);
}
/**
* Loads the page to <webview>. Can be called only once.
*/
load() {
if (this.loading_ || this.loaded_) {
throw new Error('Already loaded.');
}
this.loading_ = true;
this.loaded_ = false;
window.addEventListener('message', this.onMessageBound_);
this.webView_.addEventListener('loadstop', this.onLoadStopBound_);
this.webView_.addEventListener('loadabort', this.onLoadAbortBound_);
this.webView_.setAttribute('src', this.url_);
}
/**
* Aborts loading of the embedded dialog and performs cleanup.
*/
abort() {
window.removeEventListener('message', this.onMessageBound_);
this.webView_.removeEventListener('loadstop', this.onLoadStopBound_);
this.webView_.removeEventListener('loadabort', this.onLoadAbortBound_);
this.webView_.stop();
}
/**
* Cleans the dialog by removing all handlers.
*/
dispose() {
this.abort();
}
}
/**
* Events CWSContainerClient fires
*
* @enum {string}
* @const
*/
CWSContainerClient.Events = {
LOADED: 'CWSContainerClient.Events.LOADED',
LOAD_FAILED: 'CWSContainerClient.Events.LOAD_FAILED',
REQUEST_INSTALL: 'CWSContainerClient.Events.REQUEST_INSTALL',
INSTALL_DONE: 'CWSContainerClient.Events.INSTALL_DONE'
};
Object.freeze(CWSContainerClient.Events);