You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by ev...@apache.org on 2009/05/07 20:31:55 UTC

svn commit: r772737 - in /incubator/shindig/trunk/features/src/main/javascript/features: opensocial-data/data.js opensocial-templates/base.js opensocial-templates/container.js opensocial-templates/loader.js xmlutil/xmlutil.js

Author: evan
Date: Thu May  7 18:31:49 2009
New Revision: 772737

URL: http://svn.apache.org/viewvc?rev=772737&view=rev
Log:
SHINDIG-1046

Patch from Lev for:
- Bugs fixed in data context handling
- Support for required library declaration via "requireLibrary" param
  - Template processing deferred until required libraries are loaded
- Correct timing of feature param processing
- Minor Loader refactoring in preparation for library injection
- Namespace declarations on template container tags honored 

Modified:
    incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js
    incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/base.js
    incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js
    incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/loader.js
    incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js

Modified: incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js?rev=772737&r1=772736&r2=772737&view=diff
==============================================================================
--- incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js (original)
+++ incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js Thu May  7 18:31:49 2009
@@ -376,7 +376,7 @@
     if (request.tagName == "os:PeopleRequest") {
       var groupId = request.getAttribute("groupId");
       if ((!groupId || groupId == "@self") && data.length == 1) {
-        data = data[0]
+        data = data[0];
       }
     }
   } else {

Modified: incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/base.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/base.js?rev=772737&r1=772736&r2=772737&view=diff
==============================================================================
--- incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/base.js (original)
+++ incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/base.js Thu May  7 18:31:49 2009
@@ -114,7 +114,7 @@
   opt_id = opt_id || node.name;
   var src = node.value || node.innerHTML;
   src = os.trim(src);
-  var template = os.compileTemplateString(src, opt_id);
+  var template = os.compileTemplateString(src, opt_id, node);
   // Decorate the node with the template's ID, so we consistently render it
   // into the same DIV, and so that it doesn't get treated as anonymous anymore.
   if (! node.name) {
@@ -127,10 +127,12 @@
  * Compile a template without requiring a DOM node.
  * @param {string} src XML data to be compiled.
  * @param {string} opt_id An optional ID for the new template.
- * @return {os.Template} A compiled Template object.
+ * @param {Element} opt_container An optional container DOM Element 
+ * to look for namespaces
+ * @return {opensocial.template.Template} A compiled Template object.
  */
-os.compileTemplateString = function(src, opt_id) {
-  src = opensocial.xmlutil.prepareXML(src);
+os.compileTemplateString = function(src, opt_id, opt_container) {
+  src = opensocial.xmlutil.prepareXML(src, opt_container);
   var doc = opensocial.xmlutil.parseXML(src);
   return os.compileXMLDoc(doc, opt_id);
 };
@@ -171,6 +173,13 @@
   };
 };
 
+/**
+ * Creates a map of the named children of a node. Lower-cased element names 
+ * (including transformed custom tags) are used as keys. 
+ * Where multiple elements share a name, the map value will be an array.
+ * @param {Element} node The node whose children are to be mapped
+ * @return {object} A Map of Element names to Elements.
+ */
 os.computeChildMap_ = function(node) {
   var map = {};
   for (var i = 0; i < node.childNodes.length; i++) {

Modified: incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js?rev=772737&r1=772736&r2=772737&view=diff
==============================================================================
--- incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js (original)
+++ incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js Thu May  7 18:31:49 2009
@@ -20,17 +20,17 @@
  * @fileoverview Standard methods invoked by containers to use the template API.
  *
  * Sample usage:
- *  <script type="text/os-template" tag="os:Button">
+ *  &lt;script type="text/os-template" tag="os:Button">
  *    <button onclick="alert('Clicked'); return false;">
  *      <os:renderAll/>
  *    </button>
- *  </script>
+ *  &lt;/script]
  *
- *  <script type="text/os-template">
+ *  &lt;script type="text/os-template"]
  *    <os:Button>
  *      <div>Click me</div>
  *    </os:Button>
- *  </script>
+ *  &lt;/script]
  *
  * os.Container.registerDocumentTemplates();
  * os.Container.renderInlineTemplates();
@@ -59,21 +59,14 @@
 os.Container.domLoaded_ = false;
 
 /**
- * @type {boolean} Determines whether all templates are automatically processed.
+ * @type {number} The number of libraries needed to load.
  */
-os.Container.autoProcess_ = true;
-
+os.Container.requiredLibraries_ = 0;
 
 /**
- * In gadgets, honor the "disableAutoProcessing" feature param.
+ * @type {boolean} Determines whether all templates are automatically processed.
  */
-if (window['gadgets']) {
-  var params = gadgets.util.getFeatureParameters("opensocial-templates");
-  if (params && params.disableAutoProcessing && 
-      params.disableAutoProcessing.toLowerCase != "false") {
-    os.Container.autoProcess_ = false;
-  }
-};
+os.Container.autoProcess_ = true;
 
 /**
  * @type {boolean} Has the document been processed already?
@@ -129,9 +122,9 @@
   if (os.Container.domLoaded_) {
     return;
   }
-  while (os.Container.domLoadCallbacks_.length) {
-  try {
-      os.Container.domLoadCallbacks_.pop()();
+  for (var i = 0; i < os.Container.domLoadCallbacks_.length; i ++) {
+    try {
+      os.Container.domLoadCallbacks_[i]();
     } catch (e) {
       os.log(e);
     }
@@ -189,9 +182,9 @@
   for (var i = 0; i < nodes.length; ++i) {
     var node = nodes[i];
     if (os.Container.isTemplateType_(node.type)) {
-      var name = node.getAttribute('name') || node.getAttribute('tag');
+      var name = node.getAttribute('tag') || node.getAttribute('name');
       if (!name || name.length < 0) {
-        var template = os.compileTemplate(node);
+        var template = os.compileTemplate(node, name);
         if (template) {
           os.Container.inlineTemplates_.push(
               {'template': template, 'node': node});
@@ -203,18 +196,16 @@
   }
 };
 
-os.Container.defaultContext = null;
-
+/**
+ * @return {JsEvalContext} the default rendering context to use - this will
+ * contain all available data. 
+ */
 os.Container.getDefaultContext = function() {
-  if (!os.Container.defaultContext) {
-    if ((window['gadgets'] && gadgets.util.hasFeature('opensocial-data')) ||
-        (opensocial.data.DataContext)) {
-      os.Container.defaultContext = os.createContext(opensocial.data.DataContext.getData());
-    } else {
-      os.Container.defaultContext = os.createContext({});
-    }
+  if ((window['gadgets'] && gadgets.util.hasFeature('opensocial-data')) ||
+      (opensocial.data.getDataContext)) {
+    return os.createContext(opensocial.data.getDataContext().getData());
   }
-  return os.Container.defaultContext;
+  return os.createContext({});
 };
 
 /**
@@ -350,19 +341,60 @@
 };
 
 /**
+ * Process the gadget configuration when it is available.
+ */
+os.Container.processGadget = function() {
+  if (!window['gadgets']) {
+    return;
+  }
+  
+  // Honor the "disableAutoProcessing" feature param.
+  var params = gadgets.util.getFeatureParameters("opensocial-templates");
+  if (!params) {
+    return;
+  }
+  if (params.disableAutoProcessing && 
+      params.disableAutoProcessing.toLowerCase != "false") {
+    os.Container.autoProcess_ = false;
+  }
+  
+  // Honor the "requireLibrary" feature param.
+  // TODO: Support multiple params when Shindig does.
+  if (params.requireLibrary) {
+    os.Container.addRequiredLibrary(params.requireLibrary);
+  }  
+};
+
+//Process the gadget when the page loads.
+os.Container.executeOnDomLoad(os.Container.processGadget);
+
+/**
+ * A flag to determine if auto processing is waiting for libraries to load.
+ * @type {boolean}
+ */
+os.Container.processWaitingForLibraries_ = false;
+
+/**
  * Utility method which will automatically register all templates
  * and render all that are inline.
- * @param {Object} opt_doc Optional document to use instead of window.document.
+ * @param {Object} opt_data Optional JSON object to render templates against
+ * @param {Document} opt_doc Optional document to use instead of window.document
  */
-os.Container.processDocument = function(opt_doc) {
+os.Container.processDocument = function(opt_data, opt_doc) {
+  if (os.Container.requiredLibraries_ > 0) {
+    os.Container.processWaitingForLibraries_ = true;
+    return;
+  }
+  os.Container.processWaitingForLibraries_ = false;
   os.Container.registerDocumentTemplates(opt_doc);
-  os.Container.processInlineTemplates(opt_doc);
+  os.Container.processInlineTemplates(opt_data, opt_doc);
   os.Container.processed_ = true;
 };
 
 // Expose function in opensocial.template namespace.
 os.process = os.Container.processDocument;
 
+// Process the document when the page loads - unless requested not to.
 os.Container.executeOnDomLoad(function() {
   if (os.Container.autoProcess_) {
     os.Container.processDocument();
@@ -370,12 +402,35 @@
 });
 
 /**
+ * A handler called when one of the required libraries loads.
+ */
+os.Container.onLibraryLoad_ = function() {
+  if (os.Container.requiredLibraries_ > 0) {
+    os.Container.requiredLibraries_--;
+    if (os.Container.requiredLibraries_ == 0 && 
+        os.Container.processWaitingForLibraries_) {
+      os.Container.processDocument();
+    }
+  } 
+};
+
+/**
+ * Adds a required library - the processing will be deferred until all
+ * required libraries have loaded.
+ * @param {string} libUrl The URL of the library needed to process this page
+ */
+os.Container.addRequiredLibrary = function(libUrl) {
+  os.Container.requiredLibraries_++;
+  os.Loader.loadUrl(libUrl, os.Container.onLibraryLoad_);
+};
+
+/**
  * @type {string} Tag name of a template.
  * @private
  */
 os.Container.TAG_script_ = 'script';
 
-/***
+/**
  * @type {Object} Map of allowed template content types.
  * @private
  * TODO(davidbyttow): Remove text/template.

Modified: incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/loader.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/loader.js?rev=772737&r1=772736&r2=772737&view=diff
==============================================================================
--- incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/loader.js (original)
+++ incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/loader.js Thu May  7 18:31:49 2009
@@ -91,8 +91,7 @@
   req.open("GET", url, true);
   req.onreadystatechange = function() {
     if (req.readyState == 4) {
-      os.Loader.loadContent(req.responseText);
-      os.Loader.loadedUrls_[url] = true;
+      os.Loader.loadContent(req.responseText, url);
       callback();
     }
   };
@@ -116,8 +115,7 @@
   params[gadgets.io.RequestParameters.CONTENT_TYPE] =
       gadgets.io.ContentType.TEXT;
   gadgets.io.makeRequest(url, function(obj) {
-    os.Loader.loadContent(obj.data);
-    os.Loader.loadedUrls_[url] = true;
+    os.Loader.loadContent(obj.data, url);
     callback();
   }, params);
 };
@@ -142,10 +140,11 @@
 /**
  * Processes the XML markup of a Template Library.
  */
-os.Loader.loadContent = function(xmlString) {
+os.Loader.loadContent = function(xmlString, url) {
   var doc = opensocial.xmlutil.parseXML(xmlString);
   var templatesNode = doc.firstChild;
   os.Loader.processTemplatesNode(templatesNode);
+  os.Loader.loadedUrls_[url] = true;
 };
 
 /**

Modified: incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js?rev=772737&r1=772736&r2=772737&view=diff
==============================================================================
--- incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js (original)
+++ incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js Thu May  7 18:31:49 2009
@@ -69,21 +69,52 @@
  * the supplied code. An empty string is returned if no injection is needed.
  *
  * @param {string} xml XML-like source code.
+ * @param {Element} opt_container Optional container node to look for namespace
+ * declarations.
  * @return {string} A string of xmlns delcarations required for this XML.
  */
-opensocial.xmlutil.getRequiredNamespaces = function(xml) {
-  var codeToInject = [];
-  for (var ns in opensocial.xmlutil.NSMAP) {
-    if (xml.indexOf("<" + ns + ":") >= 0 &&
-        xml.indexOf("xmlns:" + ns + ":") < 0) {
-      codeToInject.push(" xmlns:");
-      codeToInject.push(ns);
-      codeToInject.push("=\"");
-      codeToInject.push(opensocial.xmlutil.NSMAP[ns]);
-      codeToInject.push("\"");
+opensocial.xmlutil.getRequiredNamespaces = function(xml, opt_container) {
+  var namespaces = opt_container ? 
+      opensocial.xmlutil.getNamespaceDeclarations_(opt_container) : {};
+  for (var prefix in opensocial.xmlutil.NSMAP) {
+    if (opensocial.xmlutil.NSMAP.hasOwnProperty(prefix) 
+        && !namespaces.hasOwnProperty(prefix) 
+        && xml.indexOf("<" + prefix + ":") >= 0 
+        && xml.indexOf("xmlns:" + prefix + ":") < 0) {
+      namespaces[prefix] = opensocial.xmlutil.NSMAP[prefix];
     }
   }
-  return codeToInject.join("");
+  return opensocial.xmlutil.serializeNamespaces_(namespaces);  
+};
+
+
+opensocial.xmlutil.serializeNamespaces_ = function(namespaces) {
+  var buffer = [];
+  for (var prefix in namespaces) {
+    if (namespaces.hasOwnProperty(prefix)) {
+      buffer.push(" xmlns:", prefix, "=\"", namespaces[prefix], "\"");
+    }
+  }
+  return buffer.join("");
+};
+
+
+/**
+ * Returns a map of XML namespaces declared on an DOM Element.
+ * @param {Element} el The Element to inspect
+ * @return {object(string, string)} A Map of keyed by prefix of declared 
+ * namespaces. 
+ */
+opensocial.xmlutil.getNamespaceDeclarations_ = function(el) {
+  var namespaces = {};
+  for (var i = 0; i < el.attributes.length; i++) {
+    var name = el.attributes[i].nodeName;
+    if (name.substring(0, 6) != 'xmlns:') {
+      continue;
+    }
+    namespaces[name.substring(6, name.length)] = el.getAttribute(name); 
+  }
+  return namespaces;
 };
 
 
@@ -99,10 +130,12 @@
  * Prepares an XML-like string to be parsed by browser parser. Injects a DOCTYPE
  * with entities and a top-level <root> element to encapsulate the code.
  * @param {string} xml XML string to be prepared.
+ * @param {Element} opt_container Optional container Element with namespace
+ * declarations.
  * @return {string} XML string prepared for client-side parsing.
  */
-opensocial.xmlutil.prepareXML = function(xml) {
-  var namespaces = opensocial.xmlutil.getRequiredNamespaces(xml);
+opensocial.xmlutil.prepareXML = function(xml, opt_container) {
+  var namespaces = opensocial.xmlutil.getRequiredNamespaces(xml, opt_container);
   return "<!DOCTYPE root [" + opensocial.xmlutil.ENTITIES +
       "]><root xml:space=\"preserve\"" +
       namespaces + ">" + xml + "</root>";