![JAR search and dependency download from the Maven repository](/logo.png)
features.container.container.js Maven / Gradle / Ivy
Go to download
Packages all the features that shindig provides into a single jar file to allow
loading from the classpath
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 This represents the container for the current window or create
* the container if none already exists.
*/
/**
* @param {Object=} opt_config Configuration JSON.
* @constructor
*/
osapi.container.Container = function(opt_config) {
var config = this.config_ = opt_config || {};
/**
* A list of objects containing functions to be invoked when gadgets are
* preloaded, navigated, closed or unloaded. Sample object:
*
* var callback = new Object();
* callback[osapi.container.CallbackType.ON_PRELOADED]
* = function(response){};
* callback[osapi.container.CallbackType.ON_CLOSED]
* = function(gadgetSite){};
* callback[osapi.container.CallbackType.ON_NAVIGATED]
* = function(gadgetSite){};
* callback[osapi.container.CallbackType.ON_UNLOADED]
* = function(gadgetURL){};
* @type {Array}
* @private
*/
this.gadgetLifecycleCallbacks_ = {};
/**
* A JSON list of preloaded gadget URLs.
* @type {Object}
* @private
*/
this.preloadedGadgetUrls_ = {};
/**
* @type {Object}
* @private
*/
this.sites_ = {};
/**
* @type {boolean}
* @private
*/
this.allowDefaultView_ = Boolean(
osapi.container.util.getSafeJsonValue(config,
osapi.container.ContainerConfig.ALLOW_DEFAULT_VIEW, true));
/**
* @type {boolean}
* @private
*/
this.renderCajole_ = Boolean(
osapi.container.util.getSafeJsonValue(config,
osapi.container.ContainerConfig.RENDER_CAJOLE, false));
/**
* @type {string}
* @private
*/
this.renderDebugParam_ = String(osapi.container.util.getSafeJsonValue(
config, osapi.container.ContainerConfig.RENDER_DEBUG_PARAM,
osapi.container.ContainerConfig.RENDER_DEBUG));
/**
* @type {boolean}
* @private
*/
var param = window.__CONTAINER_URI.getQP(this.renderDebugParam_);
this.renderDebug_ = (typeof param === 'undefined') ?
Boolean(osapi.container.util.getSafeJsonValue(config,
osapi.container.ContainerConfig.RENDER_DEBUG, false)) :
(param === '1');
/**
* @type {boolean}
* @private
*/
this.renderTest_ = Boolean(osapi.container.util.getSafeJsonValue(config,
osapi.container.ContainerConfig.RENDER_TEST, false));
/**
* Security token refresh interval (in ms). Set to < 0 in config to disable
* token refresh.
*
* Provided this number is >= 0, the smallest encountered token ttl or this
* number will be used as the refresh interval, whichever is smaller.
*
* @type {number}
* @private
*/
this.tokenRefreshInterval_ = Number(osapi.container.util.getSafeJsonValue(
config, osapi.container.ContainerConfig.TOKEN_REFRESH_INTERVAL, 0));
/**
* The time of the last token refresh.
* @type {number}
* @private
*/
this.lastRefresh_ = 0;
/**
* @type {number}
* @private
*/
this.navigateCallback_ = String(osapi.container.util.getSafeJsonValue(
config, osapi.container.ContainerConfig.NAVIGATE_CALLBACK,
null));
/**
* @type {osapi.container.Service}
* @private
*/
this.service_ = new osapi.container.Service(config);
/**
* result from calling window.setInterval()
* @type {?number}
* @private
*/
this.tokenRefreshTimer_ = null;
var self = this;
window[osapi.container.CallbackType.GADGET_ON_LOAD] = function(gadgetUrl){
self.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_RENDER, gadgetUrl);
};
this.initializeMixins_();
this.setupRpcArbitrator_(config);
this.preloadCaches(config);
this.registerRpcServices_();
this.onConstructed(config);
};
/**
* Create a new gadget site.
* @param {Element} gadgetEl HTML element into which to render.
* @param {Element=} opt_bufferEl Optional HTML element for double buffering.
* @return {osapi.container.GadgetSite} site created for client to hold to.
*/
osapi.container.Container.prototype.newGadgetSite = function(
gadgetEl, opt_bufferEl) {
var bufferEl = opt_bufferEl || null;
var site = new osapi.container.GadgetSite({
'container': this,
'service' : this.service_,
'navigateCallback' : this.navigateCallback_,
'gadgetEl' : gadgetEl,
'bufferEl' : bufferEl,
'gadgetOnLoad' : osapi.container.CallbackType.GADGET_ON_LOAD
});
this.sites_[site.getId()] = site;
return site;
};
/**
* Called when gadget is navigated.
*
* @param {osapi.container.GadgetSite} site destination gadget to navigate to.
* @param {string} gadgetUrl The URI of the gadget.
* @param {Object} viewParams view params for the gadget.
* @param {Object} renderParams render parameters, including the view.
* @param {function(Object)=} opt_callback Callback after gadget is loaded.
*/
osapi.container.Container.prototype.navigateGadget = function(
site, gadgetUrl, viewParams, renderParams, opt_callback) {
var callback = opt_callback || function() {},
ContainerConfig = osapi.container.ContainerConfig,
RenderParam = osapi.container.RenderParam;
if (this.allowDefaultView_) {
renderParams[RenderParam.ALLOW_DEFAULT_VIEW] = true;
}
if (this.renderCajole_) {
renderParams[RenderParam.CAJOLE] = true;
}
if (this.renderDebug_) {
renderParams[RenderParam.NO_CACHE] = true;
renderParams[RenderParam.DEBUG] = true;
}
if (this.renderTest_) {
renderParams[RenderParam.TEST_MODE] = true;
}
this.refreshService_();
var
self = this,
selfSite = site,
finishNavigate = function(preferences) {
renderParams[RenderParam.USER_PREFS] = preferences;
self.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_BEFORE_NAVIGATE,
gadgetUrl);
// TODO: Lifecycle, add ability for current gadget to cancel nav.
site.navigateTo(gadgetUrl, viewParams, renderParams, function(gadgetInfo) {
// TODO: Navigate to error screen on primary gadget load failure
// TODO: Should display error without doing a standard navigate.
// TODO: Bad if the error gadget fails to load.
if (gadgetInfo.error) {
gadgets.warn(['Failed to possibly schedule token refresh for gadget ',
gadgetUrl, '.'].join(''));
} else if (gadgetInfo[osapi.container.MetadataResponse.NEEDS_TOKEN_REFRESH]) {
self.scheduleRefreshTokens_(gadgetInfo[osapi.container.MetadataResponse.TOKEN_TTL]);
}
self.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_NAVIGATED,
selfSite);
callback(gadgetInfo);
});
};
// Try to retrieve preferences for the gadget if no preferences were explicitly provided.
if (this.config_[ContainerConfig.GET_PREFERENCES] && !renderParams[RenderParam.USER_PREFS]) {
this.config_[ContainerConfig.GET_PREFERENCES](site.getId(), gadgetUrl, finishNavigate);
}
else {
finishNavigate(renderParams[RenderParam.USER_PREFS]);
}
};
/**
* Called when gadget is closed. This may stop refreshing of tokens.
* @param {osapi.container.GadgetSite} site navigate gadget to close.
*/
osapi.container.Container.prototype.closeGadget = function(site) {
var id = site.getId();
this.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_BEFORE_CLOSE, site);
site.close();
this.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_CLOSED, site);
delete this.sites_[id];
this.unscheduleRefreshTokens_();
};
/**
* Add a callback to be called when one or more gadgets are preloaded,
* navigated to or closed.
*
* @param {string} name name of the lifecycle callback.
* @param {Object} lifeCycleCallback callback object to call back when a gadget is
* preloaded, navigated to or closed. called via preloaded, navigated
* and closed methods.
*
* @return {boolean} true if added successfully, false if a callback
* with that name is already registered.
*/
osapi.container.Container.prototype.addGadgetLifecycleCallback = function(name, lifeCycleCallback) {
if (!this.gadgetLifecycleCallbacks_[name]) {
this.gadgetLifecycleCallbacks_[name] = lifeCycleCallback;
return true;
}
return false;
};
/**
* remove a lifecycle callback previously registered with the container
* @param {string} name callback object to be removed.
*/
osapi.container.Container.prototype.removeGadgetLifecycleCallback = function(name) {
delete this.gadgetLifecycleCallbacks_[name];
};
/**
* Pre-load one gadget metadata information. More details on preloadGadgets().
* @param {string} gadgetUrl gadget URI to preload.
* @param {function(Object)=} opt_callback function to call upon data receive.
*/
osapi.container.Container.prototype.preloadGadget = function(gadgetUrl, opt_callback) {
this.preloadGadgets([gadgetUrl], opt_callback);
};
/**
* Pre-load gadgets metadata information. This is done by priming the cache,
* and making an immediate call to fetch metadata of gadgets fully specified at
* gadgetUrls. This will not render, and do additional callback operations.
* @param {Array} gadgetUrls gadgets URIs to preload.
* @param {function(Object)=} opt_callback function to call upon data receive.
*/
osapi.container.Container.prototype.preloadGadgets = function(gadgetUrls, opt_callback) {
var callback = opt_callback || function() {};
var request = osapi.container.util.newMetadataRequest(gadgetUrls);
var self = this;
this.refreshService_();
this.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_BEFORE_PRELOAD, gadgetUrls);
this.service_.getGadgetMetadata(request, function(response) {
self.addPreloadGadgets_(response);
self.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_PRELOADED,
response);
callback(response);
});
};
/**
* Unload preloaded gadget. Makes future preload request possibly uncached.
* @param {string} gadgetUrl gadget URI to unload.
*/
osapi.container.Container.prototype.unloadGadget = function(gadgetUrl) {
this.unloadGadgets([gadgetUrl]);
};
/**
* Unload preloaded gadgets. Makes future preload request possibly uncached.
* @param {Array} gadgetUrls gadgets URIs to unload.
*/
osapi.container.Container.prototype.unloadGadgets = function(gadgetUrls) {
for (var i = 0; i < gadgetUrls.length; i++) {
var url = gadgetUrls[i];
this.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_BEFORE_UNLOAD,
url);
delete this.preloadedGadgetUrls_[url];
this.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_UNLOADED,
url);
}
};
/**
* Fetch the gadget metadata commonly used by container for user preferences.
* @param {string} gadgetUrl gadgets URI to fetch metadata for. to preload.
* @param {function(Object)} callback Function called with gadget metadata.
*/
osapi.container.Container.prototype.getGadgetMetadata = function(
gadgetUrl, callback) {
var request = osapi.container.util.newMetadataRequest([gadgetUrl]);
this.refreshService_();
this.service_.getGadgetMetadata(request, callback);
};
/**
* @param {string} service name of RPC service to register.
* @param {Function} callback post-RPC function to call, with RPC-related
* arguments (with the calling GadgetSite augmented) and the
* callback response itself.
*/
osapi.container.Container.prototype.rpcRegister = function(service, callback) {
var self = this;
gadgets.rpc.register(service, function() {
// this['f'] is set by calling iframe via gadgets.rpc.
this[osapi.container.GadgetSite.RPC_ARG_KEY] =
self.getGadgetSiteByIframeId_(this['f']);
var argsCopy = [this];
for (var i = 0; i < arguments.length; ++i) {
argsCopy.push(arguments[i]);
}
return callback.apply(self, argsCopy);
});
};
/**
* Callback that occurs after instantiation/construction of this. Override to
* provide your specific functionalities.
* @param {Object=} opt_config Configuration JSON.
*/
osapi.container.Container.prototype.onConstructed = function(opt_config) {};
/**
* Adds a new namespace to the Container object. The namespace
* will contain the result of calling the function passed in.
*
* @param {string} namespace the namespace to add.
* @param {function} func to call when creating the namespace.
*/
osapi.container.Container.addMixin = function(namespace, func) {
osapi.container.Container.prototype.mixins_[namespace] = func;
};
// -----------------------------------------------------------------------------
// Valid JSON keys.
// -----------------------------------------------------------------------------
/**
* Enumeration of configuration keys for this container. This is specified in
* JSON to provide extensible configuration. These enum values are for
* documentation purposes only, it is expected that clients use the string
* values.
* @enum {string}
*/
osapi.container.ContainerConfig = {};
/**
* Allow gadgets to render in unspecified view.
* @type {string}
* @const
*/
osapi.container.ContainerConfig.ALLOW_DEFAULT_VIEW = 'allowDefaultView';
/**
* Whether cajole mode is turned on.
* @type {string}
* @const
*/
osapi.container.ContainerConfig.RENDER_CAJOLE = 'renderCajole';
/**
* Whether debug mode is turned on.
* @type {string}
* @const
*/
osapi.container.ContainerConfig.RENDER_DEBUG = 'renderDebug';
/**
* The debug param name to look for in container URL for per-request debugging.
* @type {string}
* @const
*/
osapi.container.ContainerConfig.RENDER_DEBUG_PARAM = 'renderDebugParam';
/**
* Whether test mode is turned on.
* @type {string}
* @const
*/
osapi.container.ContainerConfig.RENDER_TEST = 'renderTest';
/**
* Security token refresh interval (in ms) for debugging.
* @type {string}
* @const
*/
osapi.container.ContainerConfig.TOKEN_REFRESH_INTERVAL = 'tokenRefreshInterval';
/**
* Globally-defined callback function upon gadget navigation. Useful to
* broadcast timing and stat information back to container.
* @type {string}
* @const
*/
osapi.container.ContainerConfig.NAVIGATE_CALLBACK = 'navigateCallback';
/**
* Provide server reference time for preloaded data.
* This time is used instead of each response time in order to support server
* caching of results.
* @type {number}
* @const
*/
osapi.container.ContainerConfig.PRELOAD_REF_TIME = 'preloadRefTime';
/**
* Preloaded hash of gadgets metadata
* @type {Object}
* @const
*/
osapi.container.ContainerConfig.PRELOAD_METADATAS = 'preloadMetadatas';
/**
* Preloaded hash of gadgets tokens
* @type {Object}
* @const
*/
osapi.container.ContainerConfig.PRELOAD_TOKENS = 'preloadTokens';
/**
* Used to query the language locale part of the container page.
* @type {function}
*/
osapi.container.ContainerConfig.GET_LANGUAGE = 'GET_LANGUAGE';
/**
* Used to query the country locale part of the container page.
* @type {function}
*/
osapi.container.ContainerConfig.GET_COUNTRY = 'GET_COUNTRY';
/**
* Used to retrieve the persisted preferences for a gadget.
* @type {function}
*/
osapi.container.ContainerConfig.GET_PREFERENCES = 'GET_PREFERENCES';
/**
* Used to persist preferences for a gadget.
* @type {function}
*/
osapi.container.ContainerConfig.SET_PREFERENCES = 'SET_PREFERENCES';
/**
* Used to arbitrate RPC calls.
* @type {function}
*/
osapi.container.ContainerConfig.RPC_ARBITRATOR = 'rpcArbitrator';
/**
* Used to retrieve security tokens for gadgets.
* @type {function}
*/
osapi.container.ContainerConfig.GET_GADGET_TOKEN = 'GET_GADGET_TOKEN';
// -----------------------------------------------------------------------------
// Private variables and methods.
// -----------------------------------------------------------------------------
/**
* Adds the ability for features to extend the container with
* their own functionality that may be specific to that feature.
* @type {Object}
* @private
*/
osapi.container.Container.prototype.mixins_ = {};
/**
* Called from the constructor to add any namespace extensions.
* @private
*/
osapi.container.Container.prototype.initializeMixins_ = function() {
for (var i in this.mixins_) {
this[i] = new this.mixins_[i](this);
}
};
/**
* Add list of gadgets to preload list
* @param {Object} response hash of gadgets data.
* @private
*/
osapi.container.Container.prototype.addPreloadGadgets_ = function(response) {
for (var id in response) {
if (response[id].error) {
gadgets.warn(['Failed to preload gadget ', id, '.'].join(''));
} else {
this.addPreloadedGadgetUrl_(id);
if (response[id][osapi.container.MetadataResponse.NEEDS_TOKEN_REFRESH]) {
// Safe to re-schedule many times.
this.scheduleRefreshTokens_(response[id][osapi.container.MetadataResponse.TOKEN_TTL]);
}
}
}
};
/**
* Preload gadget metadata and tokens to avoid the need for XHR's when navigating gadget sites.
* This function is safe to call repeatedly if needed to incrementally build up the internal caches.
* Support caching by providing server time to override response time usage.
* @param {Object} preloadData object containing data to be preloaded.
*/
osapi.container.Container.prototype.preloadCaches = function(preloadData) {
var gadgets = osapi.container.util.getSafeJsonValue(
preloadData, osapi.container.ContainerConfig.PRELOAD_METADATAS, {});
var tokens = osapi.container.util.getSafeJsonValue(
preloadData, osapi.container.ContainerConfig.PRELOAD_TOKENS, {});
var refTime = osapi.container.util.getSafeJsonValue(
preloadData, osapi.container.ContainerConfig.PRELOAD_REF_TIME, null);
this.service_.addGadgetMetadatas(gadgets, refTime);
this.service_.addGadgetTokens(tokens, refTime);
this.addPreloadGadgets_(gadgets);
};
/**
* Deletes stale cached data in service. The container knows what data are safe
* to be marked for deletion.
* @private
*/
osapi.container.Container.prototype.refreshService_ = function() {
var urls = this.getActiveGadgetUrls_();
this.service_.uncacheStaleGadgetMetadataExcept(urls);
// TODO: also uncache stale gadget tokens.
};
/**
* @param {string} iframeId Iframe ID of gadget holder contained in the gadget
* site to get.
* @return {osapi.container.GadgetSite} The gadget site.
* @private
*/
osapi.container.Container.prototype.getGadgetSiteByIframeId_ = function(iframeId) {
// TODO: Support getting only the loading/active gadget in 2x buffers.
for (var siteId in this.sites_) {
var site = this.sites_[siteId];
var holder = site.getActiveGadgetHolder();
if (holder && holder.getIframeId() === iframeId) {
return site;
}
}
return null;
};
/**
* Start to schedule refreshing of tokens.
* @param {number} Encountered token time to live in seconds.
* @private
*/
osapi.container.Container.prototype.scheduleRefreshTokens_ = function(tokenTTL) {
var self = this,
oldInterval = this.tokenRefreshInterval_,
newInterval = tokenTTL ? this.setRefreshTokenInterval_(tokenTTL * 1000) : oldInterval,
refresh = function() {
self.lastRefresh_ = osapi.container.util.getCurrentTimeMs();
// Schedule the next refresh.
self.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
// Do this last so that if it ever errors, we maintain the refresh schedule.
self.refreshTokens_();
};
// If enabled, check to see if we no schedule or if the two intervals are different and update the schedule.
if (this.isRefreshTokensEnabled_() && (!this.tokenRefreshTimer_ || newInterval != oldInterval)) {
var now = osapi.container.util.getCurrentTimeMs();
if (!this.tokenRefreshTimer_) {
this.lastRefresh_ = now;
this.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
}
else {
var futureRefresh = (this.lastRefresh_ || 0) + oldInterval;
if (futureRefresh < now) {
// This really shouldn't happen, but if for some reason we missed a
// refresh, make sure we cancel any timer we have and schedule
// a new one.
futureRefresh = now + newInterval;
newInterval = 1;
}
if (futureRefresh > now + newInterval) {
// Cancel the old timer and create a new one if the next refresh is
// too far away.
clearTimeout(this.tokenRefreshTimer_);
this.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
}
}
}
};
/**
* Stop already-scheduled refreshing of tokens.
* @private
*/
osapi.container.Container.prototype.unscheduleRefreshTokens_ = function() {
if (this.tokenRefreshTimer_) {
var urls = this.getTokenRefreshableGadgetUrls_();
if (urls.length <= 0) {
window.clearInterval(this.tokenRefreshTimer_);
this.tokenRefreshTimer_ = null;
}
}
};
/**
* Token refresh gets enabled if the value of refresh interval is > 0;
*
* @return {Boolean} if token refresh interval is of valid value.
* @private
*/
osapi.container.Container.prototype.isRefreshTokensEnabled_ = function() {
return this.tokenRefreshInterval_ > 0;
};
/**
* If the refresh interval is < 0, does nothing. Otherwise updates the tokenTTL
* to the smallest value encountered.
*
* @param {number} Encountered token time to live in milliseconds.
* @return {Boolean} The ttl if the set succeeded, otherwise false.
* @private
*/
osapi.container.Container.prototype.setRefreshTokenInterval_ = function(tokenTTL) {
// TODO: Handle the case where we've closed the gadget responsible for the
// shortest refresh time, and can now safely extend this.tokenRefreshInterval_
if (tokenTTL) {
tokenTTL *= .8; // 80% of the TTL value, for buffer.
var refresh = this.tokenRefreshInterval_;
if (refresh < 0) {
return refresh;
}
else {
return this.tokenRefreshInterval_ =
refresh == 0 ? tokenTTL : Math.min(refresh, tokenTTL);
}
}
};
/**
* Register standard RPC services
* @private
*/
osapi.container.Container.prototype.registerRpcServices_ = function() {
var self = this;
this.rpcRegister('resize_iframe', function(rpcArgs, data) {
var site = rpcArgs[osapi.container.GadgetSite.RPC_ARG_KEY];
if (site) { // Check if site is not already closed.
site.setHeight(data);
}
});
this.rpcRegister('resize_iframe_width', function(rpcArgs, newWidth) {
var site = rpcArgs[osapi.container.GadgetSite.RPC_ARG_KEY];
if (site) { // Check if site is not already closed.
site.setWidth(newWidth);
}
return true;
});
/**
* @see setprefs.js setprefs feature.
*/
this.rpcRegister('set_pref', function(rpcArgs, key, value) {
var site = rpcArgs[osapi.container.GadgetSite.RPC_ARG_KEY];
var setPrefs = self.config_[osapi.container.ContainerConfig.SET_PREFERENCES];
if (site && setPrefs) { // Check if site is not already closed.
var data = {};
for (var i = 2, j = arguments.length; i < j; i += 2) {
data[arguments[i]] = arguments[i + 1];
}
setPrefs(site.getId(), site.getActiveGadgetHolder().getUrl(), data);
}
});
};
/**
* Sets up the RPC arbitrator if enabled in the container js. If
* a function is provided in the containers config the container will use
* that, if not it will use the default arbitrator.
* @private
*/
osapi.container.Container.prototype.setupRpcArbitrator_ = function(config) {
var container = gadgets.config.get('container');
if(typeof container.enableRpcArbitration !== 'undefined' &&
container.enableRpcArbitration) {
var arbitrate = osapi.container.util.getSafeJsonValue(
config, osapi.container.ContainerConfig.RPC_ARBITRATOR, null);
if(!arbitrate) {
var self = this;
//This implementation uses the metadata cache to check to allowed rpc service ids
arbitrate = function(serviceId, from) {
var site = self.getGadgetSiteByIframeId_(from);
if(site && site.getActiveGadgetHolder()) {
var cachedResponse = self.service_.getCachedGadgetMetadata(
site.getActiveGadgetHolder().getUrl());
if(!cachedResponse.error && cachedResponse.rpcServiceIds) {
for(var i = 0, rpcServiceId; rpcServiceId = cachedResponse.rpcServiceIds[i]; i++) {
if(rpcServiceId == serviceId) {
return true;
}
}
}
}
gadgets.warn('RPC call to ' + serviceId + ' was not allowed.');
return false;
};
}
gadgets.rpc.config({'arbitrator' : arbitrate});
}
};
/**
* Keep track of preloaded gadget URLs. These gadgets will have their tokens
* refreshed as part of batched token fetch.
* @param {string} gadgetUrl URL of preloaded gadget.
* @private
*/
osapi.container.Container.prototype.addPreloadedGadgetUrl_ = function(gadgetUrl) {
this.preloadedGadgetUrls_[gadgetUrl] = null;
};
/**
* Collect all URLs of gadgets that require tokens refresh. This comes from both
* preloaded gadgets and navigated-to gadgets.
* @return {Array} An array of URLs of gadgets.
* @private
*/
osapi.container.Container.prototype.getTokenRefreshableGadgetUrls_ = function() {
var result = {};
for (var url in this.getActiveGadgetUrls_()) {
var metadata = this.service_.getCachedGadgetMetadata(url);
if (metadata[osapi.container.MetadataResponse.NEEDS_TOKEN_REFRESH]) {
result[url] = null;
}
}
return osapi.container.util.toArrayOfJsonKeys(result);
};
/**
* Get gadget urls that are either navigated or preloaded.
* @return {Object} JSON of gadget URLs.
* @private
*/
osapi.container.Container.prototype.getActiveGadgetUrls_ = function() {
return osapi.container.util.mergeJsons(
this.getNavigatedGadgetUrls_(),
this.preloadedGadgetUrls_);
};
/**
* Get gadget urls that are navigated on page.
* @return {Object} JSON of gadget URLs.
* @private
*/
osapi.container.Container.prototype.getNavigatedGadgetUrls_ = function() {
var result = {};
for (var siteId in this.sites_) {
var holder = this.sites_[siteId].getActiveGadgetHolder();
if (holder) {
result[holder.getUrl()] = null;
}
}
return result;
};
/**
* Refresh security tokens immediately. This will fetch gadget metadata, along
* with its token and have the token cache updated.
* @private
*/
osapi.container.Container.prototype.refreshTokens_ = function() {
var ids = this.getTokenRefreshableGadgetUrls_();
var request = osapi.container.util.newTokenRequest(ids);
var self = this;
this.service_.getGadgetToken(request, function(response) {
// Update active token-requiring gadgets with new tokens. Do not need to
// update pre-loaded gadgets, since new tokens will take effect when they
// are navigated to, from cache.
for (var siteId in self.sites_) {
var holder = self.sites_[siteId].getActiveGadgetHolder();
var gadgetInfo = self.service_.getCachedGadgetMetadata(holder.getUrl());
if (gadgetInfo[osapi.container.MetadataResponse.NEEDS_TOKEN_REFRESH]) {
var tokenInfo = response[holder.getUrl()];
if (tokenInfo.error) {
gadgets.warn(['Failed to get token for gadget ',
holder.getUrl(), '.'].join(''));
} else {
gadgets.rpc.call(holder.getIframeId(), 'update_security_token', null,
tokenInfo[osapi.container.TokenResponse.TOKEN]);
}
}
}
});
};
/**
* invokes methods on the gadget lifecycle callback registered with the
* container.
* @param {string} methodName of the callback method to be called.
* @param {Object} data to be passed to the callback method.
* @private
*/
osapi.container.Container.prototype.applyLifecycleCallbacks_ = function(
methodName, data) {
for (name in this.gadgetLifecycleCallbacks_) {
var method = this.gadgetLifecycleCallbacks_[name][methodName];
if (method) {
method(data);
}
}
};
/**
* Creates a new URL site
* @param {Element} element the element to put the site in.
* @return {osapi.container.UrlSite} a new site.
*/
osapi.container.Container.prototype.newUrlSite = function(element) {
var args = {};
args[osapi.container.UrlSite.URL_ELEMENT] = element;
return new osapi.container.UrlSite(args);
};
/**
* Navigates to a URL
* @param {osapi.container.UrlSite} site the URL site to render the URL in.
* @param {string} url the URL to render.
* @param {Object} renderParams params to augment the rendering.
* @return {osapi.container.UrlSite} the site you passed in.
*
* Valid rendering parameters include osapi.container.RenderParam.CLASS,
* osapi.container.RenderParam.HEIGHT, and osapi.container.RenderParam.WIDTH.
*/
osapi.container.Container.prototype.navigateUrl = function(site, url, renderParams) {
site.render(url, renderParams);
return site;
};
© 2015 - 2025 Weber Informatics LLC | Privacy Policy