Author: awiner
Date: Fri May 29 22:06:03 2009
New Revision: 780123

URL: http://svn.apache.org/viewvc?rev=780123&view=rev
Log:
Enabling server-to-client handoff for @autoUpdate.  Patch from Lev Epshteyn.

Modified:
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
    
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/TemplateRewriter.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java

Modified: 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js?rev=780123&r1=780122&r2=780123&view=diff
==============================================================================
--- 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
 (original)
+++ 
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
 Fri May 29 22:06:03 2009
@@ -60,8 +60,9 @@
    * @param {Function(Array.<string>)} callback Function to call when a
    * listener is fired.
    * @param {booelan} oneTimeListener Remove this listener after first 
callback?
+   * @param {boolean} fireIfReady Instantly fire this if all data is available?
    */
-  var registerListener = function(keys, callback, oneTimeListener) {
+  var registerListener = function(keys, callback, oneTimeListener, 
fireIfReady) {
     var oneTime = !!oneTimeListener;
     var listener = {keys : {}, callback : callback, oneTime: oneTime};
 
@@ -79,7 +80,7 @@
     listeners.push(listener);
   
     // Check to see if this one should fire immediately.
-    if (keys !== '*' && isDataReady(listener.keys)) {
+    if (fireIfReady && keys !== '*' && isDataReady(listener.keys)) {
       window.setTimeout(function() {
         maybeFireListener(listener, keys);
       }, 1);
@@ -179,7 +180,7 @@
      * listener is fired.
      */
     registerListener : function(keys, callback) {
-      registerListener(keys, callback, false);
+      registerListener(keys, callback, false, true);
     },
         
     /**
@@ -190,7 +191,18 @@
      * @param {Function(Array.<string>)} callback Function to call when a 
      */
     registerOneTimeListener_ : function(keys, callback) {
-      registerListener(keys, callback, true);
+      registerListener(keys, callback, true, true);
+    },
+    
+    /**
+     * Private version of registerListener which allows listeners to be
+     * registered that do not fire initially, but only after a data change.
+     * Exposed because needed by opensocial-templates.
+     * @param {string|Array.<string>} keys Key or set of keys to listen on.
+     * @param {Function(Array.<string>)} callback Function to call when a
+     */
+    registerDeferredListener_ : function(keys, callback) {
+      registerListener(keys, callback, false, false);
     },
     
     /**

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=780123&r1=780122&r2=780123&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
 Fri May 29 22:06:03 2009
@@ -182,7 +182,7 @@
   for (var i = 0; i < nodes.length; ++i) {
     var node = nodes[i];
     if (os.Container.isTemplateType_(node.type)) {
-      var name = node.getAttribute('tag') || node.getAttribute('name');
+      var name = node.getAttribute('tag');
       if (!name || name.length < 0) {
         var template = os.compileTemplate(node, name);
         if (template) {
@@ -220,11 +220,13 @@
     var template = inlined[i].template;
     var node = inlined[i].node;
     var id = '_T_' + template.id;
+    var rendered = true;
     var el = doc.getElementById(id);
     if (!el) {
       el = doc.createElement('div');
       el.setAttribute('id', id);
       node.parentNode.insertBefore(el, node);
+      rendered = false;
     }
 
     // Only honor @before and @require attributes if the opensocial-data
@@ -247,9 +249,13 @@
         var keys = requiredData.split(/[\, ]+/);
         var callback = os.Container.createRenderClosure(template, el);
         if ("true" == node.getAttribute("autoUpdate")) {
-          opensocial.data.DataContext.registerListener(keys, callback);
+          if (rendered) {
+            opensocial.data.getDataContext().registerDeferredListener_(keys, 
callback);
+          } else {
+            opensocial.data.getDataContext().registerListener(keys, callback);
+          }
         } else {
-          opensocial.data.DataContext.registerOneTimeListener_(keys, callback);
+          opensocial.data.getDataContext().registerOneTimeListener_(keys, 
callback);
         }
       } else {
         template.renderInto(el, null, context);

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/TemplateRewriter.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/TemplateRewriter.java?rev=780123&r1=780122&r2=780123&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/TemplateRewriter.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/TemplateRewriter.java
 Fri May 29 22:06:03 2009
@@ -86,6 +86,9 @@
   
   /** Specifies what template libraries to load */
   static final Object REQUIRE_LIBRARY_PARAM = "requireLibrary";
+  
+  /** Enable client support? **/
+  static final Object CLIENT_SUPPORT_PARAM = "client";  
 
   static private final Logger logger = 
Logger.getLogger(TemplateRewriter.class.getName());
   
@@ -206,6 +209,15 @@
     TemplateContext templateContext = new TemplateContext(gadget, 
content.getPipelinedData());    
     boolean needsFeature = executeTemplates(templateContext, content, 
templates, registry);
 
+    // Check if a feature param overrides  our guess at whether the 
client-side    
+    // feature is needed.                                                  
+    String clientOverride = f.getParams().get(CLIENT_SUPPORT_PARAM);           
 
+    if ("true".equalsIgnoreCase(clientOverride)) {                             
 
+      needsFeature = true;                                                     
 
+    } else if ("false".equalsIgnoreCase(clientOverride)) {                     
 
+      needsFeature = false;                                                    
 
+    }                                                                          
 
+
     Element head = (Element) DomUtil.getFirstNamedChildNode(
         content.getDocument().getDocumentElement(), "head");
     postProcess(templateContext, needsFeature, head, templates, libraries);
@@ -351,12 +363,10 @@
     boolean needsFeature = false;
     List<Element> templates = Lists.newArrayList();
     for (Element element : allTemplates) {
-      String name = element.getAttribute("name");
       String tag = element.getAttribute("tag");
       String require = element.getAttribute("require");
 
-      if (!"".equals(name) ||
-          !checkRequiredData(require, pipelinedData.keySet())) {
+      if (!checkRequiredData(require, pipelinedData.keySet())) {
         // Can't be processed on the server at all;  keep client-side 
processing
         needsFeature = true;
       } else if ("".equals(tag)) {
@@ -371,19 +381,25 @@
           gadget.getContext().getLocale(), 
gadget.getContext().getIgnoreCache());
       MessageELResolver messageELResolver = new MessageELResolver(expressions, 
bundle);
   
+      int autoUpdateID = 0;
       for (Element template : templates) {
         DocumentFragment result = processor.get().processTemplate(
             template, templateContext, messageELResolver, registry);
-        template.getParentNode().insertBefore(result, template);
         // TODO: sanitized renders should ignore this value
         if ("true".equals(template.getAttribute("autoUpdate"))) {
           // autoUpdate requires client-side processing.
-          // TODO: give client-side processing some hope of finding the 
pre-rendered content
           needsFeature = true;
+          Element span = template.getOwnerDocument().createElement("span");    
 
+          String id = "template_auto" + (autoUpdateID++);                      
 
+          span.setAttribute("id", "_T_" + id);                                 
 
+          template.setAttribute("name", id);                                   
 
+          template.getParentNode().insertBefore(span, template);               
 
+          span.appendChild(result);                                            
 
         } else {
+          template.getParentNode().insertBefore(result, template);
           template.getParentNode().removeChild(template);
         }
-      } 
+      }
       MutableContent.notifyEdit(content.getDocument());
     } 
     return needsFeature;

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java?rev=780123&r1=780122&r2=780123&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java
 Fri May 29 22:06:03 2009
@@ -81,9 +81,6 @@
   private static final String CONTENT_REQUIRE_MISSING =
     "<script type='text/os-template' require='foo'>Hello, 
${user.name}</script>";  
 
-  private static final String CONTENT_WITH_NAME =
-    "<script type='text/os-template' name='myTemplate'>Hello, 
${user.name}</script>";  
-  
   private static final String CONTENT_WITH_TAG =
     "<script type='text/os-template' xmlns:foo='#foo' tag='foo:Bar'>Hello, 
${user.name}</script>";
   
@@ -161,14 +158,7 @@
     testExpectingNoTransform(getGadgetXml(CONTENT_REQUIRE_MISSING), "missing 
data");
     testFeatureNotRemoved();
   }
-  
-  @Test
-  public void nameAttributePresent() throws Exception {
-    // Don't render templates with a @name
-    testExpectingNoTransform(getGadgetXml(CONTENT_WITH_NAME), "with @name");
-    testFeatureNotRemoved();
-  }
-  
+   
   @Test
   public void tagAttributePresent() throws Exception {
     // Don't render templates with a @tag
@@ -192,6 +182,8 @@
         content.getContent().indexOf("Hello, John") > 0);
     assertTrue("Template tag was removed",
         content.getContent().contains("text/os-template"));
+    assertTrue("ID span was not created",
+        content.getContent().contains("<span id=\"_T_template_auto0\">"));
     testFeatureNotRemoved();
   }
 
@@ -247,6 +239,17 @@
     testFeatureRemoved();
   }
   
+  @Test
+  public void testClientOverride() throws Exception {
+    // Should normally remove feature
+    testExpectingTransform(getGadgetXml(CONTENT_PLAIN, true, "true"), "keep 
client");
+    testFeatureNotRemoved();
+    
+    // Should normally keep feature
+    testExpectingNoTransform(getGadgetXml(CONTENT_WITH_TAG, true, "false"), 
"remove client");
+    testFeatureRemoved();
+  }
+  
   private void testFeatureRemoved() {
     assertTrue("Feature wasn't removed",
         gadget.getRemovedFeatures().contains("opensocial-templates"));
@@ -302,8 +305,17 @@
   }
   
   private static String getGadgetXml(String content, boolean requireFeature) {
+    return getGadgetXml(content, requireFeature, null);
+  }
+  
+  private static String getGadgetXml(String content, boolean requireFeature, 
+      String clientParam) {
     String feature = requireFeature ?
-        "<Require feature='opensocial-templates'/>" : "";
+        "<Require feature='opensocial-templates'" + 
+        (clientParam != null ? 
+            ("><Param name='client'>" + clientParam + "</Param></Require>") 
+            : "/>") 
+        : "";
     return "<Module>" + "<ModulePrefs title='Title'>"
         + feature
         + "  <Locale>"


Reply via email to