You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/05/27 03:03:11 UTC
svn commit: r948646 - in
/shindig/trunk/features/src/main/javascript/features: ./ container/
shindig.container-1.0/
Author: lindner
Date: Thu May 27 01:03:10 2010
New Revision: 948646
URL: http://svn.apache.org/viewvc?rev=948646&view=rev
Log:
Patch from Michael Hermanto | The next generation in shindig containers!
Added:
shindig/trunk/features/src/main/javascript/features/container/
shindig/trunk/features/src/main/javascript/features/container/container.js
shindig/trunk/features/src/main/javascript/features/container/feature.xml
shindig/trunk/features/src/main/javascript/features/container/gadget_holder.js
shindig/trunk/features/src/main/javascript/features/container/gadget_site.js
shindig/trunk/features/src/main/javascript/features/container/init.js
shindig/trunk/features/src/main/javascript/features/container/service.js
shindig/trunk/features/src/main/javascript/features/container/util.js
shindig/trunk/features/src/main/javascript/features/shindig.container-1.0/
shindig/trunk/features/src/main/javascript/features/shindig.container-1.0/feature.xml
Modified:
shindig/trunk/features/src/main/javascript/features/features.txt
Added: shindig/trunk/features/src/main/javascript/features/container/container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/container.js?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/container.js (added)
+++ shindig/trunk/features/src/main/javascript/features/container/container.js Thu May 27 01:03:10 2010
@@ -0,0 +1,374 @@
+/*
+ * 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.
+ */
+var shindig = shindig || {};
+shindig.container = shindig.container || {};
+
+
+/**
+ * @param {Object=} opt_config Configuration JSON.
+ * @constructor
+ */
+shindig.container.Container = function(opt_config) {
+ var config = opt_config || {};
+
+ /**
+ * A JSON list of preloaded gadget URLs.
+ * @type {Object}
+ */
+ this.preloadedGadgetUrls_ = {};
+
+ /**
+ * @type {Object}
+ */
+ this.sites_ = {};
+
+ /**
+ * @type {boolean}
+ */
+ this.renderDebug_ = shindig.container.util.getSafeJsonValue(config,
+ shindig.container.ContainerConfig.RENDER_DEBUG, false);
+
+ /**
+ * @type {boolean}
+ */
+ this.renderTest_ = shindig.container.util.getSafeJsonValue(config,
+ shindig.container.ContainerConfig.RENDER_TEST, false);
+
+ /**
+ * @type {boolean}
+ */
+ this.sameDomain_ = shindig.container.util.getSafeJsonValue(config,
+ shindig.container.ContainerConfig.SAME_DOMAIN, true);
+
+ /**
+ * @type {number}
+ */
+ this.tokenRefreshInterval_ = shindig.container.util.getSafeJsonValue(config,
+ shindig.container.ContainerConfig.TOKEN_REFRESH_INTERVAL,
+ 30 * 60 * 1000);
+
+ /**
+ * @type {shindig.container.Service}
+ */
+ this.service_ = new shindig.container.Service(config);
+
+ /**
+ * Security token refresh interval (in ms) for debugging.
+ * @type {Object}
+ */
+ this.tokenRefreshTimer_ = null;
+
+ 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 {shindig.container.GadgetSite} site created for application to hold to.
+ */
+shindig.container.Container.prototype.newGadgetSite = function(
+ gadgetEl, opt_bufferEl) {
+ var site = new shindig.container.GadgetSite(
+ this.service_, gadgetEl, opt_bufferEl);
+ this.sites_[site.getId()] = site;
+ return site;
+};
+
+
+/**
+ * @param {string} id Iframe ID of gadget site to get.
+ * @return {shindig.container.GadgetSite} The gadget site with given holder's iframeId.
+ */
+shindig.container.Container.prototype.getGadgetSite = function(id) {
+ // TODO: Support getting only the loading/active gadget in 2x buffers.
+ for (var siteId in this.sites_) {
+ var site = this.sites_[siteId];
+ if (site.getGadgetHolder(id)) {
+ return site;
+ }
+ }
+ return null;
+};
+
+
+/**
+ * @param {string} id Iframe ID of gadget holder to get.
+ * @return {shindig.container.GadgetHolder} The gadget holder with iframe id.
+ */
+shindig.container.Container.prototype.getGadgetHolder = function(id) {
+ var site = this.getGadgetSite(id);
+ if (site) {
+ return site.getGadgetHolder(id);
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * Called when gadget is navigated.
+ *
+ * @param {shindig.container.GadgetSite} site the site where navigation is ocurring
+ * @param {string} gadgetUrl The URI of the gadget
+ * @param {Object} gadgetParams view params for the gadget
+ * @param {Object} renderParams render parameters, including the view
+ * @param {Function=} opt_callback Callback that occurs after gadget is loaded
+ */
+shindig.container.Container.prototype.navigateGadget = function(
+ site, gadgetUrl, gadgetParams, renderParams, opt_callback) {
+ if (this.renderDebug_) {
+ renderParams['nocache'] = true;
+ renderParams['debug'] = true;
+ }
+ if (this.renderTest_) {
+ renderParams['testmode'] = true;
+ }
+ var self = this;
+ var callback = function(response) {
+ // 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 (!response.error) {
+ self.scheduleRefreshTokens_();
+ }
+ if (opt_callback) {
+ opt_callback(response);
+ }
+ };
+ // TODO: Lifecycle, add ability for current gadget to cancel nav.
+ site.navigateTo(gadgetUrl, gadgetParams, renderParams, callback);
+};
+
+
+/**
+ * Called when gadget is closed. This may stop refreshing of tokens.
+ * @param {shindig.container.GadgetSite} site the site where navigation occurred.
+ */
+shindig.container.Container.prototype.closeGadget = function(site) {
+ var id = site.getId();
+ var el = this.siteEls_[id];
+ site.close();
+ if (el) {
+ el.parentNode.removeChild(el);
+ }
+ delete this.sites_[id];
+ this.unscheduleRefreshTokens_();
+};
+
+
+/**
+ * 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 {Object} request JSON containing ids of gadgets URIs to preload.
+ */
+shindig.container.Container.prototype.preloadGadgets = function(request) {
+ var metadataRequest = {
+ 'container' : window.__CONTAINER,
+ 'ids' : request['ids']
+ };
+ var self = this;
+ this.service_.getGadgetMetadata(metadataRequest, function(response) {
+ if (!response.error) {
+ var data = response.data;
+ var ids = shindig.container.util.toArrayOfJsonKeys(data);
+ for (var i = 0; i < ids.length; i++) {
+ self.addPreloadedGadgetUrl_(ids[i]);
+ }
+ self.scheduleRefreshTokens_();
+ }
+ });
+};
+
+/**
+ * Callback that occurs after instantiation/construction of this. Override to
+ * provide your specific functionalities.
+ * @param {Object=} opt_config Configuration JSON.
+ */
+shindig.container.Container.prototype.onConstructed = function(opt_config) {};
+
+
+// -----------------------------------------------------------------------------
+// Valid JSON keys.
+// -----------------------------------------------------------------------------
+
+/**
+ * Enumeation 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}
+ */
+shindig.container.ContainerConfig = {};
+// Whether debug mode is turned on.
+shindig.container.ContainerConfig.RENDER_DEBUG = 'renderDebug';
+// Whether test mode is turned on.
+shindig.container.ContainerConfig.RENDER_TEST = 'renderTest';
+// Toggle to render gadgets in the same domain.
+shindig.container.ContainerConfig.SAME_DOMAIN = 'sameDomain';
+// Security token refresh interval (in ms) for debugging.
+shindig.container.ContainerConfig.TOKEN_REFRESH_INTERVAL = 'tokenRefreshInterval';
+
+
+/**
+ * Enum keys for gadget rendering params. Gadget rendering params affect which
+ * view of a gadget of displayed and how the gadget site is rendered, and are
+ * not passed on to the actual gadget. These enum values are for documentation
+ * purposes only, it is expected that clients use the string values.
+ * @enum {string}
+ */
+shindig.container.ContainerRender = {};
+// Style class to associate to iframe.
+shindig.container.ContainerRender.CLASS = 'class';
+// Whether to turn off debugging.
+shindig.container.ContainerRender.DEBUG = 'debug';
+// The starting/default gadget iframe height (in pixels).
+shindig.container.ContainerRender.HEIGHT ='height';
+// Whether to turn off debugging.
+shindig.container.ContainerRender.TEST = 'test';
+// The gadget view name.
+shindig.container.ContainerRender.VIEW = 'view';
+// The starting/default gadget iframe width (in pixels).
+shindig.container.ContainerRender.WIDTH = 'width';
+
+
+// -----------------------------------------------------------------------------
+// Private variables and methods.
+// -----------------------------------------------------------------------------
+
+
+/**
+ * Start to schedule refreshing of tokens.
+ * @private
+ */
+shindig.container.Container.prototype.scheduleRefreshTokens_ = function() {
+ // TODO: Obtain the interval time by taking the minimum of expiry time of
+ // token in all preloaded- and navigated-to- gadgets. This should be obtained
+ // from the server. For now, constant on 50% of long-lived tokens (1 hour),
+ // which is 30 minutes.
+ if (!this.tokenRefreshTimer_) {
+ var self = this;
+ this.tokenRefreshTimer_ = window.setInterval(function() {
+ self.refreshTokens_();
+ }, this.tokenRefreshInterval_);
+ }
+};
+
+
+/**
+ * Stop already-scheduled refreshing of tokens.
+ * @private
+ */
+shindig.container.Container.prototype.unscheduleRefreshTokens_ = function() {
+ if (this.tokenRefreshTimer_) {
+ var urls = this.getTokenRefreshableGadgetUrls_();
+ if (urls.length <= 0) {
+ window.clearInterval(this.tokenRefreshTimer_);
+ this.tokenRefreshTimer_ = null;
+ }
+ }
+};
+
+
+/**
+ * Register standard RPC services
+ * @private
+ */
+shindig.container.Container.prototype.registerRpcServices_ = function() {
+ var self = this;
+ gadgets.rpc.register('resize_iframe', function(height) {
+ // this['f'] is set by calling iframe via gadgets.rpc.
+ var site = self.getGadgetSite(this['f']);
+ site.setHeight(height);
+ });
+};
+
+
+/**
+ * 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
+ */
+shindig.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
+ */
+shindig.container.Container.prototype.getTokenRefreshableGadgetUrls_ = function() {
+ // Uses a JSON to ensure uniqueness. Collect all preloaded gadget URLs.
+ var result = shindig.container.util.mergeJsons({}, this.preloadedGadgetUrls_);
+
+ // Collect all current gadget URLs.
+ for (var siteIndex in this.sites_) {
+ var holder = this.sites_[siteIndex].getActiveGadget();
+ if (holder) {
+ result[holder.getUrl()] = null;
+ }
+ }
+
+ return shindig.container.util.toArrayOfJsonKeys(result);
+};
+
+
+/**
+ * Refresh security tokens immediately. This will fetch gadget metadata, along
+ * with its token and have the token cache updated.
+ * @private
+ */
+shindig.container.Container.prototype.refreshTokens_ = function() {
+ var ids = this.getTokenRefreshableGadgetUrls_();
+ var request = {
+ 'container' : window.__CONTAINER,
+ 'ids' : ids
+ };
+
+ var self = this;
+ osapi.gadgets.getToken(request, function(response) {
+ if (!response.error) {
+ // Update current (visible) gadgets with new tokens (already stored in
+ // cache). Do not need to update pre-loaded gadgets, since new tokens will
+ // take effect when they are navigated to.
+ var data = response.data;
+ for (var key in self.sites_) {
+ var holder = self.sites_[key].getActiveGadget();
+ if (holder) {
+ var token = data[holder.getUrl()]['token'];
+ gadgets.rpc.call(holder.getIframeId(), 'update_security_token', null,
+ token);
+ }
+ }
+ }
+ // TODO: Tokens will be stale, but error should not be ignored.
+ });
+};
Added: shindig/trunk/features/src/main/javascript/features/container/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/feature.xml?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/feature.xml (added)
+++ shindig/trunk/features/src/main/javascript/features/container/feature.xml Thu May 27 01:03:10 2010
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+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.
+-->
+<feature>
+ <name>container</name>
+ <dependency>core</dependency>
+ <dependency>osapi</dependency>
+ <dependency>rpc</dependency>
+ <container>
+ <script src="util.js"/>
+ <script src="service.js"/>
+ <script src="gadget_holder.js"/>
+ <script src="gadget_site.js"/>
+ <script src="container.js"/>
+ <script src="init.js"/>
+ </container>
+</feature>
Added: shindig/trunk/features/src/main/javascript/features/container/gadget_holder.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/gadget_holder.js?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/gadget_holder.js (added)
+++ shindig/trunk/features/src/main/javascript/features/container/gadget_holder.js Thu May 27 01:03:10 2010
@@ -0,0 +1,386 @@
+/*
+ * 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 an HTML element and the associated gadget.
+ */
+var shindig = shindig || {};
+shindig.container = shindig.container || {};
+
+
+/**
+ * @param {number} siteId The id of site containing this holder.
+ * @param {Element} el The element to render gadgets in.
+ * @constructor
+ */
+shindig.container.GadgetHolder = function(siteId, el) {
+ /**
+ * Unique numeric gadget ID. Should be the same as siteId.
+ * @type {number}
+ * @private
+ */
+ this.siteId_ = siteId;
+
+ /**
+ * The element into which the gadget is rendered.
+ * @type {Element}
+ * @private
+ */
+ this.el_ = el;
+
+ /**
+ * JSON metadata for gadget
+ * @type {Object}
+ * @private
+ */
+ this.gadgetInfo_ = null;
+
+ /**
+ * View parameters to pass to gadget.
+ * @type {Object}
+ * @private
+ */
+ this.gadgetParams_ = null;
+
+ /**
+ * Whether there are any view parameters.
+ * @type {boolean}
+ * @private
+ */
+ this.hasGadgetParams_ = false;
+
+ /**
+ * Gadget rendering parameters
+ * @type {Object}
+ * @private
+ */
+ this.renderParams_ = null;
+
+ /**
+ * Unique string gadget ID. Used for DOM IDs/names.
+ * @type {string}
+ * @private
+ */
+ this.iframeId_ = null;
+
+ /**
+ * Name of current view being rendered.
+ * @type {string}
+ * @private
+ */
+ this.view_ = null;
+
+ /**
+ * JSON metadata about current view being rendered.
+ * @type {Object}
+ * @private
+ */
+ this.viewInfo_ = null;
+
+ /**
+ * A dynamically set social/security token.
+ * Social tokens are sent with original view URLs but may need
+ * to be refreshed for long lived gadgets.
+ * @type {string}
+ * @private
+ */
+ this.securityToken_ = null;
+
+ this.onConstructed();
+};
+
+
+/**
+ * Callback that occurs after instantiation/construction of this. Override to
+ * provide your specific functionalities.
+ */
+shindig.container.GadgetHolder.prototype.onConstructed = function() {};
+
+
+/**
+ * @return {Element} The HTML element containing the rendered gadget.
+ */
+shindig.container.GadgetHolder.prototype.getElement = function() {
+ return this.el_;
+};
+
+
+/**
+ * @return {string} The unique string ID for gadget iframe.
+ */
+shindig.container.GadgetHolder.prototype.getIframeId = function() {
+ return this.iframeId_;
+};
+
+
+/**
+ * @return {Object} The metadata of gadget.
+ */
+shindig.container.GadgetHolder.prototype.getGadgetInfo = function() {
+ return this.gadgetInfo_;
+};
+
+
+/**
+ * Remove the gadget from this.
+ */
+shindig.container.GadgetHolder.prototype.dispose = function() {
+ this.gadgetInfo_ = null;
+};
+
+
+/**
+ * @return {string} The URL of current gadget.
+ */
+shindig.container.GadgetHolder.prototype.getUrl = function() {
+ return (this.gadgetInfo_) ? this.gadgetInfo_['url'] : null;
+};
+
+
+/**
+ * @return {string} The view of current gadget.
+ */
+shindig.container.GadgetHolder.prototype.getView = function() {
+ return this.view_;
+};
+
+
+/**
+ * @return {string} The iframe element containing gadget.
+ */
+shindig.container.GadgetHolder.prototype.getIframeElement = function() {
+ return this.el_.firstChild;
+};
+
+
+/**
+ * @param {string} value The value to set this social/security token to.
+ * @return {shindig.container.GadgetHolder}
+ */
+shindig.container.GadgetHolder.prototype.setSecurityToken = function(value) {
+ this.securityToken_ = value;
+ return this;
+};
+
+
+/**
+ * Render a gadget into the element.
+ * @param {Object} gadgetInfo the JSON gadget description.
+ * @param {Object} gadgetParams View parameters for the gadget.
+ * @param {Object} renderParams Render parameters for the gadget, including: view, width, height.
+ */
+shindig.container.GadgetHolder.prototype.render = function(gadgetInfo, gadgetParams, renderParams) {
+ this.iframeId_ = shindig.container.GadgetHolder.IFRAME_ID_PREFIX_ + this.siteId_;
+ this.gadgetInfo_ = gadgetInfo;
+ this.gadgetParams_ = gadgetParams;
+ this.hasGadgetParams_ = false;
+ for (var key in this.gadgetParams_) {
+ this.hasGadgetParams_ = true;
+ break;
+ }
+ this.renderParams_ = renderParams;
+ this.view_ = renderParams['view'];
+ this.viewInfo_ = this.gadgetInfo_['views'][this.view_];
+ if (!this.viewInfo_) {
+ throw 'View ' + this.view_ + ' unsupported in ' + this.gadgetInfo_['url'];
+ }
+
+ this.el_.innerHTML = this.getIframeHtml_();
+
+ // Set up RPC channel. RPC relay url is on gmodules, relative to base of the
+ // container. Assumes container has set up forwarding to gmodules at /gadgets.
+ gadgets.rpc.setRelayUrl(this.iframeId_, this.viewInfo_['iframeHost'] +
+ '/gadgets/files/container/rpc_relay.html');
+ // Pull RPC token from gadget URI
+ gadgets.rpc.setAuthToken(this.iframeId_, this.getRpcToken_());
+};
+
+
+// -----------------------------------------------------------------------------
+// Private variables and methods.
+// -----------------------------------------------------------------------------
+
+
+/**
+ * Prefix for gadget HTML IDs/names.
+ * @type {string}
+ * @private
+ */
+shindig.container.GadgetHolder.IFRAME_ID_PREFIX_ = '__gadget_';
+
+
+/**
+ * Get HTML text content that can be used to render the gadget IFRAME
+ * @return {string} The HTML content of this gadget that can be rendered.
+ * @private
+ */
+shindig.container.GadgetHolder.prototype.getIframeHtml_ = function() {
+ var iframeParams = {
+ 'id': this.iframeId_,
+ 'name': this.iframeId_,
+ 'src': this.getIframeUrl_(),
+ 'scrolling': 'no',
+ 'marginwidth': '0',
+ 'marginheight': '0',
+ 'frameborder': '0',
+ 'vspace': '0',
+ 'hspace': '0',
+ 'class': this.renderParams_['class'],
+ 'height': this.renderParams_['height'],
+ 'width': this.renderParams_['width']
+ };
+
+ // Do not use DOM API (createElement(), setAttribute()), since it is slower,
+ // requires more code, and creating an element with it results in a click
+ // sound in IE (unconfirmed), setAttribute('class') may need browser-specific
+ // variants.
+ var out = [];
+ out.push('<iframe ');
+ for (var key in iframeParams) {
+ var value = iframeParams[key];
+ if (value) {
+ out.push(key + '="' + value + '" ');
+ }
+ }
+ out.push('></iframe>');
+
+ return out.join('');
+};
+
+
+/**
+ * Get the rendering iframe URL.
+ * @private
+ */
+shindig.container.GadgetHolder.prototype.getIframeUrl_ = function() {
+ var iframeHost = this.viewInfo_['iframeHost'] || '';
+ var uri = iframeHost + this.viewInfo_['iframePath'];
+ uri = this.updateBooleanParam_(uri, 'debug');
+ uri = this.updateBooleanParam_(uri, 'nocache');
+ uri = this.updateBooleanParam_(uri, 'testmode');
+ uri = this.updateUserPrefParams_(uri);
+
+ // TODO: Share this base container logic
+ // TODO: Two SD base URIs - one for container, one for gadgets
+ // Need to add parent at end of query due to gadgets parsing bug
+ uri = this.addQueryParam_(uri, 'parent', shindig.container.util.parseOrigin(
+ document.location.href));
+
+ // Remove existing social token if we have a new one
+ if (this.securityToken_) {
+ var securityTokenMatch = uri.match(/([&#?])(st=[^&#]*)/);
+ if (securityTokenMatch) {
+ // TODO: Should we move the token to the hash?
+ uri = uri.replace(securityTokenMatch[0], securityTokenMatch[1] +
+ 'st=' + this.securityToken_);
+ }
+ }
+
+ uri = this.addHashParam_(uri, 'mid', this.siteId_);
+
+ if (this.hasGadgetParams_) {
+ var gadgetParamText = gadgets.json.stringify(this.gadgetParams_);
+ uri = this.addHashParam_(uri, 'view-params',
+ encodeURIComponent(gadgetParamText));
+ }
+ return uri;
+};
+
+
+/**
+ * Updates query params of interest.
+ * @param {string} uri The URL to append query param to.
+ * @param {string} param The query param to update uri with.
+ * @return {string} The URL with param append to.
+ * @private
+ */
+shindig.container.GadgetHolder.prototype.updateBooleanParam_ = function(uri, param) {
+ if (this.renderParams_[param]) {
+ uri = this.addQueryParam_(uri, param, 1);
+ }
+ return uri;
+};
+
+
+/**
+ * Replace user prefs specified in url with only those specified. This will
+ * maintain each user prefs existence (or lack of), order (from left to right)
+ * and its appearance (in query params or fragment).
+ * @param {string} url The URL possibly containing user preferences parameters
+ * prefixed by up_.
+ * @return {string} The URL with up_ replaced by those specified in userPrefs.
+ * @private
+ */
+shindig.container.GadgetHolder.prototype.updateUserPrefParams_ = function(uri) {
+ var userPrefs = this.renderParams_['userPrefs'];
+ if (userPrefs) {
+ for (var up in userPrefs) {
+ // Maybe more efficient to have a pre-compiled regex that looks for
+ // up_ANY_TEXT and match all instances.
+ var re = new RegExp('([&#?])up_' + up + '[^&#]*');
+ if (re) {
+ var key = encodeURIComponent('up_' + up);
+ var val = userPrefs[up];
+ if (val instanceof Array) {
+ val = val.join('|');
+ }
+ val = encodeURIComponent(val);
+ uri = uri.replace(re, '$1' + key + '=' + val);
+ }
+ }
+ }
+ return uri;
+};
+
+
+/**
+ * @return {string} The current RPC token.
+ * @private
+ */
+shindig.container.GadgetHolder.prototype.getRpcToken_ = function() {
+ return this.viewInfo_['iframePath'].match(/rpctoken=([^&]+)/)[1];
+};
+
+
+/**
+ * Adds a hash parameter to a URI.
+ * @param {string} uri The URI.
+ * @param {string} key The param key.
+ * @param {string} value The param value.
+ * @return {string} The new URI.
+ * @private
+ */
+shindig.container.GadgetHolder.prototype.addHashParam_ = function(uri, key, value) {
+ return uri + ((uri.indexOf('#') == -1) ? '#' : '&') + key + '=' + value;
+};
+
+
+/**
+ * Adds a query parameter to a URI.
+ * @param {string} uri The URI.
+ * @param {string} key The param key.
+ * @param {string} value The param value.
+ * @return {string} The new URI.
+ * @private
+ */
+shindig.container.GadgetHolder.prototype.addQueryParam_ = function(uri, key, value) {
+ var hasQuery = uri.indexOf('?') != -1;
+ var insertPos = (uri.indexOf('#') != -1) ? uri.indexOf('#') : uri.length;
+ return uri.substring(0, insertPos) + (hasQuery ? '&' : '?') +
+ key + '=' + value + uri.substring(insertPos);
+};
Added: shindig/trunk/features/src/main/javascript/features/container/gadget_site.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/gadget_site.js?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/gadget_site.js (added)
+++ shindig/trunk/features/src/main/javascript/features/container/gadget_site.js Thu May 27 01:03:10 2010
@@ -0,0 +1,404 @@
+/*
+ * 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 manages rendering of gadgets in a place holder, within an
+ * HTML element in the container. The API for this is low-level. Use the
+ * container APIs to work with gadget sites.
+ */
+var shindig = shindig || {};
+shindig.container = shindig.container || {};
+
+
+/**
+ * @param {shindig.container.Service} service To fetch gadgets metadata, token.
+ * @param {Element} gadgetEl Element into which to render the gadget
+ * @param {Element=} opt_bufferEl Optional element for double buffering.
+ * @constructor
+ */
+shindig.container.GadgetSite = function(service, gadgetEl, opt_bufferEl) {
+ /**
+ * Service to fetch gadgets metadata and token.
+ * @type {shindig.container.Service}
+ * @private
+ */
+ this.service_ = service;
+
+ /**
+ * Element holding the current gadget.
+ * @type {Element}
+ * @private
+ */
+ this.curGadgetEl_ = gadgetEl;
+
+ /**
+ * Element holding the loading gadget for 2x buffering.
+ * @type {Element}
+ * @private
+ */
+ this.loadingGadgetEl_ = opt_bufferEl;
+
+ /**
+ * Unique ID of this site.
+ * @type {number}
+ * @private
+ */
+ this.id_ = shindig.container.GadgetSite.nextUniqueId_++;
+
+ /**
+ * ID of parent gadget.
+ * @type {string}
+ * @private
+ */
+ this.parentId_ = null;
+
+ /**
+ * Information about the currently visible gadget.
+ * @type {shindig.container.GadgetHolder}
+ * @private
+ */
+ this.curGadget_ = null;
+
+ /**
+ * Information about the currently loading gadget.
+ * @type {shindig.container.GadgetHolder}
+ * @private
+ */
+ this.loadingGadget_ = null;
+
+ this.onConstructed();
+};
+
+
+/**
+ * Callback that occurs after instantiation/construction of this. Override to
+ * provide your specific functionalities.
+ */
+shindig.container.GadgetSite.prototype.onConstructed = function() {};
+
+
+/**
+ * Set the height of the gadget iframe.
+ * @param {number} value The new height.
+ * @return {shindig.container.GadgetSite} This instance.
+ */
+shindig.container.GadgetSite.prototype.setHeight = function(value) {
+ var activeGadget = this.getActiveGadget();
+ if (activeGadget) {
+ var iframeEl = activeGadget.getIframeElement();
+ if (iframeEl) {
+ iframeEl.style.height = value + 'px';
+ }
+ }
+ return this;
+};
+
+
+/**
+ * Set the width of the gadget iframe.
+ * @param {number} value The new width.
+ * @return {shindig.container.GadgetSite} This instance.
+ */
+shindig.container.GadgetSite.prototype.setWidth = function(value) {
+ var activeGadget = this.getActiveGadget();
+ if (activeGadget) {
+ var iframeEl = activeGadget.getIframeElement();
+ if (iframeEl) {
+ iframeEl.style.width = value + 'px';
+ }
+ }
+ return this;
+};
+
+
+/**
+ * @param {string} value ID of parent element containing this site.
+ * @return {shindig.container.GadgetSite} This instance.
+ */
+shindig.container.GadgetSite.prototype.setParentId = function(value) {
+ this.parentId_ = value;
+ return this;
+};
+
+
+/**
+ * @return {number} The ID of this gadget site.
+ */
+shindig.container.GadgetSite.prototype.getId = function() {
+ return this.id_;
+};
+
+
+/**
+ * Returns the currently-active gadget, the loading gadget if a gadget is
+ * loading, or the currently visible gadget.
+ * @return {shindig.container.GadgetHolder} The gadget holder.
+ */
+shindig.container.GadgetSite.prototype.getActiveGadget = function() {
+ return this.loadingGadget_ || this.curGadget_;
+};
+
+
+/**
+ * Returns configuration of a feature with a given name. Defaults to current
+ * loading or visible gadget if no metadata is passed in.
+ * @param {string} name Name of the feature.
+ * @param {Object} opt_gadgetInfo Optional gadget info.
+ * @return {Object} JSON representing the feature.
+ */
+shindig.container.GadgetSite.prototype.getFeature = function(name, opt_gadgetInfo) {
+ var gadgetInfo = opt_gadgetInfo || this.getActiveGadget().getGadgetInfo();
+ return gadgetInfo['features'] && gadgetInfo['features'][name];
+};
+
+
+/**
+ * Returns the loading or visible gadget with the given ID.
+ * @param {string} id The iframe ID of gadget to return.
+ * @return {shindig.container.GadgetHolder} The gadget. Null, if not exist.
+ */
+shindig.container.GadgetSite.prototype.getGadgetHolder = function(id) {
+ if (this.curGadget_ && this.curGadget_.getIframeId() == id) {
+ return this.curGadget_;
+ }
+ if (this.loadingGadget_ && this.loadingGadget_.getIframeId() == id) {
+ return this.loadingGadget_;
+ }
+ return null;
+};
+
+
+/**
+ * @return {string} ID parent element containing this site.
+ */
+shindig.container.GadgetSite.prototype.getParentId = function() {
+ return this.parentId_;
+};
+
+
+/**
+ * Render a gadget in the site, by URI of the gadget XML.
+ * @param {string} gadgetUrl The absolute URL to gadget.
+ * @param {Object} gadgetParams View parameters for the gadget.
+ * @param {Object} renderParams. Render parameters for the gadget, including:
+ * view, width, height.
+ * @param {Function=} opt_callback Function called with gadget info after
+ * navigation has occurred.
+ */
+shindig.container.GadgetSite.prototype.navigateTo = function(gadgetUrl, gadgetParams,
+ renderParams, opt_callback) {
+ var callback = opt_callback || function() {};
+ var gadgetInfo = osapi.gadgets.getCachedMetadataInfo(gadgetUrl);
+
+ // If metadata has been loaded/cached.
+ if (gadgetInfo) {
+ this.render(gadgetInfo, gadgetParams, renderParams);
+ callback(gadgetInfo);
+
+ // Otherwise, fetch gadget metadata.
+ } else {
+ var request = {
+ 'container': window.__CONTAINER,
+ 'ids': [ gadgetUrl ]
+ };
+ var self = this;
+ this.service_.getGadgetMetadata(request, function(response) {
+ if (!response.error) {
+ var data = response.data;
+ var gadgetInfo = data[gadgetUrl];
+ self.render(gadgetInfo, gadgetParams, renderParams);
+ callback(response);
+ }
+ });
+ }
+};
+
+
+/**
+ * Render a gadget in this site, using a JSON gadget description.
+ * @param {Object} gadgetInfo the JSON gadget description.
+ * @param {Object} gadgetParams View parameters for the gadget.
+ * @param {Object} renderParams. Render parameters for the gadget, including:
+ * view, width, height.
+ */
+shindig.container.GadgetSite.prototype.render = function(gadgetInfo, gadgetParams,
+ renderParams) {
+ var curUrl = this.curGadget_ ? this.curGadget_.getUrl() : null;
+
+ var previousView = null;
+ if (curUrl == gadgetInfo['url']) {
+ previousView = this.curGadget_.getView();
+ }
+
+ // Load into the double-buffer if there is one
+ var el = this.loadingGadgetEl_ || this.curGadgetEl_;
+ this.loadingGadget_ = new shindig.container.GadgetHolder(this.id_, el);
+
+ var view = renderParams['view'] || gadgetParams['view'] || previousView
+ || 'default';
+ var viewInfo = gadgetInfo['views'][view];
+
+ var delayLoad = this.getFeature('loadstate', gadgetInfo) ||
+ this.getFeature('shell', gadgetInfo);
+
+ var localRenderParams = {};
+ for (var key in renderParams) {
+ localRenderParams[key] = renderParams[key];
+ }
+
+ // Delay load for now means we autosize.
+ if (delayLoad) {
+ localRenderParams['height'] = '0';
+ }
+ localRenderParams['view'] = view;
+ localRenderParams['width'] = localRenderParams['width'] ||
+ viewInfo['preferredWidth'] || null;
+ localRenderParams['height'] = localRenderParams['height'] ||
+ viewInfo['preferredHeight'] || '150';
+
+ this.updateSecurityToken_(gadgetInfo, localRenderParams);
+
+ this.loadingGadget_.render(gadgetInfo, gadgetParams, localRenderParams);
+
+ this.loaded_ = false;
+
+ // Resize on load only if load is delayed. If immediate, height is 0
+ this.resizeOnLoad_ = delayLoad;
+
+ if (!delayLoad) {
+ this.setLoadState_('loaded');
+ }
+};
+
+
+/**
+ * Sends RPC call to the current/visible gadget.
+ * @param {string} serviceName RPC service name to call.
+ * @param {Function} callback Function to call upon RPC completion.
+ * @param {...number} var_args payload to pass to the recipient.
+ */
+shindig.container.GadgetSite.prototype.rpcCall = function(serviceName, callback, var_args) {
+ if (this.curGadget_) {
+ gadgets.rpc.call(this.curGadget_.getIframeId(), serviceName, callback, var_args);
+ }
+};
+
+
+/**
+ * If token has been fetched at least once, set the token to the most recent
+ * one. Otherwise, leave it.
+ * @param {Object} gadgetInfo The gadgetInfo used to update security token.
+ * @param {Object} renderParams. Render parameters for the gadget, including:
+ * view, width, and height.
+ */
+shindig.container.GadgetSite.prototype.updateSecurityToken_
+ = function(gadgetInfo, renderParams) {
+ var tokenInfo = osapi.gadgets.getCachedTokenInfo(gadgetInfo['url']);
+ if (tokenInfo) {
+ var token = tokenInfo['token'];
+ this.loadingGadget_.setSecurityToken(token);
+ }
+};
+
+
+/**
+ * Close the gadget in this site. Removes the gadget elements from the
+ * containing document. Clients should only call this if they know it is OK
+ * for removal.
+ */
+shindig.container.GadgetSite.prototype.close = function() {
+ // Only remove the element (iframe) created by this, not by the container.
+ if (this.loadingGadgetEl_) {
+ this.loadingGadgetEl_.removeChild(this.loadingGadgetEl_.firstChild);
+ }
+ if (this.curGadgetEl_) {
+ this.curGadgetEl_.removeChild(this.curGadgetEl_.firstChild);
+ }
+ if (this.loadingGadget_) {
+ this.loadingGadget_.dispose();
+ }
+ if (this.curGadget_) {
+ this.curGadget_.dispose();
+ }
+};
+
+
+/**
+ * Unique ID of gadget site
+ * @type {number}
+ * @private
+ */
+shindig.container.GadgetSite.nextUniqueId_ = 0;
+
+
+/**
+ * Sets the load state of the currently loading / visible gadget.
+ * @param {string} state The current state.
+ * @private
+ */
+shindig.container.GadgetSite.prototype.setLoadState_ = function(state) {
+ if (!this.loaded_ && state == 'loaded') {
+ this.onload_();
+ }
+};
+
+
+/**
+ * Called when a gadget loads in the site. Uses double buffer, if present.
+ * @private
+ */
+shindig.container.GadgetSite.prototype.onload_ = function() {
+ this.loaded_ = true;
+ try {
+ gadgets.rpc.call(this.loadingGadget_.getIframeId(), 'onLoad', null);
+ if (this.resizeOnLoad_) {
+ this.setHeight();
+ }
+ } catch (e) {
+ // This can throw for same domain, although it shouldn't
+ gadgets.log(e);
+ }
+
+ this.swapBuffers_();
+
+ if (this.curGadget_) {
+ this.curGadget_.dispose();
+ }
+
+ this.curGadget_ = this.loadingGadget_;
+ this.loadingGadget_ = null;
+};
+
+
+/**
+ * Swap the double buffer elements, if there is a double buffer.
+ */
+shindig.container.GadgetSite.prototype.swapBuffers_ = function() {
+ // Only process double buffering if loading gadget exists
+ if (this.loadingGadgetEl_) {
+ this.loadingGadgetEl_.style.left = '';
+ this.loadingGadgetEl_.style.position = '';
+ this.curGadgetEl_.style.position = 'absolute';
+ this.curGadgetEl_.style.left = '-2000px';
+
+ // Swap references; cur_ will now again be what's visible
+ var oldCur = this.curGadgetEl_;
+ this.curGadgetEl_ = this.loadingGadgetEl_;
+ this.loadingGadgetEl_ = oldCur;
+ }
+};
Added: shindig/trunk/features/src/main/javascript/features/container/init.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/init.js?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/init.js (added)
+++ shindig/trunk/features/src/main/javascript/features/container/init.js Thu May 27 01:03:10 2010
@@ -0,0 +1,78 @@
+/*
+ * 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 Initial configuration/boot-strapping work for common container
+ * to operate. This includes setting up gadgets config and global environment
+ * variables.
+ */
+(function() {
+
+ function initializeGadgetsConfig() {
+ gadgets.config.init({
+ 'rpc': {
+ parentRelayUrl: ''
+ },
+ 'core.io': {
+ jsonProxyUrl: 'http://%host%/gadgets/makeRequest',
+ proxyUrl: 'http://%host%/gadgets/proxy?refresh=%refresh%&container=%container%%rewriteMime%&gadget=%gadget%/%rawurl%'
+ }
+ });
+ }
+
+ function initializeGlobalVars() {
+ var scriptSrc = getLastScriptSrc();
+ if (scriptSrc) {
+ window.__API_HOST = shindig.container.util.parseOrigin(scriptSrc);
+ window.__API_PREFIX_PATH = shindig.container.util.parsePrefixPath(
+ scriptSrc, '/gadgets/js/container.js');
+ window.__CONTAINER = shindig.container.util.getParamValue(
+ scriptSrc, 'container');
+ window.__CONTAINER_HOST = shindig.container.util.parseOrigin(
+ document.location.href);
+ }
+ }
+
+ /**
+ * Call a callback function if specified in &onload= query param. This is
+ * required for dynamic source script inclusion, which is asynchronous.
+ */
+ function runOnloadCallback() {
+ var scriptSrc = getLastScriptSrc();
+ if (scriptSrc) {
+ var onload = shindig.container.util.getParamValue(scriptSrc, 'onload');
+ if (onload) {
+ var re = /(^[A-Za-z0-9_]+$)/;
+ if (re.test(onload) && (typeof window[onload] === "function")) {
+ window[onload]();
+ }
+ }
+ }
+ }
+
+ function getLastScriptSrc() {
+ var scriptEls = document.getElementsByTagName('script');
+ return (scriptEls.length > 0)
+ ? scriptEls[scriptEls.length - 1].src
+ : null;
+ }
+
+ initializeGadgetsConfig();
+ initializeGlobalVars();
+ runOnloadCallback();
+})();
Added: shindig/trunk/features/src/main/javascript/features/container/service.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/service.js?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/service.js (added)
+++ shindig/trunk/features/src/main/javascript/features/container/service.js Thu May 27 01:03:10 2010
@@ -0,0 +1,104 @@
+/*
+ * 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 service layer that talks to OSAPI
+ * endpoints. All RPC requests should go into this class.
+ */
+var shindig = shindig || {};
+shindig.container = shindig.container || {};
+
+
+/**
+ * @param {Object=} opt_config. Configuration JSON.
+ * @constructor
+ */
+shindig.container.Service = function(opt_config) {
+ var config = opt_config || {};
+
+ /**
+ * @type {boolean}
+ */
+ this.sameDomain_ = shindig.container.util.getSafeJsonValue(config,
+ shindig.container.ServiceConfig.SAME_DOMAIN, true);
+
+ this.onConstructed(config);
+};
+
+
+/**
+ * Callback that occurs after instantiation/construction of this. Override to
+ * provide your specific functionalities.
+ * @param {Object=} opt_config. Configuration JSON.
+ */
+shindig.container.Service.prototype.onConstructed = function(opt_config) {};
+
+
+/**
+ * Do an immediate fetch of gadgets metadata for gadgets in request.ids, for
+ * container request.container, with its results mutated by
+ * request.sameDomain and request.aspDomain. The appropriate optional
+ * callback opt_callback will be called, after a response is received.
+ * @param {Object} request JSON object representing the request.
+ * @param {Function=} opt_callback function to call upon data receive.
+ */
+shindig.container.Service.prototype.getGadgetMetadata = function(
+ request, opt_callback) {
+ var callback = opt_callback || function() {};
+ var self = this;
+ osapi.gadgets.getMetadata(request, function(response) {
+ if (response.error) {
+ // This hides internal server error.
+ callback({
+ error : 'Failed to retrieve gadget.',
+ errorCode : 'NOLOAD'
+ });
+ } else {
+ var data = response.data;
+ var gadgetUrls = shindig.container.util.toArrayOfJsonKeys(data);
+ for (var i = 0; i < gadgetUrls.length; i++) {
+ var gadgetInfo = data[gadgetUrls[i]];
+ self.processSameDomain_(gadgetInfo);
+ }
+ callback(response);
+ }
+ });
+};
+
+
+/**
+ * @param {Object} gadgetInfo
+ * @private
+ */
+shindig.container.Service.prototype.processSameDomain_ = function(gadgetInfo) {
+ gadgetInfo['sameDomain'] = this.sameDomain_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Configuration
+// -----------------------------------------------------------------------------
+
+/**
+ * Enumeation of configuration keys for this service. This is specified in
+ * JSON to provide extensible configuration.
+ * @enum {string}
+ */
+shindig.container.ServiceConfig = {};
+//Toggle to render gadgets in the same domain.
+shindig.container.ServiceConfig.SAME_DOMAIN = 'sameDomain';
Added: shindig/trunk/features/src/main/javascript/features/container/util.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/util.js?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/util.js (added)
+++ shindig/trunk/features/src/main/javascript/features/container/util.js Thu May 27 01:03:10 2010
@@ -0,0 +1,138 @@
+/*
+ * 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 Utility methods common container.
+ */
+var shindig = shindig || {};
+shindig.container = shindig.container || {};
+shindig.container.util = shindig.container.util || {};
+
+
+/**
+ * Extract protocol and domain of container page. Valid values:
+ * http://www.cnn.com, chrome-extension://www.cnn.com
+ * @param {string} url The URL to extract path domain from.
+ * @return {string} The protocol and domain of container page.
+ */
+shindig.container.util.parseOrigin = function(uri) {
+ var indexAtStartOfAuthority = uri.indexOf('//') + 2;
+ var indexAtEndOfAuthority = uri.indexOf('/', indexAtStartOfAuthority);
+ return uri.substring(0, indexAtEndOfAuthority);
+};
+
+
+/**
+ * Extract prefix path of a URL, not including opt_postfixPath.
+ * @param {string} url The URL to extract path from.
+ * @param {string=} opt_postfixPath The URL postfix to avoid extracting.
+ * @return {string} The path in URL, before postfixPath.
+ */
+shindig.container.util.parsePrefixPath = function(uri, opt_postfixPath) {
+ var path = shindig.container.util.parsePath(uri);
+ if (path && opt_postfixPath) {
+ var endIndex = path.length - opt_postfixPath.length;
+ if (path.lastIndexOf(opt_postfixPath) == endIndex) {
+ return path.substring(0, endIndex);
+ }
+ }
+ return path;
+};
+
+/**
+ * Extract path of a URL.
+ * @param {string} url The URL to extract path from.
+ * @return {string} The path in URL.
+ */
+shindig.container.util.parsePath = function(uri) {
+ var match = uri.match(new RegExp("//[^/]+(/[^?#]*)"));
+ return match ? match[1] : null;
+};
+
+
+/**
+ * Extract the parameter value in path with name paramName.
+ * @param {string} path The path to extract parameter from.
+ * @param {string} paramName The name of parameter to exact value from.
+ * @return {string} The value of the parameter. Null otherwise.
+ */
+shindig.container.util.getParamValue = function(path, paramName) {
+ var match = path.match(new RegExp("[?&]" + paramName + "=([^&#]+)"));
+ return match ? match[1] : null;
+};
+
+
+/**
+ * Return value of json at key, if valid. Otherwise, return defaultValue.
+ * @param {Object} json The JSON to look up key param from.
+ * @param {string} key Key in config.
+ * @param {Object?} defaultValue The default value to return.
+ * @return {Object?}
+ */
+shindig.container.util.getSafeJsonValue = function(json, key, defaultValue) {
+ return (json[key] != undefined && json[key] != null)
+ ? json[key] : defaultValue;
+};
+
+
+/**
+ * Merge two JSON together. Keys in json2 will replace than in json1.
+ * @param {Object} json1 JSON to start merge with.
+ * @param {Object} json2 JSON to append/replace json1.
+ * @return {Object} the resulting JSON.
+ */
+shindig.container.util.mergeJsons = function(json1, json2) {
+ var result = {};
+ for (var key in json1) {
+ result[key] = json1[key];
+ }
+ for (var key in json2) {
+ result[key] = json2[key];
+ }
+ return result;
+};
+
+
+/**
+ * Extract keys from a JSON to an array.
+ * @param {Object} json to extract keys from.
+ * @return {array} keys in the json.
+ */
+shindig.container.util.toArrayOfJsonKeys = function(json) {
+ var result = [];
+ for (var key in json) {
+ result.push(key);
+ }
+ return result;
+};
+
+
+/**
+ * Count the number of own/self properties in json.
+ * @param {Object} json the JSON to act on.
+ * @return {number} Number of elements in json.
+ */
+shindig.container.util.countProperties = function(json) {
+ var count = 0;
+ for (var key in json) {
+ if (json.hasOwnProperty(key)) {
+ count++;
+ }
+ }
+ return count;
+};
Modified: shindig/trunk/features/src/main/javascript/features/features.txt
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/features.txt?rev=948646&r1=948645&r2=948646&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/features.txt (original)
+++ shindig/trunk/features/src/main/javascript/features/features.txt Thu May 27 01:03:10 2010
@@ -22,6 +22,7 @@ features/globals/feature.xml
features/analytics/feature.xml
features/auth-refresh/feature.xml
features/caja/feature.xml
+features/container/feature.xml
features/content-rewrite/feature.xml
features/core.auth/feature.xml
features/core.config/feature.xml
@@ -60,6 +61,7 @@ features/security-token/feature.xml
features/setprefs/feature.xml
features/settitle/feature.xml
features/shindig.container/feature.xml
+features/shindig.container-1.0/feature.xml
features/skins/feature.xml
features/swfobject/feature.xml
features/tabs/feature.xml
Added: shindig/trunk/features/src/main/javascript/features/shindig.container-1.0/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/shindig.container-1.0/feature.xml?rev=948646&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/shindig.container-1.0/feature.xml (added)
+++ shindig/trunk/features/src/main/javascript/features/shindig.container-1.0/feature.xml Thu May 27 01:03:10 2010
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<feature>
+ <name>shindig.container-1.0</name>
+ <dependency>container</dependency>
+</feature>