541 lines
14 KiB
JavaScript
541 lines
14 KiB
JavaScript
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS-IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/**
|
|
* @fileoverview A component that displays the offline status of an app.
|
|
* Currently, it is used to show an icon with a tootip for the status.
|
|
*
|
|
* @see ../demos/offline.html
|
|
*/
|
|
|
|
goog.provide('goog.ui.OfflineStatusComponent');
|
|
goog.provide('goog.ui.OfflineStatusComponent.StatusClassNames');
|
|
|
|
goog.require('goog.dom.classes');
|
|
goog.require('goog.events.EventType');
|
|
goog.require('goog.gears.StatusType');
|
|
goog.require('goog.positioning.AnchoredPosition');
|
|
goog.require('goog.positioning.Corner');
|
|
goog.require('goog.positioning.Overflow');
|
|
goog.require('goog.ui.Component');
|
|
goog.require('goog.ui.OfflineStatusCard');
|
|
goog.require('goog.ui.Popup');
|
|
|
|
|
|
|
|
/**
|
|
* An offline status component.
|
|
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
|
|
* @constructor
|
|
* @extends {goog.ui.Component}
|
|
*/
|
|
goog.ui.OfflineStatusComponent = function(opt_domHelper) {
|
|
goog.ui.Component.call(this, opt_domHelper);
|
|
};
|
|
goog.inherits(goog.ui.OfflineStatusComponent, goog.ui.Component);
|
|
|
|
|
|
/**
|
|
* The className's to use for the element of the component for each status type.
|
|
* @enum {string}
|
|
*/
|
|
goog.ui.OfflineStatusComponent.StatusClassNames = {
|
|
NOT_INSTALLED: goog.getCssName('goog-offlinestatus-notinstalled'),
|
|
INSTALLED: goog.getCssName('goog-offlinestatus-installed'),
|
|
PAUSED: goog.getCssName('goog-offlinestatus-paused'),
|
|
OFFLINE: goog.getCssName('goog-offlinestatus-offline'),
|
|
ONLINE: goog.getCssName('goog-offlinestatus-online'),
|
|
SYNCING: goog.getCssName('goog-offlinestatus-syncing'),
|
|
ERROR: goog.getCssName('goog-offlinestatus-error')
|
|
};
|
|
|
|
|
|
/**
|
|
* Whether the component is dirty and requires an upate to its display.
|
|
* @type {boolean}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.dirty_ = false;
|
|
|
|
|
|
/**
|
|
* The status of the component.
|
|
* @type {goog.gears.StatusType}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.status_ =
|
|
goog.gears.StatusType.NOT_INSTALLED;
|
|
|
|
|
|
/**
|
|
* The status of the component that is displayed.
|
|
* @type {goog.gears.StatusType?}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.displayedStatus_ = null;
|
|
|
|
|
|
/**
|
|
* The dialog that manages the install flow.
|
|
* @type {goog.ui.OfflineInstallDialog?}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.dialog_ = null;
|
|
|
|
|
|
/**
|
|
* The card for displaying the detailed status.
|
|
* @type {goog.ui.OfflineStatusCard?}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.card_ = null;
|
|
|
|
|
|
/**
|
|
* The popup for the OfflineStatusCard.
|
|
* @type {goog.ui.Popup?}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.popup_ = null;
|
|
|
|
|
|
/**
|
|
* CSS class name for the element.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.className_ =
|
|
goog.getCssName('goog-offlinestatus');
|
|
|
|
|
|
/**
|
|
* @desc New feature text for the offline acces feature.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.MSG_OFFLINE_NEW_FEATURE_ =
|
|
goog.getMsg('New! Offline Access');
|
|
|
|
|
|
/**
|
|
* @desc Connectivity status of the app indicating the app is paused (user
|
|
* initiated offline).
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.MSG_OFFLINE_STATUS_PAUSED_TITLE_ =
|
|
goog.getMsg('Paused (offline). Click to connect.');
|
|
|
|
|
|
/**
|
|
* @desc Connectivity status of the app indicating the app is offline.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.MSG_OFFLINE_STATUS_OFFLINE_TITLE_ =
|
|
goog.getMsg('Offline. No connection available.');
|
|
|
|
|
|
/**
|
|
* @desc Connectivity status of the app indicating the app is online.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.MSG_OFFLINE_STATUS_ONLINE_TITLE_ =
|
|
goog.getMsg('Online. Click for details.');
|
|
|
|
|
|
/**
|
|
* @desc Connectivity status of the app indicating the app is synchronizing with
|
|
* the server.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.MSG_OFFLINE_STATUS_SYNCING_TITLE_ =
|
|
goog.getMsg('Synchronizing. Click for details.');
|
|
|
|
|
|
/**
|
|
* @desc Connectivity status of the app indicating errors have been found.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.MSG_OFFLINE_STATUS_ERROR_TITLE_ =
|
|
goog.getMsg('Errors found. Click for details.');
|
|
|
|
|
|
/**
|
|
* Gets the status of the offline component of the app.
|
|
* @return {goog.gears.StatusType} The offline status.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.getStatus = function() {
|
|
return this.status_;
|
|
};
|
|
|
|
|
|
/**
|
|
* Sets the status of the offline component of the app.
|
|
* @param {goog.gears.StatusType} status The offline
|
|
* status.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.setStatus = function(status) {
|
|
if (this.isStatusDifferent(status)) {
|
|
this.dirty_ = true;
|
|
}
|
|
|
|
this.status_ = status;
|
|
if (this.isInDocument()) {
|
|
this.update();
|
|
}
|
|
|
|
// Set the status of the card, if necessary.
|
|
if (this.card_) {
|
|
this.card_.setStatus(status);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Returns whether the given status is different from the currently
|
|
* recorded status.
|
|
* @param {goog.gears.StatusType} status The offline status.
|
|
* @return {boolean} Whether the status is different.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.isStatusDifferent = function(status) {
|
|
return this.status_ != status;
|
|
};
|
|
|
|
|
|
/**
|
|
* Sets the install dialog.
|
|
* @param {goog.ui.OfflineInstallDialog} dialog The dialog.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.setInstallDialog = function(dialog) {
|
|
// If there is a current dialog, remove it.
|
|
if (this.dialog_ && this.indexOfChild(this.dialog_) >= 0) {
|
|
this.removeChild(this.dialog_);
|
|
}
|
|
this.dialog_ = dialog;
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the install dialog.
|
|
* @return {goog.ui.OfflineInstallDialog} dialog The dialog.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.getInstallDialog = function() {
|
|
return this.dialog_;
|
|
};
|
|
|
|
|
|
/**
|
|
* Sets the status card.
|
|
* @param {goog.ui.OfflineStatusCard} card The card.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.setStatusCard = function(card) {
|
|
// If there is a current card, remove it.
|
|
if (this.card_) {
|
|
this.getHandler().unlisten(this.card_,
|
|
goog.ui.OfflineStatusCard.EventType.DISMISS,
|
|
this.performStatusAction, false, this);
|
|
this.popup_.dispose();
|
|
if (this.indexOfChild(this.card_) >= 0) {
|
|
this.removeChild(this.card_);
|
|
}
|
|
this.popup_ = null;
|
|
this.card_ = null;
|
|
}
|
|
this.card_ = card;
|
|
this.getHandler().listen(this.card_,
|
|
goog.ui.OfflineStatusCard.EventType.DISMISS,
|
|
this.performStatusAction, false, this);
|
|
card.setStatus(this.status_);
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the status card.
|
|
* @return {goog.ui.OfflineStatusCard} The card.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.getStatusCard = function() {
|
|
return this.card_;
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates the initial DOM representation for the component.
|
|
* @override
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.createDom = function() {
|
|
var anchorProps = {
|
|
'class': this.className_,
|
|
'href': '#'
|
|
};
|
|
this.setElementInternal(
|
|
this.getDomHelper().createDom('a', anchorProps));
|
|
this.update();
|
|
};
|
|
|
|
|
|
/** @override */
|
|
goog.ui.OfflineStatusComponent.prototype.enterDocument = function() {
|
|
goog.ui.OfflineStatusComponent.superClass_.enterDocument.call(this);
|
|
|
|
this.getHandler().listen(
|
|
this.getElement(), goog.events.EventType.CLICK, this.handleClick_);
|
|
|
|
if (this.dirty_) {
|
|
this.update();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Updates the display of the component.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.update = function() {
|
|
if (this.getElement()) {
|
|
var status = this.getStatus();
|
|
var messageInfo = this.getMessageInfo(status);
|
|
|
|
// Set the title.
|
|
var element = this.getElement();
|
|
element.title = messageInfo.title;
|
|
|
|
// Set the appropriate class.
|
|
var previousStatus = this.displayStatus_;
|
|
var previousStatusClassName = this.getStatusClassName_(previousStatus);
|
|
var currentStatusClassName = this.getStatusClassName_(status);
|
|
if (previousStatus &&
|
|
goog.dom.classes.has(element, previousStatusClassName)) {
|
|
goog.dom.classes.swap(
|
|
element, previousStatusClassName, currentStatusClassName);
|
|
} else {
|
|
goog.dom.classes.add(element, currentStatusClassName);
|
|
}
|
|
|
|
// Set the current display status
|
|
this.displayStatus_ = status;
|
|
|
|
// Set the text.
|
|
if (messageInfo.textIsHtml) {
|
|
element.innerHTML = messageInfo.text;
|
|
} else {
|
|
this.getDomHelper().setTextContent(element, messageInfo.text);
|
|
}
|
|
|
|
// Clear the dirty state.
|
|
this.dirty_ = false;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the messaging info for the given status.
|
|
* @param {goog.gears.StatusType} status Status to get the message info for.
|
|
* @return {Object} Object that has three properties - text (string),
|
|
* textIsHtml (boolean), and title (string).
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.getMessageInfo = function(status) {
|
|
var title = '';
|
|
var text = ' ';
|
|
var textIsHtml = true;
|
|
|
|
switch (status) {
|
|
case goog.gears.StatusType.NOT_INSTALLED:
|
|
case goog.gears.StatusType.INSTALLED:
|
|
text = this.MSG_OFFLINE_NEW_FEATURE_;
|
|
textIsHtml = false;
|
|
break;
|
|
case goog.gears.StatusType.PAUSED:
|
|
title = this.MSG_OFFLINE_STATUS_PAUSED_TITLE_;
|
|
break;
|
|
case goog.gears.StatusType.OFFLINE:
|
|
title = this.MSG_OFFLINE_STATUS_OFFLINE_TITLE_;
|
|
break;
|
|
case goog.gears.StatusType.ONLINE:
|
|
title = this.MSG_OFFLINE_STATUS_ONLINE_TITLE_;
|
|
break;
|
|
case goog.gears.StatusType.SYNCING:
|
|
title = this.MSG_OFFLINE_STATUS_SYNCING_TITLE_;
|
|
break;
|
|
case goog.gears.StatusType.ERROR:
|
|
title = this.MSG_OFFLINE_STATUS_ERROR_TITLE_;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return {text: text, textIsHtml: textIsHtml, title: title};
|
|
};
|
|
|
|
|
|
/**
|
|
* Gets the CSS className for the given status.
|
|
* @param {goog.gears.StatusType} status Status to get the className for.
|
|
* @return {string} The className.
|
|
* @private
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.getStatusClassName_ = function(
|
|
status) {
|
|
var className = '';
|
|
switch (status) {
|
|
case goog.gears.StatusType.NOT_INSTALLED:
|
|
className =
|
|
goog.ui.OfflineStatusComponent.StatusClassNames.NOT_INSTALLED;
|
|
break;
|
|
case goog.gears.StatusType.INSTALLED:
|
|
className = goog.ui.OfflineStatusComponent.StatusClassNames.INSTALLED;
|
|
break;
|
|
case goog.gears.StatusType.PAUSED:
|
|
className = goog.ui.OfflineStatusComponent.StatusClassNames.PAUSED;
|
|
break;
|
|
case goog.gears.StatusType.OFFLINE:
|
|
className = goog.ui.OfflineStatusComponent.StatusClassNames.OFFLINE;
|
|
break;
|
|
case goog.gears.StatusType.ONLINE:
|
|
className = goog.ui.OfflineStatusComponent.StatusClassNames.ONLINE;
|
|
break;
|
|
case goog.gears.StatusType.SYNCING:
|
|
case goog.gears.StatusType.CAPTURING:
|
|
className = goog.ui.OfflineStatusComponent.StatusClassNames.SYNCING;
|
|
break;
|
|
case goog.gears.StatusType.ERROR:
|
|
className = goog.ui.OfflineStatusComponent.StatusClassNames.ERROR;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return className;
|
|
};
|
|
|
|
|
|
/**
|
|
* Handles a click on the component. Opens the applicable install dialog or
|
|
* status card.
|
|
* @param {goog.events.BrowserEvent} e The event.
|
|
* @private
|
|
* @return {boolean|undefined} Always false to prevent the anchor navigation.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.handleClick_ = function(e) {
|
|
this.performAction();
|
|
return false;
|
|
};
|
|
|
|
|
|
/**
|
|
* Performs the action as if the component was clicked.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.performAction = function() {
|
|
var status = this.getStatus();
|
|
|
|
if (status == goog.gears.StatusType.NOT_INSTALLED ||
|
|
status == goog.gears.StatusType.INSTALLED) {
|
|
this.performEnableAction();
|
|
} else {
|
|
this.performStatusAction();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Performs the action to start the flow of enabling the offline feature of
|
|
* the application.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.performEnableAction = function() {
|
|
// If Gears is not installed or if it is installed but not enabled, then
|
|
// show the install dialog.
|
|
var dialog = this.dialog_;
|
|
if (dialog) {
|
|
if (!dialog.isInDocument()) {
|
|
this.addChild(dialog);
|
|
dialog.render(this.getDomHelper().getDocument().body);
|
|
}
|
|
dialog.setVisible(true);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Performs the action to show the offline status.
|
|
* @param {goog.events.Event=} opt_evt Event.
|
|
* @param {Element=} opt_element Optional element to anchor the card against.
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.performStatusAction = function(opt_evt,
|
|
opt_element) {
|
|
// Shows the offline status card.
|
|
var card = this.card_;
|
|
if (card) {
|
|
if (!this.popup_) {
|
|
if (!card.getElement()) {
|
|
card.createDom();
|
|
}
|
|
this.insertCardElement(card);
|
|
this.addChild(card);
|
|
var popup = this.getPopupInternal();
|
|
var anchorEl = opt_element || this.getElement();
|
|
var pos = new goog.positioning.AnchoredPosition(
|
|
anchorEl, goog.positioning.Corner.BOTTOM_START,
|
|
goog.positioning.Overflow.ADJUST_X);
|
|
popup.setPosition(pos);
|
|
popup.setElement(card.getElement());
|
|
}
|
|
this.popup_.setVisible(!this.popup_.isOrWasRecentlyVisible());
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Inserts the card into the document body.
|
|
* @param {goog.ui.OfflineStatusCard} card The offline status card.
|
|
* @protected
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.insertCardElement = function(card) {
|
|
this.getDomHelper().getDocument().body.appendChild(card.getElement());
|
|
};
|
|
|
|
|
|
/**
|
|
* @return {goog.ui.Popup} A popup object, if none exists a new one is created.
|
|
* @protected
|
|
*/
|
|
goog.ui.OfflineStatusComponent.prototype.getPopupInternal = function() {
|
|
if (!this.popup_) {
|
|
this.popup_ = new goog.ui.Popup();
|
|
this.popup_.setMargin(3, 0, 0, 0);
|
|
}
|
|
return this.popup_;
|
|
};
|
|
|
|
|
|
/** @override */
|
|
goog.ui.OfflineStatusComponent.prototype.disposeInternal = function() {
|
|
goog.ui.OfflineStatusComponent.superClass_.disposeInternal.call(this);
|
|
|
|
if (this.dialog_) {
|
|
this.dialog_.dispose();
|
|
this.dialog_ = null;
|
|
}
|
|
|
|
if (this.card_) {
|
|
this.card_.dispose();
|
|
this.card_ = null;
|
|
}
|
|
|
|
if (this.popup_) {
|
|
this.popup_.dispose();
|
|
this.popup_ = null;
|
|
}
|
|
};
|