shindig-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ddum...@apache.org
Subject svn commit: r1211090 - in /shindig/trunk: content/samplecontainer/examples/conservcontainer/ features/src/main/javascript/features/actions/ features/src/main/javascript/features/container.gadget/ features/src/main/javascript/features/container.url/ fea...
Date Tue, 06 Dec 2011 20:27:38 GMT
Author: ddumont
Date: Tue Dec  6 20:27:37 2011
New Revision: 1211090

URL: http://svn.apache.org/viewvc?rev=1211090&view=rev
Log:
SHINDIG-1664 Actions, selection, and open-views feature issues in a locked domain environment.

Modified:
    shindig/trunk/content/samplecontainer/examples/conservcontainer/sample-actions-voip.xml
    shindig/trunk/features/src/main/javascript/features/actions/actions.js
    shindig/trunk/features/src/main/javascript/features/actions/actions_container.js
    shindig/trunk/features/src/main/javascript/features/actions/feature.xml
    shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js
    shindig/trunk/features/src/main/javascript/features/container.url/url_site.js
    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/open-views/feature.xml
    shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js
    shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js
    shindig/trunk/features/src/main/javascript/features/selection/feature.xml
    shindig/trunk/features/src/main/javascript/features/selection/selection.js
    shindig/trunk/features/src/main/javascript/features/selection/selection_container.js
    shindig/trunk/features/src/test/javascript/features/actions/actions_test.js
    shindig/trunk/features/src/test/javascript/features/container.url/url_site_test.js
    shindig/trunk/features/src/test/javascript/features/container/gadget_site_test.js
    shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js
    shindig/trunk/features/src/test/javascript/features/selection/selection_test.js

Modified: shindig/trunk/content/samplecontainer/examples/conservcontainer/sample-actions-voip.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/conservcontainer/sample-actions-voip.xml?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/conservcontainer/sample-actions-voip.xml (original)
+++ shindig/trunk/content/samplecontainer/examples/conservcontainer/sample-actions-voip.xml Tue Dec  6 20:27:37 2011
@@ -34,7 +34,8 @@
 <Content type="html">
 <![CDATA[
 <script>
-var chat = function(selectedObj) {
+var chat = function(selection) {
+	var selectedObj = (selection || [])[0];
 	var msgStr = 'Starting Chat';
 	if (selectedObj) {
 		msgStr += ' with '+ selectedObj["name"]["formatted"];
@@ -43,7 +44,8 @@ var chat = function(selectedObj) {
 	
 	document.getElementById("output").innerHTML = msgStr;
 };
-var call = function(selectedObj) {
+var call = function(selection) {
+	var selectedObj = (selection || [])[0];
 	var msgStr = 'Dialing number';
 	if (selectedObj) {
 		msgStr += ' for '+ selectedObj["name"]["formatted"];

Modified: shindig/trunk/features/src/main/javascript/features/actions/actions.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/actions/actions.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/actions/actions.js (original)
+++ shindig/trunk/features/src/main/javascript/features/actions/actions.js Tue Dec  6 20:27:37 2011
@@ -24,31 +24,6 @@
 gadgets['actions'] = (function() {
 
   /**
-   * Runs the callback function associated with the specified action id.
-   *
-   * Example:
-   *
-   * <pre>
-   * gadgets.actions.runAction(action);
-   * </pre>
-   *
-   * @param {Object}
-   *          action The action object.
-   *
-   * @member gadgets.actions
-   */
-  function runAction(actionData) {
-    var actionId = actionData.actionId;
-    // optional
-    var selectionObj = actionData.selectionObj;
-
-    var callback = callbackRegistry.getCallback(actionId);
-    if (callback) {
-      callback.apply(this, selectionObj ? [selectionObj] : []);
-    }
-  };
-
-  /**
    * @constructor Object that maps action ids to callback functions.
    */
   function ActionCallbackRegistry() {
@@ -64,24 +39,20 @@ gadgets['actions'] = (function() {
     };
   };
 
-  // router function called to run actions
-  function router(channel, object) {
-    var actionData = object;
-    if (channel == 'runAction') {
-      runAction(actionData);
-    }
-  };
-
-  // create the callback registry and
-  // initialize the rpc router
-  var callbackRegistry = new ActionCallbackRegistry();
-  var _init;
-  var init = function() {
-    if (!_init) {
-      gadgets.rpc.register('actions', router);
-      _init = true;
-    }
-  };
+  // create the callback registry
+  var callbackRegistry = new ActionCallbackRegistry(),
+      showListeners,
+      hideListeners;
+
+  gadgets.util.registerOnLoadHandler(function() {
+    // register rpc endpoint
+    gadgets.rpc.register('actions.runAction', function(id, selection) {
+      var callback = callbackRegistry.getCallback(id);
+      if (callback) {
+        callback.call(this, selection);
+      }
+    });
+  });
 
   return /** @scope gadgets.actions */ {
     /**
@@ -99,13 +70,16 @@ gadgets['actions'] = (function() {
      * @member gadgets.actions
      */
     addAction: function(actionObj) {
-      init();
-      var actionId = actionObj.id;
-      var actionCallback = actionObj.callback;
-      callbackRegistry.addAction(actionId, actionCallback);
+      var actionId = actionObj.id,
+          callback = actionObj.callback;
+      delete actionObj.callback;
+
+      callbackRegistry.addAction(actionId, callback);
 
       // notify the container that an action has been added.
-      gadgets.rpc.call('..', 'actions', null, 'bindAction', actionObj);
+      gadgets.rpc.call('..', 'actions.bindAction', null,
+        actionObj
+      );
     },
 
     /**
@@ -126,13 +100,17 @@ gadgets['actions'] = (function() {
       // TODO for now we only support updating the callback
       // to support the declaratively contributed actions,
       // we need to support updating the label as well.
-      init();
-      var actionId = actionObj.id;
-      var actionCallback = actionObj.callback;
-      callbackRegistry.addAction(actionId, actionCallback);
+
+      var actionId = actionObj.id,
+          callback = actionObj.callback;
+      delete actionObj.callback;
+
+      callbackRegistry.addAction(actionId, callback);
 
       // notify the container that an action has been added.
-      gadgets.rpc.call('..', 'actions', null, 'bindAction', actionObj);
+      gadgets.rpc.call('..', 'actions.bindAction', null,
+        actionObj
+      );
     },
 
     /**
@@ -148,8 +126,9 @@ gadgets['actions'] = (function() {
      * @member gadgets.actions
      */
     runAction: function(actionId, opt_selection) {
-      actionData = {"id" : actionId, "selection" : opt_selection};
-      gadgets.rpc.call('..', 'run_action', null, actionData);
+      gadgets.rpc.call('..', 'actions.runAction', null,
+        actionId, opt_selection
+      );
     },
 
     /**
@@ -167,11 +146,12 @@ gadgets['actions'] = (function() {
      * @member gadgets.actions
      */
     removeAction: function(actionId) {
-      init();
       callbackRegistry.removeAction(actionId);
 
       // notify the container to remove action from its UI
-      gadgets.rpc.call('..', 'actions', null, 'removeAction', actionId);
+      gadgets.rpc.call('..', 'actions.removeAction', null,
+        actionId
+      );
     },
 
     /**
@@ -196,7 +176,9 @@ gadgets['actions'] = (function() {
      * @member gadgets.actions
      */
     getActionsByPath: function(path, callback) {
-      gadgets.rpc.call('..', 'get_actions_by_path', callback, path);
+      gadgets.rpc.call('..', 'actions.get_actions_by_path', callback,
+        path
+      );
     },
 
     /**
@@ -221,7 +203,9 @@ gadgets['actions'] = (function() {
      * @member gadgets.actions
      */
     getActionsByDataType: function(dataType, callback) {
-      gadgets.rpc.call('..', 'get_actions_by_type', callback, dataType);
+      gadgets.rpc.call('..', 'actions.get_actions_by_type', callback,
+        dataType
+      );
     },
 
     /**
@@ -234,7 +218,16 @@ gadgets['actions'] = (function() {
      */
     registerShowActionsListener: function(listener) {
       if (typeof listener === 'function') {
-        gadgets.rpc.call('..', 'actions', null, 'addShowActionListener', listener);
+        if (!showListeners) {
+          showListeners = [];
+          gadgets.rpc.register('actions.onActionShow', function(actions) {
+            for (var i = 0, listener; listener = showListeners[i]; i++) {
+              listener(actions);
+            }
+          });
+          gadgets.rpc.call('..', 'actions.registerShowCallback');
+        }
+        showListeners.push(listener);
       }
     },
 
@@ -248,7 +241,16 @@ gadgets['actions'] = (function() {
      */
     registerHideActionsListener: function(listener) {
       if (typeof listener === 'function') {
-	gadgets.rpc.call('..', 'actions', null, 'addHideActionListener', listener);
+        if (!hideListeners) {
+          hideListeners = [];
+          gadgets.rpc.register('actions.onActionHide', function(actions) {
+            for (var i = 0, listener; listener = hideListeners[i]; i++) {
+              listener(actions);
+            }
+          });
+          gadgets.rpc.call('..', 'actions.registerHideCallback');
+        }
+        hideListeners.push(listener);
       }
     }
   };

Modified: shindig/trunk/features/src/main/javascript/features/actions/actions_container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/actions/actions_container.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/actions/actions_container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/actions/actions_container.js Tue Dec  6 20:27:37 2011
@@ -387,8 +387,21 @@
    */
   function addAction(actionObj, url) {
     registry.addAction(actionObj, url);
-    // notify the container to display the action
-    showActionHandlerProxy([actionObj]);
+
+    // Comply with spec by passing an array of the object
+    // TODO: Update spec, since there will never be more than 1 element in the array
+    showActionHandler([actionObj]);  // notify the container to display the action
+
+    for (var to in showActionSiteIds) {
+      if (!container_.getGadgetSiteByIframeId_(to)) {
+        delete showActionSiteIds[to];
+      }
+      else {
+        // Comply with spec by passing an array of the object
+        // TODO: Update spec, since there will never be more than 1 element in the array
+        gadgets.rpc.call(to, 'actions.onActionShow', null, [actionObj]);
+      }
+    }
   };
 
   /**
@@ -402,8 +415,21 @@
   function removeAction(id) {
     var actionObj = registry.getItemById(id);
     registry.removeAction(id);
-    // notify the container to hide the action
-    hideActionHandlerProxy([actionObj]);
+
+    // Comply with spec by passing an array of the object
+    // TODO: Update spec, since there will never be more than 1 element in the array
+    hideActionHandler([actionObj]);  // notify the container to hide the action
+
+    for (var to in hideActionSiteIds) {
+      if (!container_.getGadgetSiteByIframeId_(to)) {
+        delete hideActionSiteIds[to];
+      }
+      else {
+        // Comply with spec by passing an array of the object
+        // TODO: Update spec, since there will never be more than 1 element in the array
+        gadgets.rpc.call(to, 'actions.onActionHide', null, [actionObj]);
+      }
+    }
   };
 
   /**
@@ -424,37 +450,37 @@
    * Runs the action associated with the specified actionId. If the gadget has
    * not yet been rendered, renders the gadget first, then runs the action.
    *
-   * @param {String}
-   *          The unique identifier for the action.
+   * @param {string}
+   *         id The unique identifier for the action.
+   * @param {?Array.<Object>=}
+   *         selection The selection to pass to the action.
    *
    */
-  function runAction(actionId, selection) {
-    var actionData = {};
-    actionData.actionId = actionId;
-    actionData.selectionObj = selection;
+  function runAction(id, selection) {
     if (!selection && container_ && container_.selection) {
-      actionData.selectionObj = container_.selection.getSelection();
+      selection = container_.selection.getSelection();
     }
 
     // call all container listeners, if any, for this actionId
-    var list = actionListenerMap[actionId];
+    var list = actionListenerMap[id];
     if (list) {
       for (var i = 0, listener; listener = list[i]; i++) {
-        listener.call(null, actionId, actionData.selectionObj);
+        listener.call(null, id, selection);
       }
     }
     for (var i = 0, listener; listener = actionListeners[i]; i++) {
-      listener.call(null, actionId, actionData.selectionObj);
+      listener.call(null, id, selection);
     }
 
     // make rpc call to get gadgets to run callback based on action id
-    var gadgetSites = registry.getGadgetSites(actionId);
+    var gadgetSites = registry.getGadgetSites(id);
     if (gadgetSites) {
       for (var i = 0, site; site = gadgetSites[i]; i++) {
         var holder = site.getActiveGadgetHolder();
         if (holder) {
-          var frameId = holder.getIframeId();
-          gadgets.rpc.call(frameId, 'actions', null, 'runAction', actionData);
+          gadgets.rpc.call(holder.getIframeId(), 'actions.runAction', null,
+            id, selection
+          );
         }
       }
     }
@@ -470,39 +496,37 @@
   var preloadCallback = function(response) {
     for (var url in response) {
       var metadata = response[url];
-      if (!metadata.error) {
-        if (metadata.modulePrefs) {
-          var feature = metadata.modulePrefs.features['actions'];
-          if (feature && feature.params) {
-            var desc = feature.params['action-contributions'];
-            if (desc) {
-              var domResponse = createDom(desc);
-              if (domResponse && !domResponse['errors']) {
-                var jsonDesc = gadgets.json.xml
-                  .convertXmlToJson(domResponse['data']);
-                var actionsJson = jsonDesc['actions'];
-                if (actionsJson) {
-                  var actions = actionsJson['action'];
-                  if (!(actions instanceof Array)) {
-                    actions = [actions];
-                  }
-                  for (var i=0; i<actions.length; i++) {
-                    var actionObj = actions[i];
-                    var actionObj_new = {};
-                    // replace @ for attribute keys;
-                    for (itemAttr in actionObj) {
-                      var attrStr = itemAttr.substring(1);
-                      actionObj_new[attrStr] = actionObj[itemAttr];
-                    }
-                    // check if action already exists
-                    if (!registry.getItemById(actionObj_new.id)) {
-                      addAction(actionObj_new, url);
-                    }
-                  }
-                }
-              }
-            }
-          }
+      if (metadata.error || !metadata.modulePrefs) {
+        continue; // bail
+      }
+
+      var feature = metadata.modulePrefs.features['actions'],
+          desc = feature && feature.params ? feature.params['action-contributions'] : null;
+      if (!desc) {
+        continue; // bail
+      }
+
+      var domResponse = createDom(desc);
+      if (!domResponse || domResponse['errors']) {
+        continue; // bail
+      }
+
+      var jsonDesc = gadgets.json.xml.convertXmlToJson(domResponse['data']),
+          actionsJson = jsonDesc['actions'];
+      if (!actionsJson) {
+        continue; // bail
+      }
+
+      var actions = [].concat(actionsJson['action']);
+      for (var i = 0, actionObj; actionObj = actions[i]; i++) {
+        var actionClone = {};
+        // replace @ for attribute keys;
+        for (var key in actionObj) {
+          actionClone[key.substring(1)] = actionObj[key];
+        }
+        // check if action already exists
+        if (!registry.getItemById(actionClone.id)) {
+          addAction(actionClone, url);
         }
       }
     }
@@ -558,33 +582,6 @@
   actionsLifecycleCallback[osapi.container.CallbackType.ON_UNLOADED] =
     unloadedCallback;
 
-  // Function to handle RPC calls from the gadgets side
-  function router_get_actions_by_type(object) {
-    return container_.actions.getActionsByDataType(object);
-  }
-  function router_get_actions_by_path(object) {
-    return container_.actions.getActionsByPath(object);
-  }
-  function router_run_action(object) {
-    container_.actions.runAction(object.id, object.selection);
-  }
-  function router(channel, object) {
-    switch (channel) {
-    case 'bindAction':
-      bindAction(object);
-      break;
-    case 'removeAction':
-      hideActionHandlerProxy([object]);
-      break;
-    case 'addShowActionListener':
-      addShowActionListener(object);
-      break;
-    case 'addHideActionListener':
-      addHideActionListener(object);
-      break;
-    }
-  };
-
   /**
    * Function that renders actions in the container's UI
    *
@@ -592,21 +589,8 @@
    *          actionObj The object with id, label, tooltip, icon and any other
    *          information for the container to use to render the action.
    */
-  var showActionHandler = function(actions) {};
-  var showActionListeners = [];
-  var showActionHandlerProxy = function(actions) {
-    showActionHandler(actions);
-    for (var i in showActionListeners)
-      showActionListeners[i](actions);
-  };
-
-  /**
-   * Function that adds a listener to the list of listeners that will
-   * be notified of show action events.
-   */
-  function addShowActionListener(listener) {
-    showActionListeners.push(listener);
-  };
+  var showActionHandler = function(actions) {},
+      showActionSiteIds = {};
 
   /**
    * Function that hides actions from the container's UI
@@ -615,21 +599,8 @@
    *          actionObj The object with id, label, tooltip, icon and any other
    *          information for the container to use to render the action.
    */
-  var hideActionHandler = function(actions) {};
-  var hideActionListeners = [];
-  var hideActionHandlerProxy = function(actions) {
-    hideActionHandler(actions);
-    for (var i in hideActionListeners)
-      hideActionListeners[i](actions);
-  };
-
-  /**
-   * Function that adds a listener to the list of listeners that will
-   * be notified of hide action events.
-   */
-  function addHideActionListener(listener) {
-    hideActionListeners.push(listener);
-  };
+  var hideActionHandler = function(actions) {},
+      hideActionSiteIds = {};
 
   /**
    * Function that renders gadgets in container's UI
@@ -656,14 +627,31 @@
    */
   osapi.container.Container.addMixin('actions', function(container) {
     container_ = container;
-    gadgets.rpc.register('actions', router);
-    gadgets.rpc.register('get_actions_by_type', router_get_actions_by_type);
-    gadgets.rpc.register('get_actions_by_path', router_get_actions_by_path);
-    gadgets.rpc.register('run_action', router_run_action);
+
+    gadgets.rpc.register('actions.registerHideCallback', function() {
+      hideActionSiteIds[this.f] = 1;
+    });
+    gadgets.rpc.register('actions.registerShowCallback', function() {
+      showActionSiteIds[this.f] = 1;
+    });
+
+    function getActionsByDataType(dataType) {
+      return [].concat(registry.getActionsByDataType(dataType));
+    }
+    function getActionsByPath(path) {
+      return [].concat(registry.getActionsByPath(path));
+    }
+
+    gadgets.rpc.register('actions.bindAction', bindAction);
+    gadgets.rpc.register('actions.get_actions_by_type', getActionsByDataType);
+    gadgets.rpc.register('actions.get_actions_by_path', getActionsByPath);
+    gadgets.rpc.register('actions.removeAction', removeAction);
+    gadgets.rpc.register('actions.runAction', function(id, selection) {
+      container.actions.runAction(id, selection);
+    });
 
     if (container.addGadgetLifecycleCallback) {
-      container.addGadgetLifecycleCallback('actions',
-          actionsLifecycleCallback);
+      container.addGadgetLifecycleCallback('actions', actionsLifecycleCallback);
     }
 
     return /** @scope osapi.container.actions */ {
@@ -712,8 +700,8 @@
       /*
        * Uncomment the below two functions to run full jsunit tests.
        */
-      //addAction : function(actionObj) { addAction(actionObj); },
-      //removeAction : function(actionId) { removeAction(actionId); },
+      // addAction : function(actionObj) { addAction(actionObj); },
+      // removeAction : function(actionId) { removeAction(actionId); },
 
       /**
        * Executes the action associated with the action id.
@@ -780,11 +768,7 @@
        * @return {Array} An array with any action objects in the
        *         specified path.
        */
-      getActionsByPath: function(path) {
-        var actions = [];
-        actions = actions.concat(registry.getActionsByPath(path));
-        return actions;
-      },
+      getActionsByPath: getActionsByPath,
 
       /**
        * Gets action object from registry based on the dataType.
@@ -794,11 +778,7 @@
        * @return {Array} An array of action objects bound to the specified
        *         data type.
        */
-      getActionsByDataType: function(dataType) {
-        var actions = [];
-        actions = actions.concat(registry.getActionsByDataType(dataType));
-        return actions;
-      },
+      getActionsByDataType: getActionsByDataType,
 
       /**
        * Adds a listener to be notified when an action is invoked.

Modified: shindig/trunk/features/src/main/javascript/features/actions/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/actions/feature.xml?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/actions/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/actions/feature.xml Tue Dec  6 20:27:37 2011
@@ -36,23 +36,31 @@
       <exports type="js">gadgets.actions.registerHideActionsListener</exports>
       <exports type="js">osapi.container.actions.OptParam.VIEW</exports>
       <exports type="js">osapi.container.actions.OptParam.VIEW_TARGET</exports>
-      <exports type="rpc">actions</exports>
-      <uses type="rpc">actions</uses>
-      <uses type="rpc">bindAction</uses>
-      <uses type="rpc">runAction</uses>
-      <uses type="rpc">removeAction</uses>
-      <uses type="rpc">getActionsByPath</uses>
-      <uses type="rpc">getActionsByDataType</uses>
-      <uses type="rpc">addShowActionListener</uses>
-      <uses type="rpc">addHideActionListener</uses>
+      <exports type="rpc">actions.onActionShow</exports>
+      <exports type="rpc">actions.onActionHide</exports>
+      <exports type="rpc">actions.runAction</exports>
+      <uses type="rpc">actions.registerHideCallback</uses>
+      <uses type="rpc">actions.registerShowCallback</uses>
+      <uses type="rpc">actions.bindAction</uses>
+      <uses type="rpc">actions.get_actions_by_type</uses>
+      <uses type="rpc">actions.get_actions_by_path</uses>
+      <uses type="rpc">actions.runAction</uses>
     </api>
   </gadget>
   <container>
     <script src="constants.js"/>
     <script src="actions_container.js"/>
     <api>
-      <exports type="rpc">actions</exports>
-      <uses type="rpc">runAction</uses>
+      <exports type="rpc">actions.registerHideCallback</exports>
+      <exports type="rpc">actions.registerShowCallback</exports>
+      <exports type="rpc">actions.bindAction</exports>
+      <exports type="rpc">actions.get_actions_by_type</exports>
+      <exports type="rpc">actions.get_actions_by_path</exports>
+      <exports type="rpc">actions.removeAction</exports>
+      <exports type="rpc">actions.runAction</exports>
+      <uses type="rpc">actions.onActionShow</uses>
+      <uses type="rpc">actions.onActionHide</uses>
+      <uses type="rpc">actions.runAction</uses>
     </api>
   </container>
 </feature>
\ No newline at end of file

Modified: shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js Tue Dec  6 20:27:37 2011
@@ -75,7 +75,7 @@ osapi.container.GadgetSite = function(ar
    * @private
    */
   this.id_ = (this.currentGadgetEl_ && this.currentGadgetEl_.id) ? this.currentGadgetEl_.id :
-    osapi.container.GadgetSite.nextUniqueId_++;
+    osapi.container.Container.prototype.nextUniqueSiteId_++;
 
   /**
    * ID of parent gadget.
@@ -98,6 +98,14 @@ osapi.container.GadgetSite = function(ar
    */
   this.loadingGadgetHolder_ = null;
 
+  /**
+   * Used primarily by open-views feature.
+   * @type {string} ownerId_ The rpc targetId of the gadget that requested this site's creation.
+   *
+   * @private
+   */
+  this.ownerId_ = null;
+
   this.onConstructed();
 };
 

Modified: shindig/trunk/features/src/main/javascript/features/container.url/url_site.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.url/url_site.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container.url/url_site.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container.url/url_site.js Tue Dec  6 20:27:37 2011
@@ -43,7 +43,7 @@ osapi.container.UrlSite = function(args)
    * @type {number}
    * @private
    */
-  this.id_ = osapi.container.UrlSite.nextUniqueId_++;
+  this.id_ = osapi.container.Container.prototype.nextUniqueSiteId_++;
 
   /**
    * @type {Element}
@@ -57,6 +57,14 @@ osapi.container.UrlSite = function(args)
    */
   this.url_ = null;
 
+  /**
+   * Used primarily by open-views feature.
+   * @type {string} ownerId_ The rpc targetId of the gadget that requested this site's creation.
+   *
+   * @private
+   */
+  this.ownerId_ = null;
+
   this.onConstructed();
 };
 

Modified: 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=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container/container.js Tue Dec  6 20:27:37 2011
@@ -159,6 +159,13 @@ osapi.container.Container = function(opt
   this.onConstructed(config);
 };
 
+/**
+ * Unique counter for gadget and url sites.  Used if no explicit ID was provided in their creation.
+ * @type {number}
+ * @private
+ */
+osapi.container.Container.prototype.nextUniqueSiteId_ = 0;
+
 
 /**
  * Create a new gadget site.
@@ -258,7 +265,9 @@ osapi.container.Container.prototype.clos
   site.close();
   this.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_CLOSED, site);
   delete this.sites_[id];
-  this.unscheduleRefreshTokens_();
+  if (site instanceof osapi.container.GadgetSite) {
+    this.unscheduleRefreshTokens_();
+  }
 };
 
 
@@ -598,7 +607,7 @@ osapi.container.Container.prototype.getG
   // 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();
+    var holder = (site.getActiveGadgetHolder || site.getActiveUrlHolder).call(site);
     if (holder && holder.getIframeId() === iframeId) {
       return site;
     }
@@ -607,6 +616,14 @@ osapi.container.Container.prototype.getG
 };
 
 /**
+ * @param {string} siteId ID of gadget site to get.
+ * @return {osapi.container.GadgetSite|osapi.container.UrlSite} The gadget site.
+ */
+osapi.container.Container.prototype.getSiteById = function(siteId) {
+  return this.sites_[siteId];
+};
+
+/**
  * Start to schedule refreshing of tokens.
  * @param {number} Encountered token time to live in seconds.
  * @private
@@ -824,7 +841,8 @@ osapi.container.Container.prototype.getA
 osapi.container.Container.prototype.getNavigatedGadgetUrls_ = function() {
   var result = {};
   for (var siteId in this.sites_) {
-    var holder = this.sites_[siteId].getActiveGadgetHolder();
+    var site = this.sites_[siteId],
+        holder = (site.getActiveGadgetHolder || site.getActiveUrlHolder).call(site);
     if (holder) {
       result[holder.getUrl()] = null;
     }
@@ -848,16 +866,18 @@ osapi.container.Container.prototype.refr
     // 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]);
+      if (self.sites_[siteId] instanceof osapi.container.GadgetSite) {
+        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]);
+          }
         }
       }
     }
@@ -890,7 +910,9 @@ osapi.container.Container.prototype.appl
 osapi.container.Container.prototype.newUrlSite = function(element) {
   var args = {};
   args[osapi.container.UrlSite.URL_ELEMENT] = element;
-  return new osapi.container.UrlSite(args);
+  var site = new osapi.container.UrlSite(args);
+  this.sites_[site.getId()] = site;
+  return site;
 };
 
 

Modified: 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=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/container/feature.xml Tue Dec  6 20:27:37 2011
@@ -45,6 +45,7 @@ under the License.
       <exports type="js">osapi.container.Container.prototype.getGadgetMetadata</exports>
       <exports type="js">osapi.container.Container.prototype.rpcRegister</exports>
       <exports type="js">osapi.container.Container.prototype.onConstructed</exports>
+      <exports type="js">osapi.container.Container.prototype.getGadgetSiteById</exports>
       <exports type="js">osapi.container.ContainerConfig.ALLOW_DEFAULT_VIEW</exports>
       <exports type="js">osapi.container.ContainerConfig.RENDER_CAJOLE</exports>
       <exports type="js">osapi.container.ContainerConfig.RENDER_DEBUG</exports>

Modified: shindig/trunk/features/src/main/javascript/features/open-views/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/open-views/feature.xml?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/open-views/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/open-views/feature.xml Tue Dec  6 20:27:37 2011
@@ -38,6 +38,7 @@ A map of view names to view attributes. 
       <exports type="js">gadgets.views.close</exports>
       <exports type="js">gadgets.views.setReturnValue</exports>
       <exports type="js">gadgets.window.getContainerDimensions</exports>
+      <exports type="rpc">gadgets.views.deliverResult</exports>
       <uses type="rpc">gadgets.views.openGadget</uses>
       <uses type="rpc">gadgets.views.openEmbeddedExperience</uses>
       <uses type="rpc">gadgets.views.openUrl</uses>
@@ -55,6 +56,7 @@ A map of view names to view attributes. 
       <exports type="rpc">gadgets.views.close</exports>
       <exports type="rpc">gadgets.views.setReturnValue</exports>
       <exports type="rpc">gadgets.window.getContainerDimensions</exports>
+      <uses type="rpc">gadgets.views.deliverResult</uses>
     </api>
   </container>
 </feature>

Modified: shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements-container.js Tue Dec  6 20:27:37 2011
@@ -30,9 +30,6 @@
   // Mapping between id and return value
   var returnValueMap;
 
-  // mapping between iframe id and site
-  var iframeSiteMap;
-
   function init(container) {
 
     context = container;
@@ -47,14 +44,11 @@
 
     gadgets.rpc.register('gadgets.views.setReturnValue', setReturnValue);
 
-    gadgets.rpc.register('gadgets.window.getContainerDimensions',
-        getContainerDimensions);
+    gadgets.rpc.register('gadgets.window.getContainerDimensions', getContainerDimensions);
 
     resultCallbackMap = {};
 
     returnValueMap = {};
-
-    iframeSiteMap = {};
   };
   /**
    * Opens a gadget in the container UI. The location of the gadget site in the
@@ -62,13 +56,10 @@
    * would open the view in a dialog, if view target is dialog or the gadgets
    * view in a tab for view target is tab.
    *
-   * @param {function}
-   *          resultCallback: Callback function to be called when the gadget
+   * @param {number}
+   *          resultCallback: Callback id of function to be called when the gadget
    *          closes. The function will be called with the return value as a
    *          parameter.
-   * @param {function}
-   *          navigateCallback: Callback function to be called with the the
-   *          Site which has been opened and metadata.
    * @param {Object.<string, string|Object>=}
    *          opt_params: These are optional parameters which can be used to
    *          open gadgets. The following parameters may be included in this
@@ -79,11 +70,12 @@
    *          example, tab, dialog or modaldialog {Object} viewParams: View
    *          parameters for the view being rendered.
    */
-  function openGadget(resultCallback, navigateCallback, opt_params) {
+  function openGadget(resultCallback, opt_params) {
 
-    var gadgetUrl = '';
-
-    var orig_site = context.getGadgetSiteByIframeId_(this.f);
+    var navigateCallback = this.callback,
+        siteOwnerId = this.f,
+        gadgetUrl = '',
+        orig_site = context.getGadgetSiteByIframeId_(this.f);
 
     if (orig_site !== undefined &&
             orig_site.getActiveGadgetHolder() !== undefined) {
@@ -111,18 +103,19 @@
         if (result[gadgetUrl].error) {
           gadgets.error('Failed to preload gadget : ' + gadgetUrl);
           if (navigateCallback != null) {
-            navigateCallback(null, result[gadgetUrl]);
+            navigateCallback([null, result[gadgetUrl]]);
           }
           return;
         }else {
           metadata = result[gadgetUrl];
         }
       }
-      var content_div = context.views.createElementForGadget(metadata, view,
-          viewTarget);
-      var site = context.newGadgetSite(content_div);
 
-      var renderParams = {};
+      var renderParams = {},
+          site = context.newGadgetSite(
+            context.views.createElementForGadget(metadata, view, viewTarget)
+          );
+      site.ownerId_ = siteOwnerId;
 
       if (view !== undefined && view !== '') {
         renderParams[osapi.container.RenderParam.VIEW] = view;
@@ -130,53 +123,27 @@
       renderParams[osapi.container.RenderParam.WIDTH] = '100%';
       renderParams[osapi.container.RenderParam.HEIGHT] = '100%';
 
-      context.navigateGadget(site, gadgetUrl, viewParams, renderParams,
-          function(metadata) {
-            if (metadata != null) {
-              processSiteAndCallbackInfo(site, resultCallback);
-            }
-            if (navigateCallback != null) {
-              navigateCallback(site, metadata);
-            }
-          });
-
+      context.navigateGadget(site, gadgetUrl, viewParams, renderParams, function(metadata) {
+        if (metadata) {
+          resultCallbackMap[site.getId()] = resultCallback;
+        }
+        if (navigateCallback) {
+          navigateCallback([site.getId(), metadata]);
+        }
+      });
     });
   }
 
   /**
-   * Processes the site and callback information and stores it in global maps.
-   * @param {osapi.container.GadgetSite | osapi.container.UrlSite} site the site
-   * that was created for the gadget.
-   * @param {Function} resultCallback called with any result the gadget chooses
-   * to set.
-   */
-  function processSiteAndCallbackInfo(site, resultCallback) {
-    var iframeId;
-    if (site && site.getActiveGadgetHolder()) {
-      iframeId = site.getActiveGadgetHolder().getIframeId();
-    }
-
-    iframeSiteMap[iframeId] = site;
-
-    // use the site id as key
-    if (typeof site.getId() !== 'undefined' && resultCallback != null) {
-      resultCallbackMap[site.getId()] = resultCallback;
-    }
-  }
-
-  /**
    * Opens an embedded experience in the container UI. The location of the site
    * in the container will be determined by the view target passed in. The
    * container would open the embedded experience in a dialog, if view target is
    * dialog or the embedded experience view in a tab for view target is tab.
    *
-   * @param {Function}
-   *          resultCallback: Callback function to be called when the embedded
+   * @param {number}
+   *          resultCallback: Callback function id to be called when the embedded
    *          experience closes. The function will be called with the return
    *          value as a parameter.
-   * @param {Function}
-   *          navigateCallback: Callback function to be called with the embedded
-   *          experience has rendered.
    * @param {Object}
    *          dataModel: The embedded experiences data model.
    * @param {Object}
@@ -186,8 +153,10 @@
    *          the gadget. For example, tab, dialog or modaldialog {Object}
    *          viewParams: View parameters for the view being rendered.
    */
-  function openEE(resultCallback, navigateCallback, dataModel, opt_params) {
-    var gadgetUrl = dataModel.gadget;
+  function openEE(resultCallback, dataModel, opt_params) {
+    var navigateCallback = this.callback,
+        siteOwnerId = this.f,
+        gadgetUrl = dataModel.gadget;
 
     //Check to make sure we can actually reach the gadget we are going to try
     //to render before we do anything else
@@ -198,7 +167,7 @@
         //render the url, else just call the navigateCallback
         if (!dataModel.url) {
           if (navigateCallback != null) {
-            navigateCallback(null, result[gadgetUrl]);
+            navigateCallback([null, result[gadgetUrl]]);
           }
           return;
         }
@@ -234,15 +203,15 @@
       eeRenderParams[osapi.container.ee.RenderParam.GADGET_VIEW_PARAMS] =
           viewParams;
 
-      context.ee.navigate(element, dataModel, eeRenderParams, function(site,
-              metadata) {
-            if (metadata != null) {
-              processSiteAndCallbackInfo(site, resultCallback);
-            }
-            if (navigateCallback != null) {
-              navigateCallback(site, metadata);
-            }
-          });
+      context.ee.navigate(element, dataModel, eeRenderParams, function(site, metadata) {
+        site.ownerId_ = siteOwnerId;
+        if (metadata) {
+          resultCallbackMap[site.getId()] = resultCallback;
+        }
+        if (navigateCallback) {
+          navigateCallback([site.getId(), metadata]);
+        }
+      });
     });
   }
 
@@ -256,14 +225,12 @@
    * @param {string}
    *          url: URL to a web page to open in a URL site in the container.
    *          (Note this should not be a URL to a gadget definition.).
-   * @param {function}
-   *          navigateCallback: Callback function to be called with the site
-   *          which has been opened.
    * @param {string=}
    *          opt_viewTarget: Optional parameter,the view that indicates where
    *          to open the URL.
+   * @returns {string} The ID of the site created, if a callback was registered.
    */
-  function openUrl(url, navigateCallback, opt_viewTarget) {
+  function openUrl(url, opt_viewTarget) {
     var content_div = context.views.createElementForUrl(opt_viewTarget);
 
     var site = context.newUrlSite(content_div);
@@ -274,39 +241,46 @@
 
     context.navigateUrl(site, url, renderParams);
 
-    if (navigateCallback !== undefined) {
-      navigateCallback(site);
-    }
+    // record who opened this site, so that if they use the siteId to close it later,
+    // we don't inadvertently allow other gadgets to guess the id and close the site.
+    site.ownerId_ = this.f;
+    return site.getId();
   }
 
   /**
    * Closes an opened site. If the opt_id parameter is null the container will
    * close the calling site.
    *
-   * @param {object=}
+   * @param {Object=}
    *          opt_site: Optional parameter which specifies what site to close.
    *          If null it will close the current gadget site.
    */
   function close(opt_site) {
-    // this.f is the frame id
-    var iframeId = this.f;
-    var site;
+    // opt_site may be 0, do not do a truthy test on the value.
+    var orig_site = context.getGadgetSiteByIframeId_(this.f),
+        site = typeof(opt_site) != 'undefined' ? context.getSiteById(opt_site) : orig_site;
 
-    if (opt_site == undefined || opt_site == '') {
-      site = iframeSiteMap[iframeId];
-    }
-    else {
-      site = opt_site;
+    if (!site) {
+      return;
     }
 
-    if (site != null) {
-      var siteId = site.getId();
-
-      if (siteId !== undefined && resultCallbackMap[siteId] !== undefined &&
-              returnValueMap[siteId] !== undefined) {
-        var returnValue = returnValueMap[siteId];
-        // execute the result callback function with return value as parameter
-        resultCallbackMap[siteId](returnValue);
+    // A side effect of this check is that if a gadget tries to close a site it did not
+    // create, the gadget itself will be closed.  That's the price to pay for trying to
+    // be evil, I guess :)
+    var siteId = site.getId(),
+        allowed = site == orig_site || site.ownerId_ == this.f;
+
+    if (typeof(siteId) != 'undefined' && allowed) {
+      var returnValue = returnValueMap[siteId],
+          resultCallback = resultCallbackMap[siteId];
+
+      if (typeof(resultCallback) != 'undefined') { // may be 0
+        if (typeof(returnValue) != 'undefined' && site.ownerId_) {
+          gadgets.rpc.call(site.ownerId_, 'gadgets.views.deliverResult', null,
+            resultCallback, returnValue
+          );
+        }
+        delete resultCallbackMap[siteId];
       }
     }
 
@@ -322,34 +296,21 @@
    *          returnValue: Return value for this window.
    */
   function setReturnValue(returnValue) {
-    if (returnValue !== undefined && iframeSiteMap[this.f] !== undefined) {
-      var siteId = iframeSiteMap[this.f].getId();
-      // use the site id as key
-      if (siteId !== undefined) {
-        returnValueMap[siteId] = returnValue;
-      }
+    var site;
+    if (site = context.getGadgetSiteByIframeId_(this.f)) {
+      returnValueMap[site.getId()] = returnValue;
     }
   }
 
   /**
    * Gets the dimensions of the container displaying the gadget.
-   *
-   * @param {function}
-   *          resultCallback: Callback function will be called with the return
-   *          value as a parameter.
    */
-  function getContainerDimensions(resultCallback) {
-    if (resultCallback == null) {
-      return;
-    }
+  function getContainerDimensions() {
     var el = document.documentElement; // Container element
-    var result = {'width' : -1, 'height': -1};
-    if (el !== undefined) {
-      result.width = el.clientWidth;
-      result.height = el.clientHeight;
-    }
-    // return client width and client height
-    resultCallback(result);
+    return {
+      width : el ? el.clientWidth : -1,
+      height: el ? el.clientHeight : -1
+    };
   }
 
   osapi.container.Container.addMixin('views', function(container) {

Modified: shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js (original)
+++ shindig/trunk/features/src/main/javascript/features/open-views/viewenhancements.js Tue Dec  6 20:27:37 2011
@@ -24,6 +24,19 @@ gadgets['window'] = gadgets['window'] ||
 
 (function() {
 
+  var resultCallbackMap = {},
+      rcbnum = 0;
+
+  gadgets.util.registerOnLoadHandler(function() {
+    gadgets.rpc.register('gadgets.views.deliverResult', function(rcbnum, result) {
+      var resultCallback;
+      if (resultCallback = resultCallbackMap[rcbnum]) {
+        delete resultCallbackMap[rcbnum];
+        resultCallback(result);
+      }
+    });
+  });
+
   /**
    * Opens a gadget in the container UI. The location of the gadget site in the
    * container will be determined by the view target passed in. The container
@@ -50,8 +63,12 @@ gadgets['window'] = gadgets['window'] ||
 
   gadgets.views.openGadget = function(resultCallback, navigateCallback,
           opt_params) {
-    gadgets.rpc.call('..', 'gadgets.views.openGadget', null, resultCallback,
-        navigateCallback, opt_params);
+
+    resultCallbackMap[rcbnum] = resultCallback;
+    gadgets.rpc.call('..', 'gadgets.views.openGadget', function(result) {
+        navigateCallback.apply(this, result);
+      }, rcbnum++, opt_params
+    );
   };
 
   /**
@@ -78,9 +95,12 @@ gadgets['window'] = gadgets['window'] ||
    */
   gadgets.views.openEmbeddedExperience = function(resultCallback,
           navigateCallback, dataModel, opt_params) {
-    gadgets.rpc
-    .call('..', 'gadgets.views.openEmbeddedExperience', null, resultCallback,
-            navigateCallback, dataModel, opt_params);
+
+    resultCallbackMap[rcbnum] = resultCallback;
+    gadgets.rpc.call('..', 'gadgets.views.openEmbeddedExperience', function(result) {
+        navigateCallback.apply(this, result);
+      }, rcbnum++, dataModel, opt_params
+    );
   };
 
   /**
@@ -100,8 +120,10 @@ gadgets['window'] = gadgets['window'] ||
    *          to open the URL.
    */
   gadgets.views.openUrl = function(url, navigateCallback, opt_viewTarget) {
-    gadgets.rpc.call('..', 'gadgets.views.openUrl', null, url, navigateCallback,
-        opt_viewTarget);
+    gadgets.rpc.call('..', 'gadgets.views.openUrl', function(result) {
+        navigateCallback.apply(this, result);
+      }, url, opt_viewTarget
+    );
   }
 
   /**
@@ -113,7 +135,9 @@ gadgets['window'] = gadgets['window'] ||
    *          If null it will close the current gadget site.
    */
   gadgets.views.close = function(opt_site) {
-    gadgets.rpc.call('..', 'gadgets.views.close', null, opt_site);
+    gadgets.rpc.call('..', 'gadgets.views.close', null,
+      opt_site
+    );
   };
 
   /**
@@ -125,7 +149,9 @@ gadgets['window'] = gadgets['window'] ||
    *          returnValue: Return value for this window.
    */
   gadgets.views.setReturnValue = function(returnValue) {
-    gadgets.rpc.call('..', 'gadgets.views.setReturnValue', null, returnValue);
+    gadgets.rpc.call('..', 'gadgets.views.setReturnValue', null,
+      returnValue
+    );
   };
 
   /**
@@ -138,8 +164,7 @@ gadgets['window'] = gadgets['window'] ||
    *          value as a parameter.
    */
   gadgets.window.getContainerDimensions = function(resultCallback) {
-    gadgets.rpc.call('..', 'gadgets.window.getContainerDimensions',
-        null, resultCallback);
+    gadgets.rpc.call('..', 'gadgets.window.getContainerDimensions', resultCallback);
   }
 
 }());

Modified: shindig/trunk/features/src/main/javascript/features/selection/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/selection/feature.xml?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/selection/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/selection/feature.xml Tue Dec  6 20:27:37 2011
@@ -28,13 +28,17 @@ specific language governing permissions 
       <exports type="js">gadgets.selection.getSelection</exports>
       <exports type="js">gadgets.selection.addListener</exports>
       <exports type="js">gadgets.selection.removeListener</exports>
-      <uses type="rpc">gadgets.selection</uses>
+      <exports type="rpc">gadgets.selection.selectionChanged</exports>
+      <uses type="rpc">gadgets.selection.set</uses>
+      <uses type="rpc">gadgets.selection.register</uses>
     </api>
   </gadget>
   <container>
     <script src="selection_container.js"/>
     <api>
-      <exports type="rpc">gadgets.selection</exports>
+      <exports type="rpc">gadgets.selection.set</exports>
+      <exports type="rpc">gadgets.selection.register</exports>
+      <uses type="rpc">gadgets.selection.selectionChanged</uses>
     </api>
   </container>
 </feature>

Modified: shindig/trunk/features/src/main/javascript/features/selection/selection.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/selection/selection.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/selection/selection.js (original)
+++ shindig/trunk/features/src/main/javascript/features/selection/selection.js Tue Dec  6 20:27:37 2011
@@ -27,10 +27,17 @@
  * @name gadgets.selection
  */
 gadgets['selection'] = function() {
+  var listeners,
+      currentSelection;
 
-  var listeners = new Array();
-  var currentSelection = null;
-  var selectionChangedFunc = null;
+  gadgets.util.registerOnLoadHandler(function() {
+    gadgets.rpc.register('gadgets.selection.selectionChanged', function(selection) {
+      currentSelection = selection;
+      for (var i=0, currentListener; currentListener=listeners[i]; i++) {
+        listeners[i](selection);
+      }
+    });
+  });
 
   return /** @scope gadgets.selection */ {
     /**
@@ -39,7 +46,7 @@ gadgets['selection'] = function() {
      */
     setSelection: function(selection) {
       currentSelection = selection;
-      gadgets.rpc.call('..', 'gadgets.selection', null, 'set', selection);
+      gadgets.rpc.call('..', 'gadgets.selection.set', null, selection);
     },
 
     /**
@@ -55,20 +62,12 @@ gadgets['selection'] = function() {
      * @param {function} listener The listener to remove.
      */
     addListener: function(listener) {
+      if (!listeners) {
+        listeners  = [];
+        gadgets.rpc.call('..', 'gadgets.selection.register');
+      }
       if (typeof listener === 'function') {
-        // add the listener to the list
-        listeners.push(listener);
-        // lazily create and add the callback
-        if (selectionChangedFunc == null) {
-          selectionChangedFunc = function(selection) {
-            currentSelection = selection;
-            for (var i=0, currentListener; currentListener=listeners[i]; i++) {
-              listeners[i](selection);
-            }
-          };
-          gadgets.rpc.call('..', 'gadgets.selection', null, 'add',
-              selectionChangedFunc);
-        }
+        listeners.push(listener); // add the listener to the list
       }
     },
 

Modified: shindig/trunk/features/src/main/javascript/features/selection/selection_container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/selection/selection_container.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/selection/selection_container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/selection/selection_container.js Tue Dec  6 20:27:37 2011
@@ -27,15 +27,9 @@
  */
 (function() {
 
-  var listeners = new Array();
-  var _selection;
-
-  function notifySelection(selection) {
-    _selection = selection;
-    for(var i=0, currentListener; currentListener=listeners[i]; i++) {
-      listeners[i](selection);
-    }
-  }
+  var _selection,
+      listeners = [],
+      listeningGadgets = {};
 
   function addSelectionListener(listener) {
     if (typeof listener === 'function') {
@@ -52,29 +46,37 @@
     }
   }
 
-  function router(command, param) {
-    switch (command) {
-    case 'set':
-      notifySelection(param);
-      break;
-    case 'add':
-      addSelectionListener(param);
-      break;
-    default:
-      throw new Error('Unknown selection command');
+  osapi.container.Container.addMixin('selection', function(context) {
+
+    function notifySelection(selection) {
+      _selection = selection;
+      for(var i=0, currentListener; currentListener=listeners[i]; i++) {
+        listeners[i](selection);
+      }
+
+      // Call rpc endpoint in all gadgets that have registered
+      for (var to in listeningGadgets) {
+        if (!context.getGadgetSiteByIframeId_(to)) {
+          delete listeningGadgets[to];  // Remove sites that are no longer with us
+        }
+        else {
+          gadgets.rpc.call(to, 'gadgets.selection.selectionChanged', null, selection);
+        }
+      }
     }
-  }
 
-  osapi.container.Container.addMixin('selection', function(context) {
-    gadgets.rpc.register('gadgets.selection', router);
+    gadgets.rpc.register('gadgets.selection.set', notifySelection);
+    gadgets.rpc.register('gadgets.selection.register', function() {
+      listeningGadgets[this.f] = 1;
+    });
+
     return /** @scope gadgets.selection */ {
       /**
        * Sets the current selection.
        * @param {string} selection Selected object.
        */
-      setSelection: function(selection) {
-        notifySelection(selection);
-      },
+      setSelection: notifySelection,
+
       /**
        * Gets the current selection.
        * @return {Object} the current selection.
@@ -87,17 +89,13 @@
        * Registers a listener for selection.
        * @param {function} listener The listener to remove.
        */
-      addListener: function(listener) {
-        addSelectionListener(listener);
-      },
+      addListener: addSelectionListener,
 
       /**
        * Removes a listener for selection.
        * @param {function} listener The listener to remove.
        */
-      removeListener: function(listener) {
-        removeSelectionListener(listener);
-      }
+      removeListener: removeSelectionListener
     };
   });
 

Modified: shindig/trunk/features/src/test/javascript/features/actions/actions_test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/actions/actions_test.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/actions/actions_test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/actions/actions_test.js Tue Dec  6 20:27:37 2011
@@ -28,7 +28,7 @@ function DeclarativeActionsTest(name) {
 DeclarativeActionsTest.inherits(TestCase);
 
 (function() {
-  
+
 DeclarativeActionsTest.prototype.setUp = function() {
     this.apiUri = window.__API_URI;
     window.__API_URI = shindig.uri('http://shindig.com');
@@ -47,9 +47,9 @@ DeclarativeActionsTest.prototype.setUp =
 DeclarativeActionsTest.prototype.tearDown = function() {
     window.__API_URI = this.apiUri;
     window.__CONTAINER_URI = this.containerUri;
-    
+
     gadgets.rpc = this.gadgetsRpc;
-    this.rpcArguments = undefined; 
+    this.rpcArguments = undefined;
 };
 
 DeclarativeActionsTest.prototype.testGadgetsAddAction = function() {
@@ -62,22 +62,22 @@ DeclarativeActionsTest.prototype.testGad
       callback: callbackFn
     };
   gadgets.actions.addAction(_actionObj);
-  this.assertRpcCalled('..', 'actions', null, 'bindAction', _actionObj);
+  this.assertRpcCalled('..', 'actions.bindAction', null, _actionObj);
 };
 
 DeclarativeActionsTest.prototype.testGadgetsRemoveAction = function() {
   var actionId = "testAction";
   gadgets.actions.removeAction(actionId);
-  this.assertRpcCalled('..', 'actions', null,
-      'removeAction', actionId);
+  this.assertRpcCalled('..', 'actions.removeAction', null, actionId);
 };
 
 DeclarativeActionsTest.prototype.testGadgetsRunAction = function() {
   var actionId = "testAction";
   var opt_selection = "testSelection";
   gadgets.actions.runAction(actionId, opt_selection);
-  this.assertRpcCalled('..', 'run_action', null,
-    {"id":actionId, "selection":opt_selection});
+  this.assertRpcCalled('..', 'actions.runAction', null,
+    actionId, opt_selection
+  );
 };
 
 
@@ -99,7 +99,7 @@ DeclarativeActionsTest.prototype.testCon
   this.assertEquals(actionsArray, []);
 };
 
-DeclarativeActionsTest.prototype.testContainerGetActionsByDataType = 
+DeclarativeActionsTest.prototype.testContainerGetActionsByDataType =
   function(){
     var container = new osapi.container.Container();
     var actionId = "testAction";
@@ -110,7 +110,7 @@ DeclarativeActionsTest.prototype.testCon
   };
 
 /**
- * Uncomment following _Full tests once addAction() and removeAction() 
+ * Uncomment following _Full tests once addAction() and removeAction()
  * functions in actions_container.js are uncommented
  */
 /* FULL TESTS
@@ -125,7 +125,7 @@ DeclarativeActionsTest.prototype.testCon
   container.actions.addAction(actionObj_);
   var actionObj = container.actions.getAction(actionId);
   this.assertEquals(actionObj_, actionObj);
-  
+
   container.actions.removeAction(actionId);
   actionObj = container.actions.getAction(actionId);
   this.assertUndefined(actionObj);
@@ -134,44 +134,45 @@ DeclarativeActionsTest.prototype.testCon
 
 DeclarativeActionsTest.prototype.testContainerGetActions_Full = function() {
   var container = new osapi.container.Container({});
-  var actionId = "testAction";
-  var actions = [{
-    id: "test1",
-    label: "Test Action1",
-    path: "container/navigationLinks"
-  },
-  {
-    id: "test2",
-    label: "Test Action2",
-    path: "container/navigationLinks"
-  },
-  {
-    id: "test3",
-    label: "Test Action3",
-    dataType: "opensocial.Person"
-  },
-  {
-    id: "test4",
-    label: "Test Action4",
-    dataType: "opensocial.Person"
-  }
-  ];
+  var actionId = "testAction",
+      actions = [
+        {
+          id: "test1",
+          label: "Test Action1",
+          path: "container/navigationLinks"
+        },
+        {
+          id: "test2",
+          label: "Test Action2",
+          path: "container/navigationLinks"
+        },
+        {
+          id: "test3",
+          label: "Test Action3",
+          dataType: "opensocial.Person"
+        },
+        {
+          id: "test4",
+          label: "Test Action4",
+          dataType: "opensocial.Person"
+        }
+      ];
   for (actionIndex in actions) {
     container.actions.addAction(actions[actionIndex]);
   }
-  
+
   var allActions = container.actions.getAllActions();
   this.assertEquals(actions, allActions);
-  
+
   for (actionIndex in actions) {
     container.actions.removeAction(actions[actionIndex].id);
   }
-  
+
   allActions = container.actions.getAllActions();
   this.assertEquals([], allActions);
 
 };
-DeclarativeActionsTest.prototype.testContainerGetActionsByPath_Full = 
+DeclarativeActionsTest.prototype.testContainerGetActionsByPath_Full =
   function(){
     var container = new osapi.container.Container();
     var actionId = "testAction";
@@ -184,14 +185,14 @@ DeclarativeActionsTest.prototype.testCon
     var actionsArray = container.actions
       .getActionsByPath("container/navigationLinks");
     this.assertEquals(actionsArray, [ actionObj_ ]);
-    
+
     container.actions.removeAction(actionId);
     actionsArray = container.actions
       .getActionsByPath("container/navigationLinks");
     this.assertEquals(actionsArray, []);
   };
 
-DeclarativeActionsTest.prototype.testContainerGetActionsByDataType_Full = 
+DeclarativeActionsTest.prototype.testContainerGetActionsByDataType_Full =
   function() {
     var container = new osapi.container.Container();
     var actionId = "testAction";
@@ -200,17 +201,17 @@ DeclarativeActionsTest.prototype.testCon
             label: "Test Action",
             dataType: "opensocial.Person"
     };
-    
+
     container.actions.addAction(actionObj_);
     var actionsArray = container.actions
       .getActionsByDataType("opensocial.Person");
     this.assertEquals([ actionObj_ ], actionsArray);
-    
+
     container.actions.removeAction(actionId);
     actionsArray = container.actions
       .getActionsByDataType("opensocial.Person");
     this.assertEquals([], actionsArray);
-  
+
   };
 
  FULL TESTS */

Modified: shindig/trunk/features/src/test/javascript/features/container.url/url_site_test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/container.url/url_site_test.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/container.url/url_site_test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/container.url/url_site_test.js Tue Dec  6 20:27:37 2011
@@ -40,10 +40,10 @@ UrlSiteTest.prototype.testNew = function
     "urlEl" : {}
   };
   var site = new osapi.container.UrlSite(args);
-  this.assertEquals(0, site.getId());
+  this.assertEquals(osapi.container.Container.prototype.nextUniqueSiteId_ - 1, site.getId());
   this.assertNull(site.getActiveUrlHolder());
   var site2 = new osapi.container.UrlSite(args);
-  this.assertEquals(1, site2.getId());
+  this.assertEquals(osapi.container.Container.prototype.nextUniqueSiteId_ - 1, site2.getId());
   this.assertNull(site.getActiveUrlHolder());
 };
 
@@ -57,8 +57,8 @@ UrlSiteTest.prototype.testRenderNoParams
   site.render(url, {});
   this.assertNotNull(site.getActiveUrlHolder());
   this.assertEquals('<iframe' + ' marginwidth="0"' + ' hspace="0"' + ' frameborder="0"'
-          + ' scrolling="auto"' + ' marginheight="0"' + ' vspace="0"' + ' id="__url_0"'
-          + ' name="__url_0"' + ' src="http://example.com"' + ' ></iframe>', el.innerHTML);
+          + ' scrolling="auto"' + ' marginheight="0"' + ' vspace="0"' + ' id="__url_' + (osapi.container.Container.prototype.nextUniqueSiteId_ - 1) + '"'
+          + ' name="__url_' + (osapi.container.Container.prototype.nextUniqueSiteId_ - 1) + '"' + ' src="http://example.com"' + ' ></iframe>', el.innerHTML);
 };
 
 UrlSiteTest.prototype.testRenderWithParams = function() {
@@ -76,7 +76,7 @@ UrlSiteTest.prototype.testRenderWithPara
   this.assertNotNull(site.getActiveUrlHolder());
   this.assertEquals('<iframe' + ' marginwidth="0"' + ' hspace="0"' + ' height="104"'
           + ' frameborder="0"' + ' scrolling="auto"' + ' class="myClass"' + ' marginheight="0"'
-          + ' vspace="0"' + ' id="__url_0"' + ' width="54"' + ' name="__url_0"'
+          + ' vspace="0"' + ' id="__url_' + (osapi.container.Container.prototype.nextUniqueSiteId_ - 1) + '"' + ' width="54"' + ' name="__url_' + (osapi.container.Container.prototype.nextUniqueSiteId_ - 1) + '"'
           + ' src="http://example.com"' + ' ></iframe>', el.innerHTML);
 };
 

Modified: shindig/trunk/features/src/test/javascript/features/container/gadget_site_test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/container/gadget_site_test.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/container/gadget_site_test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/container/gadget_site_test.js Tue Dec  6 20:27:37 2011
@@ -34,19 +34,19 @@ GadgetSiteTest.prototype.GADGET_URL = 'h
 
 GadgetSiteTest.prototype.setUp = function() {
   var self = this;
-  
+
   this.util_getCurrentTimeMs_value = 100;
   this.util_getCurrentTimeMs_func = osapi.container.util.getCurrentTimeMs;
   osapi.container.util.getCurrentTimeMs = function() {
     return self.util_getCurrentTimeMs_value++;
   };
-  
+
   this.util_warn_value = null;
   this.util_warn_func = osapi.container.util.warn;
   osapi.container.util.warn = function(value) {
     self.util_warn_value = value;
   };
-  
+
   window[this.NAVIGATE_CALLBACK] = function(timingInfo) {
     self.window_navigateCallback_timingInfo = timingInfo;
   };
@@ -61,9 +61,9 @@ GadgetSiteTest.prototype.tearDown = func
 GadgetSiteTest.prototype.testGetId = function() {
   var site;
   site = new osapi.container.GadgetSite({});
-  this.assertEquals(0, site.getId());
+  this.assertEquals(osapi.container.Container.prototype.nextUniqueSiteId_ - 1, site.getId());
   site = new osapi.container.GadgetSite({});
-  this.assertEquals(1, site.getId());
+  this.assertEquals(osapi.container.Container.prototype.nextUniqueSiteId_ - 1, site.getId());
 };
 
 GadgetSiteTest.prototype.testNavigateToWithUncachedError = function() {

Modified: shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/open-views/viewEnhancements-test.js Tue Dec  6 20:27:37 2011
@@ -50,13 +50,12 @@ ViewEnhancementsTest.inherits(TestCase);
 
     this.assertEquals('..', rpcs[0][0]);
     this.assertEquals('gadgets.views.openGadget', rpcs[0][1]);
-    this.assertNull('Assert null error', rpcs[0][2]);
-    this.assertEquals(resultCallback, rpcs[0][3]);
-    this.assertEquals(navigateCallback, rpcs[0][4]);
-    this.assertUndefined('Assert undefined error', rpcs[0][5]);
+    this.assertNotNull('Assert not null error', rpcs[0][2]);
+    this.assertNotNull('Assert not null error', rpcs[0][3]);
+    this.assertUndefined('Assert undefined error', rpcs[0][4]);
 
     gadgets.views.openGadget(resultCallback, navigateCallback, params);
-    this.assertEquals(params, rpcs[0][5]);
+    this.assertEquals(params, rpcs[0][4]);
   };
 
   ViewEnhancementsTest.prototype.testOpenEmbeddedExperience = function() {
@@ -70,11 +69,10 @@ ViewEnhancementsTest.inherits(TestCase);
 
     this.assertEquals('..', rpcs[0][0]);
     this.assertEquals('gadgets.views.openEmbeddedExperience', rpcs[0][1]);
-    this.assertNull('Assert null error', rpcs[0][2]);
-    this.assertEquals(resultCallback, rpcs[0][3]);
-    this.assertEquals(navigateCallback, rpcs[0][4]);
-    this.assertEquals('http://www.example.com', rpcs[0][5]['url']);
-    this.assertEquals(params, rpcs[0][6]);
+    this.assertNotNull('Assert not null error', rpcs[0][2]);
+    this.assertNotNull('Assert not null error', rpcs[0][3]);
+    this.assertEquals('http://www.example.com', rpcs[0][4]['url']);
+    this.assertEquals(params, rpcs[0][5]);
   };
 
   ViewEnhancementsTest.prototype.testOpenUrl = function() {
@@ -86,13 +84,12 @@ ViewEnhancementsTest.inherits(TestCase);
 
     this.assertEquals('..', rpcs[0][0]);
     this.assertEquals('gadgets.views.openUrl', rpcs[0][1]);
-    this.assertNull('Assert null error', rpcs[0][2]);
+    this.assertNotNull('Assert not null error', rpcs[0][2]);
     this.assertEquals(url, rpcs[0][3]);
-    this.assertEquals(navigateCallback, rpcs[0][4]);
-    this.assertUndefined('Assert undefined error', rpcs[0][5]);
+    this.assertUndefined('Assert undefined error', rpcs[0][4]);
 
     gadgets.views.openUrl(url, navigateCallback, viewTarget);
-    this.assertEquals(viewTarget, rpcs[0][5]);
+    this.assertEquals(viewTarget, rpcs[0][4]);
   };
 
   ViewEnhancementsTest.prototype.testClose = function() {
@@ -123,15 +120,13 @@ ViewEnhancementsTest.inherits(TestCase);
   };
 
   ViewEnhancementsTest.prototype.testGetContainerDimensions = function() {
-
     var resultCallback = function() {};
 
     gadgets.window.getContainerDimensions(resultCallback);
 
     this.assertEquals('..', rpcs[0][0]);
     this.assertEquals('gadgets.window.getContainerDimensions', rpcs[0][1]);
-    this.assertNull('Assert null error', rpcs[0][2]);
-    this.assertEquals(resultCallback, rpcs[0][3]);
+    this.assertEquals(resultCallback, rpcs[0][2]);
   };
 
 })();

Modified: shindig/trunk/features/src/test/javascript/features/selection/selection_test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/selection/selection_test.js?rev=1211090&r1=1211089&r2=1211090&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/selection/selection_test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/selection/selection_test.js Tue Dec  6 20:27:37 2011
@@ -66,7 +66,7 @@ SelectionTest.inherits(TestCase);
     var container = new osapi.container.Container({});
     var token = "hello";
     gadgets.selection.setSelection(token);
-    this.assertRpcCalled("..", "gadgets.selection", null, "set", token);
+    this.assertRpcCalled("..", "gadgets.selection.set", null, token);
   };
 
   SelectionTest.prototype.testGadgetGetSelection = function() {
@@ -82,7 +82,7 @@ SelectionTest.inherits(TestCase);
     var callback = function() {
     };
     gadgets.selection.addListener(callback);
-    this.assertRpcCalled("..", "gadgets.selection", null, "add", callback);
+    this.assertRpcCalled("..", "gadgets.selection.register");
   };
 
   /**



Mime
View raw message