Author: woodser
Date: Thu Jul 14 19:17:36 2011
New Revision: 1146859
URL: http://svn.apache.org/viewvc?rev=1146859&view=rev
Log:
Applying Action + Selection patch (post gjslint):
http://codereview.appspot.com/4645056/
Added:
shindig/trunk/features/src/main/javascript/features/actions/
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/actions/taming.js
shindig/trunk/features/src/main/javascript/features/selection/
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/main/javascript/features/selection/taming.js
shindig/trunk/features/src/test/javascript/features/actions/
shindig/trunk/features/src/test/javascript/features/actions/actions_test.js
shindig/trunk/features/src/test/javascript/features/selection/
shindig/trunk/features/src/test/javascript/features/selection/selection_test.js
Modified:
shindig/trunk/features/pom.xml
shindig/trunk/features/src/main/javascript/features/features.txt
Modified: shindig/trunk/features/pom.xml
URL:
http://svn.apache.org/viewvc/shindig/trunk/features/pom.xml?rev=1146859&r1=1146858&r2=1146859&view=diff
==============================================================================
--- shindig/trunk/features/pom.xml (original)
+++ shindig/trunk/features/pom.xml Thu Jul 14 19:17:36 2011
@@ -177,6 +177,10 @@
<source>osapi/peoplehelpers.js</source>
<source>../../../../src/test/javascript/lib/testutils.js</source>
<source>oauthpopup/oauthpopup.js</source>
+ <source>selection/selection_container.js</source>
+ <source>selection/selection.js</source>
+ <source>actions/actions_container.js</source>
+ <source>actions/actions.js</source>
<source>opensearch/opensearch.js</source>
</sources>
<testSourceDirectory>${basedir}/src/test/javascript/features</testSourceDirectory>
Added: 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=1146859&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/actions/actions.js
(added)
+++ shindig/trunk/features/src/main/javascript/features/actions/actions.js Thu
Jul 14 19:17:36 2011
@@ -0,0 +1,212 @@
+/*
+ * 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 Provides facilities for registering action callback
+ * functions to actions that may be rendered anywhere in
+ * the container. Available to every gadget.
+ */
+gadgets['actions'] = (function() {
+
+ /**
+ * Runs the callback function associated with the specified action id.
+ *
+ * Example:
+ *
+ * <pre>
+ * gadgets.actions.runAction(actionId);
+ * </pre>
+ *
+ * @param {String}
+ * actionId The action identifier.
+ *
+ * @member gadgets.actions
+ */
+ function runAction(actionData) {
+ var actionId = actionData.actionId;
+ // optional
+ var selectionObj = actionData.selectionObj;
+
+ var callback = callbackRegistry.getCallback(actionId);
+ if (callback) {
+ var args = selectionObj ? [selectionObj] : null;
+ callback.apply(this, args);
+ }
+ };
+
+ /**
+ * @constructor Object that maps action ids to callback functions.
+ */
+ function ActionCallbackRegistry() {
+ this.registryById = {};
+ this.addAction = function(actionId, callbackFn) {
+ this.registryById[actionId] = callbackFn;
+ };
+ this.removeAction = function(actionId) {
+ delete this.registryById[actionId];
+ };
+ this.getCallback = function(actionId) {
+ return this.registryById[actionId];
+ };
+ };
+
+ // 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;
+ }
+ };
+
+ return /** @scope gadgets.actions */ {
+ /**
+ * Registers an action with the actions feature.
+ *
+ * Example:
+ *
+ * <pre>
+ * gadgets.actions.addAction(actionObj);
+ * </pre>
+ *
+ * @param {function(Object)}
+ * actionObj The action object.
+ *
+ * @member gadgets.actions
+ */
+ addAction: function(actionObj) {
+ init();
+ var actionId = actionObj.id;
+ var actionCallback = actionObj.callback;
+ callbackRegistry.addAction(actionId, actionCallback);
+
+ // notify the container that an action has been added.
+ gadgets.rpc.call('..', 'actions', null, 'bindAction', actionObj);
+ },
+
+ /**
+ * Updates an action that has already been registered.
+ *
+ * Example:
+ *
+ * <pre>
+ * gadgets.actions.updateAction(actionObj);
+ * </pre>
+ *
+ * @param {function(Object)}
+ * actionObj The action object.
+ *
+ * @member gadgets.actions
+ */
+ updateAction: function(actionObj) {
+ // 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);
+
+ // notify the container that an action has been added.
+ gadgets.rpc.call('..', 'actions', null, 'bindAction', actionObj);
+ },
+
+ /**
+ * Removes the association of a callback function with an action id.
+ *
+ * Example:
+ *
+ * <pre>
+ * gadgets.actions.removeAction(actionId);
+ * </pre>
+ *
+ * @param {string}
+ * actionId The action identifier.
+ *
+ * @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);
+ },
+
+ /**
+ * Gets array of actions at the specified path and passes the result
+ * to the callback function.
+ *
+ * Example:
+ *
+ * <pre>
+ * var callback = function(actions){
+ * ...
+ * }
+ * gadgets.actions.getActionsByPath("container/navigationLinks", callback);
+ * </pre>
+ *
+ * @param {string}
+ * path The path to the actions.
+ * @param {function}
+ * callback A callback function to handle the returned actions
+ * array.
+ *
+ * @member gadgets.actions
+ */
+ getActionsByPath: function(path, callback) {
+ gadgets.rpc.call('..', 'actions', callback, 'getActionsByPath', path);
+ },
+
+ /**
+ * Gets array of actions for the specified data type and passes the result
+ * to the callback function.
+ *
+ * Example:
+ *
+ * <pre>
+ * var callback = function(actions){
+ * ...
+ * }
+ * gadgets.actions.getActionsByDataType("opensocial.Person", callback);
+ * </pre>
+ *
+ * @param {string}
+ * dataType The String representation of an OpenSocial data type.
+ * @param {function}
+ * callback A callback function to handle the returned actions
+ * array.
+ *
+ * @member gadgets.actions
+ */
+ getActionsByDataType: function(dataType, callback) {
+ gadgets.rpc.call('..', 'actions', callback, 'getActionsByDataType',
+ dataType);
+ }
+ };
+})();
Added:
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=1146859&view=auto
==============================================================================
---
shindig/trunk/features/src/main/javascript/features/actions/actions_container.js
(added)
+++
shindig/trunk/features/src/main/javascript/features/actions/actions_container.js
Thu Jul 14 19:17:36 2011
@@ -0,0 +1,734 @@
+/*
+ * 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 Provides facilities for contributing actions to various parts
+ * of the UI. Available to the common container.
+ */
+(function() {
+
+ /**
+ * @constructor Object that tracks the actions currently registered with the
+ * container.
+ */
+ function ActionRegistry() {
+
+ // maps action ids to action objects
+ this.registryById = {};
+
+ // maps actions by contribution path
+ this.registryByPath = {};
+
+ // maps actions to OS data types
+ this.registryByDataType = {};
+
+ // maps actions to URL of the contributor
+ this.registryByUrl = {};
+
+ // one-to-many association of urls to gadget sites
+ this.urlToSite = {};
+
+ // one-to-one relationship of each url to the gadget metadata
+ this.urlToMetadata = {};
+
+ // one-to-one relationship of each action to the url
+ this.actionToUrl = {};
+
+ /**
+ * Adds an action object to the registry
+ *
+ * @param {Object}
+ * actionObj JSON object that represents an action.
+ * @param {String}
+ * url gadget spec URL, from which the action contribution
+ * originated.
+ */
+ this.addAction = function(actionObj, url) {
+ var id = actionObj.id;
+ if (!id) { /* invalid object */
+ return;
+ }
+
+ var path = actionObj.path;
+ if (path) {
+ /**
+ * We maintain a tree of arrays for actions that are contributed
+ * to paths. This is necessary to realize actions in hierarchical
+ * menus, sub-menus and drop-down toolbar buttons.
+ */
+ var partsOfPath = path.split('/');
+ var parent = this.registryByPath;
+ for (var i in partsOfPath) {
+ var currentNode = partsOfPath[i];
+ if (!parent[currentNode]) {
+ parent[currentNode] = {};
+ }
+ parent = parent[currentNode];
+ }
+ // store actions as array under attribute "@actions"
+ var actionsAtPath = parent['@actions'];
+ if (!actionsAtPath) {
+ parent['@actions'] = [actionObj];
+ } else {
+ parent['@actions'] = actionsAtPath.concat(actionObj);
+ }
+ } else if (actionObj.dataType) {
+ /**
+ * We maintain a simple map for actions that are bound to an
+ * OpenSocial data object type such as the person object.
+ */
+ var dataType = actionObj.dataType;
+ this.registryByDataType[dataType] =
+ this.registryByDataType[dataType] ?
+ this.registryByDataType[dataType].concat(actionObj) :
+ [actionObj];
+ } else {
+ // invalid object, no valid path or dataType to bind action
+ return;
+ }
+
+ // add action to id registry
+ this.registryById[id] = actionObj;
+
+ // map actions to url, used by runAction to render gadget
+ if (url) {
+ this.actionToUrl[actionObj.id] = url;
+ this.registryByUrl[url] =
+ this.registryByUrl[url] ?
+ this.registryByUrl[url].concat(actionObj) :
+ [actionObj];
+ }
+ };
+
+ /**
+ * Removes an action object from the registry
+ *
+ * @param {String}
+ * actionId unique identifier for the action, as specified in the
+ * action object.
+ */
+ this.removeAction = function(actionId) {
+ var actionObj = this.registryById[actionId];
+
+ // remove from registryById
+ delete this.registryById[actionId];
+
+ // remove from the other registries
+ var path = actionObj.path;
+ if (path) { // remove from registryByPath
+ var actionsAtPath = this.getActionsByPath(path);
+ var i = actionsAtPath.indexOf(actionObj);
+ if (i != -1) {
+ actionsAtPath.splice(i, 1);
+ }
+ } else { // remove from registryByDataType
+ var dataType = actionObj.dataType;
+ var actionsForDataType = this.registryByDataType[dataType];
+ var actionIndex = actionsForDataType.indexOf(actionObj);
+ actionsForDataType.splice(actionIndex, 1);
+ if (actionsForDataType.length == 0) {
+ delete this.registryByDataType[dataType];
+ }
+ }
+
+ // remove from url mappings
+ var url = this.actionToUrl[actionId];
+ if (url) {
+ delete this.actionToUrl[actionId];
+ var actionsForUrl = this.registryByUrl[url];
+ var actionIndex = actionsForUrl.indexOf(actionObj);
+ actionsForUrl.splice(actionIndex, 1);
+ if (actionsForUrl.length == 0) {
+ delete this.registryByUrl[url];
+ }
+ }
+ };
+
+ /**
+ * Returns the action associated with the specified id
+ *
+ * @param {String}
+ * id Unique identifier for the action object.
+ */
+ this.getItemById = function(id) {
+ var children = this.registryById ? this.registryById : {};
+ return children[id];
+ };
+
+ /**
+ * Returns all actions in the registry
+ */
+ this.getAllActions = function() {
+ var actions = [];
+ for (actionId in this.registryById) {
+ actions = actions.concat(this.registryById[actionId]);
+ }
+ return actions;
+ };
+
+ /**
+ * Returns all items associated with the given path
+ *
+ * @param {String}
+ * path Navigation path to the action, as specified in the action
+ * object.
+ */
+ this.getActionsByPath = function(path) {
+ var actions = [];
+ var partsOfPath = path.split('/');
+ var children = this.registryByPath ? this.registryByPath : {};
+ for (var i in partsOfPath) {
+ var currentNode = partsOfPath[i];
+ if (children[currentNode]) {
+ children = children[currentNode];
+ } else {
+ // if path doesn't exist, return empty array
+ return actions;
+ }
+ }
+ if (children) {
+ actions = children['@actions'];
+ }
+ return actions;
+ };
+
+ /**
+ * Returns the actions associated with the specified data object
+ *
+ * @param {String}
+ * dataType The Open Social data type associated with the action.
+ */
+ this.getActionsByDataType = function(dataType) {
+ var actions = [];
+ if (this.registryByDataType[dataType]) {
+ actions = this.registryByDataType[dataType];
+ }
+ return actions;
+ };
+
+ /**
+ * Returns the actions associated with the specified url
+ *
+ * @param {String}
+ * url The gadget spec url associated with the action(s).
+ */
+ this.getActionsByUrl = function(url) {
+ var children = [];
+ if (this.registryByUrl[url]) {
+ children = children.concat(this.registryByUrl[url]);
+ }
+ return children;
+ };
+
+ /**
+ * Adds a new active gadget site to the registry
+ *
+ * @param {String}
+ * url The gadget spec url associated with the gadget site.
+ * @param {osapi.container.GadgetSite}
+ * site The instance of the gadget site.
+ */
+ this.addGadgetSite = function(url, site) {
+ var existingSite = this.urlToSite[url];
+ if (existingSite) {
+ this.urlToSite[url] = existingSite.concat(site);
+ } else {
+ this.urlToSite[url] = [site];
+ }
+ };
+
+ /**
+ * Removes a gadget site from the registry
+ *
+ * @param {String}
+ * siteId The unique identifier for the gadget site instance.
+ */
+ this.removeGadgetSite = function(siteId) {
+ for (var url in this.urlToSite) {
+ var sites = this.urlToSite[url];
+ for (var i in sites) {
+ var site = sites[i];
+ if (site && site.getId() == siteId) {
+ sites.splice(i, 1);
+ if (sites.length == 0) {
+ delete this.urlToSite[url];
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Returns the gadget site associated with the specified action object.
+ *
+ * @param {Object}
+ * actionId The id of the action.
+ * @return {osapi.container.GadgetSite} The gadget site instance associated
+ * with the action object.
+ */
+ this.getGadgetSite = function(actionId) {
+ var url = this.actionToUrl[actionId];
+ var sites = this.urlToSite[url];
+ return sites;
+ };
+
+ /**
+ * Returns the url associated with an action
+ *
+ * @param {String}
+ * actionId The id of the action.
+ * @return {String} url Gadget spec url associated with the action.
+ */
+ this.getUrl = function(actionId) {
+ return this.actionToUrl[actionId];
+ };
+
+ /**
+ * Saves the metadata associated with a url
+ *
+ * @param {String}
+ * url Gadget spec url.
+ * @param {Object}
+ * metadata Metadata of the gadget.
+ */
+ this.setGadgetMetadata = function(url, metadata) {
+ this.urlToMetadata[url] = metadata;
+ };
+
+ /**
+ * Returns the metadata associated with a url
+ *
+ * @param {String}
+ * url Gadget spec url.
+ * @return {Object} metadata Metadata for a gadget.
+ */
+ this.getGadgetMetadata = function(url) {
+ return this.urlToMetadata[url];
+ };
+ };
+
+ /**
+ * Utility function for converting a string representation of XML to a DOM
+ * object
+ *
+ * @param {String}
+ * xmlString String representation of a valid XML object.
+ * @return {Object} response JSON object whose "data" field will contain the
+ * DOM object, otherwise, the "errors" field will contain a string
+ * description.
+ */
+ function createDom(xmlString) {
+ var response = {};
+ var dom;
+ if (typeof ActiveXObject != 'undefined') {
+ dom = new ActiveXObject('Microsoft.XMLDOM');
+ dom.async = false;
+ dom.validateOnParse = false;
+ dom.resolveExternals = false;
+ if (!dom.loadXML(xmlString)) {
+ response['errors'].push('500 Failed to parse XML');
+ response['rc'] = 500;
+ } else {
+ response['data'] = dom;
+ }
+ } else {
+ var parser = new DOMParser();
+ dom = parser.parseFromString(xmlString, 'text/xml');
+ if ('parsererror' === dom.documentElement.nodeName) {
+ response['errors'].push('500 Failed to parse XML');
+ response['rc'] = 500;
+ } else {
+ response['data'] = dom;
+ }
+ }
+ return response;
+ };
+
+ /**
+ * Container handling of an action that has been programmatically added via
+ * gadgets.actions.addAction() API
+ *
+ * @param {Object}
+ * actionObj The action object coming from the gadget side.
+ *
+ */
+ function bindAction(actionObj) {
+ var actionId = actionObj.id;
+ var containerActionObj = registry.getItemById(actionId);
+ // if action is not in registry, then this is a programmatic add
+ if (!containerActionObj) {
+ addAction(actionObj);
+ } else {
+ // check if this action needs to be run
+ var pendingAction = pendingActions[actionId];
+ if (pendingAction) {
+ runAction(actionId, pendingAction.selection);
+ delete pendingActions[actionId];
+ }
+ }
+ };
+
+ /**
+ * Adds the action to the action registry, and renders the action in the
+ * container UI.
+ *
+ * @param {Object}
+ * actionObj The action object with id, label, title, icon, and any
+ * other information needed to render the action in the container's
+ * UI.
+ * @param {String}
+ * url Optional value needed to be passed in when adding action via
+ * preload listener (for subsequent loading of the gadget).
+ *
+ */
+ function addAction(actionObj, url) {
+ registry.addAction(actionObj, url);
+ // notify the container to display the action
+ showActionHandler(actionObj);
+ };
+
+ /**
+ * Removes the action from the action registry, and removes the action from
+ * the container UI.
+ *
+ * @param {String}
+ * The action id.
+ *
+ */
+ function removeAction(id) {
+ var actionObj = registry.getItemById(id);
+ registry.removeAction(id);
+ // notify the container to hide the action
+ hideActionHandler(actionObj);
+ };
+
+ /**
+ * 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.
+ *
+ */
+ function runAction(actionId, selection) {
+ var actionData = {};
+ actionData.actionId = actionId;
+ actionData.selectionObj = selection;
+ if (!selection && container_ && container_.selection) {
+ actionData.selectionObj = container_.selection.getSelection();
+ }
+ // make rpc call to get gadget to run callback based on action id
+ var gadgetSites = registry.getGadgetSite(actionId);
+ if (gadgetSites && gadgetSites.length > 0) {
+ var frameId = gadgetSites[0].getActiveGadgetHolder().getIframeId();
+ }
+ gadgets.rpc.call(frameId, 'actions', null, 'runAction', actionData);
+ };
+
+ /**
+ * Callback for loading actions after gadget has been preloaded.
+ *
+ * @param {Array}
+ * Response from container's lifecycle handling of preloading the
+ * gadget.
+ */
+ var preloadCallback = function(response) {
+ for (var url in response) {
+ var metadata = response[url];
+ if (!metadata.error) {
+ registry.setGadgetMetadata(url, metadata);
+ 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 in actions) {
+ var actionObj = actions[i];
+ // replace @ for attribute keys;
+ for (itemAttr in actionObj) {
+ var attrStr = itemAttr.substring(1);
+ var attrVal = actionObj[itemAttr];
+ actionObj[attrStr] = attrVal;
+ delete actionObj[itemAttr];
+ }
+ // check if action already exists
+ if (!registry.getItemById(actionObj.id)) {
+ addAction(actionObj, url);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Callback for when gadget site has been navigated.
+ *
+ * @param {Object}
+ * Gadget site that has been navigated.
+ */
+ var navigatedCallback = function(site) {
+ var gadgetHolder = site.getActiveGadgetHolder();
+ if (gadgetHolder) {
+ var url = gadgetHolder.getUrl();
+ registry.addGadgetSite(url, site);
+ }
+ };
+
+ /**
+ * Callback for when a gadget site has been closed.
+ *
+ * @param {Object}
+ * Gadget site that has been closed.
+ */
+ var closedCallback = function(site) {
+ var siteId = site.getId();
+ registry.removeGadgetSite(siteId);
+ };
+
+ /**
+ * Callback for when a gadget has been unloaded.
+ *
+ * @param {String}
+ * Gadget spec url for the gadget that has been unloaded.
+ */
+ var unloadedCallback = function(url) {
+ var actionsForUrl = registry.getActionsByUrl(url);
+ for (var i in actionsForUrl) {
+ var action = actionsForUrl[i];
+ removeAction(action.id);
+ }
+ };
+
+ // Object containing gadget lifecycle listeners
+ var actionsLifecycleCallback = {};
+ actionsLifecycleCallback[osapi.container.CallbackType.ON_PRELOADED] =
+ preloadCallback;
+ actionsLifecycleCallback[osapi.container.CallbackType.ON_NAVIGATED] =
+ navigatedCallback;
+ actionsLifecycleCallback[osapi.container.CallbackType.ON_CLOSED] =
+ closedCallback;
+ actionsLifecycleCallback[osapi.container.CallbackType.ON_UNLOADED] =
+ unloadedCallback;
+
+ // Function to handle RPC calls from the gadgets side
+ function router(channel, object) {
+ var actionObj = object;
+ switch (channel) {
+ case 'bindAction':
+ bindAction(actionObj);
+ break;
+ case 'removeAction':
+ hideActionHandler(object);
+ break;
+ case 'getActionsByPath':
+ return container_.actions.getActionsByPath(object);
+ case 'getActionsByDataType':
+ return container_.actions.getActionsByDataType(object);
+ }
+ };
+
+ /**
+ * Function that renders actions in the container's UI
+ *
+ * @param {Object}
+ * actionObj The object with id, label, tooltip, icon and any other
+ * information for the container to use to render the action.
+ */
+ var showActionHandler = function(actionObj) {};
+
+ /**
+ * Function that hides actions from the container's UI
+ *
+ * @param {Object}
+ * actionObj The object with id, label, tooltip, icon and any other
+ * information for the container to use to render the action.
+ */
+ var hideActionHandler = function(actionObj) {};
+
+ /**
+ * Function that renders gadgets in container's UI
+ *
+ * @param {String}
+ * gadgetSpecUrl The gadget spec url.
+ * @param {Object}
+ * gadgetMetadata The gadget meta data.
+ */
+ var renderGadgetInContainer = function(gadgetSpecUrl, gadgetMetadata) {};
+
+ // instantiate the singleton action registry
+ var registry = new ActionRegistry();
+
+ // a map to track actions that are scheduled to run after
+ // pre-loaded gadget has been rendered
+ var pendingActions = {};
+
+ // container instance
+ var container_ = null;
+
+ /**
+ * Add the Container API for the action service.
+ */
+ osapi.container.Container.addMixin('actions', function(container) {
+ container_ = container;
+ gadgets.rpc.register('actions', router);
+
+ if (container.addGadgetLifecycleCallback) {
+ container.addGadgetLifecycleCallback('actions',
+ actionsLifecycleCallback);
+ }
+
+ return /** @scope osapi.container.actions */ {
+
+ /**
+ * Registers a function to display actions in the container.
+ *
+ * @param {function}
+ * The container's function to render actions
+ * in its UI. The function takes the action object as
+ * a parameter.
+ */
+ registerShowActionHandler: function(handler) {
+ if (typeof handler === 'function') {
+ showActionHandler = handler;
+ }
+ },
+
+ /**
+ * Registers a function to hide (remove) actions in the container.
+ *
+ * @param {function}
+ * The container's function to hide (remove) actions
+ * in its UI. The function takes the action object as
+ * a parameter.
+ */
+ registerHideActionHandler: function(handler) {
+ if (typeof handler === 'function') {
+ hideActionHandler = handler;
+ }
+ },
+
+ /**
+ * Registers a function to render gadgets in the container.
+ *
+ * @param {function}
+ * The container's function to render gadgets in its UI.
+ * The function takes in two parameters: the gadget spec
+ * url and the gadget metadata.
+ */
+ registerNavigateGadgetHandler: function(renderGadgetFunction) {
+ if (typeof renderGadgetFunction === 'function') {
+ renderGadgetInContainer = renderGadgetFunction;
+ }
+ },
+
+ /*
+ * Uncomment the below two functions to run full jsunit tests.
+ */
+ //addAction : function(actionObj) { addAction(actionObj); },
+ //removeAction : function(actionId) { removeAction(actionId); },
+
+ /**
+ * Executes the action associated with the action id.
+ *
+ * @param {String}
+ * The action id.
+ */
+ runAction: function(actionId) {
+ if (registry.getItemById(actionId)) {
+ // if gadget site has not been registered yet
+ // the gadget needs to be rendered
+ var gadgetSite = registry.getGadgetSite(actionId);
+ if (!gadgetSite) {
+ var gadgetUrl = registry.getUrl(actionId);
+ var gadgetMetadata = registry.getGadgetMetadata(gadgetUrl);
+ pendingActions[actionId] = {
+ selection: container_.selection.getSelection()
+ };
+ renderGadgetInContainer(gadgetUrl, gadgetMetadata);
+ } else {
+ runAction(actionId);
+ }
+ }
+ },
+
+ /**
+ * Gets the action object from the registry based on the action id.
+ *
+ * @param {String}
+ * id The action id.
+ * @return {Object} The action object.
+ */
+ getAction: function(id) {
+ return registry.getItemById(id);
+ },
+
+ /**
+ * Gets all action objects in the registry.
+ *
+ * @return {Array} An array with any action objects in the
+ * registry.
+ */
+ getAllActions: function() {
+ return registry.getAllActions();
+ },
+
+ /**
+ * Gets action object from registry based on the path.
+ *
+ * @param {String}
+ * The path for the action.
+ * @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;
+ },
+
+ /**
+ * Gets action object from registry based on the dataType.
+ *
+ * @param {String}
+ * The String representation of the Open Social data type.
+ * @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;
+ }
+ };
+ });
+})();
Added: 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=1146859&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/actions/feature.xml
(added)
+++ shindig/trunk/features/src/main/javascript/features/actions/feature.xml Thu
Jul 14 19:17:36 2011
@@ -0,0 +1,20 @@
+<feature>
+ <name>actions</name>
+ <dependency>globals</dependency>
+ <dependency>rpc</dependency>
+ <dependency>gadgets.json.ext</dependency>
+ <gadget>
+ <script src="actions.js"/>
+ <script src="taming.js"/>
+ <api>
+ <exports type="js">gadgets.actions.addAction</exports>
+ <exports type="js">gadgets.actions.updateAction</exports>
+ <exports type="js">gadgets.actions.removeAction</exports>
+ <exports type="js">gadgets.actions.getActionsByPath</exports>
+ <exports type="js">gadgets.actions.getActionsByDataType</exports>
+ </api>
+ </gadget>
+ <container>
+ <script src="actions_container.js"/>
+ </container>
+</feature>
\ No newline at end of file
Added: shindig/trunk/features/src/main/javascript/features/actions/taming.js
URL:
http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/actions/taming.js?rev=1146859&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/actions/taming.js
(added)
+++ shindig/trunk/features/src/main/javascript/features/actions/taming.js Thu
Jul 14 19:17:36 2011
@@ -0,0 +1,8 @@
+var tamings___ = tamings___ || [];
+tamings___.push(function(imports) {
+ ___.grantRead(gadgets.actions, 'addAction');
+ ___.grantRead(gadgets.actions, 'updateAction');
+ ___.grantRead(gadgets.actions, 'removeAction');
+ ___.grantRead(gadgets.actions, 'getActionsByPath');
+ ___.grantRead(gadgets.actions, 'getActionsByDataType');
+});
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=1146859&r1=1146858&r2=1146859&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/features.txt (original)
+++ shindig/trunk/features/src/main/javascript/features/features.txt Thu Jul 14
19:17:36 2011
@@ -19,6 +19,7 @@
# List each feature you want to support here
features/globals/feature.xml
+features/actions/feature.xml
features/analytics/feature.xml
features/auth-refresh/feature.xml
features/caja/feature.xml
@@ -77,6 +78,7 @@ features/osml/feature.xml
features/pubsub/feature.xml
features/rpc/feature.xml
features/security-token/feature.xml
+features/selection/feature.xml
features/setprefs/feature.xml
features/settitle/feature.xml
features/shindig.auth/feature.xml
Added: 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=1146859&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/selection/feature.xml
(added)
+++ shindig/trunk/features/src/main/javascript/features/selection/feature.xml
Thu Jul 14 19:17:36 2011
@@ -0,0 +1,36 @@
+<?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>selection</name>
+ <dependency>globals</dependency>
+ <dependency>rpc</dependency>
+ <gadget>
+ <script src="selection.js"/>
+ <script src="taming.js"/>
+ <api>
+ <exports type="js">gadgets.selection.setSelection</exports>
+ <exports type="js">gadgets.selection.getSelection</exports>
+ <exports type="js">gadgets.selection.addSelectionListener</exports>
+ <exports type="js">gadgets.selection.removeSelectionListener</exports>
+ </api>
+ </gadget>
+ <container>
+ <script src="selection_container.js"/>
+ </container>
+</feature>
Added:
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=1146859&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/selection/selection.js
(added)
+++ shindig/trunk/features/src/main/javascript/features/selection/selection.js
Thu Jul 14 19:17:36 2011
@@ -0,0 +1,86 @@
+/*
+ * 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 Gadget-side library for participating in selection eventing.
+ */
+
+/**
+ * @static
+ * @class Selection class for gadgets.
+ * Provides framework for selection eventing.
+ * @name gadgets.selection
+ */
+gadgets['selection'] = function() {
+
+ var listeners = new Array();
+ var currentSelection = null;
+ var selectionChangedFunc = null;
+
+ return /** @scope gadgets.selection */ {
+ /**
+ * Sets the current selection.
+ * @param {string} selection Selected object.
+ */
+ setSelection: function(selection) {
+ currentSelection = selection;
+ gadgets.rpc.call('..', 'gadgets.selection', null, 'set', selection);
+ },
+
+ /**
+ * Gets the current selection.
+ * @return {Object} the current selection.
+ */
+ getSelection: function() {
+ return currentSelection;
+ },
+
+ /**
+ * Registers a listener for selection.
+ * @param {function} listener The listener to remove.
+ */
+ addSelectionListener: function(listener) {
+ 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;
+ listeners.forEach(function(listener) {
+ listener(selection);
+ });
+ };
+ gadgets.rpc.call('..', 'gadgets.selection', null, 'add',
+ selectionChangedFunc);
+ }
+ }
+ },
+
+ /**
+ * Removes a listener for selection.
+ * @param {function} listener The listener to remove.
+ */
+ removeSelectionListener: function(listener) {
+ var index = listeners.indexOf(listener);
+ if (index != -1) {
+ listeners.splice(index, 1);
+ }
+ }
+ };
+}();
Added:
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=1146859&view=auto
==============================================================================
---
shindig/trunk/features/src/main/javascript/features/selection/selection_container.js
(added)
+++
shindig/trunk/features/src/main/javascript/features/selection/selection_container.js
Thu Jul 14 19:17:36 2011
@@ -0,0 +1,77 @@
+/*
+ * 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 Container-side selection manager.
+ */
+
+/**
+ * @static
+ * @class Manages selection and selection listeners.
+ * @name gadgets.selectionmanager
+ */
+(function() {
+
+ var listeners = new Array();
+ var _selection;
+
+ function notifySelection(selection) {
+ _selection = selection;
+ listeners.forEach(function(listener) {
+ listener(selection);
+ });
+ }
+
+ function addSelectionListener(listener) {
+ listeners.push(listener);
+ }
+
+ 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) {
+ gadgets.rpc.register('gadgets.selection', router);
+ return /** @scope gadgets.selection */ {
+ /**
+ * Sets the current selection.
+ * @param {string} selection Selected object.
+ */
+ setSelection: function(selection) {
+ notifySelection(selection);
+ },
+ /**
+ * Gets the current selection.
+ * @return {Object} the current selection.
+ */
+ getSelection: function() {
+ return _selection;
+ }
+ };
+ });
+
+})();
Added: shindig/trunk/features/src/main/javascript/features/selection/taming.js
URL:
http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/selection/taming.js?rev=1146859&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/selection/taming.js
(added)
+++ shindig/trunk/features/src/main/javascript/features/selection/taming.js Thu
Jul 14 19:17:36 2011
@@ -0,0 +1,7 @@
+var tamings___ = tamings___ || [];
+tamings___.push(function(imports) {
+ ___.grantRead(gadgets.selection, 'setSelection');
+ ___.grantRead(gadgets.selection, 'getSelection');
+ ___.grantRead(gadgets.selection, 'addSelectionListener');
+ ___.grantRead(gadgets.selection, 'removeSelectionListener');
+});
Added:
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=1146859&view=auto
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/actions/actions_test.js
(added)
+++ shindig/trunk/features/src/test/javascript/features/actions/actions_test.js
Thu Jul 14 19:17:36 2011
@@ -0,0 +1,224 @@
+/*
+ * 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 Tests for actions feature
+ */
+
+function DeclarativeActionsTest(name) {
+ TestCase.call(this, name);
+}
+
+DeclarativeActionsTest.inherits(TestCase);
+
+(function() {
+
+DeclarativeActionsTest.prototype.setUp = function() {
+ this.apiUri = window.__API_URI;
+ window.__API_URI = shindig.uri('http://shindig.com');
+ this.containerUri = window.__CONTAINER_URI;
+ window.__CONTAINER_URI = shindig.uri('http://container.com');
+
+ this.gadgetsRpc = gadgets.rpc;
+ var that = this;
+ gadgets.rpc = {};
+ gadgets.rpc.register = function() {};
+ gadgets.rpc.call = function() {
+ that.rpcArguments = Array.prototype.slice.call(arguments);
+ };
+};
+
+DeclarativeActionsTest.prototype.tearDown = function() {
+ window.__API_URI = this.apiUri;
+ window.__CONTAINER_URI = this.containerUri;
+
+ gadgets.rpc = this.gadgetsRpc;
+ this.rpcArguments = undefined;
+};
+
+DeclarativeActionsTest.prototype.testGadgetsAddAction = function() {
+ var actionId = "testAction";
+ var callbackFn = function(){};
+ var _actionObj = {
+ id: actionId,
+ label:"Test Action",
+ path:"container/navigationLinks",
+ callback: callbackFn
+ };
+ gadgets.actions.addAction(_actionObj);
+ this.assertRpcCalled('..', 'actions', null, 'bindAction', _actionObj);
+};
+
+DeclarativeActionsTest.prototype.testGadgetsRemoveAction = function() {
+ var actionId = "testAction";
+ gadgets.actions.removeAction(actionId);
+ this.assertRpcCalled('..', 'actions', null,
+ 'removeAction', actionId);
+};
+
+
+DeclarativeActionsTest.prototype.testContainerGetAction = function() {
+ var container = new osapi.container.Container({});
+ var actionId = "testAction";
+ var actionObj = container.actions.getAction(actionId);
+ // registry is empty
+ this.assertUndefined(actionObj);
+};
+
+
+DeclarativeActionsTest.prototype.testContainerGetActionsByPath = function() {
+ var container = new osapi.container.Container();
+ var actionId = "testAction";
+ var actionsArray = container.actions
+ .getActionsByPath("container/navigationLinks");
+ //registry is empty
+ this.assertEquals(actionsArray, []);
+};
+
+DeclarativeActionsTest.prototype.testContainerGetActionsByDataType =
+ function(){
+ var container = new osapi.container.Container();
+ var actionId = "testAction";
+ var actionsArray = container.actions
+ .getActionsByDataType("opensocial.Person");
+ //registry is empty
+ this.assertEquals(actionsArray, []);
+ };
+
+/**
+ * Uncomment following _Full tests once addAction() and removeAction()
+ * functions in actions_container.js are uncommented
+ */
+/* FULL TESTS
+DeclarativeActionsTest.prototype.testContainerGetAction_Full = function() {
+ var container = new osapi.container.Container({});
+ var actionId = "testAction";
+ var actionObj_ = {
+ id: actionId,
+ label: "Test Action",
+ path: "container/navigationLinks"
+ }
+ 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);
+
+};
+
+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"
+ }
+ ];
+ 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 =
+ function(){
+ var container = new osapi.container.Container();
+ var actionId = "testAction";
+ var actionObj_ = {
+ id: actionId,
+ label: "Test Action",
+ path: "container/navigationLinks"
+ }
+ container.actions.addAction(actionObj_);
+ 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 =
+ function() {
+ var container = new osapi.container.Container();
+ var actionId = "testAction";
+ var actionObj_ = {
+ id: actionId,
+ 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 */
+
+/**
+ * Asserts gadgets.rpc.call() is called with the expected arguments given.
+ */
+DeclarativeActionsTest.prototype.assertRpcCalled = function() {
+ this.assertNotUndefined("RPC was not called.", this.rpcArguments);
+ this.assertEquals("RPC argument list not valid length.", arguments.length,
+ this.rpcArguments.length);
+
+ for ( var i = 0; i < arguments.length; i++) {
+ this.assertEquals(arguments[i], this.rpcArguments[i]);
+ }
+ this.rpcArguments = undefined;
+};
+
+})();
\ No newline at end of file
Added:
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=1146859&view=auto
==============================================================================
---
shindig/trunk/features/src/test/javascript/features/selection/selection_test.js
(added)
+++
shindig/trunk/features/src/test/javascript/features/selection/selection_test.js
Thu Jul 14 19:17:36 2011
@@ -0,0 +1,117 @@
+/*
+ * 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 Tests for selection
+ */
+
+function SelectionTest(name) {
+ TestCase.call(this, name);
+}
+
+SelectionTest.inherits(TestCase);
+
+(function() {
+
+ SelectionTest.prototype.setUp = function() {
+ this.apiUri = window.__API_URI;
+ window.__API_URI = shindig.uri('http://shindig.com');
+ this.containerUri = window.__CONTAINER_URI;
+ window.__CONTAINER_URI = shindig.uri('http://container.com');
+ this.shindigContainerGadgetSite = osapi.container.GadgetSite;
+
+ this.gadgetsRpc = gadgets.rpc;
+ var that = this;
+ gadgets.rpc = {};
+ gadgets.rpc.register = function() {
+ };
+ gadgets.rpc.call = function() {
+ that.rpcArguments = Array.prototype.slice.call(arguments);
+ };
+ };
+
+ SelectionTest.prototype.tearDown = function() {
+ window.__API_URI = this.apiUri;
+ window.__CONTAINER_URI = this.containerUri;
+ osapi.container.GadgetSite = this.shindigContainerGadgetSite;
+ gadgets.rpc = this.gadgetsRpc;
+ this.rpcArguments = undefined;
+ };
+
+ SelectionTest.prototype.testContainerSetGetSelection = function() {
+ var container = new osapi.container.Container({});
+ var _token = "hello";
+ container.selection.setSelection(_token);
+ var token = container.selection.getSelection();
+ this.assertEquals(_token, token);
+ };
+
+ SelectionTest.prototype.testGadgetSetGetSelection = function() {
+ var container = new osapi.container.Container({});
+ var token = "hello";
+ gadgets.selection.setSelection(token);
+ this.assertRpcCalled("..", "gadgets.selection", null, "set", token);
+ };
+
+ SelectionTest.prototype.testGadgetGetSelection = function() {
+ var container = new osapi.container.Container({});
+ var token = "hello";
+ gadgets.selection.setSelection(token);
+ var _token = gadgets.selection.getSelection();
+ this.assertEquals(token, _token);
+ };
+
+ SelectionTest.prototype.testGadgetAddSelectionListener = function() {
+ var container = new osapi.container.Container({});
+ var callback = function() {
+ };
+ gadgets.selection.addSelectionListener(callback);
+ this.assertRpcCalled("..", "gadgets.selection", null, "add", callback);
+ };
+
+ /**
+ * Asserts gadgets.rpc.call() is called with the expected arguments given.
+ * Note that it resets this.rpcArguments for next RPC call assertion.
+ */
+ SelectionTest.prototype.assertRpcCalled = function() {
+ this.assertNotUndefined("RPC was not called.", this.rpcArguments);
+ this.assertEquals("RPC argument list not valid length.", arguments.length,
+ this.rpcArguments.length);
+
+ for ( var i = 0; i < arguments.length; i++) {
+ this.assertEquals(arguments[i], this.rpcArguments[i]);
+ }
+ this.resetRpc();
+ };
+
+ /**
+ * Resets this.rpcArguments.
+ */
+ SelectionTest.prototype.resetRpc = function() {
+ this.rpcArguments = undefined;
+ };
+
+ /**
+ * Asserts that no gadgets.rpc.call() is called.
+ */
+ SelectionTest.prototype.assertNoRpcCalled = function() {
+ this.assertUndefined("RPC was called.", this.rpcArguments);
+ };
+
+})();
\ No newline at end of file