<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>src/htc/behaviors.css</filename>
    </added>
    <added>
      <filename>src/htc/component.htc</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -8,9 +8,28 @@ THC2_PKG_DIR  = File.join(THC2_ROOT, 'pkg')
 THC2_DOC_DIR  = File.join(THC2_ROOT, 'doc')
 THC2_VERSION  = '0.1'
 JSDOC_DIR     = File.join(THC2_ROOT, 'lib/jsdoc')
+HTC_SRC_DIR   = File.join(THC2_SRC_DIR, 'htc')
+HTC_DIST_DIR  = File.join(THC2_DIST_DIR, 'htc')
 
 task :default =&gt; [:dist, :document, :package, :clean_package_source]
 
+desc &quot;Generates HTC files for IE&quot;
+task :build_htcs =&gt; :dist do
+  src = File.read(File.join(THC2_DIST_DIR, 'thc2.js'))
+  behaviors = src.grep(/CurrentPage\.registerBehaviour\([\'\&quot;](thc2-[a-z\-]+)[\'\&quot;],\s+([A-Za-z]+)\)/) { [$1, $2] }
+  puts behaviors.inspect
+  FileUtils.mkdir_p HTC_DIST_DIR
+  behaviors.each do |css, klass|
+    File.open(File.join(HTC_DIST_DIR, &quot;#{css}.htc&quot;), 'w') do |file|
+      file.print ERB.new(IO.read(File.join(HTC_SRC_DIR, 'component.htc')), nil, '%').result(binding)
+    end
+  end
+  
+  File.open(File.join(HTC_DIST_DIR, &quot;behaviors.css&quot;), 'w') do |file|
+    file.print ERB.new(IO.read(File.join(HTC_SRC_DIR, 'behaviors.css')), nil, '%').result(binding)
+  end
+end
+
 desc &quot;Builds the distribution.&quot;
 task :dist do
   $:.unshift File.join(THC2_ROOT, 'lib')</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,8 @@
  *  (c) 2007-2008 imedo GmbH
  *
  *  THC2 is freely distributable under the terms of an MIT-style license.
- *  For details, see the THC2 web site: http://devblog.imedo.de/what?
+ *  For details, see the THC2 project web site:
+ *
+ *    http://opensource.imedo.de/pages/show/thc2
  *
  *--------------------------------------------------------------------------*/
- 
\ No newline at end of file</diff>
      <filename>src/HEADER</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/core/ajax_cache.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -57,6 +57,10 @@ var Benchmark = Class.create(
     return this.stop_time - this.start_time;
   },
   
+  lapTime: function() {
+    return (new Date()) - this.start_time;
+  },
+  
   /**
    * Convenience method that logs the measured time with log level &lt;code&gt;&quot;info&quot;&lt;/code&gt;.
    * See the {@link Logger} class for details about log levels.</diff>
      <filename>src/core/benchmark.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -36,7 +36,7 @@ var Core = {
    * @return {boolean} &lt;code&gt;true&lt;/code&gt;, if the file has been loaded, &lt;code&gt;false&lt;/code&gt; otherwise.
    */
   fileLoaded: function(file) {
-    return Core.requiredFiles.include(file);
+    return $A(Core.requiredFiles).include(file);
   },
   
   /**
@@ -47,7 +47,7 @@ var Core = {
    * @return {string} The file name relative to the server root with the file extension.
    */
   fileNameFor: function(file) {
-    return '/' + Core.loadPath + '/' + file + '.js';
+    return Core.loadPath + '/' + file + '.js';
   },
   
   /**
@@ -58,7 +58,7 @@ var Core = {
    * @param {string} file The file name relative to &lt;code&gt;loadPath&lt;/code&gt;, without the extension.
    */
   loadFile: function(file) {
-    // console.debug(&quot;Loading file &quot; + file);
+    // alert(&quot;Loading file &quot; + file);
     document.write('&lt;scr' + 'ipt type=&quot;text/javascript&quot; src=&quot;' + Core.fileNameFor(file) + '&quot;&gt;&lt;/scr' + 'ipt&gt;');
   },
   
@@ -102,7 +102,7 @@ var Core = {
  * @param {boolean} blocking Load the file immediately.
  */
 function require(file, blocking) {
-  Core.require(file, blocking);
+  Core.require(file, false);
 }
 
 RegExp.prototype.argumentNames = function() { return []; }</diff>
      <filename>src/core/core.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/core/environment.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/core/globalize.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,9 +3,26 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
+var NullLogger = {
+  log: function(text) {}
+}
+
+var ConsoleLogger = {
+  log: function(text) {
+    console.debug(text);
+  }
+};
+
+var DocumentLogger = {
+  log: function(text) {
+    var element = new Element('p').update(text);
+    $('logger').insert(element);
+  }
+};
+
 /**
  * Namespace for logging functions. See the {@link Environment} namespace for log level
  * information.
@@ -13,6 +30,9 @@
  * @class
  */
 var Logger = {
+  logger: window.console ? ConsoleLogger :
+          Environment.DebugLevel == 'info' ? DocumentLogger : NullLogger,
+  
   /**
    * Logs a message in the javascript console. If no javascript console is
    * available, nothing happens.
@@ -20,9 +40,7 @@ var Logger = {
    * @param {string} text The message.
    */
   log: function(text) {
-    try {
-      console.debug(text);
-    } catch(e) {}
+    Logger.logger.log(text);
   },
   
   /**</diff>
      <filename>src/core/logger.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/core/page.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/core/profiler.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   Prototype Extensions are freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 String.prototype.format = function() {</diff>
      <filename>src/core/prototype_ext.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/core/singleton.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -13,13 +13,13 @@
  * &lt;p&gt;To observe a TinyMCE field, create a new observer like so:&lt;/p&gt;
  *
  * &lt;pre&gt;
- * new TinyMCE.Observer(editor_id, frequency, callback)
+ * new TinyMCEObserver(editor_id, frequency, callback)
  * &lt;/pre&gt;
  *
  * @class
  * @extends Abstract.TimedObserver
  */
-TinyMCE.Observer = Class.create(Abstract.TimedObserver,
+TinyMCEObserver = Class.create(Abstract.TimedObserver,
 /** @scope TinyMCE.Observer.prototype */
 {
   /**</diff>
      <filename>src/core/tiny_mce_observer.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -32,30 +32,36 @@ Object.extend(Widget,
    * &lt;p&gt;Instead of this method, you should probably call &lt;code&gt;CurrentPage.applyBehaviours&lt;/code&gt;.&lt;/p&gt;
    */
   ApplyBehaviours: function(parent, behaviours) {
-    var objects = new Array();
-    try {
-      $A($(parent || document.body).getElementsByTagName(&quot;*&quot;)).each(function(element) {
-        var names = element.className;
-        if (/thc2-/.match(names) &gt; 0) {
-          var matching_classes = names.split(' ').select(function(c) { return new String(c).startsWith(&quot;thc2-&quot;); });
-          for (var i = 0; i &lt;= matching_classes.length; i++) {
-            var className = matching_classes[i];
-            var mapping = behaviours[className];
-            if (mapping &amp;&amp; CurrentPage.find(element, className).length == 0) {
-              try {
-                var obj = new mapping.klass(element);
-                obj.behaviour = className;
-              } catch(e) {
-                Logger.error(&quot;Could not create class &quot; + className + &quot;, error: &quot; + e.message);
-                return;
-              }
-              objects.push(obj);
+    var objects = [];
+    var elements = $(parent || document.body).getElementsByTagName(&quot;*&quot;);
+    for (var k = 0; k != elements.length; ++k) {
+      var element = elements[k];
+      var names = element.className;
+      if (/thc2-/.match(names) &gt; 0) {
+        var matching_classes = names.split(' ').select(function(c) { return c.startsWith(&quot;thc2-&quot;); });
+        for (var i = 0; i != matching_classes.length; i++) {
+          var className = matching_classes[i];
+          var mapping = behaviours[className];
+          if (mapping &amp;&amp; CurrentPage.find(element, className).length == 0) {
+            try {
+              // Logger.info('' + Initializer.benchmark.lapTime() + ': Creating Behaviour of type ' + className);
+              var obj = new mapping.klass(element);
+              obj.behaviour = className;
+            } catch(e) {
+              Logger.error(&quot;Could not create class &quot; + className + &quot;, error: &quot; + e.message);
+              return;
             }
+            objects.push(obj);
           }
         }
-      });
+      }
+    }
+    try {
       return objects;
-    } catch(e) {
+    } finally {
+      if (Prototype.Browser.IE) {
+        objects = null;
+      }
     }
   }
 });</diff>
      <filename>src/core/widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -6,7 +6,7 @@
   like. Feel free to modify this file.
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 var Initializer = {</diff>
      <filename>src/examples/init.js</filename>
    </modified>
    <modified>
      <diff>@@ -2,13 +2,13 @@
 
 &lt;%= include 'core/core.js', 'core/browser.js', 'core/environment.js', 'core/logger.js', 'core/globalize.js', 'core/benchmark.js', 'core/singleton.js', 'core/ajax_cache.js', 'core/page.js', 'core/widget.js', 'core/prototype_ext.js' %&gt;
 
-if (typeof TinyMCE != &quot;undefined&quot;) {
+if (typeof tinymce != &quot;undefined&quot;) {
 &lt;%= include 'core/tiny_mce_observer.js' %&gt;
 }
 
 &lt;%= include 'widgets/bubble.js', 'widgets/ajax_bubble.js', 'widgets/bookmark_widget.js', 'widgets/bubble_manager.js', 'widgets/bubble_trigger_widget.js', 'widgets/clickable_widget.js', 'widgets/code_input_widget.js', 'widgets/form_widget.js', 'widgets/limited_textarea_widget.js', 'widgets/mnemonic_form.js', 'widgets/placeholder_input_widget.js', 'widgets/popup_widget.js', 'widgets/rating_widget.js', 'widgets/remote_form.js', 'widgets/remote_link_widget.js', 'widgets/slideshow_widget.js', 'widgets/tab_widget.js', 'widgets/toggle_widget.js', 'widgets/check_list_widget.js', 'widgets/dropdown_menu_widget.js', 'widgets/photo_album_widget.js', 'widgets/zooming_teaser_widget.js', 'widgets/autocomplete_widget.js', 'widgets/combo_box_widget.js' %&gt;
 
-if (typeof TinyMCE != &quot;undefined&quot;) {
+if (typeof tinymce != &quot;undefined&quot;) {
 &lt;%= include 'widgets/tiny_mce_widget.js' %&gt;
 &lt;%= include 'widgets/editor_tab_widget.js' %&gt;
 }</diff>
      <filename>src/thc2.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
 
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/ajax_bubble.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
   
   Parts of this file are modified from an original version Copyright (c) 2007 stickmanlabs.
   See below for details.
@@ -35,8 +35,8 @@ var AutocompleteWidget = Class.create(Widget,
   initialize: function(element) {
     Widget.prototype.initialize.apply(this, arguments);
     this.autocompleteBox = $('autocomplete');
-    this.options = $('autocomplete-options').childElements().map(function(e){ return e.innerHTML; })
-    this.completer = new Autocompleter.Local(this.element, this.autocompleteBox, this.options);
+    this.items = $('autocomplete-options').childElements().map(function(e){ return e.innerHTML; })
+    this.completer = new Autocompleter.Local(this.element, this.autocompleteBox, this.items);
   }
 });
 </diff>
      <filename>src/widgets/autocomplete_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/bookmark_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
 
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -47,7 +47,7 @@ var Bubble = Class.create(
    * Calculates the bubble's vertical position.
    */
   verticalPosition: function(element_offset, bubble_size){
-    this.element.style.top = (( element_offset[1] - bubble_size['height']) + &quot;px&quot;);
+    this.element.style.top = (( element_offset[1] - bubble_size['height'] + this.verticalOffset()) + &quot;px&quot;);
   },
   
   /**
@@ -64,7 +64,21 @@ var Bubble = Class.create(
         left = element_offset[0]-bubble_size['width'];
       break;
     };
-    this.element.style.left = left + 'px';
+    this.element.style.left = (left + this.horizontalOffset()) + 'px';
+  },
+  
+  /**
+   * Override this method to specify a vertical offset for the bubble size.
+   */
+  verticalOffset: function() {
+    return 0;
+  },
+  
+  /**
+   * Override this method to specify a horizontal offset for the bubble size.
+   */
+  horizontalOffset: function() {
+    return 0;
   },
   
   /**</diff>
      <filename>src/widgets/bubble.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/bubble_manager.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
 
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/bubble_trigger_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -31,9 +31,9 @@ var CheckListWidget = Class.create(Widget,
    */
   initialize: function(element) {
     Widget.prototype.initialize.apply(this, arguments);
-    var selectAllElements = this.element.select('.select_all');
-    var deselectAllElements = this.element.select('.deselect_all');
-    var invertAllElements = this.element.select('.invert_all');
+    var selectAllElements = this.element.getElementsByClassName('select_all');
+    var deselectAllElements = this.element.getElementsByClassName('deselect_all');
+    var invertAllElements = this.element.getElementsByClassName('invert_all');
     
     selectAllElements.each(function(element) {
       Event.observe(element, 'click', this.selectAll.bindAsEventListener(this));</diff>
      <filename>src/widgets/check_list_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/clickable_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/code_input_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/combo_box_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 var DropdownMenuWidget = Class.create(Widget, {</diff>
      <filename>src/widgets/dropdown_menu_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
   
   TODO:
   -----</diff>
      <filename>src/widgets/editor_tab_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -55,9 +55,9 @@ var FormWidget = Class.create(Widget,
   initialize: function(element) {
     Widget.prototype.initialize.apply(this, arguments);
     
-    this.validators = new Array();
+    this.validators = [];
     this.form = this.element;
-    this.element.observe('submit', this.submit.bindAsEventListener(this));
+    Event.observe(this.element, 'submit', this.submit.bindAsEventListener(this));
   },
   
   /**
@@ -90,13 +90,29 @@ var FormWidget = Class.create(Widget,
    * Adds a validator to this form that checks if the specified field is non-empty.
    * If it is, the validation fails.
    *
+   * If your validate a radiogroup, the validator will check if at one of the radio buttons is selected.
+   * For radiogroups you have to use the name property as id, for the following example:
+   * 
+   * &lt;pre&gt;
+   * &amp;lt;form class=&quot;thc2-form-validation-widget&quot; action=&quot;/users&quot; id=&quot;signup-form&quot; method=&quot;post&quot;&amp;gt;
+   *   &amp;lt;input id=&quot;user_gender_male&quot;  name=&quot;user[gender]&quot; type=&quot;radio&quot; id=&quot;user_gender&quot; value=&quot;1&quot; /&amp;gt; male
+   *   &amp;lt;input id=&quot;user_gender_female&quot; name=&quot;user[gender]&quot; type=&quot;radio&quot; id=&quot;user_gender&quot; value=&quot;0&quot; /&amp;gt; female
+   * &amp;lt;input type=&quot;submit&quot; value=&quot;submit&quot; /&amp;gt;
+   * &lt;/pre&gt;
+   *
+   * you should use this validator-code:
+   *
+   * &lt;pre&gt;
+   * this.validatesPresenceOf('user[gender]', 'Please chose your gender.');
+   * &lt;/pre&gt;
    * @param {String,HTMLElement} id The form element that needs to be validated.
    * @message {String} An error message that is shown on failure.
    */
   validatesPresenceOf: function(id, message) {
     var field = $(id);
     this.validators.push(function() {
-      if (field &amp;&amp; (field.value == &quot;&quot; || $F(id) == null)) {
+      if ((field &amp;&amp; (field.value == &quot;&quot; || $F(id) == null)) 
+      || (!field &amp;&amp; ($$('input:checked[type=&quot;radio&quot;][name=&quot;'+id+'&quot;]') == 0))) {
         FormWidget.handleError(field, message);
         return false;
       }</diff>
      <filename>src/widgets/form_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
   
   TODO:
   -----</diff>
      <filename>src/widgets/limited_textarea_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -29,7 +29,7 @@ var MnemonicForm = Class.create(FormWidget,
       if (element.type != 'submit')
         this.inputs.push(element);
       if (element.type == 'text')
-        Event.observe(element, 'keyup', this.storeValues.bindAsEventListener(self));
+        Event.observe(element, 'keyup', this.storeValues.bindAsEventListener(this));
     }.bind(this));
     this.values = new Hash();
     this.storeValues();</diff>
      <filename>src/widgets/mnemonic_form.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
   
   TODO:
   -----</diff>
      <filename>src/widgets/photo_album_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -9,11 +9,9 @@
 /**
  * This widget displays a placeholder in a text input field that disappears on focus.
  *
- * &lt;p&gt;The placeholder is the title of the text input field. If no title is set the value
- * is used instead. If the field is empty on
+ * &lt;p&gt;The placeholder is the value of the text input field. If the field is empty on
  * blur, the placeholder appears again. Because of that, it is possible that the
- * placeholder is sent along with the enclosing form on submit. This does not happen when
- * using the title which is the recommended use.&lt;/p&gt;
+ * placeholder is sent along with the enclosing form on submit.&lt;/p&gt;
  *
  * &lt;p&gt;When the placeholder is displayed, the text field has the CSS class
  * &lt;code&gt;placeholder-input&lt;/code&gt;. You can use this fact for shading the text field
@@ -31,11 +29,11 @@ var PlaceholderInputWidget = Class.create(Widget,
   initialize: function(element) {
     Widget.prototype.initialize.apply(this, arguments);
 		this.element.value = this.element.value || this.element.title;
-    this.placeholder = this.element.value;
+    this.placeholder = this.element.title || this.element.value;
 		
     Event.observe(this.element, &quot;focus&quot;, this.focus.bindAsEventListener(this));
     Event.observe(this.element, &quot;blur&quot;, this.blur.bindAsEventListener(this));
-    Event.observe(this.element.up('form'), 'submit', this.submit.bindAsEventListener(this));
+    Event.observe(this.findForm(this.element), 'submit', this.submit.bindAsEventListener(this));
 
 		if((this.element.title &amp;&amp; this.element.title == this.element.value) || !this.element.title) {
     	this.element.addClassName(&quot;placeholder-input&quot;);
@@ -71,7 +69,17 @@ var PlaceholderInputWidget = Class.create(Widget,
 		if(this.element.value == this.placeholder) {
 			this.element.value = '';
 		}
+	},
+	
+	findForm: function(element) {
+	  if (element.tagName.toUpperCase() == 'HTML') {
+	    return undefined;
+	  } else if (element.tagName.toUpperCase() == 'FORM') {
+	    return element;
+	  } else {
+	    return this.findForm(element.parentNode);
+	  }
 	}
 });
 
-CurrentPage.registerBehaviour(&quot;thc2-placeholder-input&quot;, PlaceholderInputWidget);
+CurrentPage.registerBehaviour(&quot;thc2-placeholder-input&quot;, PlaceholderInputWidget);
\ No newline at end of file</diff>
      <filename>src/widgets/placeholder_input_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/popup_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
   
   BUT this only applies to this file. You'll need to come up with your own
   star image.
@@ -150,7 +150,7 @@ var RatingStar = Class.create(
   /**
    * Default star height. Adjust this property to use differently sized stars.
    */
-  starheight: 20,
+  starheight: 14,
   
   /**
    * Constructor.</diff>
      <filename>src/widgets/rating_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/remote_form.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/remote_link_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**</diff>
      <filename>src/widgets/slideshow_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -18,7 +18,7 @@
  * &lt;pre&gt;
  * &amp;lt;div&amp;gt;
  *   &amp;lt;ul class=&amp;quot;tab-list&amp;quot;&amp;gt;
- *     &amp;lt;li class=&amp;quot;on&amp;quot; title=&amp;quot;First tab&amp;quot;&amp;gt;
+ *     &amp;lt;li class=&amp;quot;select&amp;quot; title=&amp;quot;First tab&amp;quot;&amp;gt;
  *       &amp;lt;a href=&amp;quot;/first/tab&amp;quot;&amp;gt;First tab&amp;lt;/a&amp;gt;
  *     &amp;lt;/li&amp;gt;
  *     &amp;lt;li title=&amp;quot;Second tab&amp;quot;&amp;gt;
@@ -46,13 +46,18 @@ var TabWidget = Class.create(Widget,
    */
   initialize: function(element) {
     Widget.prototype.initialize.apply(this, arguments);
-    var i = 0;
+    this.initTabs();
+  },
+
+  /**
+   * Initializes the tabs.
+   * Call again if tab element reloaded/changed via AJAX.
+   */
+  initTabs: function() {
     this.list = $A(this.element.getElementsByClassName('tab-list')[0].getElementsByTagName(&quot;li&quot;));
-    var tabwidget = this;
-    
     this.tabs = this.list.collect(function(item) {
       var tab = new Tab(this, $(item));
-      if (item.hasClassName('on'))
+      if (item.hasClassName(Tab.activeClassName))
         this.currentTab = tab;
       return tab;
     }.bind(this));
@@ -120,6 +125,23 @@ var TabWidget = Class.create(Widget,
 });
 
 /**
+* FUCKO: Move effect to some better place. It's shit here
+*/
+Effect.PhaseIn = function(element, options) {
+  return new Effect.Parallel([
+    new Effect.Appear(element, { sync: true }),
+    new Effect.BlindDown(element, { sync: true, scaleFrom: 10})
+  ], options);
+}
+
+Effect.PhaseOut = function(element, options) {
+  return new Effect.Parallel([
+    new Effect.BlindUp(element, { sync: true, scaleTo: 10}),
+    new Effect.Fade(element, { sync: true })
+  ], options);
+}
+
+/**
  * This class provides a tab widget that loads the content of tabs
  * on the fly via ajax. The contents of already visited tabs are
  * cached. Note that this class automatically applies behaviours
@@ -133,6 +155,11 @@ var TabWidget = Class.create(Widget,
 var AjaxTabWidget = Class.create(TabWidget,
 /** @scope AjaxTabWidget.prototype */
 {
+  initialize: function(element) {
+    TabWidget.prototype.initialize.apply(this, arguments);
+    AjaxCache.self().store(this.currentTab.link, this.tabContent().innerHTML);
+  },
+  
   /**
    * Callback before the fade before a tab switch.
    */
@@ -183,7 +210,7 @@ var AjaxTabWidget = Class.create(TabWidget,
 
       this.beforeFade();
 
-      this.fadeEffect = new Effect.Fade(this.tabContainer(), {
+      this.fadeEffect = new Effect.PhaseOut(this.tabContainer(), {
         queue: { position: 'end', scope:'a' },
         afterFinish:this.fadeCallback.bind(this),
         duration: 0.5
@@ -219,7 +246,7 @@ var AjaxTabWidget = Class.create(TabWidget,
       this.contentBox.update(html);
       this.beforeAppear();
       this.switchCurrent(this.currentTab, this.nextTab);
-      this.appearEffect = new Effect.Appear(this.tabContainer(), {
+      this.appearEffect = new Effect.PhaseIn(this.tabContainer(), {
         queue: { position: 'end', scope:'b' },
         afterFinish:this.appearCallback.bind(this),
         duration: 0.5
@@ -281,13 +308,15 @@ var Tab = Class.create(
    * Sets the tab to &quot;on&quot; state.
    */
   turnOn: function() {
-    this.button.addClassName('on');
+    this.button.addClassName(Tab.activeClassName);
   },
   
   /**
    * Sets the tab to &quot;off&quot; state.
    */
   turnOff: function() {
-    this.button.removeClassName('on');
+    this.button.removeClassName(Tab.activeClassName);
   }
 });
+
+Tab.activeClassName = 'selected';</diff>
      <filename>src/widgets/tab_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -16,13 +16,21 @@ var TinyMCEWidget = Class.create(Widget,
 /** @scope TinyMCEWidget.prototype */
 {
   /**
-   * Constructor.
+  * Settings for TinyMCE, which will be applied on initialization
+  */
+  settings: { relative_urls: false,
+              convert_urls: false
+            },
+  
+  /**
+   * Constructor. Also applies settings to editor
    */
   initialize: function(element) {
     Widget.prototype.initialize.apply(this, arguments);
+    tinyMCE.settings = this.settings;
     tinyMCE.execCommand('mceAddControl', true, this.element.id);
   },
-  
+
   /**
    * Returns the TinyMCE editor instance for this widget.
    * @return {TinyMCE} The editor instance.</diff>
      <filename>src/widgets/tiny_mce_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -43,6 +43,8 @@ var ToggleWidget = Class.create(Widget,
   init: false,
   defaultEffect: 'blind',
   defaultDuration: 0.5,
+  defaultOpenClass: 'open',
+  defaultClosedClass: 'closed',
 
   /**
    * Constructor.
@@ -54,6 +56,8 @@ var ToggleWidget = Class.create(Widget,
     Widget.prototype.initialize.apply(this, arguments);
     this.effect = this.defaultEffect;
     this.duration = this.defaultDuration;
+    this.openClass = this.defaultOpenClass;
+    this.closedClass = this.defaultClosedClass;
     
     if (options &amp;&amp; options['target']) {
       this.setLink(this.element);
@@ -71,11 +75,26 @@ var ToggleWidget = Class.create(Widget,
     if (!this.init) {
       this.extractParameters();
     }
-    Effect.toggle(this.target, this.effect, {duration: this.duration});
+    Effect.toggle(this.target, this.effect, {duration: this.duration, afterFinish: this.toggleClassNames.bind(this)});
     event.stop();
   },
   
   /**
+  * Toggle open and closed classes. 
+  * If none of the class names is present to begin with, nothing will happen.
+  * Default classes are 'open' and 'closed'.
+  */
+  toggleClassNames: function(){
+    if(this.element.hasClassName(this.closedClass)){
+      this.element.removeClassName(this.closedClass);
+      this.element.addClassName(this.openClass);
+    } else if(this.element.hasClassName(this.openClass)) {
+      this.element.removeClassName(this.openClass);
+      this.element.addClassName(this.closedClass);
+    }
+  },
+  
+  /**
    * Sets the link to &lt;code&gt;link&lt;/code&gt; and observes the click event.
    * If another link has been set before, the old click event handler
    * is removed.
@@ -133,13 +152,20 @@ var ToggleWidget = Class.create(Widget,
    * in the options hash.
    */
   extractTarget: function() {
-    var target = $w($(this.element).className).find(function(klass) { return klass.startsWith(&quot;toggle_&quot;); });
+    var classNames = $(this.element).className.split(' ');
+    for (var i = 0; i != classNames.length; ++i) {
+      if (classNames[i].startsWith(&quot;toggle_&quot;)) {
+        var target = classNames[i];
+        break;
+      }
+    }
+    
     if (target) {
       this.setLink(this.element);
       this.target = $(target.gsub(&quot;toggle_&quot;, ''));
     } else {
       this.setLink(this.element.getElementsByTagName(&quot;a&quot;)[0]);
-      targetElement = this.element.getElementsBySelector(&quot;div&quot;)[0];
+      var targetElement = this.element.getElementsByTagName(&quot;div&quot;)[0];
       if (targetElement) {
         this.target = targetElement;
       }</diff>
      <filename>src/widgets/toggle_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
    (c) 2007 imedo GmbH
  
   This file is freely distributable under the terms of an MIT-style license.
-  For details, see the imedo.de web site: http://www.imedo.de
+  For details, see the project home page: http://opensource.imedo.de/pages/show/thc2
 */
 
 /**
@@ -45,15 +45,14 @@ var ZoomingTeaserWidget = Class.create(Widget,
    * @inner
    */
   resetItems: function(item){
-    var self = this;
     this.findChildren(item);
     this.items.each(function(subitem){
-      self.findChildren(subitem);
+      this.findChildren(subitem);
       if(item != subitem){
         subitem.over.hide();
         subitem.out.show();
       }
-    });
+    }.bind(this));
     item.out.hide();
     item.over.show();
   },</diff>
      <filename>src/widgets/zooming_teaser_widget.js</filename>
    </modified>
    <modified>
      <diff>@@ -21,7 +21,7 @@ class Browser
   end
   
   def windows?
-    host.include?('mswin')
+    host.include?('mswin') || host.include?('cygwin')
   end
   
   def linux?
@@ -35,19 +35,23 @@ class Browser
 end
 
 class FirefoxBrowser &lt; Browser
-  def initialize(path=File.join(ENV['ProgramFiles'] || 'c:\Program Files', '\Mozilla Firefox\firefox.exe'))
+  def initialize(path=File.join(ENV['ProgramFiles'] || '/cygdrive/c/Programme', 'Mozilla Firefox/firefox.exe'))
     @path = path
   end
 
   def visit(url)
     system(&quot;open -a Firefox '#{url}'&quot;) if macos?
-    system(&quot;#{@path} #{url}&quot;) if windows? 
+    system(&quot;'#{@path}' #{url}&quot;) if windows? 
     system(&quot;firefox #{url}&quot;) if linux?
   end
 
   def to_s
     &quot;Firefox&quot;
   end
+  
+  def teardown
+    system('taskkill /f /im firefox.exe') if windows?
+  end
 end
 
 class SafariBrowser &lt; Browser
@@ -95,6 +99,10 @@ class IEBrowser &lt; Browser
   def to_s
     &quot;Internet Explorer&quot;
   end
+  
+  def teardown
+    system('taskkill /f /im iexplore.exe') if windows?
+  end
 end
 
 class KonquerorBrowser &lt; Browser
@@ -136,7 +144,7 @@ class KonquerorBrowser &lt; Browser
 end
 
 class OperaBrowser &lt; Browser
-  def initialize(path='c:\Program Files\Opera\Opera.exe')
+  def initialize(path='/cygdrive/c/Programme/Opera/Opera.exe')
     @path = path
   end
   
@@ -157,7 +165,7 @@ class OperaBrowser &lt; Browser
     system(&quot;#{@path} #{url}&quot;) if windows? 
     system(&quot;opera #{url}&quot;)  if linux?
   end
-
+  
   def to_s
     &quot;Opera&quot;
   end
@@ -294,6 +302,8 @@ class JavaScriptTestTask &lt; ::Rake::TaskLib
       trap(&quot;INT&quot;) { @server.shutdown }
       t = Thread.new { @server.start }
       
+      success = true
+      
       # run all combinations of browsers and tests
       @browsers.each do |browser|
         if browser.supported?
@@ -312,6 +322,7 @@ class JavaScriptTestTask &lt; ::Rake::TaskLib
           
           print &quot;\nFinished in #{Time.now - t0} seconds.&quot;
           print test_suite_results
+          success &amp;&amp;= !test_suite_results.error? &amp;&amp; !test_suite_results.failure?
           browser.teardown
         else
           puts &quot;\nSkipping #{browser}, not supported on this OS.&quot;
@@ -320,6 +331,8 @@ class JavaScriptTestTask &lt; ::Rake::TaskLib
 
       @server.shutdown
       t.join
+      
+      raise &quot;failed&quot; unless success
     end
   end
   </diff>
      <filename>test/lib/jstest.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,7 @@
         &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
 &lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
 &lt;head&gt;
-  &lt;title&gt;THC2 Unit test file | &lt;%= @title %&gt;&lt;/title&gt;
+  &lt;title&gt;&lt;%= @title %&gt; | THC2 Unit test file&lt;/title&gt;
   &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
   &lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;
     var eventResults = {};
@@ -31,6 +31,8 @@
 &lt;h1&gt;THC2 Unit test file&lt;/h1&gt;
 &lt;h2&gt;&lt;%= @title %&gt;&lt;/h2&gt;
 
+&lt;p&gt;&lt;a href=&quot;file://&lt;%= File.expand_path(&quot;#{Dir.pwd}/test/unit/tmp/#{@js_filename.sub(/\.js/, '.html')}&quot;) %&gt;&quot; id=&quot;reload-link&quot;&gt;Reload locally&lt;/a&gt;&lt;/p&gt;
+
 &lt;!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify &lt;%= @fixtures_filename %&gt; --&gt;
 
 &lt;!-- Log output start --&gt;</diff>
      <filename>test/lib/template.erb</filename>
    </modified>
    <modified>
      <diff>@@ -52,4 +52,13 @@
     This is a toggle box where toggle link and toggle target are connected in Javascript.
   &lt;/p&gt;
 &lt;/li&gt;
+&lt;li&gt;
+  &lt;p&gt;Link and Target specified in Javascript code with toggle class&lt;/p&gt;
+  
+  &lt;a href=&quot;#&quot; id=&quot;toggle_with_js_target_and_toggle_class&quot; class=&quot;open&quot;&gt;Toggle me (specified in JS)&lt;/a&gt;
+  
+  &lt;p id=&quot;target_js_toggle_class&quot; style=&quot;display:none; border: 1px solid #000;&quot;&gt;
+    This is a toggle box where toggle link and toggle target are connected in Javascript.
+  &lt;/p&gt;
+&lt;/li&gt;
 &lt;/ul&gt;</diff>
      <filename>test/unit/fixtures/toggle_widget.html</filename>
    </modified>
    <modified>
      <diff>@@ -19,20 +19,20 @@ new Test.Unit.Runner({
     var w = new RemoteLinkWidget($('remote_link'));
     Event.simulateMouse(w.element, 'click');
     
-  }},
-
-  testCallbacks: function() { with(this) {
-    var w = new RemoteLinkWidget($('remote_link'));
-    var numCalled = 0;
-    var callbacks = ['loading', 'loaded', 'interactive', 'success', 'failure', 'complete'];
-    callbacks.each(function(callback) {
-      mockup(w, callback, function() {
-        numCalled++;
-      }.bind(this));
-    }.bind(this));
-    Event.simulateMouse(w.element, 'click');
-    this.wait(1000, function() {
-      this.assertEqual(callbacks.length, numCalled);
-    }.bind(this));
-  }}
-});
+  }}// ,
+  // 
+  //   testCallbacks: function() { with(this) {
+  //     var w = new RemoteLinkWidget($('remote_link'));
+  //     var numCalled = 0;
+  //     var callbacks = ['loading', 'loaded', 'interactive', 'success', 'failure', 'complete'];
+  //     callbacks.each(function(callback) {
+  //       mockup(w, callback, function() {
+  //         numCalled++;
+  //       }.bind(this));
+  //     }.bind(this));
+  //     Event.simulateMouse(w.element, 'click');
+  //     this.wait(1000, function() {
+  //       this.assertEqual(callbacks.length, numCalled);
+  //     }.bind(this));
+  //   }}
+  });</diff>
      <filename>test/unit/remote_link_widget_test.js</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,8 @@ new Test.Unit.Runner({
   
   teardown: function() {
     ['auto-toggler', 'toggle_with_explicit_target', 'toggle_with_js_target',
-     'auto-toggler-effect', 'toggle_with_explicit_target_and_effect', 'toggle_with_js_target_and_effect'].each(function(w) {
+     'auto-toggler-effect', 'toggle_with_explicit_target_and_effect', 'toggle_with_js_target_and_effect',
+     'toggle_with_js_target_and_toggle_class'].each(function(w) {
       Event.stopObserving(w, 'click');
     });
   },
@@ -111,5 +112,17 @@ new Test.Unit.Runner({
     var w = new ToggleWidget($('toggle_with_auto_target'));
     w.extractParameters();
     assertEqual(w.defaultEffect, w.effect);
+  }},
+  
+  testToggleClassesWhenClassOpenGiven: function(){ with(this) {
+    // this does not work right now, because the change of the class name
+    // is the transition effect's after hook, which happens asynchronously
+
+    // var w = new ToggleWidget($('toggle_with_js_target_and_toggle_class'), { target: 'target_js_toggle_class' });
+    // assert(w.element.hasClassName('open'));
+    // Event.simulateMouse(w.link, 'click');
+    // assert(w.element.hasClassName('closed'));
+    // Event.simulateMouse(w.link, 'click');
+    // assert(w.element.hasClassName('open'));
   }}
 });</diff>
      <filename>test/unit/toggle_widget_test.js</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>examples/placeholder_widget.html</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>1f0bc09c9a4dd96c9c60b521b9a84d72932d0bbf</id>
    </parent>
    <parent>
      <id>8b366845f3e2afb8b8f7285022dabe1183b924df</id>
    </parent>
  </parents>
  <author>
    <name>Thomas Kadauke</name>
    <email>tkadauke@imedo.de</email>
  </author>
  <url>http://github.com/imedo/thc2/commit/3e8fe9912e539b54d1044294a54601789cf21395</url>
  <id>3e8fe9912e539b54d1044294a54601789cf21395</id>
  <committed-date>2009-04-30T19:07:53-07:00</committed-date>
  <authored-date>2009-04-30T19:05:49-07:00</authored-date>
  <message>merge with main repository</message>
  <tree>9b585dd0f40dfab3969e168f3dec7e8c969f3fc2</tree>
  <committer>
    <name>Thomas Kadauke</name>
    <email>tkadauke@imedo.de</email>
  </committer>
</commit>
