You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2005/09/28 12:25:30 UTC

svn commit: r292158 [3/4] - in /cocoon: blocks/ajax/ blocks/ajax/trunk/ blocks/ajax/trunk/WEB-INF/ blocks/ajax/trunk/WEB-INF/xconf/ blocks/ajax/trunk/java/ blocks/ajax/trunk/java/org/ blocks/ajax/trunk/java/org/apache/ blocks/ajax/trunk/java/org/apache...

Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/unittest.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/unittest.js?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/unittest.js (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/unittest.js Wed Sep 28 03:24:51 2005
@@ -0,0 +1,363 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//           (c) 2005 Jon Tirsen (http://www.tirsen.com)
+//           (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/)
+//
+// See scriptaculous.js for full license.
+
+// experimental, Firefox-only
+Event.simulateMouse = function(element, eventName) {
+  var options = Object.extend({
+    pointerX: 0,
+    pointerY: 0,
+    buttons: 0
+  }, arguments[2] || {});
+  var oEvent = document.createEvent("MouseEvents");
+  oEvent.initMouseEvent(eventName, true, true, document.defaultView, 
+    options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, 
+    false, false, false, false, 0, $(element));
+  
+  if(this.mark) Element.remove(this.mark);
+  this.mark = document.createElement('div');
+  this.mark.appendChild(document.createTextNode(" "));
+  document.body.appendChild(this.mark);
+  this.mark.style.position = 'absolute';
+  this.mark.style.top = options.pointerY + "px";
+  this.mark.style.left = options.pointerX + "px";
+  this.mark.style.width = "5px";
+  this.mark.style.height = "5px;";
+  this.mark.style.borderTop = "1px solid red;"
+  this.mark.style.borderLeft = "1px solid red;"
+  
+  if(this.step)
+    alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
+  
+  $(element).dispatchEvent(oEvent);
+};
+
+// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
+// You need to downgrade to 1.0.4 for now to get this working
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
+Event.simulateKey = function(element, eventName) {
+  var options = Object.extend({
+    ctrlKey: false,
+    altKey: false,
+    shiftKey: false,
+    metaKey: false,
+    keyCode: 0,
+    charCode: 0
+  }, arguments[2] || {});
+
+  var oEvent = document.createEvent("KeyEvents");
+  oEvent.initKeyEvent(eventName, true, true, window, 
+    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
+    options.keyCode, options.charCode );
+  $(element).dispatchEvent(oEvent);
+};
+
+Event.simulateKeys = function(element, command) {
+  for(var i=0; i<command.length; i++) {
+    Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
+  }
+};
+
+var Test = {}
+Test.Unit = {};
+
+// security exception workaround
+Test.Unit.inspect = function(obj) {
+  var info = [];
+
+  if(typeof obj=="string" || 
+     typeof obj=="number") {
+    return obj;
+  } else {
+    for(property in obj)
+      if(typeof obj[property]!="function")
+        info.push(property + ' => ' + 
+          (typeof obj[property] == "string" ?
+            '"' + obj[property] + '"' :
+            obj[property]));
+  }
+
+  return ("'" + obj + "' #" + typeof obj + 
+    ": {" + info.join(", ") + "}");
+}
+
+Test.Unit.Logger = Class.create();
+Test.Unit.Logger.prototype = {
+  initialize: function(log) {
+    this.log = $(log);
+    if (this.log) {
+      this._createLogTable();
+    }
+  },
+  start: function(testName) {
+    if (!this.log) return;
+    this.testName = testName;
+    this.lastLogLine = document.createElement('tr');
+    this.statusCell = document.createElement('td');
+    this.nameCell = document.createElement('td');
+    this.nameCell.appendChild(document.createTextNode(testName));
+    this.messageCell = document.createElement('td');
+    this.lastLogLine.appendChild(this.statusCell);
+    this.lastLogLine.appendChild(this.nameCell);
+    this.lastLogLine.appendChild(this.messageCell);
+    this.loglines.appendChild(this.lastLogLine);
+  },
+  finish: function(status, summary) {
+    if (!this.log) return;
+    this.lastLogLine.className = status;
+    this.statusCell.innerHTML = status;
+    this.messageCell.innerHTML = this._toHTML(summary);
+  },
+  message: function(message) {
+    if (!this.log) return;
+    this.messageCell.innerHTML = this._toHTML(message);
+  },
+  summary: function(summary) {
+    if (!this.log) return;
+    this.logsummary.innerHTML = this._toHTML(summary);
+  },
+  _createLogTable: function() {
+    this.log.innerHTML =
+    '<div id="logsummary"></div>' +
+    '<table id="logtable">' +
+    '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
+    '<tbody id="loglines"></tbody>' +
+    '</table>';
+    this.logsummary = $('logsummary')
+    this.loglines = $('loglines');
+  },
+  _toHTML: function(txt) {
+    return txt.escapeHTML().replace(/\n/g,"<br/>");
+  }
+}
+
+Test.Unit.Runner = Class.create();
+Test.Unit.Runner.prototype = {
+  initialize: function(testcases) {
+    this.options = Object.extend({
+      testLog: 'testlog'
+    }, arguments[1] || {});
+    this.options.resultsURL = this.parseResultsURLQueryParameter();
+    if (this.options.testLog) {
+      this.options.testLog = $(this.options.testLog) || null;
+    }
+    if(this.options.tests) {
+      this.tests = [];
+      for(var i = 0; i < this.options.tests.length; i++) {
+        if(/^test/.test(this.options.tests[i])) {
+          this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
+        }
+      }
+    } else {
+      if (this.options.test) {
+        this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
+      } else {
+        this.tests = [];
+        for(var testcase in testcases) {
+          if(/^test/.test(testcase)) {
+            this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"]));
+          }
+        }
+      }
+    }
+    this.currentTest = 0;
+    this.logger = new Test.Unit.Logger(this.options.testLog);
+    setTimeout(this.runTests.bind(this), 1000);
+  },
+  parseResultsURLQueryParameter: function() {
+    return window.location.search.parseQuery()["resultsURL"];
+  },
+  // Returns:
+  //  "ERROR" if there was an error,
+  //  "FAILURE" if there was a failure, or
+  //  "SUCCESS" if there was neither
+  getResult: function() {
+    var hasFailure = false;
+    for(var i=0;i<this.tests.length;i++) {
+      if (this.tests[i].errors > 0) {
+        return "ERROR";
+      }
+      if (this.tests[i].failures > 0) {
+        hasFailure = true;
+      }
+    }
+    if (hasFailure) {
+      return "FAILURE";
+    } else {
+      return "SUCCESS";
+    }
+  },
+  postResults: function() {
+    if (this.options.resultsURL) {
+      new Ajax.Request(this.options.resultsURL, 
+        { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
+    }
+  },
+  runTests: function() {
+    var test = this.tests[this.currentTest];
+    if (!test) {
+      // finished!
+      this.postResults();
+      this.logger.summary(this.summary());
+      return;
+    }
+    if(!test.isWaiting) {
+      this.logger.start(test.name);
+    }
+    test.run();
+    if(test.isWaiting) {
+      this.logger.message("Waiting for " + test.timeToWait + "ms");
+      setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
+    } else {
+      this.logger.finish(test.status(), test.summary());
+      this.currentTest++;
+      // tail recursive, hopefully the browser will skip the stackframe
+      this.runTests();
+    }
+  },
+  summary: function() {
+    var assertions = 0;
+    var failures = 0;
+    var errors = 0;
+    var messages = [];
+    for(var i=0;i<this.tests.length;i++) {
+      assertions +=   this.tests[i].assertions;
+      failures   +=   this.tests[i].failures;
+      errors     +=   this.tests[i].errors;
+    }
+    return (
+      this.tests.length + " tests, " + 
+      assertions + " assertions, " + 
+      failures   + " failures, " +
+      errors     + " errors");
+  }
+}
+
+Test.Unit.Assertions = Class.create();
+Test.Unit.Assertions.prototype = {
+  initialize: function() {
+    this.assertions = 0;
+    this.failures   = 0;
+    this.errors     = 0;
+    this.messages   = [];
+  },
+  summary: function() {
+    return (
+      this.assertions + " assertions, " + 
+      this.failures   + " failures, " +
+      this.errors     + " errors" + "\n" +
+      this.messages.join("\n"));
+  },
+  pass: function() {
+    this.assertions++;
+  },
+  fail: function(message) {
+    this.failures++;
+    this.messages.push("Failure: " + message);
+  },
+  error: function(error) {
+    this.errors++;
+    this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
+  },
+  status: function() {
+    if (this.failures > 0) return 'failed';
+    if (this.errors > 0) return 'error';
+    return 'passed';
+  },
+  assert: function(expression) {
+    var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
+    try { expression ? this.pass() : 
+      this.fail(message); }
+    catch(e) { this.error(e); }
+  },
+  assertEqual: function(expected, actual) {
+    var message = arguments[2] || "assertEqual";
+    try { (expected == actual) ? this.pass() :
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
+        '", actual "' + Test.Unit.inspect(actual) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertNotEqual: function(expected, actual) {
+    var message = arguments[2] || "assertNotEqual";
+    try { (expected != actual) ? this.pass() : 
+      this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertNull: function(obj) {
+    var message = arguments[1] || 'assertNull'
+    try { (obj==null) ? this.pass() : 
+      this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertHidden: function(element) {
+    var message = arguments[1] || 'assertHidden';
+    this.assertEqual("none", element.style.display, message);
+  },
+  assertNotNull: function(object) {
+    var message = arguments[1] || 'assertNotNull';
+    this.assert(object != null, message);
+  },
+  assertInstanceOf: function(expected, actual) {
+    var message = arguments[2] || 'assertInstanceOf';
+    try { 
+      (actual instanceof expected) ? this.pass() : 
+      this.fail(message + ": object was not an instance of the expected type"); }
+    catch(e) { this.error(e); } 
+  },
+  assertNotInstanceOf: function(expected, actual) {
+    var message = arguments[2] || 'assertNotInstanceOf';
+    try { 
+      !(actual instanceof expected) ? this.pass() : 
+      this.fail(message + ": object was an instance of the not expected type"); }
+    catch(e) { this.error(e); } 
+  },
+  _isVisible: function(element) {
+    element = $(element);
+    if(!element.parentNode) return true;
+    this.assertNotNull(element);
+    if(element.style && Element.getStyle(element, 'display') == 'none')
+      return false;
+    
+    return this._isVisible(element.parentNode);
+  },
+  assertNotVisible: function(element) {
+    this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
+  },
+  assertVisible: function(element) {
+    this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
+  }
+}
+
+Test.Unit.Testcase = Class.create();
+Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
+  initialize: function(name, test, setup, teardown) {
+    Test.Unit.Assertions.prototype.initialize.bind(this)();
+    this.name           = name;
+    this.test           = test || function() {};
+    this.setup          = setup || function() {};
+    this.teardown       = teardown || function() {};
+    this.isWaiting      = false;
+    this.timeToWait     = 1000;
+  },
+  wait: function(time, nextPart) {
+    this.isWaiting = true;
+    this.test = nextPart;
+    this.timeToWait = time;
+  },
+  run: function() {
+    try {
+      try {
+        if (!this.isWaiting) this.setup.bind(this)();
+        this.isWaiting = false;
+        this.test.bind(this)();
+      } finally {
+        if(!this.isWaiting) {
+          this.teardown.bind(this)();
+        }
+      }
+    }
+    catch(e) { this.error(e); }
+  }
+});
\ No newline at end of file

Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/unittest.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/unittest.js
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/util.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/util.js?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/util.js (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/util.js Wed Sep 28 03:24:51 2005
@@ -0,0 +1,521 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// See scriptaculous.js for full license.
+
+Object.inspect = function(obj) {
+  var info = [];
+  
+  if(typeof obj in ["string","number"]) {
+    return obj;
+  } else {
+    for(property in obj)
+      if(typeof obj[property]!="function")
+        info.push(property + ' => ' + 
+          (typeof obj[property] == "string" ?
+            '"' + obj[property] + '"' :
+            obj[property]));
+  }
+  
+  return ("'" + obj + "' #" + typeof obj + 
+    ": {" + info.join(", ") + "}");
+}
+
+// borrowed from http://www.schuerig.de/michael/javascript/stdext.js
+// Copyright (c) 2005, Michael Schuerig, michael@schuerig.de
+
+Array.flatten = function(array, excludeUndefined) {
+  if (excludeUndefined === undefined) {
+    excludeUndefined = false;
+  }
+  var result = [];
+  var len = array.length;
+  for (var i = 0; i < len; i++) {
+    var el = array[i];
+    if (el instanceof Array) {
+      var flat = el.flatten(excludeUndefined);
+      result = result.concat(flat);
+    } else if (!excludeUndefined || el != undefined) {
+      result.push(el);
+    }
+  }
+  return result;
+};
+
+if (!Array.prototype.flatten) {
+  Array.prototype.flatten = function(excludeUndefined) {
+    return Array.flatten(this, excludeUndefined);
+  }
+}
+
+String.prototype.toArray = function() {
+  var results = [];
+  for (var i = 0; i < this.length; i++)
+    results.push(this.charAt(i));
+  return results;
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Builder = {
+  node: function(elementName) {
+    var element = document.createElement('div');
+    element.innerHTML = 
+      "<" + elementName + "></" + elementName + ">";
+
+    // attributes (or text)
+    if(arguments[1])
+      if(this._isStringOrNumber(arguments[1]) ||
+        (arguments[1] instanceof Array)) {
+          this._children(element.firstChild, arguments[1]);
+        } else {
+          var attrs = this._attributes(arguments[1]);
+          if(attrs.length) 
+            element.innerHTML = "<" +elementName + " " +
+              attrs + "></" + elementName + ">";
+        } 
+
+    // text, or array of children
+    if(arguments[2])
+      this._children(element.firstChild, arguments[2]);
+
+     return element.firstChild;
+  },
+  _text: function(text) {
+     return document.createTextNode(text);
+  },
+  _attributes: function(attributes) {
+    var attrs = [];
+    for(attribute in attributes)
+      attrs.push((attribute=='className' ? 'class' : attribute) +
+          '="' + attributes[attribute].toString().escapeHTML() + '"');
+    return attrs.join(" ");
+  },
+  _children: function(element, children) {
+    if(typeof children=='object') { // array can hold nodes and text
+      children.flatten().each( function(e) {
+        if(typeof e=='object')
+          element.appendChild(e)
+        else
+          if(Builder._isStringOrNumber(e))
+            element.appendChild(Builder._text(e));
+      });
+    } else
+      if(Builder._isStringOrNumber(children)) 
+         element.appendChild(Builder._text(children));
+  },
+  _isStringOrNumber: function(param) {
+    return(typeof param=='string' || typeof param=='number');
+  }
+}
+
+/* ------------- element ext -------------- */
+
+// adapted from http://dhtmlkitchen.com/learn/js/setstyle/index4.jsp
+// note: Safari return null on elements with display:none; see http://bugzilla.opendarwin.org/show_bug.cgi?id=4125
+// instead of "auto" values returns null so it's easier to use with || constructs
+
+String.prototype.camelize = function() {
+  var oStringList = this.split('-');
+  if(oStringList.length == 1)    
+    return oStringList[0];
+  var ret = this.indexOf("-") == 0 ? 
+    oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) : oStringList[0];
+  for(var i = 1, len = oStringList.length; i < len; i++){
+    var s = oStringList[i];
+    ret += s.charAt(0).toUpperCase() + s.substring(1)
+  }
+  return ret;
+}
+
+Element.getStyle = function(element, style) {
+  element = $(element);
+  var value = element.style[style.camelize()];
+  if(!value)
+    if(document.defaultView && document.defaultView.getComputedStyle) {
+      var css = document.defaultView.getComputedStyle(element, null);
+      value = (css!=null) ? css.getPropertyValue(style) : null;
+    } else if(element.currentStyle) {
+      value = element.currentStyle[style.camelize()];
+    }
+  
+  // If top, left, bottom, or right values have been queried, return "auto" for consistency resaons 
+  // if position is "static", as Opera (and others?) returns the pixel values relative to root element 
+  // (or positioning context?)
+  if (window.opera && (style == "left" || style == "top" || style == "right" || style == "bottom"))
+    if (Element.getStyle(element, "position") == "static") value = "auto";
+    
+  if(value=='auto') value = null;
+  return value;
+}
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+  color = "#";
+  if(this.slice(0,4) == "rgb(") {
+    var cols = this.slice(4,this.length-1).split(',');
+    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+  } else {
+    if(this.slice(0,1) == '#') {
+      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+      if(this.length==7) color = this.toLowerCase();
+    }
+  }
+  return(color.length==7 ? color : (arguments[0] || this));
+}
+
+Element.makePositioned = function(element) {
+  element = $(element);
+  var pos = Element.getStyle(element, 'position');
+  if(pos =='static' || !pos) {
+    element._madePositioned = true;
+    element.style.position = "relative";
+    // Opera returns the offset relative to the positioning context, when an element is position relative 
+    // but top and left have not been defined
+    if (window.opera){
+      element.style.top = 0;
+      element.style.left = 0;
+    }  
+  }
+}
+  
+Element.undoPositioned = function(element) {
+  element = $(element);
+  if(typeof element._madePositioned != "undefined"){
+    element._madePositioned = undefined;
+    element.style.position = "";
+    element.style.top = "";
+    element.style.left = "";
+    element.style.bottom = "";
+    element.style.right = "";	  
+  }
+}
+
+Element.makeClipping = function(element) {
+  element = $(element);
+  if (typeof element._overflow != 'undefined') return;
+  element._overflow = element.style.overflow;
+  if((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') element.style.overflow = 'hidden';
+}
+
+Element.undoClipping = function(element) {
+  element = $(element);
+  if (typeof element._overflow == 'undefined') return;
+  element.style.overflow = element._overflow;
+  element._overflow = undefined;
+}
+
+Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
+  var children = $(element).childNodes;
+  var text     = "";
+  var classtest = new RegExp("^([^ ]+ )*" + ignoreclass+ "( [^ ]+)*$","i");
+
+  for (var i = 0; i < children.length; i++) {
+    if(children[i].nodeType==3) {
+      text+=children[i].nodeValue;
+    } else {
+      if((!children[i].className.match(classtest)) && children[i].hasChildNodes())
+        text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass);
+    }
+  }
+
+  return text;
+}
+
+Element.setContentZoom = function(element, percent) {
+  element = $(element);
+  element.style.fontSize = (percent/100) + "em";  
+  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+}
+
+Element.getOpacity = function(element){
+  return parseFloat(Element.getStyle(element, "opacity") || '1');
+}
+
+Element.setOpacity = function(element, value){
+  element= $(element);
+  var els = element.style;
+  if (value == 1){
+    els.opacity = '0.999999';
+    els.filter  = null;
+  } else {
+    if(value < 0.00001) value = 0;
+    els.opacity = value;
+    els.filter  = "alpha(opacity:"+value*100+")";
+  }  
+}
+
+Element.getInlineOpacity = function(element){
+  element= $(element);
+  var op;
+  op = element.style.opacity;
+  if (typeof op != "undefined" && op != "") return op;
+  return "";
+}
+
+Element.setInlineOpacity = function(element, value){
+  element= $(element);
+  var els = element.style;
+  els.opacity = value;
+}
+
+Element.getDimensions = function(element){
+  element = $(element);
+  // All *Width and *Height properties give 0 on elements with display "none", so enable the element temporarily
+  if (element.style.display == "none"){
+    var originalVisibility = element.style.visibility;
+    var originalPosition = element.style.position;
+    element.style.visibility = "hidden";
+    element.style.position = "absolute";
+    element.style.display = "";
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    element.style.display = "none";
+    element.style.position = originalPosition;
+    element.style.visibility = originalVisibility;
+    return {width: originalWidth, height: originalHeight};    
+  } else {
+    return {width: element.offsetWidth, height: element.offsetHeight};
+  }
+} 
+
+/*--------------------------------------------------------------------------*/
+
+Position.positionedOffset = function(element) {
+  var valueT = 0, valueL = 0;
+  do {
+    valueT += element.offsetTop  || 0;
+    valueL += element.offsetLeft || 0;
+    element = element.offsetParent;
+    if (element) {
+      p = Element.getStyle(element,'position');
+      if(p == 'relative' || p == 'absolute') break;
+    }
+  } while (element);
+  return [valueL, valueT];
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely positioned.
+// for performance reasons, we create a specialized version of Position.cumulativeOffset for
+// KHTML/WebKit only
+
+if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+  Position.cumulativeOffset = function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      
+      if (element.offsetParent==document.body) 
+        if (Element.getStyle(element,'position')=='absolute') break;
+        
+      element = element.offsetParent;
+    } while (element);
+    return [valueL, valueT];
+  }
+}
+
+Position.page = function(forElement) {
+  var valueT = 0, valueL = 0;
+
+  var element = forElement;
+  do {
+    valueT += element.offsetTop  || 0;
+    valueL += element.offsetLeft || 0;
+
+    // Safari fix
+    if (element.offsetParent==document.body)
+      if (Element.getStyle(element,'position')=='absolute') break;
+      
+  } while (element = element.offsetParent);
+
+  element = forElement;
+  do {
+    valueT -= element.scrollTop  || 0;
+    valueL -= element.scrollLeft || 0;    
+  } while (element = element.parentNode);
+
+  return [valueL, valueT];
+}
+
+// elements with display:none don't return an offsetParent, 
+// fall back to  manual calculation
+Position.offsetParent = function(element) {
+  if(element.offsetParent) return element.offsetParent;
+  if(element == document.body) return element;
+  
+  while ((element = element.parentNode) && element != document.body)
+    if (Element.getStyle(element,'position')!='static')
+      return element;
+  
+  return document.body;
+}
+
+Position.clone = function(source, target) {
+  var options = Object.extend({
+    setLeft:    true,
+    setTop:     true,
+    setWidth:   true,
+    setHeight:  true,
+    offsetTop:  0,
+    offsetLeft: 0
+  }, arguments[2] || {})
+  
+  // find page position of source
+  source = $(source);
+  var p = Position.page(source);
+
+  // find coordinate system to use
+  target = $(target);
+  var delta = [0, 0];
+  var parent = null;
+  // delta [0,0] will do fine with position: fixed elements, 
+  // position:absolute needs offsetParent deltas
+  if (Element.getStyle(target,'position') == 'absolute') {
+    parent = Position.offsetParent(target);
+    delta = Position.page(parent);
+  }
+  
+  // correct by body offsets (fixes Safari)
+  if (parent==document.body) {
+    delta[0] -= document.body.offsetLeft;
+    delta[1] -= document.body.offsetTop; 
+  }
+
+  // set position
+  if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + "px";
+  if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + "px";
+  if(options.setWidth)  target.style.width = source.offsetWidth + "px";
+  if(options.setHeight) target.style.height = source.offsetHeight + "px";
+}
+
+Position.absolutize = function(element) {
+  element = $(element);
+  if(element.style.position=='absolute') return;
+  Position.prepare();
+
+  var offsets = Position.positionedOffset(element);
+  var top     = offsets[1];
+  var left    = offsets[0];
+  var width   = element.clientWidth;
+  var height  = element.clientHeight;
+
+  element._originalLeft   = left - parseFloat(element.style.left  || 0);
+  element._originalTop    = top  - parseFloat(element.style.top || 0);
+  element._originalWidth  = element.style.width;
+  element._originalHeight = element.style.height;
+
+  element.style.position = 'absolute';
+  element.style.top    = top + 'px';;
+  element.style.left   = left + 'px';;
+  element.style.width  = width + 'px';;
+  element.style.height = height + 'px';;
+}
+
+Position.relativize = function(element) {
+  element = $(element);
+  if(element.style.position=='relative') return;
+  Position.prepare();
+
+  element.style.position = 'relative';
+  var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
+  var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+  element.style.top    = top + 'px';
+  element.style.left   = left + 'px';
+  element.style.height = element._originalHeight;
+  element.style.width  = element._originalWidth;
+}
+
+/*--------------------------------------------------------------------------*/
+
+Element.Class = {
+    // Element.toggleClass(element, className) toggles the class being on/off
+    // Element.toggleClass(element, className1, className2) toggles between both classes,
+    //   defaulting to className1 if neither exist
+    toggle: function(element, className) {
+      if(Element.Class.has(element, className)) {
+        Element.Class.remove(element, className);
+        if(arguments.length == 3) Element.Class.add(element, arguments[2]);
+      } else {
+        Element.Class.add(element, className);
+        if(arguments.length == 3) Element.Class.remove(element, arguments[2]);
+      }
+    },
+
+    // gets space-delimited classnames of an element as an array
+    get: function(element) {
+      element = $(element);
+      return element.className.split(' ');
+    },
+
+    // functions adapted from original functions by Gavin Kistner
+    remove: function(element) {
+      element = $(element);
+      var regEx;
+      for(var i = 1; i < arguments.length; i++) {
+        regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)", 'g');
+        element.className = element.className.replace(regEx, '')
+      }
+    },
+
+    add: function(element) {
+      element = $(element);
+      for(var i = 1; i < arguments.length; i++) {
+        Element.Class.remove(element, arguments[i]);
+        element.className += (element.className.length > 0 ? ' ' : '') + arguments[i];
+      }
+    },
+
+    // returns true if all given classes exist in said element
+    has: function(element) {
+      element = $(element);
+      if(!element || !element.className) return false;
+      var regEx;
+      for(var i = 1; i < arguments.length; i++) {
+        if((typeof arguments[i] == 'object') && 
+          (arguments[i].constructor == Array)) {
+          for(var j = 0; j < arguments[i].length; j++) {
+            regEx = new RegExp("(^|\\s)" + arguments[i][j] + "(\\s|$)");
+            if(!regEx.test(element.className)) return false;
+          }
+        } else {
+          regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)");
+          if(!regEx.test(element.className)) return false;
+        }
+      }
+      return true;
+    },
+
+    // expects arrays of strings and/or strings as optional paramters
+    // Element.Class.has_any(element, ['classA','classB','classC'], 'classD')
+    has_any: function(element) {
+      element = $(element);
+      if(!element || !element.className) return false;
+      var regEx;
+      for(var i = 1; i < arguments.length; i++) {
+        if((typeof arguments[i] == 'object') && 
+          (arguments[i].constructor == Array)) {
+          for(var j = 0; j < arguments[i].length; j++) {
+            regEx = new RegExp("(^|\\s)" + arguments[i][j] + "(\\s|$)");
+            if(regEx.test(element.className)) return true;
+          }
+        } else {
+          regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)");
+          if(regEx.test(element.className)) return true;
+        }
+      }
+      return false;
+    },
+
+    childrenWith: function(element, className) {
+      var children = $(element).getElementsByTagName('*');
+      var elements = new Array();
+
+      for (var i = 0; i < children.length; i++)
+        if (Element.Class.has(children[i], className))
+          elements.push(children[i]);
+
+      return elements;
+    }
+}
\ No newline at end of file

Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/util.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/ajax/resources/js/util.js
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java (added)
+++ cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.cocoon.transformation;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.util.Deprecation;
+import org.xml.sax.SAXException;
+
+/**
+ * @deprectated use {@link org.apache.cocoon.ajax.BrowserUpdateTransformer}
+ * @version $Id$
+ */
+public class BrowserUpdateTransformer extends org.apache.cocoon.ajax.BrowserUpdateTransformer {
+
+    public static final String AJAXMODE_PARAM = "cocoon-ajax";
+    
+    public static final String BU_NSURI = "http://apache.org/cocoon/browser-update/1.0";
+    
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
+        Deprecation.logger.warn("Please use the BrowserUpdateTransformer in the Ajax block");
+        super.setup(resolver, objectModel, src, par);
+    }
+}

Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/pom.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/pom.xml?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/pom.xml (added)
+++ cocoon/blocks/ajax/trunk/pom.xml Wed Sep 28 03:24:51 2005
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2005 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--+
+    | @version $Id$
+    |
+    +-->
+<project>
+  <parent>
+    <groupId>apache-cocoon</groupId>
+    <artifactId>cocoon</artifactId>
+    <version>2.2-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>apache-cocoon</groupId>
+  <artifactId>cocoon-ajax</artifactId>
+  <version>2.2-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <build>
+    <sourceDirectory>java</sourceDirectory>
+    <testSourceDirectory>test</testSourceDirectory>
+    <resources>
+      <resource>
+        <directory>java</directory>
+        <excludes>
+          <exclude>**/*.java</exclude>
+        </excludes>
+      </resource>
+    </resources>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>apache-cocoon</groupId>
+      <artifactId>cocoon-core</artifactId>
+      <version>2.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>apache-cocoon</groupId>
+      <artifactId>cocoon-test-core</artifactId>
+      <version>2.2-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>

Propchange: cocoon/blocks/ajax/trunk/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/pom.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/samples/ajax.xsamples
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/samples/ajax.xsamples?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/samples/ajax.xsamples (added)
+++ cocoon/blocks/ajax/trunk/samples/ajax.xsamples Wed Sep 28 03:24:51 2005
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<xsamples xpath="/samples" unless="group[@name='Ajax Block']">
+
+  <group name="Ajax">
+    <sample name="Ajax Block" href="ajax/">
+      Ajax block examples. This block is also used by <a href="forms/">Cocoon Forms</a>.
+    </sample>
+  </group>
+
+</xsamples>

Added: cocoon/blocks/ajax/trunk/samples/display-suggestions.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/samples/display-suggestions.xml?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/samples/display-suggestions.xml (added)
+++ cocoon/blocks/ajax/trunk/samples/display-suggestions.xml Wed Sep 28 03:24:51 2005
@@ -0,0 +1,12 @@
+<ul class="suggestions" xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
+  <jx:forEach var="suggestion" items="${suggestions}">
+    <jx:choose>
+      <jx:when test="${suggestion == selection}">
+        <li class="selected">${suggestion}</li>
+      </jx:when>
+      <jx:otherwise>
+        <li>${suggestion}</li>
+      </jx:otherwise>
+    </jx:choose>
+  </jx:forEach>
+</ul>
\ No newline at end of file

Propchange: cocoon/blocks/ajax/trunk/samples/display-suggestions.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/samples/display-suggestions.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/samples/file-browser-suggest.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/samples/file-browser-suggest.xml?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/samples/file-browser-suggest.xml (added)
+++ cocoon/blocks/ajax/trunk/samples/file-browser-suggest.xml Wed Sep 28 03:24:51 2005
@@ -0,0 +1,7 @@
+<ul class="contacts" xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
+  <jx:set var="root" value="#{java.io.File.new('/Users/sylvain/')}"/>
+  <jx:set var="file" value="
+  <jx:forEach var="child" items="${file.list()}">
+    <li>${child}</li>
+  </jx:forEach>
+</ul>
\ No newline at end of file

Propchange: cocoon/blocks/ajax/trunk/samples/file-browser-suggest.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/samples/file-browser-suggest.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/samples/file-browser.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/samples/file-browser.xml?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/samples/file-browser.xml (added)
+++ cocoon/blocks/ajax/trunk/samples/file-browser.xml Wed Sep 28 03:24:51 2005
@@ -0,0 +1,43 @@
+<page>
+  <title>Cocoon suggests</title>
+  <!-- include ajax scripts -->
+  <script type="text/javascript" src="resources/ajax/js/cocoon-ajax.js"/>
+  <style type="text/css">
+    /* autocompletion popup */
+    div.auto_complete {
+      height:200px;
+      overflow:scroll;
+      background-color:white;
+      border:1px solid #888;
+      margin:0px;
+      padding:0px;
+    }
+    /* autocompletion items */
+    ul.suggestions  {
+      list-style-type: none;
+      margin:0px;
+      padding:0px;
+    }
+    /* selected autocompletion item */
+    ul.suggestions li.selected { background-color: #ffb; }
+
+  </style>
+
+<content>
+  <p>This sample shows autocompletion in action. The input below expects a filename in Cocoon's "samples" directory.
+  Start by either typing some letter or a '/' and see what happens...</p>
+  
+  <form action="">
+    Please chose a file in the samples directory:<br/>
+    <input  autocomplete="off" id="filename" name="filename" size="50"/>
+    <div class="auto_complete" id="update"/>
+    <script type="text/javascript">
+      // Parameters are [id of the input], [id of the suggestion div], [url to be called to get suggestions]
+      new Ajax.Autocompleter('filename', 'update', 'file-browser-suggest');
+    </script>
+  </form>
+  
+  <p><em>Note: there's no submit button on this form as we don't really care about actually using
+         that information...</em></p>
+</content>
+</page>
\ No newline at end of file

Propchange: cocoon/blocks/ajax/trunk/samples/file-browser.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/samples/file-browser.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/samples/flow.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/samples/flow.js?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/samples/flow.js (added)
+++ cocoon/blocks/ajax/trunk/samples/flow.js Wed Sep 28 03:24:51 2005
@@ -0,0 +1,52 @@
+/*
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+*/
+
+/**
+ * @version $Id$
+ */
+var resolver = cocoon.getComponent(org.apache.excalibur.source.SourceResolver.ROLE);
+
+function fileBrowserSuggest() {
+    var prefix = "context://samples/";
+    var filename = cocoon.request.getParameter("filename");
+    
+    var src = resolver.resolveURI(prefix + filename);
+    var suggestions = new java.util.ArrayList();
+    if (src.exists() && src.isCollection()) {
+        var children = src.children;
+        if (!filename.endsWith('/')) filename += "/";
+        suggestions.add(filename);
+        for (var i = 0; i < children.size(); i++) {
+            suggestions.add(filename + children.get(i).getName());
+        }
+    } else {
+        var parent = src.parent;
+        var children = parent.children;
+        if (filename.indexOf('/') != -1) {
+            filename = filename.substring(0, filename.lastIndexOf('/') + 1);
+        } else {
+            filename = "";
+        }
+        for (var i = 0; i < children.size(); i++) {
+            var child = children.get(i);
+            if (child.name.startsWith(src.name))
+                suggestions.add(filename + children.get(i).getName());
+        }
+    }
+    
+    cocoon.sendPage("display-suggestions", { suggestions: suggestions, selection: cocoon.request.getParameter("filename")});
+    
+}
\ No newline at end of file

Propchange: cocoon/blocks/ajax/trunk/samples/flow.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/samples/flow.js
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/samples/sitemap.xmap
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/samples/sitemap.xmap?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/samples/sitemap.xmap (added)
+++ cocoon/blocks/ajax/trunk/samples/sitemap.xmap Wed Sep 28 03:24:51 2005
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<!--
+  @version $Id$
+  -->
+<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
+
+ <map:resources>
+   <!-- this will later become a virtual transformer -->
+   <map:resource name="simple-page2html">
+     <map:transform src="context://samples/common/style/xsl/html/simple-page2html.xsl">
+       <map:parameter name="contextPath" value="{request:contextPath}"/>
+       <map:parameter name="servletPath" value="{request:servletPath}"/>
+       <map:parameter name="sitemapURI" value="{request:sitemapURI}"/>
+       <map:parameter name="file" value="{file}"/>
+       <map:parameter name="remove" value="{../0}"/>
+     </map:transform> 
+   </map:resource>
+ </map:resources>
+
+<map:flow>
+  <map:script src="flow.js"/>
+</map:flow>
+
+<map:pipelines>
+  <map:pipeline>
+     <map:match pattern="">
+      <map:generate src="welcome.xml"/>
+      <map:transform src="context://samples/common/style/xsl/html/simple-samples2html.xsl">
+         <map:parameter name="contextPath" value="{request:contextPath}"/>
+      </map:transform>
+      <map:serialize/>
+     </map:match>
+     
+     <!-- Main page of the file browser -->
+     <map:match pattern="file-browser">
+       <map:generate type="jx" src="file-browser.xml"/>
+       <map:call resource="simple-page2html">
+         <map:param name="file" value="file-browser.xml"/>
+       </map:call>
+       <map:serialize type="html"/>
+     </map:match>
+     
+     <!--  Ajax callback to get suggestions -->
+     <map:match pattern="file-browser-suggest">
+       <map:call function="fileBrowserSuggest"/>
+     </map:match>
+     
+     <!-- Called by the fileBrowserSuggest function -->
+     <map:match pattern="display-suggestions">
+       <map:generate type="jx" src="display-suggestions.xml"/>
+       <map:serialize type="xml"/>
+     </map:match>
+     
+     <!-- Generic pipeline to load resources in jars -->
+     <map:match pattern="resources/*/**">
+       <map:read src="resource://org/apache/cocoon/{1}/resources/{2}"/>
+     </map:match>
+  </map:pipeline>
+</map:pipelines>
+</map:sitemap>
\ No newline at end of file

Propchange: cocoon/blocks/ajax/trunk/samples/sitemap.xmap
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/samples/sitemap.xmap
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/ajax/trunk/samples/welcome.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/ajax/trunk/samples/welcome.xml?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/ajax/trunk/samples/welcome.xml (added)
+++ cocoon/blocks/ajax/trunk/samples/welcome.xml Wed Sep 28 03:24:51 2005
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--
+  @version $Id$
+-->
+<samples name="Ajax Block Samples" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <group name="Back">
+  <sample name="Back" href="../..">to Cocoon Samples main page</sample>
+  <sample name="Back" href="..">to Cocoon Blocks Samples main page</sample>
+ </group>
+
+ <group name="Basic Samples">
+  <sample name="File explorer" href="file-browser">Browse through the files in Cocoon's sample directory with Ajax autocompletion.</sample>
+ </group>
+</samples>

Propchange: cocoon/blocks/ajax/trunk/samples/welcome.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/ajax/trunk/samples/welcome.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/flow/javascript/Form.js Wed Sep 28 03:24:51 2005
@@ -118,6 +118,9 @@
 
     var comingBack = false;
     var bookmark = cocoon.createWebContinuation(ttl);
+    
+    // Attach the form to the continuation so that we can access by just knowing the continuation id
+    bookmark.setAttribute("form", this.form);
 
     if (comingBack) {
         // We come back to the bookmark: process the form
@@ -162,7 +165,7 @@
                 if (httpResponse) {
                     httpResponse.setContentType("text/xml");
                     var text = "<?xml version='1.0'?><bu:document xmlns:bu='" +
-                        org.apache.cocoon.transformation.BrowserUpdateTransformer.BU_NSURI +
+                        org.apache.cocoon.ajax.BrowserUpdateTransformer.BU_NSURI +
                         "'></bu:document>";
                     httpResponse.writer.print(text);
                 } else {

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractDatatypeWidgetDefinitionBuilder.java Wed Sep 28 03:24:51 2005
@@ -76,31 +76,40 @@
         // when definition are managed like components.
         definition.service(this.serviceManager);
 
-        Element selectionListElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, "selection-list");
+        SelectionList list = buildSelectionList(widgetElement, definition, "selection-list");
+        if (list != null) {
+            definition.setSelectionList(list);
+        }
+    }
+    
+    protected SelectionList buildSelectionList(
+            Element widgetElement, AbstractDatatypeWidgetDefinition definition, String name) throws Exception {
+        Element selectionListElement = DomHelper.getChildElement(widgetElement, Constants.DEFINITION_NS, name);
         
         if(selectionListElement != null && definition.getDatatype() == null)
-        	throw new Exception("A widget with a selection list always requires a datatype as well! (at "+DomHelper.getLocation(selectionListElement)+" )");
+            throw new Exception("A widget with a selection list always requires a datatype as well! (at "+DomHelper.getLocation(selectionListElement)+" )");
         
-        if (selectionListElement != null) {
-            // Get an appropriate list builder
-            ServiceSelector builderSelector = (ServiceSelector)this.serviceManager.lookup(SelectionListBuilder.ROLE + "Selector");
-            SelectionListBuilder builder = null;
-            try {
-                // listType can be null, meaning we will use the default selection list
-                String listType = selectionListElement.getAttribute("type");
-                if ("".equals(listType)) {
-                    listType = null;
-                }
+        if (selectionListElement == null)
+            return null;
 
-                builder = (SelectionListBuilder)builderSelector.select(listType);
-                SelectionList list = builder.build(selectionListElement, definition.getDatatype());
-                definition.setSelectionList(list);
-            } finally {
-                if (builder != null) {
-                    builderSelector.release(builder);
-                }
-                this.serviceManager.release(builderSelector);
+        // Get an appropriate list builder
+        ServiceSelector builderSelector = (ServiceSelector)this.serviceManager.lookup(SelectionListBuilder.ROLE + "Selector");
+        SelectionListBuilder builder = null;
+        try {
+            // listType can be null, meaning we will use the default selection list
+            String listType = selectionListElement.getAttribute("type");
+            if ("".equals(listType)) {
+                listType = null;
             }
+
+            builder = (SelectionListBuilder)builderSelector.select(listType);
+            return builder.build(selectionListElement, definition.getDatatype());
+
+        } finally {
+            if (builder != null) {
+                builderSelector.release(builder);
+            }
+            this.serviceManager.release(builderSelector);
         }
     }
 }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/AbstractWidget.java Wed Sep 28 03:24:51 2005
@@ -484,6 +484,10 @@
 
             generateDisplayData(contentHandler);
 
+            if (locale == null) {
+                locale = getForm().getLocale();
+            }
+
             generateItemSaxFragment(contentHandler, locale);
 
             contentHandler.endElement(Constants.INSTANCE_NS, element, Constants.INSTANCE_PREFIX_COLON + element);

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/Field.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/Field.java?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/Field.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/Field.java Wed Sep 28 03:24:51 2005
@@ -502,6 +502,10 @@
     public void setSelectionList(Object model, String valuePath, String labelPath) {
         setSelectionList(getFieldDefinition().buildSelectionListFromModel(model, valuePath, labelPath));
     }
+    
+    public SelectionList getSuggestionList() {
+        return getFieldDefinition().getSuggestionList();
+    }
 
     public Datatype getDatatype() {
         return getFieldDefinition().getDatatype();

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java Wed Sep 28 03:24:51 2005
@@ -15,6 +15,8 @@
  */
 package org.apache.cocoon.forms.formmodel;
 
+import org.apache.cocoon.forms.datatype.SelectionList;
+
 /**
  * The {@link WidgetDefinition} part of a Field widget, see {@link Field} for more information.
  * 
@@ -22,6 +24,7 @@
  */
 public class FieldDefinition extends AbstractDatatypeWidgetDefinition {
     private boolean required;
+    private SelectionList suggestionList;
 
     public Widget createInstance() {
         Field field = new Field(this);
@@ -32,16 +35,18 @@
      * initialize this definition with the other, sort of like a copy constructor
      */
     public void initializeFrom(WidgetDefinition definition) throws Exception {
-    	super.initializeFrom(definition);
-    	
-    	if(definition instanceof FieldDefinition) {
-    		FieldDefinition other = (FieldDefinition)definition;
-    		
-    		this.required = other.required;
-    		
-    	} else {
-    		throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
-    	}
+        if(!(definition instanceof FieldDefinition)) {
+            throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+        }
+        super.initializeFrom(definition);
+        
+        FieldDefinition other = (FieldDefinition)definition;
+        
+        this.required = other.required;
+        
+        if (suggestionList == null) {
+            suggestionList = other.getSuggestionList();
+        }
     }
 
     public boolean isRequired() {
@@ -51,5 +56,13 @@
     public void setRequired(boolean required) {
         checkMutable();
         this.required = required;
+    }
+
+    public SelectionList getSuggestionList() {
+        return this.suggestionList;
+    }
+
+    public void setSuggestionList(SelectionList list) {
+        this.suggestionList = list;
     }
 }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java Wed Sep 28 03:24:51 2005
@@ -15,6 +15,8 @@
  */
 package org.apache.cocoon.forms.formmodel;
 
+import org.apache.cocoon.forms.Constants;
+import org.apache.cocoon.forms.datatype.SelectionList;
 import org.apache.cocoon.forms.util.DomHelper;
 import org.w3c.dom.Element;
 
@@ -38,5 +40,10 @@
         // parse "@required"
         if(widgetElement.hasAttribute("required"))
             definition.setRequired(DomHelper.getAttributeAsBoolean(widgetElement, "required", false));
+        
+        SelectionList list = buildSelectionList(widgetElement, definition, "suggestion-list");
+        if (list != null) {
+            definition.setSuggestionList(list);
+        }
     }
 }

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java Wed Sep 28 03:24:51 2005
@@ -16,13 +16,14 @@
 
 package org.apache.cocoon.forms.generation;
 
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.cocoon.ajax.BrowserUpdateTransformer;
 import org.apache.cocoon.environment.Request;
 import org.apache.cocoon.forms.Constants;
 import org.apache.cocoon.forms.FormsRuntimeException;
@@ -32,7 +33,6 @@
 import org.apache.cocoon.forms.formmodel.tree.Tree;
 import org.apache.cocoon.forms.formmodel.tree.TreeWalker;
 import org.apache.cocoon.forms.validation.ValidationError;
-import org.apache.cocoon.transformation.BrowserUpdateTransformer;
 import org.apache.cocoon.xml.AbstractXMLPipe;
 import org.apache.cocoon.xml.AttributesImpl;
 import org.apache.cocoon.xml.XMLConsumer;
@@ -40,6 +40,7 @@
 import org.apache.commons.collections.ArrayStack;
 import org.apache.commons.lang.BooleanUtils;
 import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
 /**
@@ -58,7 +59,6 @@
     private boolean ajaxTemplate;
     private Set updatedWidgets;
     private Set childUpdatedWidgets;
-    private Set parentUpdatedWidgets;
 
     /**
      * Builds and helper object, given the generator's consumer.
@@ -75,7 +75,6 @@
         this.request = request;
         this.ajaxRequest = request.getParameter("cocoon-ajax") != null;
     }
-    
 
     public Form getForm(Form form, String attributeName) {
         Form returnForm = form;
@@ -93,7 +92,6 @@
         
         this.updatedWidgets = form.getUpdatedWidgetIds();
         this.childUpdatedWidgets = form.getChildUpdatedWidgetIds();
-        this.parentUpdatedWidgets = new HashSet();
         
         // build attributes
         AttributesImpl attrs = new AttributesImpl();
@@ -272,11 +270,11 @@
      * @param locale
      * @throws SAXException
      */
-    public void generateWidget(Widget widget, Locale locale) throws SAXException {
+    public void generateWidget(Widget widget, Map arguments) throws SAXException {
         // Needs to be buffered
-        RootBufferingPipe pipe = new RootBufferingPipe(this.cocoonConsumer);
+        RootBufferingPipe pipe = new RootBufferingPipe(this.cocoonConsumer, arguments);
         this.pipeStack.push(pipe);
-        widget.generateSaxFragment(pipe, locale);
+        widget.generateSaxFragment(pipe, null);
     }
 
     /**
@@ -365,13 +363,50 @@
             this.cocoonConsumer.endElement(Constants.INSTANCE_NS, "placeholder", Constants.INSTANCE_PREFIX_COLON + "placeholder");
             this.cocoonConsumer.endElement(BrowserUpdateTransformer.BU_NSURI, "replace", "bu:replace");
         }
-        
+
         return visible;
     }
     
     public boolean isModified(Widget widget) {
         return this.updatedWidgets.contains(widget.getRequestParameterName());
     }
+    
+    public boolean generateStyling(Map attributes) throws SAXException {
+        return generateStyling(this.cocoonConsumer, attributes);
+    }
+
+    /**
+     * Generate a <code>&lt;fi:styling&gt;</code> element holding the attributes of a <code>ft:*</code>
+     * element that are in the "fi:" namespace.
+     * 
+     * @param attributes the template instruction attributes
+     * @return true if a <code>&lt;fi:styling&gt;</code> was produced
+     * @throws SAXException
+     */
+    public static boolean generateStyling(ContentHandler handler, Map attributes) throws SAXException {
+        AttributesImpl attr = null;
+        Iterator entries = attributes.entrySet().iterator();
+        while(entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            String key = (String)entry.getKey();
+            
+            // FIXME: JXTG only gives the local name of attributes, so we can't distinguish namespaces...            
+            if (!"id".equals(key) && !"widget-id".equals(key)) {
+                if (attr == null)
+                    attr = new AttributesImpl();
+                attr.addCDATAAttribute(key, (String)entry.getValue());
+            }
+        }
+        
+        if (attr != null) {
+            // There were some styling attributes
+            handler.startElement(Constants.INSTANCE_NS, "styling", Constants.INSTANCE_PREFIX_COLON + "styling", attr);
+            handler.endElement(Constants.INSTANCE_NS, "styling", Constants.INSTANCE_PREFIX_COLON + "styling");
+            return true;
+        } else {
+            return false;
+        }
+    }
 
     /**
      * A SAX pipe that buffers the <code>endElement()</code> event of the root element.
@@ -385,22 +420,37 @@
         private String rootUri;
         private String rootLoc;
         private String rootRaw;
+        private Map arguments;
+        private boolean forbidStyling = false;
 
         public RootBufferingPipe(XMLConsumer next) {
+            this(next, Collections.EMPTY_MAP);
+        }
+
+        public RootBufferingPipe(XMLConsumer next, Map arguments) {
             this.setConsumer(next);
+            this.arguments = arguments;
         }
 
         public void startElement(String uri, String loc, String raw, Attributes a)
         throws SAXException {
+            super.startElement(uri, loc, raw, a);
             if (depth == 0) {
                 // Root element: keep its description
                 this.rootUri = uri;
                 this.rootLoc = loc;
                 this.rootRaw = raw;
+                
+                // And produce fi:styling from attributes
+                this.forbidStyling = generateStyling(this.contentHandler, arguments);
+            }
+            
+            if (depth == 1 && forbidStyling &&
+                uri.equals(Constants.INSTANCE_NS) && loc.equals("styling")) {
+                throw new SAXException("Cannot use 'fi:*' attributes and <fi:styling> at the same time");
             }
 
             depth++;
-            super.startElement(uri, loc, raw, a);
         }
 
         public void endElement(String uri, String loc, String raw)

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SelectionListFilter.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SelectionListFilter.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SelectionListFilter.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SelectionListFilter.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+package org.apache.cocoon.forms.generation;
+
+import org.apache.cocoon.forms.Constants;
+import org.apache.cocoon.xml.AbstractXMLPipe;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A filter for selection lists, that keeps only those items that start with a given filter value.
+ *
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class SelectionListFilter extends AbstractXMLPipe {
+    
+    private ContentHandler next;
+    private int filterDepth = 0;
+    private int depth = 0;
+    private String filterValue;
+    private static final ContentHandler NULL_HANDLER = new DefaultHandler();
+
+    public SelectionListFilter(String filterValue, ContentHandler next) {
+        this.next = next;
+        this.setContentHandler(next);
+        this.filterValue = filterValue;
+    }
+    
+    public void startElement(String uri, String loc, String raw, Attributes a) throws SAXException {
+        depth++;
+
+        if (uri.equals(Constants.INSTANCE_NS) && loc.equals("item")) {
+            String value = a.getValue("value");
+            if (!value.startsWith(this.filterValue)) {
+                filterDepth = depth;
+                setContentHandler(NULL_HANDLER);
+            }
+        }
+
+        super.startElement(uri, loc, raw, a);
+    }
+    
+    public void endElement(String uri, String loc, String raw) throws SAXException {
+        super.endElement(uri, loc, raw);
+        
+        if (depth == filterDepth) {
+            filterDepth = 0;
+            setContentHandler(this.next);
+        }
+
+        depth--;
+    }
+}

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SelectionListFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SelectionListFilter.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java (added)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java Wed Sep 28 03:24:51 2005
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+package org.apache.cocoon.forms.generation;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.flow.ContinuationsManager;
+import org.apache.cocoon.components.flow.InvalidContinuationException;
+import org.apache.cocoon.components.flow.WebContinuation;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.forms.Constants;
+import org.apache.cocoon.forms.datatype.SelectionList;
+import org.apache.cocoon.forms.formmodel.Field;
+import org.apache.cocoon.forms.formmodel.Form;
+import org.apache.cocoon.generation.ServiceableGenerator;
+import org.apache.cocoon.sitemap.SitemapParameters;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * A generator for suggestion lists.
+ *
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class SuggestionListGenerator extends ServiceableGenerator {
+
+    private ContinuationsManager contManager;
+    private WebContinuation wk;
+    private SelectionList list;
+    private String filter;
+    private Locale locale;
+
+    public void service(ServiceManager manager) throws ServiceException {
+        super.service(manager);
+        this.contManager = (ContinuationsManager)manager.lookup(ContinuationsManager.ROLE);
+    }
+
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
+        super.setup(resolver, objectModel, src, par);
+        
+        Request req = ObjectModelHelper.getRequest(objectModel);
+        
+        String continuationId = par.getParameter("continuation-id", req.getParameter("continuation-id"));
+        String widgetPath = par.getParameter("widget-id", req.getParameter("widget-id")).replace('.', '/');
+        String widgetId = widgetPath.replace('/', '.');
+        this.filter = par.getParameter("filter", req.getParameter(widgetId));
+        
+        // The interpreter id is the sitemap's URI
+        String interpreterId = SitemapParameters.getLocation(parameters).getURI();
+        wk = this.contManager.lookupWebContinuation(continuationId, interpreterId);
+        if (wk == null || wk.disposed()) {
+            throw new InvalidContinuationException("Cannot get continuation for suggestion list");
+        }
+        
+        Form form = (Form)wk.getAttribute("form");
+        if (form == null) {
+            throw new ProcessingException("No form is attached to the continuation");
+        }
+        
+        this.locale = form.getLocale();
+        
+        Field field = (Field)form.lookupWidget(widgetPath);
+        list = field.getSuggestionList();
+        if (list == null) {
+            throw new ProcessingException(field + " has no suggestion list");
+        }
+    }
+    
+    public void generate() throws IOException, SAXException, ProcessingException {
+        super.contentHandler.startDocument();
+        super.contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
+        ContentHandler handler;
+        if (filter == null || filter.length() == 0) {
+            handler = super.contentHandler;
+        } else {
+            handler = new SelectionListFilter(filter, super.contentHandler);
+        }
+        list.generateSaxFragment(handler, this.locale);
+        
+        super.contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
+        super.contentHandler.endDocument();
+    }
+
+}

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/jx-macros.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/jx-macros.xml?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/jx-macros.xml (original)
+++ cocoon/blocks/forms/trunk/java/org/apache/cocoon/forms/generation/jx-macros.xml Wed Sep 28 03:24:51 2005
@@ -44,7 +44,7 @@
       
       <jx:if test="${cformsHelper.pushWidget(id)}">
         <jx:set var="widget" value="${cformsHelper.peekWidget()}"/>
-        <jx:set var="cformsDummy" value="${cformsHelper.generateWidget(widget, locale)}"/>
+        <jx:set var="cformsDummy" value="${cformsHelper.generateWidget(widget, macro.arguments)}"/>
         <jx:evalBody/>
         <jx:set var="cformsDummy" value="${cformsHelper.flushRootAndPop()}"/>
       </jx:if>

Modified: cocoon/blocks/forms/trunk/samples/flow/forms_flow_example.js
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/flow/forms_flow_example.js?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/samples/flow/forms_flow_example.js (original)
+++ cocoon/blocks/forms/trunk/samples/flow/forms_flow_example.js Wed Sep 28 03:24:51 2005
@@ -164,11 +164,9 @@
         {title: "Tree binding is not yet done", document: null}
     );
 }
-function do_xdoceditor() {
-    var form = new Form("forms/xdoceditor.xml");
-    form.showForm("xdoceditor-display-pipeline.jx");
 
-    print(form.lookupWidget("doc").getValue());
+function do_suggest() {
+    var form = new Form("forms/ajax_suggest_form.xml");
+    form.showForm("ajax_suggest-display-pipeline.jx");
+    
 }
-
-

Added: cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_form.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_form.xml?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_form.xml (added)
+++ cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_form.xml Wed Sep 28 03:24:51 2005
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!-- form used to illustrate suggestion lists. -->
+<fd:form
+  xmlns:fd="http://apache.org/cocoon/forms/1.0#definition"
+  xmlns:i18n="http://apache.org/cocoon/i18n/2.1">
+
+  <fd:widgets>
+    <fd:field id="path">
+      <fd:datatype base="string"/>
+      <fd:suggestion-list>
+        <fd:item value="aaa"/>
+        <fd:item value="abb"/>
+        <fd:item value="abc"/>
+        <fd:item value="acc">
+          <fd:label>The last one</fd:label>
+        </fd:item>
+      </fd:suggestion-list>
+    </fd:field>
+  </fd:widgets>
+</fd:form>

Propchange: cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_form.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_form.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_template.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_template.xml?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_template.xml (added)
+++ cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_template.xml Wed Sep 28 03:24:51 2005
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<page xmlns:ft="http://apache.org/cocoon/forms/1.0#template" xmlns:fi="http://apache.org/cocoon/forms/1.0#instance"  xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
+   <!-- Import the macros that define CForms template elements -->
+   <jx:import uri="resource://org/apache/cocoon/forms/generation/jx-macros.xml"/>
+    <script type="text/javascript" src="resources/ajax/js/cocoon-ajax.js"/>
+    <style type="text/css">
+    div.auto_complete {
+      background-color:white;
+      border:1px solid #888;
+      margin:0px;
+      padding:0px;
+    }
+    div.auto_complete ul  {
+      list-style-type: none;
+      margin:0px;
+      padding:0px;
+    }
+    div.auto_complete li.selected { background-color: #ffb; }
+    </style>
+  <h4 class="samplesGroup">AJAX sample</h4>
+  <title>Cocoon suggests</title>
+  <content>
+      
+    <para><em>Work in progress!</em> This simple example illustrates the &lt;fd:suggestion-list&gt; feature.
+    </para>
+  
+  
+    <ft:form-template action="continue" method="POST" ajax="true">
+      <ft:continuation-id/>
+        Type the letter 'a' in the field below<br/>
+        <ft:widget id="path"/>
+        <div id="autocomplete" class="auto_complete"/>
+        <script type="text/javascript">
+          new Ajax.Autocompleter("path-input", "autocomplete", "system_forms_suggest_path",
+          	{ parameters: "continuation-id=${cocoon.continuation.id}" });
+        </script>
+    </ft:form-template>
+    <p>
+      <a href="./">Back to Forms samples</a>
+    </p>
+  </content>
+</page>

Propchange: cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_template.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/samples/forms/ajax_suggest_template.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/blocks/forms/trunk/samples/forms/form1_template.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/forms/form1_template.xml?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/samples/forms/form1_template.xml (original)
+++ cocoon/blocks/forms/trunk/samples/forms/form1_template.xml Wed Sep 28 03:24:51 2005
@@ -44,9 +44,9 @@
               <fi:items>
                 <ft:widget id="email"/>
                 <ft:widget id="birthdate"/>
-                <ft:widget id="fourchars">
-                  <!-- particular styling for the enumeration -->
-                  <fi:styling list-type="listbox" listbox-size="4"/>
+                <ft:widget id="fourchars" fi:list-type="listbox" fi:listbox-size="4">
+                  <!-- particular styling for the enumeration 
+                  <fi:styling list-type="llistbox" listbox-size="4"/-->
                 </ft:widget>
               </fi:items>
             </fi:group>

Modified: cocoon/blocks/forms/trunk/samples/forms/sampletree_template.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/forms/sampletree_template.xml?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/samples/forms/sampletree_template.xml (original)
+++ cocoon/blocks/forms/trunk/samples/forms/sampletree_template.xml Wed Sep 28 03:24:51 2005
@@ -101,15 +101,14 @@
       </ft:tree>
       <br/>
       <ft:tree id="tree2">
-      <div>
-        Tree sample:
-        ${java.lang.System.err.println("In tree2")}
+        <div>
+          Tree sample:
           <ft:tree-nodes>
             <div style="margin-left: 15px"><toggle-icon/>${treeNode.node.data}
               <ft:tree-children/>
             </div>
           </ft:tree-nodes>
-      </div>
+        </div>
       </ft:tree>
       
       Example of a tree-table

Modified: cocoon/blocks/forms/trunk/samples/sitemap.xmap
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/sitemap.xmap?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/samples/sitemap.xmap (original)
+++ cocoon/blocks/forms/trunk/samples/sitemap.xmap Wed Sep 28 03:24:51 2005
@@ -18,9 +18,12 @@
 <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
 
  <map:components>
+  <map:generators default="file">
+    <map:generator name="suggestion-list" src="org.apache.cocoon.forms.generation.SuggestionListGenerator"/>
+  </map:generators>
 
   <map:transformers default="xslt">    
-    <map:transformer name="browser-update" src="org.apache.cocoon.transformation.BrowserUpdateTransformer"/>
+    <map:transformer name="browser-update" src="org.apache.cocoon.ajax.BrowserUpdateTransformer"/>
     <map:transformer name="i18n" src="org.apache.cocoon.transformation.I18nTransformer">
       <catalogues default="other">
         <catalogue id="other" name="OtherMessages" location="messages"/>
@@ -177,6 +180,17 @@
      </map:match>
 
      <!--
+        | Show a suggestion list 
+         -->
+     <map:match pattern="system_forms_suggest_*">
+        <map:generate type="suggestion-list">
+          <map:parameter name="widget-id" value="{1}"/>
+        </map:generate>
+        <map:transform type="i18n"/>
+        <map:transform src="suggest-list.xsl"/>
+        <map:serialize type="xml"/>
+     </map:match>
+     <!--
         | Show a form, using the forms transformer
         -->
      <map:match pattern="*-display-pipeline">
@@ -448,6 +462,10 @@
      <map:match pattern="htmlarea-success-pipeline">
        <map:generate type="jx" src="forms/htmlarea_success.jx"/>
        <map:serialize type="xml"/>
+     </map:match>
+
+     <map:match type="regexp" pattern="resources/(ajax)/(.*)">
+       <map:read src="resource://org/apache/cocoon/{1}/resources/{2}"/>
      </map:match>
 
      <map:match pattern="resources/**">

Added: cocoon/blocks/forms/trunk/samples/suggest-list.xsl
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/suggest-list.xsl?rev=292158&view=auto
==============================================================================
--- cocoon/blocks/forms/trunk/samples/suggest-list.xsl (added)
+++ cocoon/blocks/forms/trunk/samples/suggest-list.xsl Wed Sep 28 03:24:51 2005
@@ -0,0 +1,19 @@
+<xsl:stylesheet
+  version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:fi="http://apache.org/cocoon/forms/1.0#instance">
+  <xsl:template match="/">
+    <ul>
+      <xsl:apply-templates/>
+    </ul>
+  </xsl:template>
+  
+  <xsl:template match="fi:item">
+    <li>
+      <xsl:value-of select="@value"/>
+      <xsl:if test="fi:label and (fi:label != @value)">
+        <span class="informal"> (<xsl:copy-of select="fi:label/node()"/>)</span>
+      </xsl:if>
+    </li>
+  </xsl:template>
+</xsl:stylesheet>

Propchange: cocoon/blocks/forms/trunk/samples/suggest-list.xsl
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/blocks/forms/trunk/samples/suggest-list.xsl
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/blocks/forms/trunk/samples/welcome.xml
URL: http://svn.apache.org/viewcvs/cocoon/blocks/forms/trunk/samples/welcome.xml?rev=292158&r1=292157&r2=292158&view=diff
==============================================================================
--- cocoon/blocks/forms/trunk/samples/welcome.xml (original)
+++ cocoon/blocks/forms/trunk/samples/welcome.xml Wed Sep 28 03:24:51 2005
@@ -127,6 +127,12 @@
    </sample>
  </group>
  
+ <group name="Advanced Ajax samples (work in progress)">
+   <sample name="Cocoon suggests" href="do-suggest.flow">
+     (Ajax) Very simple demo of the &lt;suggestion-list&gt; feature.
+   </sample>
+ </group>
+ 
  <group name="Dynamic repeater template and event handling">
     <sample name="Dynamic repeater template" href="dreamteam">
       Create your Euro 2004 soccer dream team