You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2011/06/23 20:52:05 UTC
svn commit: r1139034 - in /shindig/trunk:
content/samplecontainer/examples/commoncontainer/ features/
features/src/main/javascript/features/
features/src/main/javascript/features/opensearch/
features/src/test/javascript/features/opensearch/
Author: lindner
Date: Thu Jun 23 18:52:05 2011
New Revision: 1139034
URL: http://svn.apache.org/viewvc?rev=1139034&view=rev
Log:
Patch from igor1x@gmail.com | Opensearch feature reference implementation for Shindig
Added:
shindig/trunk/content/samplecontainer/examples/commoncontainer/search.js
shindig/trunk/features/src/main/javascript/features/opensearch/
shindig/trunk/features/src/main/javascript/features/opensearch/feature.xml
shindig/trunk/features/src/main/javascript/features/opensearch/opensearch.js
shindig/trunk/features/src/test/javascript/features/opensearch/
shindig/trunk/features/src/test/javascript/features/opensearch/opensearch_test.js
Modified:
shindig/trunk/content/samplecontainer/examples/commoncontainer/gadgetCollections.json
shindig/trunk/content/samplecontainer/examples/commoncontainer/index.html
shindig/trunk/features/pom.xml
shindig/trunk/features/src/main/javascript/features/features.txt
Modified: shindig/trunk/content/samplecontainer/examples/commoncontainer/gadgetCollections.json
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/commoncontainer/gadgetCollections.json?rev=1139034&r1=1139033&r2=1139034&view=diff
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/commoncontainer/gadgetCollections.json (original)
+++ shindig/trunk/content/samplecontainer/examples/commoncontainer/gadgetCollections.json Thu Jun 23 18:52:05 2011
@@ -29,6 +29,14 @@
{"name": "Horoscope", "url": "http://www.google.com/ig/modules/horoscope.xml"},
{"name": "TODO", "url": "http://www.labpixies.com/campaigns/todo/todo.xml"}
]
+ },
+ {
+ "name": "OpenSearch Demo",
+ "Description": "Sample gadgets used for opensearch",
+ "apps" : [
+ {"name": "Twitter", "url": "http://hosting.gmodules.com/ig/gadgets/file/109228598702359180066/twitterfinal.xml"},
+ {"name": "MySpace", "url": "http://hosting.gmodules.com/ig/gadgets/file/109228598702359180066/myspacefinal.xml"}
+ ]
}
]
}
\ No newline at end of file
Modified: shindig/trunk/content/samplecontainer/examples/commoncontainer/index.html
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/commoncontainer/index.html?rev=1139034&r1=1139033&r2=1139034&view=diff
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/commoncontainer/index.html (original)
+++ shindig/trunk/content/samplecontainer/examples/commoncontainer/index.html Thu Jun 23 18:52:05 2011
@@ -21,9 +21,9 @@
<head>
<!-- My OpenSocial Beginnings -->
- <link rel="stylesheet" href="../../../container/gadgets.css">
- <script src="../../../gadgets/js/container:rpc:pubsub-2.js?c=1&debug=1&container=default"></script>
- </script>
+ <link rel="stylesheet" href="/container/gadgets.css">
+ <script type="text/javascript"
+ src="/gadgets/js/container:views:opensearch:rpc:pubsub-2.js?c=1&debug=1&container=default""></script>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script
@@ -34,6 +34,8 @@
<script type="text/javascript" src="./assembler.js"></script>
<script type="text/javascript" src="./viewController.js"></script>
<script type="text/javascript" src="./layout.js"></script>
+ <script type="text/javascript" src="./cconviews.js"></script>
+ <script type="text/javascript" src="./search.js"></script>
<style>
.portlet-header .ui-icon { float: right; }
@@ -78,13 +80,29 @@
#viewsDropdown li.li-header ul li a {
padding: 5px; height: 17px;
}
-
+
+ #tabs li .ui-icon-close { float: left; margin: 0.4em 0.2em 0 0; cursor: pointer; }
+
+ .resultTitle {
+ color: blue;
+ }
+
+ .searchEngine {
+ border: 1px solid blue;
+ }
+
</style>
</head>
<body onLoad="CommonContainer.init();">
<!-- Need to add in an improved header with links to specification -->
-<a href="http://www.opensocial.org/"><img alt="OpenSocial" src="http://api.ning.com/files/chwE7fbkJ5D1q8NSzNCYJzzCqOiuo3xYyToZCsYuY0SViOKQ7EG-3UUv4KFSxOMACbIzs3oWtD076*cbEL-*ABd9hCO0p7Al/opensocialsitelogo1.png?width=288&height=70&xn_auth=no&type=png"></a><div id="content">
+<a href="http://www.opensocial.org/"><img alt="OpenSocial" src="http://api.ning.com/files/chwE7fbkJ5D1q8NSzNCYJzzCqOiuo3xYyToZCsYuY0SViOKQ7EG-3UUv4KFSxOMACbIzs3oWtD076*cbEL-*ABd9hCO0p7Al/opensocialsitelogo1.png?width=288&height=70&xn_auth=no&type=png"></a>
+<span style="float:right">
+<input type="text" id="query"/>
+ <button name="search" id="searchButton" onClick="updateSearchURLs()">Search </button>
+ <br/><span id="engineList"></span>
+ </span>
+<div id="content">
<div id="controlPanel">
@@ -144,6 +162,8 @@ Enter the event payload
<div>
<div id="gadgetArea" class="column">
</div>
+<div id="results"></div>
+</div>
</div>
</div>
<span class="ui-icon ui-icon-grip-dotted-horizontal"
Added: shindig/trunk/content/samplecontainer/examples/commoncontainer/search.js
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/commoncontainer/search.js?rev=1139034&view=auto
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/commoncontainer/search.js (added)
+++ shindig/trunk/content/samplecontainer/examples/commoncontainer/search.js Thu Jun 23 18:52:05 2011
@@ -0,0 +1,221 @@
+/*
+ * 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.
+*/
+
+var currentEngines = [];
+var templateMap = [];
+/**
+ * Helper function to extract create map of new engines, keyed by template url
+ * @param searchURLs template search urls
+ * @param description
+ * opensearch description being added or removed
+ * @param added
+ * true if new description, false if removed.
+ */
+extractURLs = function(searchUrls, description, added) {
+ var newEngines = [];
+ for (var i in searchUrls) {
+ var template = searchUrls[i]["@template"];
+ if (template != null) {
+ var descType = searchUrls[i]["@type"];
+ if (descType == "application/atom+xml") {
+ if (added) {
+ if (currentEngines[template] == null) {
+ newEngines[template] = description.OpenSearchDescription.ShortName;
+ templateMap[template] = 1;
+ } else {
+ templateMap[template]++;
+ }
+ } else {
+ if (currentEngines[template] != null) {
+ if (templateMap[template] == 1) {
+ var oldEngine = document.getElementById(template);
+ oldEngine.parentNode.removeChild(oldEngine);
+ delete currentEngines[template];
+ } else {
+ templateMap[template]--;
+ }
+ }
+ }
+ }
+ }
+ }
+ return newEngines;
+}
+
+/**
+ * Callback passed to the opensearch feature to react to addition/removal of
+ * gadgets containing OpenSearch descriptions.
+ *
+ * @param description
+ * opensearch description being added or removed
+ * @param added
+ * true if new description, false if removed.
+ */
+updateEngines = function(description, added) {
+
+ var searchUrls = [];
+ if (!(description.OpenSearchDescription.Url instanceof Array)) {
+ searchUrls.push(description.OpenSearchDescription.Url);
+ } else {
+ searchUrls = description.OpenSearchDescription.Url;
+ }
+
+ var newEngines = extractURLs(searchUrls, description, added);
+
+ var span = document.getElementById("engineList");
+ for (templateUrl in newEngines) {
+ var current = newEngines[templateUrl];
+ span.innerHTML = span.innerHTML
+ + "<input type=\"checkbox\" checked=\"true\" id=\"" + templateUrl
+ + "\" />" + current;
+ span.innerHTML = span.innerHTML + "<br/>";
+ currentEngines[templateUrl] = current;
+ }
+
+}
+
+CommonContainer.opensearch.addOpenSearchCallback(updateEngines);
+
+/**
+ * Clears old search results, and fetches new ones.
+ *
+ */
+function updateSearchURLs() {
+ // clear the old results
+ $(function() {
+ $("#results").dialog( {
+ autoOpen : false
+ });
+ });
+ $("#results").dialog("option", "minWidth", 1000);
+ $("#results").dialog('open');
+ //var div = document.getElementById("results");
+ /*while (div.hasChildNodes()) {
+ div.removeChild(div.firstChild);
+ }*/
+ $("#results").empty();
+ //div.innerHTML = document.getElementById("query").value;
+ $("#results").innerHTML = document.getElementById("query").value;
+ // fetch new results.
+ getSearchResults(currentEngines, document.getElementById("query").value);
+}
+
+/**
+ * Iterates over template urls and fetches search results.
+ *
+ * @param urls
+ * all the opensearch template urls in the container
+ * @param query
+ * query string.
+ */
+function getSearchResults(urls, query) {
+ // callback function to be called by the fetching code.
+ /**
+ * @param obj
+ * the result data object, should be XML
+ * @param engineTitle
+ * title of the engine being searched
+ */
+ function urlResponse(obj, engineTitle) {
+ // create placeholder for results
+ var su = document.getElementById("results");
+ var resultDiv = document.createElement("div");
+ su.appendChild(resultDiv);
+ // if there are no errors, parse the results
+ if (obj.errors.length == 0) {
+ resultDiv.className = "searchEngine";
+ var domdata = obj.data;
+ if (domdata != null) {
+ var entries = domdata.getElementsByTagName("entry");
+ resultDiv.innerHTML = resultDiv.innerHTML + engineTitle + ":<br/>";
+ if (entries.legnth == 0) {
+ resultDiv.innerHTML = resultDiv.innerHTML + ("No results found");
+ } else {
+ var resultCount = entries.length;
+ if (resultCount > 15) {
+ resultCount = 15;
+ }
+ for (i = 0; i < resultCount; i++) {
+ if (entries[i].getElementsByTagName("title").length > 0) {
+ titles = entries[i].getElementsByTagName("title")
+ title = titles[0].childNodes[0].nodeValue;
+ } else {
+ title = "Untitled";
+ }
+ var link = null;
+ //for standard atom results, we can extract the link
+ if (entries[i].getElementsByTagName("link").length > 0) {
+ links = entries[i].getElementsByTagName("link");
+ link = links[0].attributes.href.nodeValue;
+ }
+ var summaryNode = entries[i].getElementsByTagName("summary")[0];
+ if (summaryNode == null) {
+ summaryNode = entries[i].getElementsByTagName("description")[0];
+ }
+ if (link == null) {
+ resultDiv.innerHTML = resultDiv.innerHTML
+ + "<p style=\"color:blue\"/>"
+ + gadgets.util.escapeString(title);
+ } else {
+ resultDiv.innerHTML = resultDiv.innerHTML
+ + "<p style=\"color:blue\"/>"
+ + "<a href=\""+link+"\" target=\"_blank\">"
+ + gadgets.util.escapeString(title)
+ + "</a>";
+ }
+ if (summaryNode != null) {
+ var summary = summaryNode.textContent;
+ if (summary != null) {
+ resultDiv.innerHTML = resultDiv.innerHTML
+ + gadgets.util.escapeString(summary);
+ }
+ }
+ }
+ }
+ }
+ } else { // errors occured, notify the user.
+ resultDiv.innerHTML = resultDiv.innerHTML + engineTitle
+ + "<br/> An error has occured:" + obj.errors[0];
+ }
+ }
+ var params = {};
+ for (url in currentEngines) {
+ // check if the current engine is selected.
+ if (document.getElementById(url).checked) {
+ title = currentEngines[url];
+ // replace placeholder with actual search term.
+ url = url.replace('{searchTerms}', query);
+ // for now, start on page 1
+ url = url.replace('{startPage?}', 1);
+ // makes sure that the title corresponds to the engine being search.
+ // Resolves a prior timing issue.
+ var callback = function() {
+ var myTitle = '' + title;
+ return function(response) {
+ urlResponse(response, myTitle)
+ };
+ }();
+ // go fetch the results.
+ params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.DOM;
+ gadgets.io.makeRequest(url, callback, params);
+
+ }
+ }
+
+};
Modified: shindig/trunk/features/pom.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/pom.xml?rev=1139034&r1=1139033&r2=1139034&view=diff
==============================================================================
--- shindig/trunk/features/pom.xml (original)
+++ shindig/trunk/features/pom.xml Thu Jun 23 18:52:05 2011
@@ -177,6 +177,7 @@
<source>osapi/peoplehelpers.js</source>
<source>../../../../src/test/javascript/lib/testutils.js</source>
<source>oauthpopup/oauthpopup.js</source>
+ <source>opensearch/opensearch.js</source>
</sources>
<testSourceDirectory>${basedir}/src/test/javascript/features</testSourceDirectory>
<testSuites>
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=1139034&r1=1139033&r2=1139034&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/features.txt (original)
+++ shindig/trunk/features/src/main/javascript/features/features.txt Thu Jun 23 18:52:05 2011
@@ -57,6 +57,7 @@ features/jsondom/feature.xml
features/locked-domain/feature.xml
features/minimessage/feature.xml
features/oauthpopup/feature.xml
+features/opensearch/feature.xml
features/opensocial-0.6/feature.xml
features/opensocial-0.7/feature.xml
features/opensocial-0.8/feature.xml
Added: shindig/trunk/features/src/main/javascript/features/opensearch/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/opensearch/feature.xml?rev=1139034&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/opensearch/feature.xml (added)
+++ shindig/trunk/features/src/main/javascript/features/opensearch/feature.xml Thu Jun 23 18:52:05 2011
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+-->
+<feature>
+ <name>opensearch</name>
+ <dependency>globals</dependency>
+ <dependency>container</dependency>
+ <dependency>gadgets.json.ext</dependency>
+ <container>
+ <script src="opensearch.js"/>
+ <api>
+ <exports type="js">osapi.container.Container.prototype.opensearch.getOpenSearchURLs</exports>
+ <exports type="js">osapi.container.Container.prototype.opensearch.getOpenSearchDescriptions</exports>
+ <exports type="js">osapi.container.Container.prototype.opensearch.addOpenSearchCallback</exports>
+ <exports type="js">osapi.container.Container.prototype.opensearch.removeOpenSearchCallback</exports>
+ </api>
+ </container>
+</feature>
Added: shindig/trunk/features/src/main/javascript/features/opensearch/opensearch.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/opensearch/opensearch.js?rev=1139034&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/opensearch/opensearch.js (added)
+++ shindig/trunk/features/src/main/javascript/features/opensearch/opensearch.js Thu Jun 23 18:52:05 2011
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+/**
+ * @fileoverview This library adds open search support to the container.
+ */
+
+(function(){
+ // array of opensearch descriptors.
+ var descriptions = {};
+ var ids = {};
+ // open search callbacks.
+ var callbacks = new Array();
+
+ /**
+ * Converts an XML string into a DOM object
+ *
+ * @param {xmlString}
+ * string representation of a valid XML object
+ * @return DOM Object
+ */
+ function createDom(xmlString){
+ var xmlDoc;
+ if (window.DOMParser){
+ var parser = new DOMParser();
+ xmlDoc = parser.parseFromString(xmlString,"text/xml");
+ }
+ else{
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = "false";
+ xmlDoc.loadXML(xmlString);
+ }
+ return xmlDoc;
+ }
+
+ /**
+ * Extracts OpenSearch descriptions from XML string containing the
+ * description and stores them in the internal map If valid
+ * descriptions are found, notifies all callbacks about changes.
+ *
+ * @param {domDesc}
+ * stringified XML OpenSearch description
+ * @param {title}
+ * the title of the gadget that the description belongs to
+ */
+ function extractDescriptions(domDesc, url) {
+ var jsonDesc = gadgets.json.xml.convertXmlToJson(domDesc);
+ if (jsonDesc != null) {
+ if (jsonDesc.OpenSearchDescription.Url != null) {
+ if (descriptions[url] == null) {
+ descriptions[url] = jsonDesc;
+ applyCallbacks(true, jsonDesc);
+ }
+ }
+ }
+ }
+
+ /**
+ * Notifies the registered callbacks of changes in the OpenSearch registry.
+ *
+ * @param added
+ * true if added, false if removed.
+ * @param description
+ * opensearch description
+ * @return
+ */
+ function applyCallbacks(added, description) {
+ for (var i in callbacks) {
+ callbacks[i].apply(this, [description, added]);
+ }
+ }
+
+ /**
+ * Removes an opensearch description from the registry after the containing
+ * gadget is unloaded or closed.
+ *
+ * @param url
+ * url of the gadget to be removed.
+ */
+ function removeDescription(url) {
+ if (descriptions[url] != null) {
+ applyCallbacks(false, descriptions[url]);
+ delete descriptions[url];
+ }
+ }
+
+ /**
+ * Processes a new gadget definition and checks if it has an opensearch
+ * feature
+ *
+ * @param {response}
+ * Metadata response containing the json representation of the
+ * gadget module
+ */
+ function preloaded(response) {
+ for (item in response) {
+ if (!response[item].error) {
+ // check for os feature
+ var feature = response[item].modulePrefs.features['opensearch'];
+ var title = response[item].modulePrefs.title;
+ if (feature != null) {
+ var params = feature.params;
+ if (params != null) {
+ // retrieve the description
+ var desc = params["opensearch-description"];
+ // The full description is in the gadget
+ if (desc != null) {
+ // convert string to dom object
+ var domDesc = createDom(desc);
+ // convert dom object to json
+ extractDescriptions(domDesc, item);
+ // only the url to the full description is provided.
+ } else {
+ var openSearchUrl = params["opensearch-url"];
+ if (openSearchUrl != null) {
+ function urlCallback(response){
+ if (response.errors.length == 0) {
+ var domData = response.data;
+ if (domData != null) {
+ extractDescriptions(domData, item);
+ }
+ }
+ }
+ var params = {};
+ params[gadgets.io.RequestParameters.CONTENT_TYPE]
+ = gadgets.io.ContentType.DOM;
+ gadgets.io.makeRequest(openSearchUrl, urlCallback, params);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * When a gadget is closed, checks if it has a corresponding OpenSearch
+ * definition that needs to be removed, and notifies the appropriate
+ * callbacks.
+ *
+ * @param {gadgetSite}
+ * site of the gadget being closed
+ */
+ function closed(gadgetSite) {
+ if (gadgetSite != null) {
+ url=ids[gadgetSite.getId()];
+ removeDescription(url);
+ }
+ }
+
+ /**
+ * called when a gadget is navigated to.
+ *
+ * @param {gadgetInfo}
+ * json object representing the gadget module.
+ */
+ function navigated(gadgetSite) {
+ if (gadgetSite != null) {
+ if (gadgetSite.getActiveGadgetHolder() != null) {
+ url = gadgetSite.getActiveGadgetHolder().getUrl();
+ if (descriptions[url]==null) {
+ preloaded([gadgetSite.getActiveGadgetHolder().getGadgetInfo()]);
+ }
+ ids[gadgetSite.getId()]=url;
+ }
+ }
+ }
+
+ /**
+ * called when a gadget is unloaded
+ *
+ * @param {gadgetURL}
+ * the gadget url of the unloaded gadget.
+ */
+ function unloaded(gadgetURL) {
+ // do nothing--this doesn't guarantee the gadget is actually removed.
+ }
+
+ /**
+ * finds opensearch descriptions/urls based on the mimetype of the search
+ * results
+ *
+ * @param {type}
+ * mimeType of the search results
+ * @param {isUrl}
+ * true if looking for template urls, false if looking for full
+ * OpenSearch descriptions
+ */
+ var findByType = function(type, isUrl) {
+ var typedDescriptions = [];
+ for (url in descriptions) {
+ var searchUrls = [];
+ if (!(descriptions[url].OpenSearchDescription.Url instanceof Array)) {
+ searchUrls.push(descriptions[url].OpenSearchDescription.Url);
+ } else {
+ searchUrls = descriptions[url].OpenSearchDescription.Url;
+ }
+ var found = false;
+ // go through all the urls in a description.
+ // if a description contains a template of the type, the
+ // entire description is returned. For URLs, only the matching
+ // template url is returned.
+ for (var i in searchUrls) {
+ var template = searchUrls[i]["@template"];
+ if (template != null) {
+ var descType = searchUrls[i]["@type"];
+ if (descType == type || type == null) {
+ if (isUrl) {
+ typedDescriptions.push(template);
+ } else {
+ typedDescriptions.push(descriptions[url]);
+ break;
+ }
+ }
+ }
+ }
+ }
+ return typedDescriptions;
+ }
+
+ var containerCallback = new Object();
+ containerCallback[osapi.container.CallbackType.ON_PRELOADED]
+ = preloaded;
+ containerCallback[osapi.container.CallbackType.ON_CLOSED]
+ = closed;
+ containerCallback[osapi.container.CallbackType.ON_NAVIGATED]
+ = navigated;
+
+ osapi.container.Container.addMixin('opensearch',function(context){
+
+ context.addGadgetLifecycleCallback('opensearch', containerCallback);
+
+ return /** @scope container.opensearch */ {
+ /**
+ * @param {type}
+ * type type name, eg search-xml, search-atom, search-hmtl
+ * @return opensearch template URLs of a given type, or all URLs if type
+ * was null
+ */
+ getOpenSearchURLs: function(type) {
+ return findByType(type, true);
+ },
+
+ /**
+ *
+ * @param {type}
+ * type type name, eg search-xml, search-atom, search-hmtl
+ * @return Returns OpenSearch descriptions of a given type, or all
+ * descriptions if type was null
+ */
+ getOpenSearchDescriptions: function(type) {
+ return findByType(type, false);
+ },
+
+ /**
+ * Allows other functions to subscribe to changes in the OpenSearch
+ * registry
+ *
+ * @param {callback}
+ * function(description, boolean added), where description is the
+ * opensearch description being updated and where added is true
+ * if the gadget is new, and false if it has been
+ * closed/unloaded.
+ *
+ */
+ addOpenSearchCallback: function(callback) {
+ callbacks.push(callback);
+ },
+
+ /**
+ * Removes a previously registered callback
+ *
+ * @param {callback}
+ * previously registered callback function
+ * @return true if function was present, false otherwise.
+ *
+ */
+ removeOpenSearchCallback: function(callback) {
+ for (index in callbacks) {
+ if(callbacks[index]==callback) {
+ callbacks.splice(index,1);
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /*
+ * Convenience method for unit testing, allowing the test script to set
+ * internal descriptions. Uncomment for unit testing.
+ *
+ */
+ //setDescriptions_: function(testDescriptions) {
+ // descriptions=testDescriptions;
+ //},
+ }
+ });
+})();
\ No newline at end of file
Added: shindig/trunk/features/src/test/javascript/features/opensearch/opensearch_test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/opensearch/opensearch_test.js?rev=1139034&view=auto
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/opensearch/opensearch_test.js (added)
+++ shindig/trunk/features/src/test/javascript/features/opensearch/opensearch_test.js Thu Jun 23 18:52:05 2011
@@ -0,0 +1,205 @@
+/*
+ * 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
+ *
+ * Unittests for the opensearch feature
+ */
+function OpenSearchTest(name) {
+ TestCase.call(this, name);
+}
+
+OpenSearchTest.inherits(TestCase);
+
+OpenSearchTest.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.shindigContainerUrlSite = osapi.container.UrlSite;
+ this.gadgetsRpc = gadgets.rpc;
+};
+
+OpenSearchTest.prototype.tearDown = function() {
+ window.__API_URI = this.apiUri;
+ window.__CONTAINER_URI = this.containerUri;
+ osapi.container.GadgetSite = this.shindigContainerGadgetSite;
+ osapi.container.UrlSite = this.shindigContainerUrlSite;
+ gadgets.rpc = this.gadgetsRpc;
+};
+
+setDescriptions = function(container) {
+ container.opensearch
+ .setDescriptions_( {
+ "http://hosting.gmodules.com/ig/gadgets/file/109228598702359180066/twitterfinal.xml" : {
+ "OpenSearchDescription" : {
+ "@xmlns" : "http://a9.com/-/spec/opensearch/1.1/",
+ "#text" : [ "\u000a ", "\u000a ", "\u000a ", "\u000a ", "\u000a ",
+ "\u000a ", "\u000a\u000a" ],
+ "ShortName" : "Twitter Search",
+ "Description" : "Realtime Twitter Search",
+ "Url" : {
+ "@type" : "application/atom+xml",
+ "@method" : "get",
+ "@template" : "http://search.twitter.com/search.atom?q={searchTerms}"
+ },
+ "Image" : {
+ "@width" : "16",
+ "@height" : "16",
+ "#text" : "http://search.twitter.com/favicon.png"
+ },
+ "InputEncoding" : "UTF-8",
+ "SearchForm" : "http://search.twitter.com/"
+ }
+ },
+ "http://hosting.gmodules.com/ig/gadgets/file/109228598702359180066/myspacefinal.xml" : {
+ "OpenSearchDescription" : {
+ "@xmlns" : "http://a9.com/-/spec/opensearch/1.1/",
+ "#text" : [ "\u000a ", "\u000a ", "\u000a ", "\u000a ", "\u000a ",
+ "\u000a ", "\u000a" ],
+ "ShortName" : "MySpace Video",
+ "Description" : "Search MySpace videos.",
+ "Tags" : "myspace opensearch search video",
+ "Image" : {
+ "@height" : "16",
+ "@width" : "16",
+ "@type" : "image/x-icon",
+ "#text" : "http://www.myspace.com/favicon.ico"
+ },
+ "Url" : {
+ "@type" : "application/atom+xml",
+ "@xmlns:myspace" : "http://api.myspace.com/-/opensearch/extensions/1.0/",
+ "@template" : "http://api.myspace.com/opensearch/videos?format=xml&searchTerms={searchTerms}"
+ },
+ "Attribution" : "Search data Copyright 2003-2010 MySpace.com. All Rights Reserved."
+ }
+ },
+ "http://hosting.gmodules.com/ig/gadgets/file/109228598702359180066/myspacemultitemplate.xml" : {
+ "OpenSearchDescription" : {
+ "@xmlns" : "http://a9.com/-/spec/opensearch/1.1/",
+ "#text" : [ "\u000a ", "\u000a ", "\u000a ", "\u000a ", "\u000a ",
+ "\u000a ", "\u000a\u000a ", "\u000a ", "\u000a" ],
+ "ShortName" : "MySpace Video",
+ "Description" : "Search MySpace videos.",
+ "Tags" : "myspace opensearch search video",
+ "Image" : {
+ "@height" : "16",
+ "@width" : "16",
+ "@type" : "image/x-icon",
+ "#text" : "http://www.myspace.com/favicon.ico"
+ },
+ "Url" : [
+ {
+ "@type" : "text/html",
+ "@xmlns:myspace" : "http://api.myspace.com/-/opensearch/extensions/1.0/",
+ "@template" : "http://searchservice.myspace.com/index.cfm?fuseaction=sitesearch.results&type=MySpaceTV&qry={searchTerms}&pg={startPage?}"
+ },
+ {
+ "@type" : "application/atom+json",
+ "@xmlns:myspace" : "http://api.myspace.com/-/opensearch/extensions/1.0/",
+ "@template" : "http://api.myspace.com/opensearch/videos?format=json&searchTerms={searchTerms}&count={count?}&startPage={startPage?}&tag={myspace:tag?}&videoMode={myspace:videoMode?}&culture={myspace:culture?}"
+ },
+ {
+ "@type" : "application/atom+xml",
+ "@xmlns:myspace" : "http://api.myspace.com/-/opensearch/extensions/1.0/",
+ "@template" : "http://api.myspace.com/opensearch/videos?format=xml&searchTerms={searchTerms}&count={count?}&startPage={startPage?}&tag={myspace:tag?}&videoMode={myspace:videoMode?}&culture={myspace:culture?}"
+ } ],
+ "Attribution" : "Search data Copyright 2003-2010 MySpace.com. All Rights Reserved."
+ }
+ }
+ });
+}
+
+//The following two methods should be uncommented for unit testing after
+//uncommenting the setDescriptions method in the opensearch.js code.
+/*OpenSearchTest.prototype.testUrls = function() {
+ this.setupGadgetsRpcRegister();
+ var container = new osapi.container.Container();
+ setDescriptions(container);
+ urls = container.opensearch.getOpenSearchURLs();
+ this.assertEquals('all urls', 5, urls.length);
+ urls = container.opensearch.getOpenSearchURLs("application/atom+xml");
+ this.assertEquals('atom urls', 3, urls.length);
+ urls = container.opensearch.getOpenSearchURLs("text/html");
+ this.assertEquals('text/html urls', 1, urls.length);
+ urls = container.opensearch.getOpenSearchURLs("application/shindig");
+ this.assertEquals('bad type urls', 0, urls.length);
+
+};*/
+
+/*OpenSearchTest.prototype.testDescriptions = function() {
+ this.setupGadgetsRpcRegister();
+ var container = new osapi.container.Container();
+
+ setDescriptions(container);
+
+ descriptions = container.opensearch.getOpenSearchDescriptions();
+ this.assertEquals('all descriptions', 3, descriptions.length);
+ descriptions = container.opensearch
+ .getOpenSearchDescriptions("application/atom+xml");
+ this.assertEquals('atom descriptions', 3, descriptions.length);
+ descriptions = container.opensearch.getOpenSearchDescriptions("text/html");
+ this.assertEquals('text/html descriptions', 1, descriptions.length);
+ descriptions = container.opensearch
+ .getOpenSearchDescriptions("application/shindig");
+ this.assertEquals('bad type descriptions', 0, descriptions.length);
+};*/
+
+OpenSearchTest.prototype.testCallbacks = function() {
+ this.setupGadgetsRpcRegister();
+ var container = new osapi.container.Container();
+ callback = function() {
+ };
+ //add callback to the container
+ container.opensearch.addOpenSearchCallback(callback);
+ //remove callback
+ this.assertTrue(container.opensearch.removeOpenSearchCallback(callback));
+ //check that the removed callback is no longer there.
+ this.assertFalse(container.opensearch.removeOpenSearchCallback(callback));
+};
+
+OpenSearchTest.prototype.setupGadgetSite = function(id, gadgetInfo,
+ gadgetHolder) {
+ var self = this;
+ osapi.container.GadgetSite = function() {
+ return {
+ 'getId' : function() {
+ return id;
+ },
+ 'navigateTo' : function(gadgetUrl, viewParams, renderParams, func) {
+ self.site_navigateTo_gadgetUrl = gadgetUrl;
+ self.site_navigateTo_viewParams = viewParams;
+ self.site_navigateTo_renderParams = renderParams;
+ func(gadgetInfo);
+ },
+ 'getActiveGadgetHolder' : function() {
+ return gadgetHolder;
+ }
+ };
+ };
+};
+
+OpenSearchTest.prototype.setupGadgetsRpcRegister = function() {
+ gadgets.rpc = {
+ register : function() {
+ }
+ }
+};