click-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadr...@apache.org
Subject svn commit: r1538295 [6/8] - in /click/branches/click-3.0.0/click: ./ build/ documentation/docs/ examples/ examples/src/org/apache/click/examples/control/ examples/src/org/apache/click/examples/page/ examples/src/org/apache/click/examples/page/ajax/for...
Date Sat, 02 Nov 2013 22:15:34 GMT
Propchange: click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/prototype.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/scriptaculous.js
URL: http://svn.apache.org/viewvc/click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/scriptaculous.js?rev=1538295&view=auto
==============================================================================
--- click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/scriptaculous.js (added)
+++ click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/scriptaculous.js Sat Nov  2 22:15:31 2013
@@ -0,0 +1,68 @@
+// script.aculo.us scriptaculous.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Scriptaculous = {
+  Version: '1.8.3',
+  require: function(libraryName) {
+    try{
+      // inserting via DOM fails in Safari 2.0, so brute force approach
+      document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
+    } catch(e) {
+      // for xhtml+xml served content, fall back to DOM methods
+      var script = document.createElement('script');
+      script.type = 'text/javascript';
+      script.src = libraryName;
+      document.getElementsByTagName('head')[0].appendChild(script);
+    }
+  },
+  REQUIRED_PROTOTYPE: '1.6.0.3',
+  load: function() {
+    function convertVersionString(versionString) {
+      var v = versionString.replace(/_.*|\./g, '');
+      v = parseInt(v + '0'.times(4-v.length));
+      return versionString.indexOf('_') > -1 ? v-1 : v;
+    }
+
+    if((typeof Prototype=='undefined') ||
+       (typeof Element == 'undefined') ||
+       (typeof Element.Methods=='undefined') ||
+       (convertVersionString(Prototype.Version) <
+        convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
+       throw("script.aculo.us requires the Prototype JavaScript framework >= " +
+        Scriptaculous.REQUIRED_PROTOTYPE);
+
+    var js = /scriptaculous\.js(\?.*)?$/;
+    $$('head script[src]').findAll(function(s) {
+      return s.src.match(js);
+    }).each(function(s) {
+      var path = s.src.replace(js, ''),
+      includes = s.src.match(/\?.*load=([a-z,]*)/);
+      (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
+       function(include) { Scriptaculous.require(path+include+'.js') });
+    });
+  }
+};
+
+Scriptaculous.load();
\ No newline at end of file

Propchange: click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/scriptaculous.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/slider.js
URL: http://svn.apache.org/viewvc/click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/slider.js?rev=1538295&view=auto
==============================================================================
--- click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/slider.js (added)
+++ click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/slider.js Sat Nov  2 22:15:31 2013
@@ -0,0 +1,275 @@
+// script.aculo.us slider.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Marty Haught, Thomas Fuchs
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if (!Control) var Control = { };
+
+// options:
+//  axis: 'vertical', or 'horizontal' (default)
+//
+// callbacks:
+//  onChange(value)
+//  onSlide(value)
+Control.Slider = Class.create({
+  initialize: function(handle, track, options) {
+    var slider = this;
+
+    if (Object.isArray(handle)) {
+      this.handles = handle.collect( function(e) { return $(e) });
+    } else {
+      this.handles = [$(handle)];
+    }
+
+    this.track   = $(track);
+    this.options = options || { };
+
+    this.axis      = this.options.axis || 'horizontal';
+    this.increment = this.options.increment || 1;
+    this.step      = parseInt(this.options.step || '1');
+    this.range     = this.options.range || $R(0,1);
+
+    this.value     = 0; // assure backwards compat
+    this.values    = this.handles.map( function() { return 0 });
+    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
+    this.options.startSpan = $(this.options.startSpan || null);
+    this.options.endSpan   = $(this.options.endSpan || null);
+
+    this.restricted = this.options.restricted || false;
+
+    this.maximum   = this.options.maximum || this.range.end;
+    this.minimum   = this.options.minimum || this.range.start;
+
+    // Will be used to align the handle onto the track, if necessary
+    this.alignX = parseInt(this.options.alignX || '0');
+    this.alignY = parseInt(this.options.alignY || '0');
+
+    this.trackLength = this.maximumOffset() - this.minimumOffset();
+
+    this.handleLength = this.isVertical() ?
+      (this.handles[0].offsetHeight != 0 ?
+        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :
+      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
+        this.handles[0].style.width.replace(/px$/,""));
+
+    this.active   = false;
+    this.dragging = false;
+    this.disabled = false;
+
+    if (this.options.disabled) this.setDisabled();
+
+    // Allowed values array
+    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
+    if (this.allowedValues) {
+      this.minimum = this.allowedValues.min();
+      this.maximum = this.allowedValues.max();
+    }
+
+    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
+    this.eventMouseMove = this.update.bindAsEventListener(this);
+
+    // Initialize handles in reverse (make sure first handle is active)
+    this.handles.each( function(h,i) {
+      i = slider.handles.length-1-i;
+      slider.setValue(parseFloat(
+        (Object.isArray(slider.options.sliderValue) ?
+          slider.options.sliderValue[i] : slider.options.sliderValue) ||
+         slider.range.start), i);
+      h.makePositioned().observe("mousedown", slider.eventMouseDown);
+    });
+
+    this.track.observe("mousedown", this.eventMouseDown);
+    document.observe("mouseup", this.eventMouseUp);
+    document.observe("mousemove", this.eventMouseMove);
+
+    this.initialized = true;
+  },
+  dispose: function() {
+    var slider = this;
+    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
+    Event.stopObserving(document, "mouseup", this.eventMouseUp);
+    Event.stopObserving(document, "mousemove", this.eventMouseMove);
+    this.handles.each( function(h) {
+      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
+    });
+  },
+  setDisabled: function(){
+    this.disabled = true;
+  },
+  setEnabled: function(){
+    this.disabled = false;
+  },
+  getNearestValue: function(value){
+    if (this.allowedValues){
+      if (value >= this.allowedValues.max()) return(this.allowedValues.max());
+      if (value <= this.allowedValues.min()) return(this.allowedValues.min());
+
+      var offset = Math.abs(this.allowedValues[0] - value);
+      var newValue = this.allowedValues[0];
+      this.allowedValues.each( function(v) {
+        var currentOffset = Math.abs(v - value);
+        if (currentOffset <= offset){
+          newValue = v;
+          offset = currentOffset;
+        }
+      });
+      return newValue;
+    }
+    if (value > this.range.end) return this.range.end;
+    if (value < this.range.start) return this.range.start;
+    return value;
+  },
+  setValue: function(sliderValue, handleIdx){
+    if (!this.active) {
+      this.activeHandleIdx = handleIdx || 0;
+      this.activeHandle    = this.handles[this.activeHandleIdx];
+      this.updateStyles();
+    }
+    handleIdx = handleIdx || this.activeHandleIdx || 0;
+    if (this.initialized && this.restricted) {
+      if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
+        sliderValue = this.values[handleIdx-1];
+      if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
+        sliderValue = this.values[handleIdx+1];
+    }
+    sliderValue = this.getNearestValue(sliderValue);
+    this.values[handleIdx] = sliderValue;
+    this.value = this.values[0]; // assure backwards compat
+
+    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
+      this.translateToPx(sliderValue);
+
+    this.drawSpans();
+    if (!this.dragging || !this.event) this.updateFinished();
+  },
+  setValueBy: function(delta, handleIdx) {
+    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
+      handleIdx || this.activeHandleIdx || 0);
+  },
+  translateToPx: function(value) {
+    return Math.round(
+      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
+      (value - this.range.start)) + "px";
+  },
+  translateToValue: function(offset) {
+    return ((offset/(this.trackLength-this.handleLength) *
+      (this.range.end-this.range.start)) + this.range.start);
+  },
+  getRange: function(range) {
+    var v = this.values.sortBy(Prototype.K);
+    range = range || 0;
+    return $R(v[range],v[range+1]);
+  },
+  minimumOffset: function(){
+    return(this.isVertical() ? this.alignY : this.alignX);
+  },
+  maximumOffset: function(){
+    return(this.isVertical() ?
+      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
+        this.track.style.height.replace(/px$/,"")) - this.alignY :
+      (this.track.offsetWidth != 0 ? this.track.offsetWidth :
+        this.track.style.width.replace(/px$/,"")) - this.alignX);
+  },
+  isVertical:  function(){
+    return (this.axis == 'vertical');
+  },
+  drawSpans: function() {
+    var slider = this;
+    if (this.spans)
+      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
+    if (this.options.startSpan)
+      this.setSpan(this.options.startSpan,
+        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
+    if (this.options.endSpan)
+      this.setSpan(this.options.endSpan,
+        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
+  },
+  setSpan: function(span, range) {
+    if (this.isVertical()) {
+      span.style.top = this.translateToPx(range.start);
+      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
+    } else {
+      span.style.left = this.translateToPx(range.start);
+      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
+    }
+  },
+  updateStyles: function() {
+    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
+    Element.addClassName(this.activeHandle, 'selected');
+  },
+  startDrag: function(event) {
+    if (Event.isLeftClick(event)) {
+      if (!this.disabled){
+        this.active = true;
+
+        var handle = Event.element(event);
+        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
+        var track = handle;
+        if (track==this.track) {
+          var offsets  = this.track.cumulativeOffset();
+          this.event = event;
+          this.setValue(this.translateToValue(
+           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
+          ));
+          var offsets  = this.activeHandle.cumulativeOffset();
+          this.offsetX = (pointer[0] - offsets[0]);
+          this.offsetY = (pointer[1] - offsets[1]);
+        } else {
+          // find the handle (prevents issues with Safari)
+          while((this.handles.indexOf(handle) == -1) && handle.parentNode)
+            handle = handle.parentNode;
+
+          if (this.handles.indexOf(handle)!=-1) {
+            this.activeHandle    = handle;
+            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
+            this.updateStyles();
+
+            var offsets  = this.activeHandle.cumulativeOffset();
+            this.offsetX = (pointer[0] - offsets[0]);
+            this.offsetY = (pointer[1] - offsets[1]);
+          }
+        }
+      }
+      Event.stop(event);
+    }
+  },
+  update: function(event) {
+   if (this.active) {
+      if (!this.dragging) this.dragging = true;
+      this.draw(event);
+      if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+      Event.stop(event);
+   }
+  },
+  draw: function(event) {
+    var pointer = [Event.pointerX(event), Event.pointerY(event)];
+    var offsets = this.track.cumulativeOffset();
+    pointer[0] -= this.offsetX + offsets[0];
+    pointer[1] -= this.offsetY + offsets[1];
+    this.event = event;
+    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
+    if (this.initialized && this.options.onSlide)
+      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
+  },
+  endDrag: function(event) {
+    if (this.active && this.dragging) {
+      this.finishDrag(event, true);
+      Event.stop(event);
+    }
+    this.active = false;
+    this.dragging = false;
+  },
+  finishDrag: function(event, success) {
+    this.active = false;
+    this.dragging = false;
+    this.updateFinished();
+  },
+  updateFinished: function() {
+    if (this.initialized && this.options.onChange)
+      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
+    this.event = null;
+  }
+});
\ No newline at end of file

Propchange: click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/slider.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/unittest.js
URL: http://svn.apache.org/viewvc/click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/unittest.js?rev=1538295&view=auto
==============================================================================
--- click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/unittest.js (added)
+++ click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/unittest.js Sat Nov  2 22:15:31 2013
@@ -0,0 +1,568 @@
+// script.aculo.us unittest.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//           (c) 2005-2009 Jon Tirsen (http://www.tirsen.com)
+//           (c) 2005-2009 Michael Schuerig (http://www.schuerig.de/michael/)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// experimental, Firefox-only
+Event.simulateMouse = function(element, eventName) {
+  var options = Object.extend({
+    pointerX: 0,
+    pointerY: 0,
+    buttons:  0,
+    ctrlKey:  false,
+    altKey:   false,
+    shiftKey: false,
+    metaKey:  false
+  }, arguments[2] || {});
+  var oEvent = document.createEvent("MouseEvents");
+  oEvent.initMouseEvent(eventName, true, true, document.defaultView, 
+    options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, 
+    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 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 = Object.inspect;
+
+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.className = "nameCell";
+    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);
+    this.addLinksToResults();
+  },
+  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/>");
+  },
+  addLinksToResults: function(){ 
+    $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
+      td.title = "Run only this test";
+      Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
+    });
+    $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
+      td.title = "Run all tests";
+      Event.observe(td, 'click', function(){ window.location.search = "";});
+    });
+  }
+};
+
+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();
+    this.options.tests      = this.parseTestsQueryParameter();
+    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(
+                 this.options.context ? ' -> ' + this.options.titles[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"];
+  },
+  parseTestsQueryParameter: function(){
+    if (window.location.search.parseQuery()["tests"]){
+        return window.location.search.parseQuery()["tests"].split(',');
+    };
+  },
+  // 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.options.context ? this.options.context + ': ': '') + 
+      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);
+  },
+  info: function(message) {
+    this.messages.push("Info: " + 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); }
+  },
+  assertInspect: function(expected, actual) {
+    var message = arguments[2] || "assertInspect";
+    try { (expected == actual.inspect()) ? this.pass() :
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
+        '", actual "' + Test.Unit.inspect(actual) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertEnumEqual: function(expected, actual) {
+    var message = arguments[2] || "assertEnumEqual";
+    try { $A(expected).length == $A(actual).length && 
+      expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
+        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); }
+  },
+  assertIdentical: function(expected, actual) { 
+    var message = arguments[2] || "assertIdentical"; 
+    try { (expected === actual) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + Test.Unit.inspect(actual) + '"'); } 
+    catch(e) { this.error(e); } 
+  },
+  assertNotIdentical: function(expected, actual) { 
+    var message = arguments[2] || "assertNotIdentical"; 
+    try { !(expected === actual) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + 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); }
+  },
+  assertMatch: function(expected, actual) {
+    var message = arguments[2] || 'assertMatch';
+    var regex = new RegExp(expected);
+    try { (regex.exec(actual)) ? this.pass() :
+      this.fail(message + ' : regex: "' +  Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
+    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);
+  },
+  assertType: function(expected, actual) {
+    var message = arguments[2] || 'assertType';
+    try { 
+      (actual.constructor == expected) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + (actual.constructor) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertNotOfType: function(expected, actual) {
+    var message = arguments[2] || 'assertNotOfType';
+    try { 
+      (actual.constructor != expected) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + (actual.constructor) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  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); } 
+  },
+  assertRespondsTo: function(method, obj) {
+    var message = arguments[2] || 'assertRespondsTo';
+    try {
+      (obj[method] && typeof obj[method] == 'function') ? this.pass() : 
+      this.fail(message + ": object doesn't respond to [" + method + "]"); }
+    catch(e) { this.error(e); }
+  },
+  assertReturnsTrue: function(method, obj) {
+    var message = arguments[2] || 'assertReturnsTrue';
+    try {
+      var m = obj[method];
+      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+      m() ? this.pass() : 
+      this.fail(message + ": method returned false"); }
+    catch(e) { this.error(e); }
+  },
+  assertReturnsFalse: function(method, obj) {
+    var message = arguments[2] || 'assertReturnsFalse';
+    try {
+      var m = obj[method];
+      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+      !m() ? this.pass() : 
+      this.fail(message + ": method returned true"); }
+    catch(e) { this.error(e); }
+  },
+  assertRaise: function(exceptionName, method) {
+    var message = arguments[2] || 'assertRaise';
+    try { 
+      method();
+      this.fail(message + ": exception expected but none was raised"); }
+    catch(e) {
+      ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e); 
+    }
+  },
+  assertElementsMatch: function() {
+    var expressions = $A(arguments), elements = $A(expressions.shift());
+    if (elements.length != expressions.length) {
+      this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
+      return false;
+    }
+    elements.zip(expressions).all(function(pair, index) {
+      var element = $(pair.first()), expression = pair.last();
+      if (element.match(expression)) return true;
+      this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
+    }.bind(this)) && this.pass();
+  },
+  assertElementMatches: function(element, expression) {
+    this.assertElementsMatch([element], expression);
+  },
+  benchmark: function(operation, iterations) {
+    var startAt = new Date();
+    (iterations || 1).times(operation);
+    var timeTaken = ((new Date())-startAt);
+    this.info((arguments[2] || 'Operation') + ' finished ' + 
+       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+    return timeTaken;
+  },
+  _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]));
+  },
+  benchmark: function(operation, iterations) {
+    var startAt = new Date();
+    (iterations || 1).times(operation);
+    var timeTaken = ((new Date())-startAt);
+    this.info((arguments[2] || 'Operation') + ' finished ' + 
+       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+    return timeTaken;
+  }
+};
+
+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;
+    
+    if(typeof test == 'string') {
+      test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
+      test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
+      this.test = function() {
+        eval('with(this){'+test+'}');
+      }
+    } else {
+      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); }
+  }
+});
+
+// *EXPERIMENTAL* BDD-style testing to please non-technical folk
+// This draws many ideas from RSpec http://rspec.rubyforge.org/
+
+Test.setupBDDExtensionMethods = function(){
+  var METHODMAP = {
+    shouldEqual:     'assertEqual',
+    shouldNotEqual:  'assertNotEqual',
+    shouldEqualEnum: 'assertEnumEqual',
+    shouldBeA:       'assertType',
+    shouldNotBeA:    'assertNotOfType',
+    shouldBeAn:      'assertType',
+    shouldNotBeAn:   'assertNotOfType',
+    shouldBeNull:    'assertNull',
+    shouldNotBeNull: 'assertNotNull',
+    
+    shouldBe:        'assertReturnsTrue',
+    shouldNotBe:     'assertReturnsFalse',
+    shouldRespondTo: 'assertRespondsTo'
+  };
+  var makeAssertion = function(assertion, args, object) { 
+   	this[assertion].apply(this,(args || []).concat([object]));
+  };
+  
+  Test.BDDMethods = {};   
+  $H(METHODMAP).each(function(pair) { 
+    Test.BDDMethods[pair.key] = function() { 
+       var args = $A(arguments); 
+       var scope = args.shift(); 
+       makeAssertion.apply(scope, [pair.value, args, this]); }; 
+  });
+  
+  [Array.prototype, String.prototype, Number.prototype, Boolean.prototype].each(
+    function(p){ Object.extend(p, Test.BDDMethods) }
+  );
+};
+
+Test.context = function(name, spec, log){
+  Test.setupBDDExtensionMethods();
+  
+  var compiledSpec = {};
+  var titles = {};
+  for(specName in spec) {
+    switch(specName){
+      case "setup":
+      case "teardown":
+        compiledSpec[specName] = spec[specName];
+        break;
+      default:
+        var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
+        var body = spec[specName].toString().split('\n').slice(1);
+        if(/^\{/.test(body[0])) body = body.slice(1);
+        body.pop();
+        body = body.map(function(statement){ 
+          return statement.strip()
+        });
+        compiledSpec[testName] = body.join('\n');
+        titles[testName] = specName;
+    }
+  }
+  new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
+};
\ No newline at end of file

Propchange: click/branches/click-3.0.0/click/prototypejs/src/META-INF/resources/click/prototype/unittest.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: click/branches/click-3.0.0/click/prototypejs/src/extras-prototypejs-controls.xml
URL: http://svn.apache.org/viewvc/click/branches/click-3.0.0/click/prototypejs/src/extras-prototypejs-controls.xml?rev=1538295&view=auto
==============================================================================
--- click/branches/click-3.0.0/click/prototypejs/src/extras-prototypejs-controls.xml (added)
+++ click/branches/click-3.0.0/click/prototypejs/src/extras-prototypejs-controls.xml Sat Nov  2 22:15:31 2013
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<click-app>
+
+  <controls>
+  </controls>
+
+</click-app>

Propchange: click/branches/click-3.0.0/click/prototypejs/src/extras-prototypejs-controls.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/CheckList.java
URL: http://svn.apache.org/viewvc/click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/CheckList.java?rev=1538295&view=auto
==============================================================================
--- click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/CheckList.java (added)
+++ click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/CheckList.java Sat Nov  2 22:15:31 2013
@@ -0,0 +1,1183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.click.extras.prototypejs;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.click.Context;
+import org.apache.click.control.Field;
+import org.apache.click.control.Option;
+import org.apache.click.dataprovider.DataProvider;
+import org.apache.click.element.CssImport;
+import org.apache.click.element.Element;
+import org.apache.click.element.JsImport;
+import org.apache.click.element.JsScript;
+import org.apache.click.service.ConfigService;
+import org.apache.click.service.PropertyService;
+import org.apache.click.util.ClickUtils;
+import org.apache.click.util.HtmlStringBuffer;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Provides a check list control. This is an implementation of the Checklist
+ * from <a href="http://c82.net/article.php?ID=25">Check it don't select it</a>
+ * <p/>
+ * A check list is a more user friendly substitution for
+ * multiple-select-boxes. It is a scrollable div which has many select-boxes.
+ *
+ * <h3><a name="checklist-example"></a>CheckList Examples</h3>
+ *
+ * <pre class="prettyprint">
+ * public class MyPage extends Page {
+ *
+ *     public void onInit() {
+ *
+ *         CheckList checkList = new ChecList("languages");
+ *
+ *         checkList.add(new Option("001", "Java"));
+ *         checkList.add(new Option("002", "Ruby"));
+ *         checkList.add(new Option("003", "Perl"));
+ *
+ *         // Set the Java as a selected option
+ *         checkList.addSelectedValue("001");
+ *     }
+ * } </pre>
+ *
+ * Unless you use a <a href="#dataprovider">DataProvider</a>, remember to always
+ * populate the CheckList option list before it is processed. Do not populate the
+ * option list in a Page's onRender() method.
+ *
+ * <h3><a name="dataprovider"></a>DataProvider</h3>
+ * A common issue new Click users face is which page event (onInit or onRender)
+ * to populate the CheckList {@link #getOptionList() optionList} in. To alleviate
+ * this problem you can set a
+ * {@link #setDataProvider(org.apache.click.dataprovider.DataProvider) dataProvider}
+ * which allows the CheckList to fetch data when needed. This is
+ * particularly useful if retrieving CheckList data is expensive e.g. loading
+ * from a database.
+ * <p/>
+ * Below is a simple example:
+ *
+ * <pre class="prettyprint">
+ * public class LanguagePage extends Page {
+ *
+ *     public Form form = new Form();
+ *
+ *     private Select languageCheckList = new CheckList("languages");
+ *
+ *     public LanguagePage() {
+ *
+ *         // Set a DataProvider which "getData" method will be called to
+ *         // populate the optionList. The "getData" method is only called when
+ *         // the optionList data is needed
+ *         languageCheckList.setDataProvider(new DataProvider() {
+ *             public List getData() {
+ *                 List options = new ArrayList();
+ *                 options.add(new Option("001", "Java"));
+ *                 options.add(new Option("002", "Ruby"));
+ *                 options.add(new Option("003", "Perl"));
+ *                 return options;
+ *             }
+ *         });
+ *
+ *         form.add(languageCheckList);
+ *
+ *         form.add(new Submit("ok", "  OK  "));
+ *     }
+ * } </pre>
+ *
+ * CheckList also supports a scrollable mode. To make the CheckList scrollable,
+ * set the height of the CheckList through {@link #setHeight(String)}.
+ * <p/>
+ * <b>Note</b> when setting the height it is recommended that the CheckList
+ * should not be sortable, because of browser incompatibilities.
+ * <p/>
+ * The CheckList is also sortable by drag-drop if the
+ * {@link #setSortable(boolean)} property is set to true. In this case the
+ * method {@link #getSortorder()} returns the keys of all the options whether
+ * they where selected or not in the order provided by the user.
+ * <p/>
+ * Sortable is provided by scriptaculous which is only supported on IE6, FF and
+ * Safari1.2 and higher. This control is only tested on IE6 and FF on Windows.
+ * With IE the text of the dragged element has a black-outline which does not
+ * look good. To turn this off define an explicit back-ground color for the
+ * &lt;li&gt; elements. Typically you will do this in a style: .listClass li
+ * {background-color: #xxx}, where the listClass is set through
+ * {@link #addStyleClass(String)}.
+ * <p/>
+ * If a select is required at least one item must be
+ * selected so that the input is valid. Other validations are not done.
+ * <p/>
+ * The Control listener will be invoked in any case whether the CheckList is valid or not.
+ * <p/>
+ * The values of the CheckList are provided by
+ * {@link org.apache.click.control.Option} instances. To populate the CheckList with
+ * Options, use the add methods.
+ * <p/>
+ * The label of the Option is shown to the user and the value is what is
+ * provided in the {@link #getSelectedValues()} and {@link #getSortorder()}
+ * Lists.
+ * <p/>
+ * The selected values can be retrieved from {@link #getSelectedValues()}. The
+ * get/setValue() property is not supported.
+ * <p/>
+ * The select uses the /click/checklist/checklist.css style. By providing a style which
+ * extends this style the appearance of the list can be changed.
+ * <p/>
+ * To set the additional style class use {@link #addStyleClass(String)}.
+ * This will append the given class to the default class of this control.
+ * Alternatively {@link #setStyle(String, String)} can be used to set the style
+ * of the outer div.
+ * <p/>
+ * For an example please look at the click-examples and the at the above blog.
+ *
+ * <a name="resources"></a>
+ * <h3>CSS and JavaScript resources</h3>
+ *
+ * The CheckList control makes use of the following resources
+ * (which Click automatically deploys to the application directories,
+ * <tt>/click/checklist</tt> and <tt>/click/prototype</tt>):
+ *
+ * <ul>
+ * <li><tt>click/checklist/checklist.css</tt></li>
+ * <li><tt>click/checklist/checklist.js</tt></li>
+ * <li><tt>click/prototype/builder.js</tt></li>
+ * <li><tt>click/prototype/controls.js</tt></li>
+ * <li><tt>click/prototype/dragdrop.js</tt></li>
+ * <li><tt>click/prototype/effects.js</tt></li>
+ * <li><tt>click/prototype/prototype.js</tt></li>
+ * <li><tt>click/prototype/slider.js</tt></li>
+ * </ul>
+ *
+ * To import these CheckList files simply reference the variables
+ * <span class="blue">$headElements</span> and
+ * <span class="blue">$jsElements</span> in the page template.
+ *
+ * @see org.apache.click.control.Option
+ */
+public class CheckList extends Field {
+
+    // Constants --------------------------------------------------------------
+
+    private static final long serialVersionUID = 1L;
+
+    /** The style class which is always set on this element (checkList). */
+    protected static final String STYLE_CLASS = "checkList";
+
+    /**
+     * The field validation JavaScript function template.
+     * The function template arguments are: <ul>
+     * <li>0 - is the field id</li>
+     * <li>1 - is the name of the checkbox</li>
+     * <li>2 - is the id of the form</li>
+     * <li>3 - is the Field required status</li>
+     * <li>4 - is the localized error message for required validation</li>
+     * </ul>
+     */
+    protected final static String VALIDATE_CHECKLIST_FUNCTION =
+        "function validate_{0}() '{'\n"
+        + "   var msg = validateCheckList(''{1}'', ''{2}'', {3}, [''{4}'']);\n"
+        + "   if (msg) '{'\n"
+        + "      return msg + ''|{0}'';\n"
+        + "   '}' else '{'\n"
+        + "      return null;\n"
+        + "   '}'\n"
+        + "'}'\n";
+
+    // Instance Variables -----------------------------------------------------
+
+    /** The select data provider. */
+    protected DataProvider<Option> dataProvider;
+
+    /** The height if null not scrollable. */
+    protected String height;
+
+    /** The Select Option list. */
+    protected List<Option> optionList;
+
+    /** If sortable by drag and drop. */
+    protected boolean sortable;
+
+    /**
+     * The key of the values in the order they are present (only set when
+     * sortable).
+     */
+    protected List<String> sortorder;
+
+    /** The selected values. */
+    protected List<String> selectedValues;
+
+    // Constructors -----------------------------------------------------------
+
+    /**
+     * Create a CheckList field with the given name.
+     *
+     * @param name the name of the field
+     */
+    public CheckList(String name) {
+        super(name);
+    }
+
+    /**
+     * Create a CheckList field with the given name and label.
+     *
+     * @param name the name of the field
+     * @param label the label of the field
+     */
+    public CheckList(String name, String label) {
+        super(name, label);
+    }
+
+    /**
+     * Create a CheckList field with the given name and required status.
+     *
+     * @param name the name of the field
+     * @param required the field required status
+     */
+    public CheckList(String name, boolean required) {
+        super(name);
+        setRequired(required);
+    }
+
+    /**
+     * Create a CheckList field with the given name, label and required status.
+     *
+     * @param name the name of the field
+     * @param label the label of the field
+     * @param required the field required status
+     */
+    public CheckList(String name, String label, boolean required) {
+        super(name, label);
+        setRequired(required);
+    }
+
+    /**
+     * Create a CheckList field with no name defined.
+     * <p/>
+     * <b>Please note</b> the control's name must be defined before it is valid.
+     */
+    public CheckList() {
+    }
+
+    // Public Attributes ------------------------------------------------------
+
+    /**
+     * @see org.apache.click.control.AbstractControl#getTag()
+     *
+     * @return this controls html tag
+     */
+    @Override
+    public String getTag() {
+        return "div";
+    }
+
+    /**
+     * Add the given Option.
+     *
+     * @param option the Option value to add
+     * @throws IllegalArgumentException if option is null
+     */
+    public void add(Option option) {
+        if (option == null) {
+            String msg = "option parameter cannot be null";
+            throw new IllegalArgumentException(msg);
+        }
+        getOptionList().add(option);
+    }
+
+    /**
+     * Add the given option value. This convenience method will create a new
+     * {@link Option} with the given value and add it to the CheckList. The new
+     * Option display label will be the same as its value.
+     *
+     * @param value the option value to add
+     * @throws IllegalArgumentException if the value is null
+     */
+    public void add(String value) {
+        if (value == null) {
+            String msg = "value parameter cannot be null";
+            throw new IllegalArgumentException(msg);
+        }
+        getOptionList().add(new Option(value));
+    }
+
+    /**
+     * Add the given Option/String/Number/Boolean to the CheckList.
+     *
+     * @param option one of either Option/String/Number/Boolean to add
+     * @throws IllegalArgumentException if option is null, or the option
+     * is an unsupported class
+     */
+    public void add(Object option) {
+        if (option instanceof Option) {
+            getOptionList().add((Option) option);
+
+        } else if (option instanceof String) {
+            getOptionList().add(new Option(option.toString()));
+
+        } else if (option instanceof Number) {
+            getOptionList().add(new Option(option.toString()));
+
+        } else if (option instanceof Boolean) {
+            getOptionList().add(new Option(option.toString()));
+
+        } else {
+            String message = "Unsupported options class "
+                + option.getClass().getName() + ". Please use method "
+                + "CheckList.addAll(Collection, String, String) instead.";
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    /**
+     * Add the given Option/String/Number/Boolean collection to the CheckList.
+     *
+     * @param options the collection of Option/String/Number/Boolean
+     * objects to add
+     * @throws IllegalArgumentException if options is null, or the collection
+     * contains an unsupported class
+     */
+    public void addAll(Collection<?> options) {
+        if (options == null) {
+            String msg = "options parameter cannot be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!options.isEmpty()) {
+            for (Object option : options) {
+                add(option);
+            }
+        }
+    }
+
+    /**
+     * Add the given Map of option values and labels to the CheckList. The Map
+     * entry key will be used as the option value and the Map entry value will
+     * be used as the option label.
+     * <p/>
+     * It is recommended that <tt>LinkedHashMap</tt> is used as the Map
+     * parameter to maintain the order of the option vales.
+     *
+     * @param options the Map of option values and labels to add
+     * @throws IllegalArgumentException if options is null
+     */
+    public void addAll(Map<?, ?> options) {
+        if (options == null) {
+            String msg = "options parameter cannot be null";
+            throw new IllegalArgumentException(msg);
+        }
+        for (Map.Entry<?, ?> entry : options.entrySet()) {
+            Option option = new Option(entry.getKey().toString(), entry
+                    .getValue().toString());
+            getOptionList().add(option);
+        }
+    }
+
+    /**
+     * Add the given array of string options to the Select option list. <p/> The
+     * options array string value will be used for the {@link Option#value} and
+     * {@link Option#label}.
+     *
+     * @param options the array of option values to add
+     * @throws IllegalArgumentException if options is null
+     */
+    public void addAll(String[] options) {
+        if (options == null) {
+            String msg = "options parameter cannot be null";
+            throw new IllegalArgumentException(msg);
+        }
+        for (String option : options) {
+            getOptionList().add(new Option(option, option));
+        }
+    }
+
+    /**
+     * Add the given collection of objects to the CheckList, creating new Option
+     * instances based on the object properties specified by optionValueProperty
+     * and optionLabelProperty.
+     *
+     * <pre class="prettyprint">
+     *   CheckList list = new CheckList("type", "Type:");
+     *   list.addAll(getCustomerService().getCustomerTypes(), "id", "name");
+     *   form.add(select); </pre>
+     *
+     * For example given the Collection of CustomerType <tt>objects</tt>,
+     * <tt>optionValueProperty</tt> "id" and <tt>optionLabelProperty</tt> "name",
+     * the <tt>id</tt> and <tt>name</tt> properties of each CustomerType will be
+     * retrieved. For each CustomerType in the Collection a new
+     * {@link org.apache.click.control.Option} instance is created and its
+     * <tt>value</tt> and <tt>label</tt> is set to the <tt>id</tt> and
+     * <tt>name</tt> retrieved from the CustomerType instance.
+     *
+     * @param objects the collection of objects to render as options
+     * @param optionValueProperty the name of the object property to render as
+     * the Option value
+     * @param optionLabelProperty the name of the object property to render as
+     * the Option label
+     * @throws IllegalArgumentException if objects or optionValueProperty
+     * parameter is null
+     */
+    public void addAll(Collection<?> objects, String optionValueProperty,
+        String optionLabelProperty) {
+        if (objects == null) {
+            String msg = "objects parameter cannot be null";
+            throw new IllegalArgumentException(msg);
+        }
+        if (optionValueProperty == null) {
+            String msg = "optionValueProperty parameter cannot be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (objects.isEmpty()) {
+            return;
+        }
+
+        ConfigService configService = ClickUtils.getConfigService();
+        PropertyService propertyService = configService.getPropertyService();
+        Map<?, ?> methodCache = new HashMap<Object, Object>();
+
+        for (Object object : objects) {
+            try {
+                Object valueResult =
+                    propertyService.getValue(object,
+                                             optionValueProperty,
+                                             methodCache);
+
+                // Default labelResult to valueResult
+                Object labelResult = valueResult;
+
+                // If optionLabelProperty is specified, lookup the labelResult
+                // from the object
+                if (optionLabelProperty != null) {
+                    labelResult =
+                        propertyService.getValue(object,
+                                                 optionLabelProperty,
+                                                 methodCache);
+                }
+
+                Option option = null;
+
+                if (labelResult != null) {
+                    option = new Option(valueResult, labelResult.toString());
+                } else {
+                    option = new Option(valueResult.toString());
+                }
+
+                getOptionList().add(option);
+
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Return the CheckList optionList DataProvider.
+     *
+     * @return the CheckList optionList DataProvider
+     */
+    public DataProvider<Option> getDataProvider() {
+        return dataProvider;
+    }
+
+    /**
+     * Set the CheckList option list DataProvider. The dataProvider must return
+     * a list containing Option values.
+     * <p/>
+     * Example usage:
+     *
+     * <pre class="prettyprint">
+     * CheckList checkList = new CheckList("languages");
+     *
+     * select.setDataProvider(new DataProvider() {
+     *     public List getData() {
+     *         List options = new ArrayList();
+     *         options.add(new Option("001", "Java"));
+     *         options.add(new Option("002", "Ruby"));
+     *         options.add(new Option("003", "Perl"));
+     *         return options;
+     *     }
+     * }); </pre>
+     *
+     * @param dataProvider the CheckList option list DataProvider
+     */
+    public void setDataProvider(DataProvider<Option> dataProvider) {
+        this.dataProvider = dataProvider;
+        if (dataProvider != null) {
+            if (optionList != null) {
+                ClickUtils.getLogService().warn("please note that setting a"
+                    + " dataProvider nullifies the optionList");
+            }
+            setOptionList(null);
+        }
+    }
+
+    /**
+     * Adds the given style-value pair to the style attribute of the outer div.
+     * Does not check whether the style is already set.
+     * <p/>
+     * Typically used for the width:
+     *
+     * <pre class="codeJava">
+     * list.addStyle(<span class="st">"&quot;width: 100%; height: 25em&quot;"</span>); </pre>
+     *
+     * @param style the style name:value pair without a ending ;
+     *
+     * @deprecated use @{link #setStyle(String, String)}
+     */
+    public void addStyle(String style) {
+        if (StringUtils.isBlank(style)) {
+            throw new IllegalArgumentException("The style is empty");
+        }
+        style = style.trim();
+
+        if (style.charAt(style.length() - 1) == ';') {
+            style = style + ";";
+        }
+
+        String old = getAttribute("style");
+        if (old == null || (old = old.trim()).length() == 0) {
+            setAttribute("style", style);
+        } else {
+            if (old.charAt(old.length() - 1) != ';') {
+                old = old + ';';
+            }
+            old = old + style;
+            setAttribute("style", old);
+        }
+    }
+
+    /**
+     * Return the Field focus JavaScript.
+     *
+     * @return the Field focus JavaScript
+     */
+    @Override
+    public String getFocusJavaScript() {
+        HtmlStringBuffer buffer = new HtmlStringBuffer();
+
+        buffer.append("setFocus('");
+        buffer.append(getName() + "_0");
+        buffer.append("');");
+
+        return buffer.toString();
+    }
+
+    /**
+     * The css height attribute-value.
+     * If null no height is set and the CheckList is not scrollable.
+     *
+     * @param height one of css height values (ie 40px) or null.
+     */
+    public void setHeight(String height) {
+        this.height = height;
+    }
+
+    /**
+     * The css-height attribute.
+     *
+     * @return Returns the height or null.
+     */
+    public String getHeight() {
+        return height;
+    }
+
+    /**
+     * Set the given html class. The class will be set on the select list
+     * together with the {@link #STYLE_CLASS}. Ie class="checkList my-class"
+     * where my-class is the set class. The default value is null.
+     *
+     * @deprecated use {@link #addStyleClass(String)} instead
+     *
+     * @param clazz the class to set or null
+     */
+    public void setHtmlClass(String clazz) {
+        addStyleClass(clazz);
+    }
+
+    /**
+     * The html class to set on this control.
+     *
+     * @see #setHtmlClass(String)
+     *
+     * @deprecated use {@link #getAttribute(String)} instead
+     *
+     * @return the class or null (default null)
+     */
+    public String getHtmlClass() {
+        return getAttribute("class");
+    }
+
+    /**
+     * Return the CheckList HEAD elements to be included in the page.
+     * The following resources are returned:
+     * <ul>
+     * <li><tt>click/checklist/checklist.css</tt></li>
+     * <li><tt>click/checklist/checklist.js</tt></li>
+     * <li><tt>click/prototype/builder.js</tt></li>
+     * <li><tt>click/prototype/controls.js</tt></li>
+     * <li><tt>click/prototype/dragdrop.js</tt></li>
+     * <li><tt>click/prototype/effects.js</tt></li>
+     * <li><tt>click/prototype/prototype.js</tt></li>
+     * <li><tt>click/prototype/slider.js</tt></li>
+     * </ul>
+     *
+     * @see org.apache.click.Control#getHeadElements()
+     *
+     * @return the HTML head import statements for the control
+     */
+    @Override
+    public List<Element> getHeadElements() {
+        if (headElements == null) {
+            Context context = getContext();
+            String versionIndicator = ClickUtils.getResourceVersionIndicator(context);
+
+            headElements = super.getHeadElements();
+
+            headElements.add(new CssImport("/click/checklist/checklist.css",
+                versionIndicator));
+            headElements.add(new JsImport("/click/checklist/checklist.js",
+                versionIndicator));
+
+            if (isSortable()) {
+                headElements.add(new JsImport("/click/prototype/prototype.js",
+                    versionIndicator));
+                headElements.add(new JsImport("/click/prototype/builder.js",
+                    versionIndicator));
+                headElements.add(new JsImport("/click/prototype/effects.js",
+                    versionIndicator));
+                headElements.add(new JsImport("/click/prototype/dragdrop.js",
+                    versionIndicator));
+                headElements.add(new JsImport("/click/prototype/controls.js",
+                    versionIndicator));
+                headElements.add(new JsImport("/click/prototype/slider.js",
+                    versionIndicator));
+            }
+        }
+
+        String checkListId = getId();
+        JsScript script = new JsScript();
+        script.setId(checkListId + "-js-setup");
+
+        if (!headElements.contains(script)) {
+            script.setExecuteOnDomReady(true);
+
+            HtmlStringBuffer buffer = new HtmlStringBuffer(50);
+
+            if (isSortable()) {
+                if (getHeight() != null) {
+                    buffer.append("Position.includeScrollOffset = true;\n");
+                }
+                // Script to execute
+                buffer.append("Sortable.create('");
+                buffer.append(StringEscapeUtils.escapeJavaScript(checkListId));
+                buffer.append("-ul'");
+
+                if (getHeight() != null) {
+                    buffer.append(", { scroll : '");
+                    buffer.append(StringEscapeUtils.escapeJavaScript(checkListId));
+                    buffer.append("'}");
+                }
+                buffer.append(");");
+
+            } else {
+                buffer.append("initChecklist('");
+                buffer.append(StringEscapeUtils.escapeJavaScript(checkListId));
+                buffer.append("-ul');\n");
+            }
+            script.setContent(buffer.toString());
+            headElements.add(script);
+        }
+
+        return headElements;
+    }
+
+    /**
+     * Return the Option list.
+     *
+     * @return the Option list
+     */
+    public List<Option> getOptionList() {
+        if (optionList == null) {
+
+            DataProvider<Option> dp = getDataProvider();
+
+            if (dp != null) {
+                Iterable<Option> iterableData = dp.getData();
+
+                if (iterableData instanceof List<?>) {
+                    // Set optionList to data
+                    setOptionList((List<Option>) iterableData);
+
+                } else {
+                    // Create and populate the optionList from the Iterable data
+                    optionList = new ArrayList<Option>();
+
+                    if (iterableData != null) {
+                        // Populate optionList from options
+                        for (Object option : iterableData) {
+                            add(option);
+                        }
+                    }
+                }
+            } else {
+                // Create empty list
+                optionList = new ArrayList<Option>();
+            }
+        }
+        return optionList;
+    }
+
+    /**
+     * Set the Option list. Note: if the CheckList is sortable
+     * than the List <b>must be fully modifiable</b>, because
+     * it will be sorted according to the order chosen by the
+     * user.
+     *
+     * @param options a list of Option objects
+     */
+    public void setOptionList(List<Option> options) {
+        optionList = options;
+    }
+    /**
+     * Whether the list should be drag-drop sortable. This is supported by
+     * scriptaculous. Note when the list also has a size than this might not work
+     * on different browsers.
+     *
+     * @param sortable default is false.
+     */
+    public void setSortable(boolean sortable) {
+        this.sortable = sortable;
+    }
+
+    /**
+     * Whether the list is also sortable.
+     *
+     * @return Returns the sortable.
+     */
+    public boolean isSortable() {
+        return sortable;
+    }
+
+    /**
+     * A list of the values transmitted in the order they are present in the
+     * list. This is only available if the list is sortable
+     *
+     * @return Returns list of strings of the option values.
+     */
+    public List<String> getSortorder() {
+        return sortorder;
+    }
+
+    /**
+     * Return the list of selected values as a <tt>List</tt> of Strings. The
+     * returned List will contain the values of the Options selected.
+     *
+     * @deprecated use {@link #getSelectedValues()} instead
+     *
+     * @return a list of Strings
+     */
+    public List<String> getValues() {
+        return getSelectedValues();
+    }
+
+    /**
+     * Return the list of selected values as a <tt>List</tt> of Strings. The
+     * returned List will contain the values of the Options selected.
+     *
+     * @return the list of selected values
+     */
+    public List<String> getSelectedValues() {
+        if (selectedValues != null) {
+            return selectedValues;
+
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    /**
+     * Set the list of selected values. The specified values must be Strings and
+     * match the values of the Options.
+     *
+     * @deprecated use {@link #setSelectedValues(List)} instead
+     *
+     * @param values a list of strings or null
+     */
+    public void setValues(List<String> values) {
+        this.selectedValues = values;
+    }
+
+    /**
+     * Set the list of selected values. The specified values must be Strings and
+     * match the values of the Options.
+     * <p/>
+     * For example:
+     * <pre class="prettyprint">
+     * CheckList checkList = new CheckList("checkList");
+     *
+     * public void onInit() {
+     *     List options = new ArrayList();
+     *     options.add(new Option("1", "Option 1");
+     *     options.add(new Option("2", "Option 2");
+     *     options.add(new Option("3", "Option 3");
+     *     checkList.setOptionList(options);
+     *     ...
+     * }
+     *
+     * public void onRender() {
+     *     // Preselect some Options.
+     *     List selected = new ArrayList();
+     *     selected.add("1"));
+     *     selected.add("3");
+     *     checkList.setSelectedValues(selected);
+     * } </pre>
+     *
+     * @param selectedValues the list of selected string values or null
+     */
+    public void setSelectedValues(List<String> selectedValues) {
+        this.selectedValues = selectedValues;
+    }
+
+    /**
+     * This method delegates to {@link #getSelectedValues()} to return the
+     * selected values as a <tt>java.util.List</tt> of Strings.
+     *
+     * @see org.apache.click.control.Field#getValueObject()
+     * @see #getSelectedValues()
+     *
+     * @return selected values as a List of Strings
+     */
+    @Override
+    public Object getValueObject() {
+        return getSelectedValues();
+    }
+
+    /**
+     * This method delegates to {@link #setSelectedValues(java.util.List)}
+     * to set the selected values of the CheckList. The given object parameter
+     * must be a <tt>java.util.List</tt> of Strings, otherwise it is ignored.
+     * <p/>
+     * The List of values match the values of the Options.
+     *
+     * @see org.apache.click.control.Field#setValueObject(java.lang.Object)
+     * @see #setSelectedValues(java.util.List)
+     *
+     * @param object a List of Strings
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public void setValueObject(Object object) {
+        if (object instanceof List<?>) {
+            setSelectedValues((List<String>) object);
+        }
+    }
+
+    /**
+     * Return the CheckList JavaScript client side validation function.
+     *
+     * @return the field JavaScript client side validation function
+     */
+    @Override
+    public String getValidationJavaScript() {
+        Object[] args = new Object[5];
+        args[0] = getId();
+        args[1] = getName();
+        args[2] = getForm().getId();
+        args[3] = String.valueOf(isRequired());
+        args[4] = getMessage("field-required-error", getErrorLabel());
+
+        return MessageFormat.format(VALIDATE_CHECKLIST_FUNCTION, args);
+    }
+
+    // Public Methods ---------------------------------------------------------
+
+    /**
+     * Bind the request submission, setting the {@link #selectedValues} and
+     * sort order if the checkList is sortable.
+     */
+    @Override
+    public void bindRequestValue() {
+
+        Context context = getContext();
+
+        // Page developer has not initialized options, which are required
+        // to support sorting
+        if (getOptionList().isEmpty()) {
+            return;
+        }
+
+        // Load the selected items.
+        List<String> localSelectedValues = new ArrayList<String>();
+
+        String[] parameterValues = context.getRequestParameterValues(getName());
+
+        if (parameterValues != null) {
+            for (String parameterValue : parameterValues) {
+                localSelectedValues.add(parameterValue);
+            }
+        }
+
+        if (isSortable()) {
+            String[] orderParameterValues = context.getRequest().getParameterValues(
+                    getName() + "_order");
+            if (orderParameterValues != null) {
+                this.sortorder = new ArrayList<String>(orderParameterValues.length);
+                for (String orderParameterValue : orderParameterValues) {
+                    if (orderParameterValue != null) {
+                        sortorder.add(orderParameterValue);
+                    }
+                }
+                sortOptions(orderParameterValues);
+            }
+        }
+        setSelectedValues(localSelectedValues);
+    }
+
+    /**
+     * Process the request Context setting the CheckList selectedValues if
+     * selected and invoking the control's listener if defined.
+     *
+     * @return true to continue Page event processing, false otherwise
+     */
+    @Override
+    public boolean onProcess() {
+        if (isDisabled()) {
+            Context context = getContext();
+
+            // Switch off disabled property if control has incoming request
+            // parameter. Normally this means the field was enabled via JS
+            if (context.hasRequestParameter(getName())) {
+                setDisabled(false);
+            } else {
+                // If field is disabled skip process event
+                return true;
+            }
+        }
+
+        // In Html an unchecked CheckList does not submit it's name/value so we
+        // always validate and dispatch registered events
+        bindRequestValue();
+
+        if (getValidate()) {
+            validate();
+        }
+
+        dispatchActionEvent();
+
+        return true;
+    }
+
+    /**
+     * Sorts the current Options List. This method is called
+     * in {@link #bindRequestValue()} when the CheckList
+     * is sortable.
+     *
+     * @param order values in the order to sort the list.
+     */
+    protected void sortOptions(String[] order) {
+        final List<Option> options = getOptionList();
+        final List<Option> orderList = new ArrayList<Option>(options.size());
+
+        for (int i = 0, size = order.length; i < size; i++) {
+            String orderValue = order[i];
+            if (orderValue != null) {
+                int oI = -1;
+                for (int j = 0, jSize = options.size(); j < jSize; j++) {
+                    Option optT = options.get(j);
+                    if (orderValue.equals(optT.getValue())) {
+                        oI = j;
+                    }
+                }
+                if (oI != -1) {
+                    orderList.add(options.remove(oI));
+                }
+            }
+        }
+        options.addAll(0, orderList);
+    }
+
+    /**
+     * @see org.apache.click.control.AbstractControl#getControlSizeEst()
+     *
+     * @return the estimated rendered control size in characters
+     */
+    @Override
+    public int getControlSizeEst() {
+        int bufferSize = 50;
+        if (!getOptionList().isEmpty()) {
+            bufferSize = bufferSize + (optionList.size() * 48);
+        }
+        return bufferSize;
+    }
+
+    /**
+     * Render the HTML representation of the CheckList.
+     *
+     * @see #toString()
+     *
+     * @param buffer the specified buffer to render the control's output to
+     */
+    @Override
+    public void render(HtmlStringBuffer buffer) {
+        final boolean sortable = isSortable();
+
+        // the div element
+        buffer.elementStart(getTag());
+
+        buffer.appendAttribute("id", getId());
+
+        // style class
+        addStyleClass(STYLE_CLASS);
+
+        if (isValid()) {
+            removeStyleClass("error");
+        } else {
+            addStyleClass("error");
+        }
+
+        // set the style
+        setStyle("height", getHeight());
+
+        if (sortable && getHeight() == null) {
+            setStyle("overflow", "hidden");
+        } else {
+            setStyle("overflow", "auto");
+        }
+
+        appendAttributes(buffer);
+
+        buffer.closeTag();
+
+        // the ul tag
+        buffer.elementStart("ul");
+        buffer.append(" id=\"").append(getId()).append("-ul\"");
+        buffer.closeTag();
+
+        // the options
+        List<Option> optionsList = getOptionList();
+        if (!optionsList.isEmpty()) {
+            int i = -1;
+            for (Option option : optionsList) {
+                i++;
+
+                buffer.append("<li>");
+                if (sortable) {
+                    buffer.elementStart("div");
+                    buffer.appendAttribute("style", "cursor:move;");
+                } else {
+                    buffer.elementStart("label");
+                    buffer.append(" for=\"").append(getName()).append('_').append(i).append("\"");
+                }
+                buffer.appendAttribute("class", "checkListLabel");
+                buffer.closeTag();
+
+                buffer.append("<input type=\"checkbox\" ");
+                buffer.appendAttributeEscaped("value", option.getValue());
+                buffer.append(" id=\"").append(getName()).append('_').append(i).append("\"");
+                buffer.appendAttribute("name", getName());
+
+                if (sortable) {
+                    buffer.appendAttribute("style", "cursor:default;");
+                }
+
+                // set checked status
+                boolean checked = false;
+                List<String> values = getSelectedValues();
+                for (int k = 0; k < values.size(); k++) {
+                    if (String.valueOf(values.get(k)).equals(option.getValue())) {
+                        checked = true;
+                    }
+                }
+
+                if (checked) {
+                    buffer.appendAttribute("checked", "checked");
+                }
+                if (isReadonly() || isDisabled()) {
+                    buffer.appendAttributeDisabled();
+                }
+                buffer.elementEnd();
+                buffer.appendEscaped(option.getLabel());
+
+                if (sortable) {
+                    buffer.append("</div>");
+                } else {
+                    buffer.append("</label>");
+                }
+
+                if (checked && (isReadonly() || isDisabled())) {
+                    buffer.elementStart("input");
+                    buffer.appendAttribute("type", "hidden");
+                    buffer.appendAttribute("name", getName());
+                    buffer.appendAttributeEscaped("value", option.getValue());
+                    buffer.elementEnd();
+                }
+
+                // hiddenfield if sortable
+
+                if (sortable) {
+                    buffer.append("<input type=\"hidden\"");
+                    buffer.appendAttribute("name", getName() + "_order");
+                    buffer.appendAttributeEscaped("value", option.getValue());
+                    buffer.elementEnd();
+                }
+
+                buffer.append("</li>");
+            }
+        }
+        buffer.append("</ul>");
+        buffer.elementEnd(getTag());
+    }
+
+    /**
+     * Validate the CheckList request submission.
+     * <p/>
+     * If a CheckList is {@link #required} then the user must select a value,
+     * otherwise the Select will have a validation error. If the Select is not
+     * required then no validation errors will occur.
+     * <p/>
+     * A field error message is displayed if a validation error occurs. These
+     * messages are defined in the resource bundle: <blockquote>
+     *
+     * <pre class="codeConfig>
+     *  /click-control.properties </pre>
+     *
+     * </blockquote> <p/> Error message bundle key names include: <blockquote>
+     * <ul>
+     * <li>select-error</li>
+     * </ul>
+     * </blockquote>
+     */
+    @Override
+    public void validate() {
+        if (isRequired()) {
+            if (getSelectedValues().isEmpty()) {
+                setErrorMessage("select-error");
+            }
+        }
+    }
+
+}

Propchange: click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/CheckList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/ColorPicker.htm
URL: http://svn.apache.org/viewvc/click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/ColorPicker.htm?rev=1538295&view=auto
==============================================================================
--- click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/ColorPicker.htm (added)
+++ click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/ColorPicker.htm Sat Nov  2 22:15:31 2013
@@ -0,0 +1,33 @@
+<!--
+#* Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.*#
+-->
+
+#if(${field.showTextField})
+  <input id="${id}" type="text" name="${field.name}" value="${value}" ${attributes}/>
+#else
+  <input id="${id}" type="hidden" name="${field.name}" value="${value}" ${attributes}/>
+  <span id="${id}_p" style="background-color:${value}" class="colorPickerPreview"></span>
+#end
+
+<img align="top" class="colorPickerImg" id="${id}_i"
+    onclick="Click.colorPicker.showColorPicker({
+        inputObjId:'${id}', imageId: '${id}_i', closeMsg:'${closeMsg}',
+        clearMsg: '${noColorMsg}', resourcePath:'${path}', isRequired:${field.required}
+        #if(!${field.showTextField}),previewId:'${id}_p' #end
+    })"
+    title="${chooseColorMsg}" src="${path}/click/colorpicker/images/color-picker.png"/>
\ No newline at end of file

Propchange: click/branches/click-3.0.0/click/prototypejs/src/org/apache/click/extras/prototypejs/ColorPicker.htm
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message