Author: sylvain
Date: Fri May  6 15:01:55 2005
New Revision: 168669

URL: http://svn.apache.org/viewcvs?rev=168669&view=rev
Log:
Ajax: fix a bug with boolean inputs, add some visual sugar by highlighting 
updated areas

Modified:
    
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js
    
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/resources/js/cforms.js
    cocoon/blocks/core/forms/trunk/samples/forms/carselector_template.xml
    cocoon/blocks/core/forms/trunk/samples/welcome.xml

Modified: 
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js
URL: 
http://svn.apache.org/viewcvs/cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js?rev=168669&r1=168668&r2=168669&view=diff
==============================================================================
--- 
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js
 (original)
+++ 
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js
 Fri May  6 15:01:55 2005
@@ -114,11 +114,7 @@
         this.locale = java.util.Locale.getDefault();
     viewdata["locale"] = this.locale;
 
-    // Keep the first continuation that will be created as the result of this 
function
-    var result = null;
-
     var finished = false;
-    this.isValid = false;
 
     var comingBack = false;
     var bookmark = cocoon.createWebContinuation(ttl);
@@ -126,10 +122,11 @@
     if (comingBack) {
         // We come back to the bookmark: process the form
         
-        if (cocoon.request.getParameter("cocoon-ajax-continue") != null) {
-            //TODO(SW): when exiting AJAX rountrips, better send a new 
continuation
-            //to ensure we really come back from a "100-continue" response 
(see below)
-            //and this isn't a forged request
+        if (finished && cocoon.request.getParameter("cocoon-ajax-continue") != 
null) {
+            // A request with this parameter is sent by the client upon 
receiving the indication
+            // that Ajax interaction on the form is finished (see below).
+            // We also check "finished" to ensure we won't exit showForm() 
because of some
+            // faulty or hacked request. It's set to false, this will simply 
redisplay the form.
             return bookmark;
         }
         
@@ -155,7 +152,7 @@
                 // Ask the client to load the page
                 cocoon.response.setHeader("X-Cocoon-Ajax", "continue");
                 cocoon.response.setHeader("Content-Length", "0");
-                cocoon.sendStatus(200); // Continue
+                cocoon.sendStatus(200);
                 FOM_Cocoon.suicide();
             }
             

Modified: 
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/resources/js/cforms.js
URL: 
http://svn.apache.org/viewcvs/cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/resources/js/cforms.js?rev=168669&r1=168668&r2=168669&view=diff
==============================================================================
--- 
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/resources/js/cforms.js
 (original)
+++ 
cocoon/blocks/core/forms/trunk/java/org/apache/cocoon/forms/resources/js/cforms.js
 Fri May  6 15:01:55 2005
@@ -94,10 +94,15 @@
     // Iterate on all form controls
     for (var i = 0; i < form.elements.length; i++) {
         input = form.elements[i];
-        if (input.type != "submit" && input.type != "image") {
+        if (input.type == "submit" || input.type == "image") {
             // Skip buttons
-            result += "&" + encodeURIComponent(input.name) + "=" + 
encodeURIComponent(input.value);
+            continue;
         }
+        if ((input.type == "checkbox" || input.type == "radio") && 
!input.checked) {
+            // Skip unchecked checkboxes and radio buttons
+            continue;
+        }
+        result += "&" + encodeURIComponent(input.name) + "=" + 
encodeURIComponent(input.value);
     }
     return result;
 }
@@ -131,10 +136,20 @@
                    return;
                }
         
-            BrowserUpdate.processResponse(doc);
-        }
+           BrowserUpdate.processResponse(doc);
+       }
     } else {
-        alert("request failed : " + request.status);
+/*        var str = "";
+        for(prop in request) {
+           str += prop
+           str += " = " 
+           str += request[prop];
+           str += '\n';
+        }
+        alert(str);
+        alert(request.getAllResponseHeaders());
+*/
+        alert("request failed - status: " + request.status);
     }
 }
 
@@ -146,7 +161,7 @@
     ATTRIBUTE_NODE : 2,
     TEXT_NODE : 3,
     CDATA_SECTION_NODE : 4,
-       ENTITY_REFERENCE_NODE : 5,
+    ENTITY_REFERENCE_NODE : 5,
     ENTITY_NODE : 6,
     PROCESSING_INSTRUCTION_NODE : 7,
     COMMENT_NODE : 8,
@@ -269,6 +284,140 @@
            oldElement.parentNode.replaceChild(newElement, oldElement);
            // Ensure the new node has the correct id
            newElement.setAttribute("id", id);
+           
+           if (BrowserUpdate.highlight) {
+              BrowserUpdate.highlight(newElement);
+           }
        }
+}
+
+//-------------------------------------------------------------------------------------------------
+// Fader used to highlight page areas that have been updated
+//-------------------------------------------------------------------------------------------------
+
+/**
+ * Create a fader that will progressively change an element's background color 
from
+ * a given color back to its original color.
+ *
+ * @param elt the element to fade
+ * @param color the starting color (default yellow)
+ * @param duration the fade duration in msecs (default 1000)
+ * @param fps the animation frames per seconds (default 25)
+ */
+function Fader(elt, color, duration, fps) {
+   // Set default values
+   if (!color) color = "#FFFF80"; // yellow
+   if (!duration) duration = 1000; // 1 sec
+   if (!fps) fps = 25; // 25 frames/sec
+   
+   this.element = elt;
+   this.fromColor = Fader.colorToRgb(color);
+   this.toColor = Fader.colorToRgb(Fader.getBgColor(this.element));
+   
+   this.maxFrames = Math.round(fps * duration / 1000.0);
+   this.delay = duration / this.maxFrames;
+}
+
+/**
+ * Creates a default fader for a given element. This function can be used to 
set BrowserUpdate.highlight
+ */
+Fader.fade = function(elt) {
+   new Fader(elt).start();
+}
+
+Fader.prototype.start = function() {
+   this.frame = 0;
+   this._changeColor();
+}
+
+Fader.prototype._changeColor = function() {
+    if (this.frame < this.maxFrames) {
+        // Schedule the next iteration right now to keep a more accurate timing
+        var fader = this;
+        setTimeout(function() {fader._changeColor();}, this.delay);
+    }
+    var newColor = new Array(3);
+    for (var channel = 0; channel < 3; channel++) {
+        newColor[channel] = Math.floor(
+            this.fromColor[channel] * ((this.maxFrames - this.frame) / 
this.maxFrames) +
+            this.toColor[channel] * (this.frame/this.maxFrames)
+        );
+    }
+
+    this.frame++;
+    var color = Fader.rgbToColor(newColor[0], newColor[1], newColor[2]);
+    this.element.style.backgroundColor = color;
+}
+
+/** Converts a "#RRGGBB" color as an array of 3 ints */
+Fader.colorToRgb = function(hex) {
+    return [
+        parseInt(hex.substr(1,2),16),
+        parseInt(hex.substr(3,2),16),
+        parseInt(hex.substr(5,2),16) ];
+}
+
+/** Converts rgb values to a "#RRGGBB" color */
+Fader.rgbToColor = function(r, g, b) {
+    r = r.toString(16); if (r.length == 1) r = '0' + r;
+    g = g.toString(16); if (g.length == 1) g = '0' + g;
+    b = b.toString(16); if (b.length == 1) b = '0' + b;
+    return "#" + r + g + b;
+}
+
+/** Get the background color of an element */
+Fader.getBgColor = function(elt) {
+    while(elt) {
+        var c;
+        if (window.getComputedStyle) c = 
window.getComputedStyle(elt,null).getPropertyValue("background-color");
+        if (elt.currentStyle) c = elt.currentStyle.backgroundColor;
+        if ((c != "" && c != "transparent") || elt.tagName == "BODY") { break; 
}
+        elt = elt.parentNode;
+    }
+    if (c == undefined || c == "" || c == "transparent" || c == "white") c = 
"#FFFFFF";
+
+    var rgb = 
c.match(/rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/);
+    if (rgb) return 
this.rgbToColor(parseInt(rgb[1]),parseInt(rgb[2]),parseInt(rgb[3]));
+    return c;
+}
+
+BrowserUpdate.highlight = Fader.fade;
+
+//-------------------------------------------------------------------------------------------------
+// Blinker used to highlight page areas that have been updated
+//-------------------------------------------------------------------------------------------------
+
+function Blinker(elt, color, hltDelay, normalDelay, blinks) {
+    this.element = elt;
+    if (!color) color = "#FFFF80"; // yellow
+    if (!hltDelay) hltDelay = 100;
+    if (!normalDelay) normalDelay = 100;
+    if (!blinks) blinks = 2;
+    
+    this.hltColor = color;
+    this.hltDelay = hltDelay;
+    this.normalDelay = normalDelay;
+    this.normalColor = Fader.getBgColor(elt);
+    this.maxBlinks = blinks * 2;
+    this.blink = 0;
+}
+
+Blinker.prototype.start = function() {
+   this.blink = 0;
+   this._doBlink();
+}
+
+Blinker.blink = function(elt) {
+   new Blinker(elt).start();
+}
+
+Blinker.prototype._doBlink = function() {
+   var hlt = (this.blink % 2 == 0);
+   this.element.style.backgroundColor = hlt ? this.hltColor : 
this.normalColor;;
+   if (this.blink <= this.maxBlinks) {
+      var blinker = this;
+      setTimeout(function() {blinker._doBlink();}, hlt ? this.hltDelay : 
this.normalDelay);
+   }
+   this.blink++;
 }
 

Modified: cocoon/blocks/core/forms/trunk/samples/forms/carselector_template.xml
URL: 
http://svn.apache.org/viewcvs/cocoon/blocks/core/forms/trunk/samples/forms/carselector_template.xml?rev=168669&r1=168668&r2=168669&view=diff
==============================================================================
--- cocoon/blocks/core/forms/trunk/samples/forms/carselector_template.xml 
(original)
+++ cocoon/blocks/core/forms/trunk/samples/forms/carselector_template.xml Fri 
May  6 15:01:55 2005
@@ -18,11 +18,11 @@
    <!-- Import the macros that define CForms template elements -->
    <jx:import 
uri="resource://org/apache/cocoon/forms/generation/jx-macros.xml"/>
   <title>Car selector</title>
-  <para>This example illustrates how you can programmatically update the
-    content of a selection list.</para>
-  <para>
-    This sample illustrates event-handling in Cocoon Forms and how selection 
lists can be changed
-    programmatically.
+  <para>This example illustrates:
+     <ul>
+        <li>how you can programmatically update the content of a selection 
list,</li>
+        <li>the AJAX features that allow partial page reloads and the 
associated visual effects.</li>
+     </ul>
   </para>
   <para>
     Event-handlers are defined in the form definition to update the selection 
lists and set
@@ -34,6 +34,30 @@
     See "carselector_form.xml" and "carselector_template.xml" to see how this 
is done.
   </para>
   <content>
+    <script language="JavaScript">
+       var currentEffect = "fade";
+       function setEffect(effect) {
+           if (effect == "none") {
+               BrowserUpdate.highlight = null;
+           } else if (effect == "fade") {
+               BrowserUpdate.highlight = Fader.fade;
+           } else if (effect == "blink") {
+               BrowserUpdate.highlight = Blinker.blink;
+           }
+           
+           document.getElementById(currentEffect).style.fontWeight = "";
+           document.getElementById(effect).style.fontWeight = "bold";
+           currentEffect = effect;
+           return false;
+       }
+    </script>
+    <para>
+      Page update effect:
+      <a id="none" href="#" onclick="setEffect('none')">None</a> - 
+      <a style="font-weight: bold" id="fade" href="#" 
onclick="setEffect('fade')">Fade</a> - 
+      <a id="blink" href="#" onclick="setEffect('blink')">Blink</a>
+    </para>
+      
     <ft:form-template action="carselector" method="POST" ajax="true">
       <ft:continuation-id/>
       <fi:group>

Modified: cocoon/blocks/core/forms/trunk/samples/welcome.xml
URL: 
http://svn.apache.org/viewcvs/cocoon/blocks/core/forms/trunk/samples/welcome.xml?rev=168669&r1=168668&r2=168669&view=diff
==============================================================================
--- cocoon/blocks/core/forms/trunk/samples/welcome.xml (original)
+++ cocoon/blocks/core/forms/trunk/samples/welcome.xml Fri May  6 15:01:55 2005
@@ -30,14 +30,18 @@
   <sample name="Cocoon Forms Documentation" 
href="http://cocoon.apache.org/2.1/userdocs/forms/";>
     Documentation is available on the Cocoon site.
   </sample>
+  <note>
+     Samples with the (Ajax) mark use the new transparent Ajax (Asynchronous 
Javascript And XML) framework
+     to reduce client/server roundtrips and perform partial page updates.
+  </note>
  </group>
 
  <group name="Basic Samples">
   <sample name="Various (Actions)" href="form1">This sample shows validation, 
event handling and various Cocoon Forms features.</sample>
   <sample name="Various (Flowscript)" href="form1.flow">The same sample as 
above using Flowscript.</sample>
   <sample name="Registration" href="registration">A simple registration 
form.</sample>
-  <sample name="Car selector" href="carselector">Illustrates programmatically 
changing selectionlists.</sample>
-  <sample name="XHR Car selector" href="xhr_carselector">Same sample, using 
XmlHttpRequest to reduce client/server roundtrips.</sample>
+  <sample name="Car selector" href="carselector">(Ajax) Illustrates 
programmatically changing selectionlists.</sample>
+  <sample name="XHR Car selector" href="xhr_carselector">Same sample, with the 
historical first use of XmlHttpRequest to reduce client/server 
roundtrips.</sample>
   <sample name="Country selector" href="countryselector">Illustrates 
programmatically changing flow-jxpath selectionlists.</sample>
   <sample name="Upload" href="upload">Shows an upload widget used with 
Flowscript</sample>
   <sample name="Form Model GUI" href="form_model_gui.flow">Illustrates the use 
of Class, New, Struct, and Union.</sample>
@@ -88,14 +92,14 @@
      widgets.
    </note>
    <sample name="Dynamic repeater template" href="do-dynaRepeater.flow">
-     Shows a simple repeater, which isn't displayed at all if empty, and whose 
row action depend on
+     (Ajax) Shows a simple repeater, which isn't displayed at all if empty, 
and whose row action depend on
      the row number.
    </sample>
    <sample name="Datasource chooser" href="do-datasourceChooser.flow">
-     A datasource chooser, illustrating the fd:union widget.
+     (Ajax) A datasource chooser, illustrating the fd:union widget.
    </sample>
    <sample name="Task tree" href="do-taskTree.flow">
-     A project work breakdown into a hierarchy of tasks, showing the use of 
the fd:class and fd:new
+     (Ajax) A project work breakdown into a hierarchy of tasks, showing the 
use of the fd:class and fd:new
      widgets.
    </sample>
  </group>


Reply via email to