You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2007/11/12 23:23:28 UTC

svn commit: r594319 [22/40] - in /tapestry/tapestry5/trunk: ./ tapestry-annotations/ tapestry-annotations/src/main/java/org/apache/tapestry/beaneditor/ tapestry-annotations/src/site/ tapestry-component-report/ tapestry-component-report/src/main/java/or...

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/controls.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/controls.js?rev=594319&r1=594318&r2=594319&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/controls.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/controls.js Mon Nov 12 14:22:31 2007
@@ -36,339 +36,395 @@
 // useful when one of the tokens is \n (a newline), as it 
 // allows smart autocompletion after linebreaks.
 
-if(typeof Effect == 'undefined')
-  throw("controls.js requires including script.aculo.us' effects.js library");
+if (typeof Effect == 'undefined')
+    throw("controls.js requires including script.aculo.us' effects.js library");
 
 var Autocompleter = { }
 Autocompleter.Base = Class.create({
-  baseInitialize: function(element, update, options) {
-    element          = $(element)
-    this.element     = element; 
-    this.update      = $(update);  
-    this.hasFocus    = false; 
-    this.changed     = false; 
-    this.active      = false; 
-    this.index       = 0;     
-    this.entryCount  = 0;
-    this.oldElementValue = this.element.value;
-
-    if(this.setOptions)
-      this.setOptions(options);
-    else
-      this.options = options || { };
-
-    this.options.paramName    = this.options.paramName || this.element.name;
-    this.options.tokens       = this.options.tokens || [];
-    this.options.frequency    = this.options.frequency || 0.4;
-    this.options.minChars     = this.options.minChars || 1;
-    this.options.onShow       = this.options.onShow || 
-      function(element, update){ 
-        if(!update.style.position || update.style.position=='absolute') {
-          update.style.position = 'absolute';
-          Position.clone(element, update, {
-            setHeight: false, 
-            offsetTop: element.offsetHeight
-          });
-        }
-        Effect.Appear(update,{duration:0.15});
-      };
-    this.options.onHide = this.options.onHide || 
-      function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+    baseInitialize: function(element, update, options)
+    {
+        element = $(element)
+        this.element = element;
+        this.update = $(update);
+        this.hasFocus = false;
+        this.changed = false;
+        this.active = false;
+        this.index = 0;
+        this.entryCount = 0;
+        this.oldElementValue = this.element.value;
 
-    if(typeof(this.options.tokens) == 'string') 
-      this.options.tokens = new Array(this.options.tokens);
+        if (this.setOptions)
+            this.setOptions(options);
+        else
+            this.options = options || { };
+
+        this.options.paramName = this.options.paramName || this.element.name;
+        this.options.tokens = this.options.tokens || [];
+        this.options.frequency = this.options.frequency || 0.4;
+        this.options.minChars = this.options.minChars || 1;
+        this.options.onShow = this.options.onShow ||
+                              function(element, update)
+                              {
+                                  if (!update.style.position || update.style.position == 'absolute')
+                                  {
+                                      update.style.position = 'absolute';
+                                      Position.clone(element, update, {
+                                          setHeight: false,
+                                          offsetTop: element.offsetHeight
+                                      });
+                                  }
+                                  Effect.Appear(update, {duration:0.15});
+                              };
+        this.options.onHide = this.options.onHide ||
+                              function(element, update)
+                              {
+                                  new Effect.Fade(update, {duration:0.15})
+                              };
+
+        if (typeof(this.options.tokens) == 'string')
+            this.options.tokens = new Array(this.options.tokens);
     // Force carriage returns as token delimiters anyway
-    if (!this.options.tokens.include('\n'))
-      this.options.tokens.push('\n');
+        if (!this.options.tokens.include('\n'))
+            this.options.tokens.push('\n');
 
-    this.observer = null;
-    
-    this.element.setAttribute('autocomplete','off');
-
-    Element.hide(this.update);
-
-    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
-    Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));
-  },
-
-  show: function() {
-    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
-    if(!this.iefix && 
-      (Prototype.Browser.IE) &&
-      (Element.getStyle(this.update, 'position')=='absolute')) {
-      new Insertion.After(this.update, 
-       '<iframe id="' + this.update.id + '_iefix" '+
-       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
-       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
-      this.iefix = $(this.update.id+'_iefix');
-    }
-    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
-  },
-  
-  fixIEOverlapping: function() {
-    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
-    this.iefix.style.zIndex = 1;
-    this.update.style.zIndex = 2;
-    Element.show(this.iefix);
-  },
-
-  hide: function() {
-    this.stopIndicator();
-    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
-    if(this.iefix) Element.hide(this.iefix);
-  },
-
-  startIndicator: function() {
-    if(this.options.indicator) Element.show(this.options.indicator);
-  },
-
-  stopIndicator: function() {
-    if(this.options.indicator) Element.hide(this.options.indicator);
-  },
-
-  onKeyPress: function(event) {
-    if(this.active)
-      switch(event.keyCode) {
-       case Event.KEY_TAB:
-       case Event.KEY_RETURN:
-         this.selectEntry();
-         Event.stop(event);
-       case Event.KEY_ESC:
-         this.hide();
-         this.active = false;
-         Event.stop(event);
-         return;
-       case Event.KEY_LEFT:
-       case Event.KEY_RIGHT:
-         return;
-       case Event.KEY_UP:
-         this.markPrevious();
-         this.render();
-         if(Prototype.Browser.WebKit) Event.stop(event);
-         return;
-       case Event.KEY_DOWN:
-         this.markNext();
-         this.render();
-         if(Prototype.Browser.WebKit) Event.stop(event);
-         return;
-      }
-     else 
-       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
-         (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
-
-    this.changed = true;
-    this.hasFocus = true;
-
-    if(this.observer) clearTimeout(this.observer);
-      this.observer = 
-        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
-  },
-
-  activate: function() {
-    this.changed = false;
-    this.hasFocus = true;
-    this.getUpdatedChoices();
-  },
-
-  onHover: function(event) {
-    var element = Event.findElement(event, 'LI');
-    if(this.index != element.autocompleteIndex) 
+        this.observer = null;
+
+        this.element.setAttribute('autocomplete', 'off');
+
+        Element.hide(this.update);
+
+        Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
+        Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));
+    },
+
+    show: function()
     {
-        this.index = element.autocompleteIndex;
-        this.render();
-    }
-    Event.stop(event);
-  },
-  
-  onClick: function(event) {
-    var element = Event.findElement(event, 'LI');
-    this.index = element.autocompleteIndex;
-    this.selectEntry();
-    this.hide();
-  },
-  
-  onBlur: function(event) {
-    // needed to make click events working
-    setTimeout(this.hide.bind(this), 250);
-    this.hasFocus = false;
-    this.active = false;     
-  }, 
-  
-  render: function() {
-    if(this.entryCount > 0) {
-      for (var i = 0; i < this.entryCount; i++)
-        this.index==i ? 
-          Element.addClassName(this.getEntry(i),"selected") : 
-          Element.removeClassName(this.getEntry(i),"selected");
-      if(this.hasFocus) { 
-        this.show();
-        this.active = true;
-      }
-    } else {
-      this.active = false;
-      this.hide();
-    }
-  },
-  
-  markPrevious: function() {
-    if(this.index > 0) this.index--
-      else this.index = this.entryCount-1;
-    this.getEntry(this.index).scrollIntoView(true);
-  },
-  
-  markNext: function() {
-    if(this.index < this.entryCount-1) this.index++
-      else this.index = 0;
-    this.getEntry(this.index).scrollIntoView(false);
-  },
-  
-  getEntry: function(index) {
-    return this.update.firstChild.childNodes[index];
-  },
-  
-  getCurrentEntry: function() {
-    return this.getEntry(this.index);
-  },
-  
-  selectEntry: function() {
-    this.active = false;
-    this.updateElement(this.getCurrentEntry());
-  },
-
-  updateElement: function(selectedElement) {
-    if (this.options.updateElement) {
-      this.options.updateElement(selectedElement);
-      return;
-    }
-    var value = '';
-    if (this.options.select) {
-      var nodes = $(selectedElement).select('.' + this.options.select) || [];
-      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
-    } else
-      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
-    
-    var bounds = this.getTokenBounds();
-    if (bounds[0] != -1) {
-      var newValue = this.element.value.substr(0, bounds[0]);
-      var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
-      if (whitespace)
-        newValue += whitespace[0];
-      this.element.value = newValue + value + this.element.value.substr(bounds[1]);
-    } else {
-      this.element.value = value;
-    }
-    this.oldElementValue = this.element.value;
-    this.element.focus();
-    
-    if (this.options.afterUpdateElement)
-      this.options.afterUpdateElement(this.element, selectedElement);
-  },
-
-  updateChoices: function(choices) {
-    if(!this.changed && this.hasFocus) {
-      this.update.innerHTML = choices;
-      Element.cleanWhitespace(this.update);
-      Element.cleanWhitespace(this.update.down());
-
-      if(this.update.firstChild && this.update.down().childNodes) {
-        this.entryCount = 
-          this.update.down().childNodes.length;
-        for (var i = 0; i < this.entryCount; i++) {
-          var entry = this.getEntry(i);
-          entry.autocompleteIndex = i;
-          this.addObservers(entry);
+        if (Element.getStyle(this.update, 'display') == 'none') this.options.onShow(this.element, this.update);
+        if (!this.iefix &&
+            (Prototype.Browser.IE) &&
+            (Element.getStyle(this.update, 'position') == 'absolute'))
+        {
+            new Insertion.After(this.update,
+                    '<iframe id="' + this.update.id + '_iefix" ' +
+                    'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+                    'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+            this.iefix = $(this.update.id + '_iefix');
         }
-      } else { 
-        this.entryCount = 0;
-      }
+        if (this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+    },
+
+    fixIEOverlapping: function()
+    {
+        Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+        this.iefix.style.zIndex = 1;
+        this.update.style.zIndex = 2;
+        Element.show(this.iefix);
+    },
+
+    hide: function()
+    {
+        this.stopIndicator();
+        if (Element.getStyle(this.update, 'display') != 'none') this.options.onHide(this.element, this.update);
+        if (this.iefix) Element.hide(this.iefix);
+    },
+
+    startIndicator: function()
+    {
+        if (this.options.indicator) Element.show(this.options.indicator);
+    },
+
+    stopIndicator: function()
+    {
+        if (this.options.indicator) Element.hide(this.options.indicator);
+    },
 
-      this.stopIndicator();
-      this.index = 0;
-      
-      if(this.entryCount==1 && this.options.autoSelect) {
+    onKeyPress: function(event)
+    {
+        if (this.active)
+            switch (event.keyCode)
+                    {
+                case Event.KEY_TAB:
+                case Event.KEY_RETURN:
+                    this.selectEntry();
+                    Event.stop(event);
+                case Event.KEY_ESC:
+                    this.hide();
+                    this.active = false;
+                    Event.stop(event);
+                    return;
+                case Event.KEY_LEFT:
+                case Event.KEY_RIGHT:
+                    return;
+                case Event.KEY_UP:
+                    this.markPrevious();
+                    this.render();
+                    if (Prototype.Browser.WebKit) Event.stop(event);
+                    return;
+                case Event.KEY_DOWN:
+                    this.markNext();
+                    this.render();
+                    if (Prototype.Browser.WebKit) Event.stop(event);
+                    return;
+            }
+        else
+            if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN ||
+                (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
+
+        this.changed = true;
+        this.hasFocus = true;
+
+        if (this.observer) clearTimeout(this.observer);
+        this.observer =
+        setTimeout(this.onObserverEvent.bind(this), this.options.frequency * 1000);
+    },
+
+    activate: function()
+    {
+        this.changed = false;
+        this.hasFocus = true;
+        this.getUpdatedChoices();
+    },
+
+    onHover: function(event)
+    {
+        var element = Event.findElement(event, 'LI');
+        if (this.index != element.autocompleteIndex)
+        {
+            this.index = element.autocompleteIndex;
+            this.render();
+        }
+        Event.stop(event);
+    },
+
+    onClick: function(event)
+    {
+        var element = Event.findElement(event, 'LI');
+        this.index = element.autocompleteIndex;
         this.selectEntry();
         this.hide();
-      } else {
-        this.render();
-      }
-    }
-  },
+    },
 
-  addObservers: function(element) {
-    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
-    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
-  },
-
-  onObserverEvent: function() {
-    this.changed = false;   
-    this.tokenBounds = null;
-    if(this.getToken().length>=this.options.minChars) {
-      this.getUpdatedChoices();
-    } else {
-      this.active = false;
-      this.hide();
-    }
-    this.oldElementValue = this.element.value;
-  },
+    onBlur: function(event)
+    {
+        // needed to make click events working
+        setTimeout(this.hide.bind(this), 250);
+        this.hasFocus = false;
+        this.active = false;
+    },
+
+    render: function()
+    {
+        if (this.entryCount > 0)
+        {
+            for (var i = 0; i < this.entryCount; i++)
+                this.index == i ?
+                Element.addClassName(this.getEntry(i), "selected") :
+                Element.removeClassName(this.getEntry(i), "selected");
+            if (this.hasFocus)
+            {
+                this.show();
+                this.active = true;
+            }
+        }
+        else
+        {
+            this.active = false;
+            this.hide();
+        }
+    },
 
-  getToken: function() {
-    var bounds = this.getTokenBounds();
-    return this.element.value.substring(bounds[0], bounds[1]).strip();
-  },
-
-  getTokenBounds: function() {
-    if (null != this.tokenBounds) return this.tokenBounds;
-    var value = this.element.value;
-    if (value.strip().empty()) return [-1, 0];
-    var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
-    var offset = (diff == this.oldElementValue.length ? 1 : 0);
-    var prevTokenPos = -1, nextTokenPos = value.length;
-    var tp;
-    for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
-      tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
-      if (tp > prevTokenPos) prevTokenPos = tp;
-      tp = value.indexOf(this.options.tokens[index], diff + offset);
-      if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
+    markPrevious: function()
+    {
+        if (this.index > 0) this.index--
+        else this.index = this.entryCount - 1;
+        this.getEntry(this.index).scrollIntoView(true);
+    },
+
+    markNext: function()
+    {
+        if (this.index < this.entryCount - 1) this.index++
+        else this.index = 0;
+        this.getEntry(this.index).scrollIntoView(false);
+    },
+
+    getEntry: function(index)
+    {
+        return this.update.firstChild.childNodes[index];
+    },
+
+    getCurrentEntry: function()
+    {
+        return this.getEntry(this.index);
+    },
+
+    selectEntry: function()
+    {
+        this.active = false;
+        this.updateElement(this.getCurrentEntry());
+    },
+
+    updateElement: function(selectedElement)
+    {
+        if (this.options.updateElement)
+        {
+            this.options.updateElement(selectedElement);
+            return;
+        }
+        var value = '';
+        if (this.options.select)
+        {
+            var nodes = $(selectedElement).select('.' + this.options.select) || [];
+            if (nodes.length > 0) value = Element.collectTextNodes(nodes[0], this.options.select);
+        }
+        else
+            value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+
+        var bounds = this.getTokenBounds();
+        if (bounds[0] != -1)
+        {
+            var newValue = this.element.value.substr(0, bounds[0]);
+            var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
+            if (whitespace)
+                newValue += whitespace[0];
+            this.element.value = newValue + value + this.element.value.substr(bounds[1]);
+        }
+        else
+        {
+            this.element.value = value;
+        }
+        this.oldElementValue = this.element.value;
+        this.element.focus();
+
+        if (this.options.afterUpdateElement)
+            this.options.afterUpdateElement(this.element, selectedElement);
+    },
+
+    updateChoices: function(choices)
+    {
+        if (!this.changed && this.hasFocus)
+        {
+            this.update.innerHTML = choices;
+            Element.cleanWhitespace(this.update);
+            Element.cleanWhitespace(this.update.down());
+
+            if (this.update.firstChild && this.update.down().childNodes)
+            {
+                this.entryCount =
+                this.update.down().childNodes.length;
+                for (var i = 0; i < this.entryCount; i++)
+                {
+                    var entry = this.getEntry(i);
+                    entry.autocompleteIndex = i;
+                    this.addObservers(entry);
+                }
+            }
+            else
+            {
+                this.entryCount = 0;
+            }
+
+            this.stopIndicator();
+            this.index = 0;
+
+            if (this.entryCount == 1 && this.options.autoSelect)
+            {
+                this.selectEntry();
+                this.hide();
+            }
+            else
+            {
+                this.render();
+            }
+        }
+    },
+
+    addObservers: function(element)
+    {
+        Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+        Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+    },
+
+    onObserverEvent: function()
+    {
+        this.changed = false;
+        this.tokenBounds = null;
+        if (this.getToken().length >= this.options.minChars)
+        {
+            this.getUpdatedChoices();
+        }
+        else
+        {
+            this.active = false;
+            this.hide();
+        }
+        this.oldElementValue = this.element.value;
+    },
+
+    getToken: function()
+    {
+        var bounds = this.getTokenBounds();
+        return this.element.value.substring(bounds[0], bounds[1]).strip();
+    },
+
+    getTokenBounds: function()
+    {
+        if (null != this.tokenBounds) return this.tokenBounds;
+        var value = this.element.value;
+        if (value.strip().empty()) return [-1, 0];
+        var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
+        var offset = (diff == this.oldElementValue.length ? 1 : 0);
+        var prevTokenPos = -1, nextTokenPos = value.length;
+        var tp;
+        for (var index = 0, l = this.options.tokens.length; index < l; ++index)
+        {
+            tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
+            if (tp > prevTokenPos) prevTokenPos = tp;
+            tp = value.indexOf(this.options.tokens[index], diff + offset);
+            if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
+        }
+        return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
     }
-    return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
-  }
 });
 
-Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
-  var boundary = Math.min(newS.length, oldS.length);
-  for (var index = 0; index < boundary; ++index)
-    if (newS[index] != oldS[index])
-      return index;
-  return boundary;
+Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS)
+{
+    var boundary = Math.min(newS.length, oldS.length);
+    for (var index = 0; index < boundary; ++index)
+        if (newS[index] != oldS[index])
+            return index;
+    return boundary;
 };
 
 Ajax.Autocompleter = Class.create(Autocompleter.Base, {
-  initialize: function(element, update, url, options) {
-    this.baseInitialize(element, update, options);
-    this.options.asynchronous  = true;
-    this.options.onComplete    = this.onComplete.bind(this);
-    this.options.defaultParams = this.options.parameters || null;
-    this.url                   = url;
-  },
-
-  getUpdatedChoices: function() {
-    this.startIndicator();
-    
-    var entry = encodeURIComponent(this.options.paramName) + '=' + 
-      encodeURIComponent(this.getToken());
-
-    this.options.parameters = this.options.callback ?
-      this.options.callback(this.element, entry) : entry;
-
-    if(this.options.defaultParams) 
-      this.options.parameters += '&' + this.options.defaultParams;
-    
-    new Ajax.Request(this.url, this.options);
-  },
-
-  onComplete: function(request) {
-    this.updateChoices(request.responseText);
-  }
+    initialize: function(element, update, url, options)
+    {
+        this.baseInitialize(element, update, options);
+        this.options.asynchronous = true;
+        this.options.onComplete = this.onComplete.bind(this);
+        this.options.defaultParams = this.options.parameters || null;
+        this.url = url;
+    },
+
+    getUpdatedChoices: function()
+    {
+        this.startIndicator();
+
+        var entry = encodeURIComponent(this.options.paramName) + '=' +
+                    encodeURIComponent(this.getToken());
+
+        this.options.parameters = this.options.callback ?
+                                  this.options.callback(this.element, entry) : entry;
+
+        if (this.options.defaultParams)
+            this.options.parameters += '&' + this.options.defaultParams;
+
+        new Ajax.Request(this.url, this.options);
+    },
+
+    onComplete: function(request)
+    {
+        this.updateChoices(request.responseText);
+    }
 });
 
 // The local array autocompleter. Used when you'd prefer to
@@ -407,63 +463,73 @@
 // you support them.
 
 Autocompleter.Local = Class.create(Autocompleter.Base, {
-  initialize: function(element, update, array, options) {
-    this.baseInitialize(element, update, options);
-    this.options.array = array;
-  },
-
-  getUpdatedChoices: function() {
-    this.updateChoices(this.options.selector(this));
-  },
-
-  setOptions: function(options) {
-    this.options = Object.extend({
-      choices: 10,
-      partialSearch: true,
-      partialChars: 2,
-      ignoreCase: true,
-      fullSearch: false,
-      selector: function(instance) {
-        var ret       = []; // Beginning matches
-        var partial   = []; // Inside matches
-        var entry     = instance.getToken();
-        var count     = 0;
-
-        for (var i = 0; i < instance.options.array.length &&  
-          ret.length < instance.options.choices ; i++) { 
-
-          var elem = instance.options.array[i];
-          var foundPos = instance.options.ignoreCase ? 
-            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
-            elem.indexOf(entry);
-
-          while (foundPos != -1) {
-            if (foundPos == 0 && elem.length != entry.length) { 
-              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
-                elem.substr(entry.length) + "</li>");
-              break;
-            } else if (entry.length >= instance.options.partialChars && 
-              instance.options.partialSearch && foundPos != -1) {
-              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
-                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
-                  elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
-                  foundPos + entry.length) + "</li>");
-                break;
-              }
-            }
+    initialize: function(element, update, array, options)
+    {
+        this.baseInitialize(element, update, options);
+        this.options.array = array;
+    },
 
-            foundPos = instance.options.ignoreCase ? 
-              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
-              elem.indexOf(entry, foundPos + 1);
-
-          }
-        }
-        if (partial.length)
-          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
-        return "<ul>" + ret.join('') + "</ul>";
-      }
-    }, options || { });
-  }
+    getUpdatedChoices: function()
+    {
+        this.updateChoices(this.options.selector(this));
+    },
+
+    setOptions: function(options)
+    {
+        this.options = Object.extend({
+            choices: 10,
+            partialSearch: true,
+            partialChars: 2,
+            ignoreCase: true,
+            fullSearch: false,
+            selector: function(instance)
+            {
+                var ret = []; // Beginning matches
+                var partial = []; // Inside matches
+                var entry = instance.getToken();
+                var count = 0;
+
+                for (var i = 0; i < instance.options.array.length &&
+                                ret.length < instance.options.choices; i++)
+                {
+
+                    var elem = instance.options.array[i];
+                    var foundPos = instance.options.ignoreCase ?
+                                   elem.toLowerCase().indexOf(entry.toLowerCase()) :
+                                   elem.indexOf(entry);
+
+                    while (foundPos != -1)
+                    {
+                        if (foundPos == 0 && elem.length != entry.length)
+                        {
+                            ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
+                                     elem.substr(entry.length) + "</li>");
+                            break;
+                        }
+                        else if (entry.length >= instance.options.partialChars &&
+                                 instance.options.partialSearch && foundPos != -1)
+                        {
+                            if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos - 1, 1)))
+                            {
+                                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+                                             elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+                                        foundPos + entry.length) + "</li>");
+                                break;
+                            }
+                        }
+
+                        foundPos = instance.options.ignoreCase ?
+                                   elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
+                                   elem.indexOf(entry, foundPos + 1);
+
+                    }
+                }
+                if (partial.length)
+                    ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
+                return "<ul>" + ret.join('') + "</ul>";
+            }
+        }, options || { });
+    }
 });
 
 // AJAX in-place editor and collection editor
@@ -472,381 +538,438 @@
 // Use this if you notice weird scrolling problems on some browsers,
 // the DOM might be a bit confused when this gets called so do this
 // waits 1 ms (with setTimeout) until it does the activation
-Field.scrollFreeActivate = function(field) {
-  setTimeout(function() {
-    Field.activate(field);
-  }, 1);
+Field.scrollFreeActivate = function(field)
+{
+    setTimeout(function()
+    {
+        Field.activate(field);
+    }, 1);
 }
 
 Ajax.InPlaceEditor = Class.create({
-  initialize: function(element, url, options) {
-    this.url = url;
-    this.element = element = $(element);
-    this.prepareOptions();
-    this._controls = { };
-    arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
-    Object.extend(this.options, options || { });
-    if (!this.options.formId && this.element.id) {
-      this.options.formId = this.element.id + '-inplaceeditor';
-      if ($(this.options.formId))
-        this.options.formId = '';
-    }
-    if (this.options.externalControl)
-      this.options.externalControl = $(this.options.externalControl);
-    if (!this.options.externalControl)
-      this.options.externalControlOnly = false;
-    this._originalBackground = this.element.getStyle('background-color') || 'transparent';
-    this.element.title = this.options.clickToEditText;
-    this._boundCancelHandler = this.handleFormCancellation.bind(this);
-    this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
-    this._boundFailureHandler = this.handleAJAXFailure.bind(this);
-    this._boundSubmitHandler = this.handleFormSubmission.bind(this);
-    this._boundWrapperHandler = this.wrapUp.bind(this);
-    this.registerListeners();
-  },
-  checkForEscapeOrReturn: function(e) {
-    if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
-    if (Event.KEY_ESC == e.keyCode)
-      this.handleFormCancellation(e);
-    else if (Event.KEY_RETURN == e.keyCode)
-      this.handleFormSubmission(e);
-  },
-  createControl: function(mode, handler, extraClasses) {
-    var control = this.options[mode + 'Control'];
-    var text = this.options[mode + 'Text'];
-    if ('button' == control) {
-      var btn = document.createElement('input');
-      btn.type = 'submit';
-      btn.value = text;
-      btn.className = 'editor_' + mode + '_button';
-      if ('cancel' == mode)
-        btn.onclick = this._boundCancelHandler;
-      this._form.appendChild(btn);
-      this._controls[mode] = btn;
-    } else if ('link' == control) {
-      var link = document.createElement('a');
-      link.href = '#';
-      link.appendChild(document.createTextNode(text));
-      link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
-      link.className = 'editor_' + mode + '_link';
-      if (extraClasses)
-        link.className += ' ' + extraClasses;
-      this._form.appendChild(link);
-      this._controls[mode] = link;
-    }
-  },
-  createEditField: function() {
-    var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
-    var fld;
-    if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
-      fld = document.createElement('input');
-      fld.type = 'text';
-      var size = this.options.size || this.options.cols || 0;
-      if (0 < size) fld.size = size;
-    } else {
-      fld = document.createElement('textarea');
-      fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
-      fld.cols = this.options.cols || 40;
-    }
-    fld.name = this.options.paramName;
-    fld.value = text; // No HTML breaks conversion anymore
-    fld.className = 'editor_field';
-    if (this.options.submitOnBlur)
-      fld.onblur = this._boundSubmitHandler;
-    this._controls.editor = fld;
-    if (this.options.loadTextURL)
-      this.loadExternalText();
-    this._form.appendChild(this._controls.editor);
-  },
-  createForm: function() {
-    var ipe = this;
-    function addText(mode, condition) {
-      var text = ipe.options['text' + mode + 'Controls'];
-      if (!text || condition === false) return;
-      ipe._form.appendChild(document.createTextNode(text));
-    };
-    this._form = $(document.createElement('form'));
-    this._form.id = this.options.formId;
-    this._form.addClassName(this.options.formClassName);
-    this._form.onsubmit = this._boundSubmitHandler;
-    this.createEditField();
-    if ('textarea' == this._controls.editor.tagName.toLowerCase())
-      this._form.appendChild(document.createElement('br'));
-    if (this.options.onFormCustomization)
-      this.options.onFormCustomization(this, this._form);
-    addText('Before', this.options.okControl || this.options.cancelControl);
-    this.createControl('ok', this._boundSubmitHandler);
-    addText('Between', this.options.okControl && this.options.cancelControl);
-    this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
-    addText('After', this.options.okControl || this.options.cancelControl);
-  },
-  destroy: function() {
-    if (this._oldInnerHTML)
-      this.element.innerHTML = this._oldInnerHTML;
-    this.leaveEditMode();
-    this.unregisterListeners();
-  },
-  enterEditMode: function(e) {
-    if (this._saving || this._editing) return;
-    this._editing = true;
-    this.triggerCallback('onEnterEditMode');
-    if (this.options.externalControl)
-      this.options.externalControl.hide();
-    this.element.hide();
-    this.createForm();
-    this.element.parentNode.insertBefore(this._form, this.element);
-    if (!this.options.loadTextURL)
-      this.postProcessEditField();
-    if (e) Event.stop(e);
-  },
-  enterHover: function(e) {
-    if (this.options.hoverClassName)
-      this.element.addClassName(this.options.hoverClassName);
-    if (this._saving) return;
-    this.triggerCallback('onEnterHover');
-  },
-  getText: function() {
-    return this.element.innerHTML;
-  },
-  handleAJAXFailure: function(transport) {
-    this.triggerCallback('onFailure', transport);
-    if (this._oldInnerHTML) {
-      this.element.innerHTML = this._oldInnerHTML;
-      this._oldInnerHTML = null;
-    }
-  },
-  handleFormCancellation: function(e) {
-    this.wrapUp();
-    if (e) Event.stop(e);
-  },
-  handleFormSubmission: function(e) {
-    var form = this._form;
-    var value = $F(this._controls.editor);
-    this.prepareSubmission();
-    var params = this.options.callback(form, value) || '';
-    if (Object.isString(params))
-      params = params.toQueryParams();
-    params.editorId = this.element.id;
-    if (this.options.htmlResponse) {
-      var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
-      Object.extend(options, {
-        parameters: params,
-        onComplete: this._boundWrapperHandler,
-        onFailure: this._boundFailureHandler
-      });
-      new Ajax.Updater({ success: this.element }, this.url, options);
-    } else {
-      var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
-      Object.extend(options, {
-        parameters: params,
-        onComplete: this._boundWrapperHandler,
-        onFailure: this._boundFailureHandler
-      });
-      new Ajax.Request(this.url, options);
-    }
-    if (e) Event.stop(e);
-  },
-  leaveEditMode: function() {
-    this.element.removeClassName(this.options.savingClassName);
-    this.removeForm();
-    this.leaveHover();
-    this.element.style.backgroundColor = this._originalBackground;
-    this.element.show();
-    if (this.options.externalControl)
-      this.options.externalControl.show();
-    this._saving = false;
-    this._editing = false;
-    this._oldInnerHTML = null;
-    this.triggerCallback('onLeaveEditMode');
-  },
-  leaveHover: function(e) {
-    if (this.options.hoverClassName)
-      this.element.removeClassName(this.options.hoverClassName);
-    if (this._saving) return;
-    this.triggerCallback('onLeaveHover');
-  },
-  loadExternalText: function() {
-    this._form.addClassName(this.options.loadingClassName);
-    this._controls.editor.disabled = true;
-    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
-    Object.extend(options, {
-      parameters: 'editorId=' + encodeURIComponent(this.element.id),
-      onComplete: Prototype.emptyFunction,
-      onSuccess: function(transport) {
-        this._form.removeClassName(this.options.loadingClassName);
-        var text = transport.responseText;
-        if (this.options.stripLoadedTextTags)
-          text = text.stripTags();
-        this._controls.editor.value = text;
-        this._controls.editor.disabled = false;
-        this.postProcessEditField();
-      }.bind(this),
-      onFailure: this._boundFailureHandler
-    });
-    new Ajax.Request(this.options.loadTextURL, options);
-  },
-  postProcessEditField: function() {
-    var fpc = this.options.fieldPostCreation;
-    if (fpc)
-      $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
-  },
-  prepareOptions: function() {
-    this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
-    Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
-    [this._extraDefaultOptions].flatten().compact().each(function(defs) {
-      Object.extend(this.options, defs);
-    }.bind(this));
-  },
-  prepareSubmission: function() {
-    this._saving = true;
-    this.removeForm();
-    this.leaveHover();
-    this.showSaving();
-  },
-  registerListeners: function() {
-    this._listeners = { };
-    var listener;
-    $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
-      listener = this[pair.value].bind(this);
-      this._listeners[pair.key] = listener;
-      if (!this.options.externalControlOnly)
-        this.element.observe(pair.key, listener);
-      if (this.options.externalControl)
-        this.options.externalControl.observe(pair.key, listener);
-    }.bind(this));
-  },
-  removeForm: function() {
-    if (!this._form) return;
-    this._form.remove();
-    this._form = null;
-    this._controls = { };
-  },
-  showSaving: function() {
-    this._oldInnerHTML = this.element.innerHTML;
-    this.element.innerHTML = this.options.savingText;
-    this.element.addClassName(this.options.savingClassName);
-    this.element.style.backgroundColor = this._originalBackground;
-    this.element.show();
-  },
-  triggerCallback: function(cbName, arg) {
-    if ('function' == typeof this.options[cbName]) {
-      this.options[cbName](this, arg);
-    }
-  },
-  unregisterListeners: function() {
-    $H(this._listeners).each(function(pair) {
-      if (!this.options.externalControlOnly)
-        this.element.stopObserving(pair.key, pair.value);
-      if (this.options.externalControl)
-        this.options.externalControl.stopObserving(pair.key, pair.value);
-    }.bind(this));
-  },
-  wrapUp: function(transport) {
-    this.leaveEditMode();
+    initialize: function(element, url, options)
+    {
+        this.url = url;
+        this.element = element = $(element);
+        this.prepareOptions();
+        this._controls = { };
+        arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
+        Object.extend(this.options, options || { });
+        if (!this.options.formId && this.element.id)
+        {
+            this.options.formId = this.element.id + '-inplaceeditor';
+            if ($(this.options.formId))
+                this.options.formId = '';
+        }
+        if (this.options.externalControl)
+            this.options.externalControl = $(this.options.externalControl);
+        if (!this.options.externalControl)
+            this.options.externalControlOnly = false;
+        this._originalBackground = this.element.getStyle('background-color') || 'transparent';
+        this.element.title = this.options.clickToEditText;
+        this._boundCancelHandler = this.handleFormCancellation.bind(this);
+        this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
+        this._boundFailureHandler = this.handleAJAXFailure.bind(this);
+        this._boundSubmitHandler = this.handleFormSubmission.bind(this);
+        this._boundWrapperHandler = this.wrapUp.bind(this);
+        this.registerListeners();
+    },
+    checkForEscapeOrReturn: function(e)
+    {
+        if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
+        if (Event.KEY_ESC == e.keyCode)
+            this.handleFormCancellation(e);
+        else if (Event.KEY_RETURN == e.keyCode)
+            this.handleFormSubmission(e);
+    },
+    createControl: function(mode, handler, extraClasses)
+    {
+        var control = this.options[mode + 'Control'];
+        var text = this.options[mode + 'Text'];
+        if ('button' == control)
+        {
+            var btn = document.createElement('input');
+            btn.type = 'submit';
+            btn.value = text;
+            btn.className = 'editor_' + mode + '_button';
+            if ('cancel' == mode)
+                btn.onclick = this._boundCancelHandler;
+            this._form.appendChild(btn);
+            this._controls[mode] = btn;
+        }
+        else if ('link' == control)
+        {
+            var link = document.createElement('a');
+            link.href = '#';
+            link.appendChild(document.createTextNode(text));
+            link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
+            link.className = 'editor_' + mode + '_link';
+            if (extraClasses)
+                link.className += ' ' + extraClasses;
+            this._form.appendChild(link);
+            this._controls[mode] = link;
+        }
+    },
+    createEditField: function()
+    {
+        var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
+        var fld;
+        if (1 >= this.options.rows && !/\r|\n/.test(this.getText()))
+        {
+            fld = document.createElement('input');
+            fld.type = 'text';
+            var size = this.options.size || this.options.cols || 0;
+            if (0 < size) fld.size = size;
+        }
+        else
+        {
+            fld = document.createElement('textarea');
+            fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
+            fld.cols = this.options.cols || 40;
+        }
+        fld.name = this.options.paramName;
+        fld.value = text; // No HTML breaks conversion anymore
+        fld.className = 'editor_field';
+        if (this.options.submitOnBlur)
+            fld.onblur = this._boundSubmitHandler;
+        this._controls.editor = fld;
+        if (this.options.loadTextURL)
+            this.loadExternalText();
+        this._form.appendChild(this._controls.editor);
+    },
+    createForm: function()
+    {
+        var ipe = this;
+        function addText(mode, condition)
+        {
+            var text = ipe.options['text' + mode + 'Controls'];
+            if (!text || condition === false) return;
+            ipe._form.appendChild(document.createTextNode(text));
+        }
+        ;
+        this._form = $(document.createElement('form'));
+        this._form.id = this.options.formId;
+        this._form.addClassName(this.options.formClassName);
+        this._form.onsubmit = this._boundSubmitHandler;
+        this.createEditField();
+        if ('textarea' == this._controls.editor.tagName.toLowerCase())
+            this._form.appendChild(document.createElement('br'));
+        if (this.options.onFormCustomization)
+            this.options.onFormCustomization(this, this._form);
+        addText('Before', this.options.okControl || this.options.cancelControl);
+        this.createControl('ok', this._boundSubmitHandler);
+        addText('Between', this.options.okControl && this.options.cancelControl);
+        this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
+        addText('After', this.options.okControl || this.options.cancelControl);
+    },
+    destroy: function()
+    {
+        if (this._oldInnerHTML)
+            this.element.innerHTML = this._oldInnerHTML;
+        this.leaveEditMode();
+        this.unregisterListeners();
+    },
+    enterEditMode: function(e)
+    {
+        if (this._saving || this._editing) return;
+        this._editing = true;
+        this.triggerCallback('onEnterEditMode');
+        if (this.options.externalControl)
+            this.options.externalControl.hide();
+        this.element.hide();
+        this.createForm();
+        this.element.parentNode.insertBefore(this._form, this.element);
+        if (!this.options.loadTextURL)
+            this.postProcessEditField();
+        if (e) Event.stop(e);
+    },
+    enterHover: function(e)
+    {
+        if (this.options.hoverClassName)
+            this.element.addClassName(this.options.hoverClassName);
+        if (this._saving) return;
+        this.triggerCallback('onEnterHover');
+    },
+    getText: function()
+    {
+        return this.element.innerHTML;
+    },
+    handleAJAXFailure: function(transport)
+    {
+        this.triggerCallback('onFailure', transport);
+        if (this._oldInnerHTML)
+        {
+            this.element.innerHTML = this._oldInnerHTML;
+            this._oldInnerHTML = null;
+        }
+    },
+    handleFormCancellation: function(e)
+    {
+        this.wrapUp();
+        if (e) Event.stop(e);
+    },
+    handleFormSubmission: function(e)
+    {
+        var form = this._form;
+        var value = $F(this._controls.editor);
+        this.prepareSubmission();
+        var params = this.options.callback(form, value) || '';
+        if (Object.isString(params))
+            params = params.toQueryParams();
+        params.editorId = this.element.id;
+        if (this.options.htmlResponse)
+        {
+            var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
+            Object.extend(options, {
+                parameters: params,
+                onComplete: this._boundWrapperHandler,
+                onFailure: this._boundFailureHandler
+            });
+            new Ajax.Updater({ success: this.element }, this.url, options);
+        }
+        else
+        {
+            var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+            Object.extend(options, {
+                parameters: params,
+                onComplete: this._boundWrapperHandler,
+                onFailure: this._boundFailureHandler
+            });
+            new Ajax.Request(this.url, options);
+        }
+        if (e) Event.stop(e);
+    },
+    leaveEditMode: function()
+    {
+        this.element.removeClassName(this.options.savingClassName);
+        this.removeForm();
+        this.leaveHover();
+        this.element.style.backgroundColor = this._originalBackground;
+        this.element.show();
+        if (this.options.externalControl)
+            this.options.externalControl.show();
+        this._saving = false;
+        this._editing = false;
+        this._oldInnerHTML = null;
+        this.triggerCallback('onLeaveEditMode');
+    },
+    leaveHover: function(e)
+    {
+        if (this.options.hoverClassName)
+            this.element.removeClassName(this.options.hoverClassName);
+        if (this._saving) return;
+        this.triggerCallback('onLeaveHover');
+    },
+    loadExternalText: function()
+    {
+        this._form.addClassName(this.options.loadingClassName);
+        this._controls.editor.disabled = true;
+        var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+        Object.extend(options, {
+            parameters: 'editorId=' + encodeURIComponent(this.element.id),
+            onComplete: Prototype.emptyFunction,
+            onSuccess: function(transport)
+            {
+                this._form.removeClassName(this.options.loadingClassName);
+                var text = transport.responseText;
+                if (this.options.stripLoadedTextTags)
+                    text = text.stripTags();
+                this._controls.editor.value = text;
+                this._controls.editor.disabled = false;
+                this.postProcessEditField();
+            }.bind(this),
+            onFailure: this._boundFailureHandler
+        });
+        new Ajax.Request(this.options.loadTextURL, options);
+    },
+    postProcessEditField: function()
+    {
+        var fpc = this.options.fieldPostCreation;
+        if (fpc)
+            $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
+    },
+    prepareOptions: function()
+    {
+        this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
+        Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
+        [this._extraDefaultOptions].flatten().compact().each(function(defs)
+        {
+            Object.extend(this.options, defs);
+        }.bind(this));
+    },
+    prepareSubmission: function()
+    {
+        this._saving = true;
+        this.removeForm();
+        this.leaveHover();
+        this.showSaving();
+    },
+    registerListeners: function()
+    {
+        this._listeners = { };
+        var listener;
+        $H(Ajax.InPlaceEditor.Listeners).each(function(pair)
+        {
+            listener = this[pair.value].bind(this);
+            this._listeners[pair.key] = listener;
+            if (!this.options.externalControlOnly)
+                this.element.observe(pair.key, listener);
+            if (this.options.externalControl)
+                this.options.externalControl.observe(pair.key, listener);
+        }.bind(this));
+    },
+    removeForm: function()
+    {
+        if (!this._form) return;
+        this._form.remove();
+        this._form = null;
+        this._controls = { };
+    },
+    showSaving: function()
+    {
+        this._oldInnerHTML = this.element.innerHTML;
+        this.element.innerHTML = this.options.savingText;
+        this.element.addClassName(this.options.savingClassName);
+        this.element.style.backgroundColor = this._originalBackground;
+        this.element.show();
+    },
+    triggerCallback: function(cbName, arg)
+    {
+        if ('function' == typeof this.options[cbName])
+        {
+            this.options[cbName](this, arg);
+        }
+    },
+    unregisterListeners: function()
+    {
+        $H(this._listeners).each(function(pair)
+        {
+            if (!this.options.externalControlOnly)
+                this.element.stopObserving(pair.key, pair.value);
+            if (this.options.externalControl)
+                this.options.externalControl.stopObserving(pair.key, pair.value);
+        }.bind(this));
+    },
+    wrapUp: function(transport)
+    {
+        this.leaveEditMode();
     // Can't use triggerCallback due to backward compatibility: requires
-    // binding + direct element
-    this._boundComplete(transport, this.element);
-  }
+        // binding + direct element
+        this._boundComplete(transport, this.element);
+    }
 });
 
 Object.extend(Ajax.InPlaceEditor.prototype, {
-  dispose: Ajax.InPlaceEditor.prototype.destroy
+    dispose: Ajax.InPlaceEditor.prototype.destroy
 });
 
 Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
-  initialize: function($super, element, url, options) {
-    this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
-    $super(element, url, options);
-  },
-
-  createEditField: function() {
-    var list = document.createElement('select');
-    list.name = this.options.paramName;
-    list.size = 1;
-    this._controls.editor = list;
-    this._collection = this.options.collection || [];
-    if (this.options.loadCollectionURL)
-      this.loadCollection();
-    else
-      this.checkForExternalText();
-    this._form.appendChild(this._controls.editor);
-  },
-
-  loadCollection: function() {
-    this._form.addClassName(this.options.loadingClassName);
-    this.showLoadingText(this.options.loadingCollectionText);
-    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
-    Object.extend(options, {
-      parameters: 'editorId=' + encodeURIComponent(this.element.id),
-      onComplete: Prototype.emptyFunction,
-      onSuccess: function(transport) {
-        var js = transport.responseText.strip();
-        if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
-          throw 'Server returned an invalid collection representation.';
-        this._collection = eval(js);
-        this.checkForExternalText();
-      }.bind(this),
-      onFailure: this.onFailure
-    });
-    new Ajax.Request(this.options.loadCollectionURL, options);
-  },
-
-  showLoadingText: function(text) {
-    this._controls.editor.disabled = true;
-    var tempOption = this._controls.editor.firstChild;
-    if (!tempOption) {
-      tempOption = document.createElement('option');
-      tempOption.value = '';
-      this._controls.editor.appendChild(tempOption);
-      tempOption.selected = true;
-    }
-    tempOption.update((text || '').stripScripts().stripTags());
-  },
+    initialize: function($super, element, url, options)
+    {
+        this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
+        $super(element, url, options);
+    },
 
-  checkForExternalText: function() {
-    this._text = this.getText();
-    if (this.options.loadTextURL)
-      this.loadExternalText();
-    else
-      this.buildOptionList();
-  },
-
-  loadExternalText: function() {
-    this.showLoadingText(this.options.loadingText);
-    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
-    Object.extend(options, {
-      parameters: 'editorId=' + encodeURIComponent(this.element.id),
-      onComplete: Prototype.emptyFunction,
-      onSuccess: function(transport) {
-        this._text = transport.responseText.strip();
-        this.buildOptionList();
-      }.bind(this),
-      onFailure: this.onFailure
-    });
-    new Ajax.Request(this.options.loadTextURL, options);
-  },
-
-  buildOptionList: function() {
-    this._form.removeClassName(this.options.loadingClassName);
-    this._collection = this._collection.map(function(entry) {
-      return 2 === entry.length ? entry : [entry, entry].flatten();
-    });
-    var marker = ('value' in this.options) ? this.options.value : this._text;
-    var textFound = this._collection.any(function(entry) {
-      return entry[0] == marker;
-    }.bind(this));
-    this._controls.editor.update('');
-    var option;
-    this._collection.each(function(entry, index) {
-      option = document.createElement('option');
-      option.value = entry[0];
-      option.selected = textFound ? entry[0] == marker : 0 == index;
-      option.appendChild(document.createTextNode(entry[1]));
-      this._controls.editor.appendChild(option);
-    }.bind(this));
-    this._controls.editor.disabled = false;
-    Field.scrollFreeActivate(this._controls.editor);
-  }
+    createEditField: function()
+    {
+        var list = document.createElement('select');
+        list.name = this.options.paramName;
+        list.size = 1;
+        this._controls.editor = list;
+        this._collection = this.options.collection || [];
+        if (this.options.loadCollectionURL)
+            this.loadCollection();
+        else
+            this.checkForExternalText();
+        this._form.appendChild(this._controls.editor);
+    },
+
+    loadCollection: function()
+    {
+        this._form.addClassName(this.options.loadingClassName);
+        this.showLoadingText(this.options.loadingCollectionText);
+        var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+        Object.extend(options, {
+            parameters: 'editorId=' + encodeURIComponent(this.element.id),
+            onComplete: Prototype.emptyFunction,
+            onSuccess: function(transport)
+            {
+                var js = transport.responseText.strip();
+                if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
+                    throw 'Server returned an invalid collection representation.';
+                this._collection = eval(js);
+                this.checkForExternalText();
+            }.bind(this),
+            onFailure: this.onFailure
+        });
+        new Ajax.Request(this.options.loadCollectionURL, options);
+    },
+
+    showLoadingText: function(text)
+    {
+        this._controls.editor.disabled = true;
+        var tempOption = this._controls.editor.firstChild;
+        if (!tempOption)
+        {
+            tempOption = document.createElement('option');
+            tempOption.value = '';
+            this._controls.editor.appendChild(tempOption);
+            tempOption.selected = true;
+        }
+        tempOption.update((text || '').stripScripts().stripTags());
+    },
+
+    checkForExternalText: function()
+    {
+        this._text = this.getText();
+        if (this.options.loadTextURL)
+            this.loadExternalText();
+        else
+            this.buildOptionList();
+    },
+
+    loadExternalText: function()
+    {
+        this.showLoadingText(this.options.loadingText);
+        var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+        Object.extend(options, {
+            parameters: 'editorId=' + encodeURIComponent(this.element.id),
+            onComplete: Prototype.emptyFunction,
+            onSuccess: function(transport)
+            {
+                this._text = transport.responseText.strip();
+                this.buildOptionList();
+            }.bind(this),
+            onFailure: this.onFailure
+        });
+        new Ajax.Request(this.options.loadTextURL, options);
+    },
+
+    buildOptionList: function()
+    {
+        this._form.removeClassName(this.options.loadingClassName);
+        this._collection = this._collection.map(function(entry)
+        {
+            return 2 === entry.length ? entry : [entry, entry].flatten();
+        });
+        var marker = ('value' in this.options) ? this.options.value : this._text;
+        var textFound = this._collection.any(function(entry)
+        {
+            return entry[0] == marker;
+        }.bind(this));
+        this._controls.editor.update('');
+        var option;
+        this._collection.each(function(entry, index)
+        {
+            option = document.createElement('option');
+            option.value = entry[0];
+            option.selected = textFound ? entry[0] == marker : 0 == index;
+            option.appendChild(document.createTextNode(entry[1]));
+            this._controls.editor.appendChild(option);
+        }.bind(this));
+        this._controls.editor.disabled = false;
+        Field.scrollFreeActivate(this._controls.editor);
+    }
 });
 
 //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
@@ -854,89 +977,97 @@
 //**** users adapt to  the new API.  Read up on the new ****
 //**** API and convert your code to it ASAP!            ****
 
-Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
-  if (!options) return;
-  function fallback(name, expr) {
-    if (name in options || expr === undefined) return;
-    options[name] = expr;
-  };
-  fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
-    options.cancelLink == options.cancelButton == false ? false : undefined)));
-  fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
-    options.okLink == options.okButton == false ? false : undefined)));
-  fallback('highlightColor', options.highlightcolor);
-  fallback('highlightEndColor', options.highlightendcolor);
+Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options)
+{
+    if (!options) return;
+    function fallback(name, expr)
+    {
+        if (name in options || expr === undefined) return;
+        options[name] = expr;
+    }
+    ;
+    fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
+                                                              options.cancelLink == options.cancelButton == false ? false : undefined)));
+    fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
+                                                      options.okLink == options.okButton == false ? false : undefined)));
+    fallback('highlightColor', options.highlightcolor);
+    fallback('highlightEndColor', options.highlightendcolor);
 };
 
 Object.extend(Ajax.InPlaceEditor, {
-  DefaultOptions: {
-    ajaxOptions: { },
-    autoRows: 3,                                // Use when multi-line w/ rows == 1
-    cancelControl: 'link',                      // 'link'|'button'|false
-    cancelText: 'cancel',
-    clickToEditText: 'Click to edit',
-    externalControl: null,                      // id|elt
-    externalControlOnly: false,
-    fieldPostCreation: 'activate',              // 'activate'|'focus'|false
-    formClassName: 'inplaceeditor-form',
-    formId: null,                               // id|elt
-    highlightColor: '#ffff99',
-    highlightEndColor: '#ffffff',
-    hoverClassName: '',
-    htmlResponse: true,
-    loadingClassName: 'inplaceeditor-loading',
-    loadingText: 'Loading...',
-    okControl: 'button',                        // 'link'|'button'|false
-    okText: 'ok',
-    paramName: 'value',
-    rows: 1,                                    // If 1 and multi-line, uses autoRows
-    savingClassName: 'inplaceeditor-saving',
-    savingText: 'Saving...',
-    size: 0,
-    stripLoadedTextTags: false,
-    submitOnBlur: false,
-    textAfterControls: '',
-    textBeforeControls: '',
-    textBetweenControls: ''
-  },
-  DefaultCallbacks: {
-    callback: function(form) {
-      return Form.serialize(form);
-    },
-    onComplete: function(transport, element) {
-      // For backward compatibility, this one is bound to the IPE, and passes
-      // the element directly.  It was too often customized, so we don't break it.
-      new Effect.Highlight(element, {
-        startcolor: this.options.highlightColor, keepBackgroundImage: true });
-    },
-    onEnterEditMode: null,
-    onEnterHover: function(ipe) {
-      ipe.element.style.backgroundColor = ipe.options.highlightColor;
-      if (ipe._effect)
-        ipe._effect.cancel();
-    },
-    onFailure: function(transport, ipe) {
-      alert('Error communication with the server: ' + transport.responseText.stripTags());
-    },
-    onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
-    onLeaveEditMode: null,
-    onLeaveHover: function(ipe) {
-      ipe._effect = new Effect.Highlight(ipe.element, {
-        startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
-        restorecolor: ipe._originalBackground, keepBackgroundImage: true
-      });
+    DefaultOptions: {
+        ajaxOptions: { },
+        autoRows: 3,                                // Use when multi-line w/ rows == 1
+        cancelControl: 'link',                      // 'link'|'button'|false
+        cancelText: 'cancel',
+        clickToEditText: 'Click to edit',
+        externalControl: null,                      // id|elt
+        externalControlOnly: false,
+        fieldPostCreation: 'activate',              // 'activate'|'focus'|false
+        formClassName: 'inplaceeditor-form',
+        formId: null,                               // id|elt
+        highlightColor: '#ffff99',
+        highlightEndColor: '#ffffff',
+        hoverClassName: '',
+        htmlResponse: true,
+        loadingClassName: 'inplaceeditor-loading',
+        loadingText: 'Loading...',
+        okControl: 'button',                        // 'link'|'button'|false
+        okText: 'ok',
+        paramName: 'value',
+        rows: 1,                                    // If 1 and multi-line, uses autoRows
+        savingClassName: 'inplaceeditor-saving',
+        savingText: 'Saving...',
+        size: 0,
+        stripLoadedTextTags: false,
+        submitOnBlur: false,
+        textAfterControls: '',
+        textBeforeControls: '',
+        textBetweenControls: ''
+    },
+    DefaultCallbacks: {
+        callback: function(form)
+        {
+            return Form.serialize(form);
+        },
+        onComplete: function(transport, element)
+        {
+            // For backward compatibility, this one is bound to the IPE, and passes
+            // the element directly.  It was too often customized, so we don't break it.
+            new Effect.Highlight(element, {
+                startcolor: this.options.highlightColor, keepBackgroundImage: true });
+        },
+        onEnterEditMode: null,
+        onEnterHover: function(ipe)
+        {
+            ipe.element.style.backgroundColor = ipe.options.highlightColor;
+            if (ipe._effect)
+                ipe._effect.cancel();
+        },
+        onFailure: function(transport, ipe)
+        {
+            alert('Error communication with the server: ' + transport.responseText.stripTags());
+        },
+        onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
+        onLeaveEditMode: null,
+        onLeaveHover: function(ipe)
+        {
+            ipe._effect = new Effect.Highlight(ipe.element, {
+                startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
+                restorecolor: ipe._originalBackground, keepBackgroundImage: true
+            });
+        }
+    },
+    Listeners: {
+        click: 'enterEditMode',
+        keydown: 'checkForEscapeOrReturn',
+        mouseover: 'enterHover',
+        mouseout: 'leaveHover'
     }
-  },
-  Listeners: {
-    click: 'enterEditMode',
-    keydown: 'checkForEscapeOrReturn',
-    mouseover: 'enterHover',
-    mouseout: 'leaveHover'
-  }
 });
 
 Ajax.InPlaceCollectionEditor.DefaultOptions = {
-  loadingCollectionText: 'Loading options...'
+    loadingCollectionText: 'Loading options...'
 };
 
 // Delayed observer, like Form.Element.Observer, 
@@ -944,22 +1075,25 @@
 // Ideal for live-search fields
 
 Form.Element.DelayedObserver = Class.create({
-  initialize: function(element, delay, callback) {
-    this.delay     = delay || 0.5;
-    this.element   = $(element);
-    this.callback  = callback;
-    this.timer     = null;
-    this.lastValue = $F(this.element); 
-    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
-  },
-  delayedListener: function(event) {
-    if(this.lastValue == $F(this.element)) return;
-    if(this.timer) clearTimeout(this.timer);
-    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
-    this.lastValue = $F(this.element);
-  },
-  onTimerEvent: function() {
-    this.timer = null;
-    this.callback(this.element, $F(this.element));
-  }
+    initialize: function(element, delay, callback)
+    {
+        this.delay = delay || 0.5;
+        this.element = $(element);
+        this.callback = callback;
+        this.timer = null;
+        this.lastValue = $F(this.element);
+        Event.observe(this.element, 'keyup', this.delayedListener.bindAsEventListener(this));
+    },
+    delayedListener: function(event)
+    {
+        if (this.lastValue == $F(this.element)) return;
+        if (this.timer) clearTimeout(this.timer);
+        this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+        this.lastValue = $F(this.element);
+    },
+    onTimerEvent: function()
+    {
+        this.timer = null;
+        this.callback(this.element, $F(this.element));
+    }
 });