Changeset 67

Show
Ignore:
Timestamp:
01/07/08 17:28:25 (11 months ago)
Author:
jweiss
Message:

update to Prototype 1.6

Location:
trunk/public/javascripts
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • trunk/public/javascripts/controls.js

    r1 r67  
    3838  throw("controls.js requires including script.aculo.us' effects.js library"); 
    3939 
    40 var Autocompleter = {} 
    41 Autocompleter.Base = function() {}; 
    42 Autocompleter.Base.prototype = { 
     40var Autocompleter = { } 
     41Autocompleter.Base = Class.create({ 
    4342  baseInitialize: function(element, update, options) { 
    4443    element          = $(element) 
     
    5049    this.index       = 0;      
    5150    this.entryCount  = 0; 
     51    this.oldElementValue = this.element.value; 
    5252 
    5353    if(this.setOptions) 
    5454      this.setOptions(options); 
    5555    else 
    56       this.options = options || {}; 
     56      this.options = options || { }; 
    5757 
    5858    this.options.paramName    = this.options.paramName || this.element.name; 
     
    7676    if(typeof(this.options.tokens) == 'string')  
    7777      this.options.tokens = new Array(this.options.tokens); 
     78    // Force carriage returns as token delimiters anyway 
     79    if (!this.options.tokens.include('\n')) 
     80      this.options.tokens.push('\n'); 
    7881 
    7982    this.observer = null; 
     
    8487 
    8588    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); 
    86     Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this)); 
    87  
    88     // Turn autocomplete back on when the user leaves the page, so that the 
    89     // field's value will be remembered on Mozilla-based browsers. 
    90     Event.observe(window, 'beforeunload', function(){  
    91       element.setAttribute('autocomplete', 'on');  
    92     }); 
     89    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); 
    9390  }, 
    9491 
     
    146143         this.markPrevious(); 
    147144         this.render(); 
    148          if(Prototype.Browser.WebKit) Event.stop(event); 
     145         Event.stop(event); 
    149146         return; 
    150147       case Event.KEY_DOWN: 
    151148         this.markNext(); 
    152149         this.render(); 
    153          if(Prototype.Browser.WebKit) Event.stop(event); 
     150         Event.stop(event); 
    154151         return; 
    155152      } 
     
    244241    var value = ''; 
    245242    if (this.options.select) { 
    246       var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; 
     243      var nodes = $(selectedElement).select('.' + this.options.select) || []; 
    247244      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); 
    248245    } else 
    249246      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); 
    250247     
    251     var lastTokenPos = this.findLastToken(); 
    252     if (lastTokenPos != -1) { 
    253       var newValue = this.element.value.substr(0, lastTokenPos + 1); 
    254       var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); 
     248    var bounds = this.getTokenBounds(); 
     249    if (bounds[0] != -1) { 
     250      var newValue = this.element.value.substr(0, bounds[0]); 
     251      var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); 
    255252      if (whitespace) 
    256253        newValue += whitespace[0]; 
    257       this.element.value = newValue + value; 
     254      this.element.value = newValue + value + this.element.value.substr(bounds[1]); 
    258255    } else { 
    259256      this.element.value = value; 
    260257    } 
     258    this.oldElementValue = this.element.value; 
    261259    this.element.focus(); 
    262260     
     
    302300  onObserverEvent: function() { 
    303301    this.changed = false;    
     302    this.tokenBounds = null; 
    304303    if(this.getToken().length>=this.options.minChars) { 
    305304      this.getUpdatedChoices(); 
     
    308307      this.hide(); 
    309308    } 
     309    this.oldElementValue = this.element.value; 
    310310  }, 
    311311 
    312312  getToken: function() { 
    313     var tokenPos = this.findLastToken(); 
    314     if (tokenPos != -1) 
    315       var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); 
    316     else 
    317       var ret = this.element.value; 
    318  
    319     return /\n/.test(ret) ? '' : ret; 
    320   }, 
    321  
    322   findLastToken: function() { 
    323     var lastTokenPos = -1; 
    324  
    325     for (var i=0; i<this.options.tokens.length; i++) { 
    326       var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]); 
    327       if (thisTokenPos > lastTokenPos) 
    328         lastTokenPos = thisTokenPos; 
    329     } 
    330     return lastTokenPos; 
     313    var bounds = this.getTokenBounds(); 
     314    return this.element.value.substring(bounds[0], bounds[1]).strip(); 
     315  }, 
     316 
     317  getTokenBounds: function() { 
     318    if (null != this.tokenBounds) return this.tokenBounds; 
     319    var value = this.element.value; 
     320    if (value.strip().empty()) return [-1, 0]; 
     321    var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); 
     322    var offset = (diff == this.oldElementValue.length ? 1 : 0); 
     323    var prevTokenPos = -1, nextTokenPos = value.length; 
     324    var tp; 
     325    for (var index = 0, l = this.options.tokens.length; index < l; ++index) { 
     326      tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); 
     327      if (tp > prevTokenPos) prevTokenPos = tp; 
     328      tp = value.indexOf(this.options.tokens[index], diff + offset); 
     329      if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; 
     330    } 
     331    return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); 
    331332  } 
    332 } 
    333  
    334 Ajax.Autocompleter = Class.create(); 
    335 Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { 
     333}); 
     334 
     335Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { 
     336  var boundary = Math.min(newS.length, oldS.length); 
     337  for (var index = 0; index < boundary; ++index) 
     338    if (newS[index] != oldS[index]) 
     339      return index; 
     340  return boundary; 
     341}; 
     342 
     343Ajax.Autocompleter = Class.create(Autocompleter.Base, { 
    336344  initialize: function(element, update, url, options) { 
    337345    this.baseInitialize(element, update, options); 
     
    360368    this.updateChoices(request.responseText); 
    361369  } 
    362  
    363370}); 
    364371 
     
    398405// you support them. 
    399406 
    400 Autocompleter.Local = Class.create(); 
    401 Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { 
     407Autocompleter.Local = Class.create(Autocompleter.Base, { 
    402408  initialize: function(element, update, array, options) { 
    403409    this.baseInitialize(element, update, options); 
     
    455461        return "<ul>" + ret.join('') + "</ul>"; 
    456462      } 
    457     }, options || {}); 
     463    }, options || { }); 
    458464  } 
    459465}); 
    460466 
    461 // AJAX in-place editor 
    462 // 
    463 // see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor 
     467// AJAX in-place editor and collection editor 
     468// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007). 
    464469 
    465470// Use this if you notice weird scrolling problems on some browsers, 
     
    472477} 
    473478 
    474 Ajax.InPlaceEditor = Class.create(); 
    475 Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; 
    476 Ajax.InPlaceEditor.prototype = { 
     479Ajax.InPlaceEditor = Class.create({ 
    477480  initialize: function(element, url, options) { 
    478481    this.url = url; 
    479     this.element = $(element); 
    480  
    481     this.options = Object.extend({ 
    482       paramName: "value", 
    483       okButton: true, 
    484       okLink: false, 
    485       okText: "ok", 
    486       cancelButton: false, 
    487       cancelLink: true, 
    488       cancelText: "cancel", 
    489       textBeforeControls: '', 
    490       textBetweenControls: '', 
    491       textAfterControls: '', 
    492       savingText: "Saving...", 
    493       clickToEditText: "Click to edit", 
    494       okText: "ok", 
    495       rows: 1, 
    496       onComplete: function(transport, element) { 
    497         new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); 
    498       }, 
    499       onFailure: function(transport) { 
    500         alert("Error communicating with the server: " + transport.responseText.stripTags()); 
    501       }, 
    502       callback: function(form) { 
    503         return Form.serialize(form); 
    504       }, 
    505       handleLineBreaks: true, 
    506       loadingText: 'Loading...', 
    507       savingClassName: 'inplaceeditor-saving', 
    508       loadingClassName: 'inplaceeditor-loading', 
    509       formClassName: 'inplaceeditor-form', 
    510       highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, 
    511       highlightendcolor: "#FFFFFF", 
    512       externalControl: null, 
    513       submitOnBlur: false, 
    514       ajaxOptions: {}, 
    515       evalScripts: false 
    516     }, options || {}); 
    517  
    518     if(!this.options.formId && this.element.id) { 
    519       this.options.formId = this.element.id + "-inplaceeditor"; 
    520       if ($(this.options.formId)) { 
    521         // there's already a form with that name, don't specify an id 
    522         this.options.formId = null; 
    523       } 
    524     } 
    525      
    526     if (this.options.externalControl) { 
     482    this.element = element = $(element); 
     483    this.prepareOptions(); 
     484    this._controls = { }; 
     485    arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! 
     486    Object.extend(this.options, options || { }); 
     487    if (!this.options.formId && this.element.id) { 
     488      this.options.formId = this.element.id + '-inplaceeditor'; 
     489      if ($(this.options.formId)) 
     490        this.options.formId = ''; 
     491    } 
     492    if (this.options.externalControl) 
    527493      this.options.externalControl = $(this.options.externalControl); 
    528     } 
    529      
    530     this.originalBackground = Element.getStyle(this.element, 'background-color'); 
    531     if (!this.originalBackground) { 
    532       this.originalBackground = "transparent"; 
    533     } 
    534      
     494    if (!this.options.externalControl) 
     495      this.options.externalControlOnly = false; 
     496    this._originalBackground = this.element.getStyle('background-color') || 'transparent'; 
    535497    this.element.title = this.options.clickToEditText; 
    536      
    537     this.onclickListener = this.enterEditMode.bindAsEventListener(this); 
    538     this.mouseoverListener = this.enterHover.bindAsEventListener(this); 
    539     this.mouseoutListener = this.leaveHover.bindAsEventListener(this); 
    540     Event.observe(this.element, 'click', this.onclickListener); 
    541     Event.observe(this.element, 'mouseover', this.mouseoverListener); 
    542     Event.observe(this.element, 'mouseout', this.mouseoutListener); 
    543     if (this.options.externalControl) { 
    544       Event.observe(this.options.externalControl, 'click', this.onclickListener); 
    545       Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); 
    546       Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); 
    547     } 
    548   }, 
    549   enterEditMode: function(evt) { 
    550     if (this.saving) return; 
    551     if (this.editing) return; 
    552     this.editing = true; 
    553     this.onEnterEditMode(); 
    554     if (this.options.externalControl) { 
    555       Element.hide(this.options.externalControl); 
    556     } 
    557     Element.hide(this.element); 
     498    this._boundCancelHandler = this.handleFormCancellation.bind(this); 
     499    this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); 
     500    this._boundFailureHandler = this.handleAJAXFailure.bind(this); 
     501    this._boundSubmitHandler = this.handleFormSubmission.bind(this); 
     502    this._boundWrapperHandler = this.wrapUp.bind(this); 
     503    this.registerListeners(); 
     504  }, 
     505  checkForEscapeOrReturn: function(e) { 
     506    if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; 
     507    if (Event.KEY_ESC == e.keyCode) 
     508      this.handleFormCancellation(e); 
     509    else if (Event.KEY_RETURN == e.keyCode) 
     510      this.handleFormSubmission(e); 
     511  }, 
     512  createControl: function(mode, handler, extraClasses) { 
     513    var control = this.options[mode + 'Control']; 
     514    var text = this.options[mode + 'Text']; 
     515    if ('button' == control) { 
     516      var btn = document.createElement('input'); 
     517      btn.type = 'submit'; 
     518      btn.value = text; 
     519      btn.className = 'editor_' + mode + '_button'; 
     520      if ('cancel' == mode) 
     521        btn.onclick = this._boundCancelHandler; 
     522      this._form.appendChild(btn); 
     523      this._controls[mode] = btn; 
     524    } else if ('link' == control) { 
     525      var link = document.createElement('a'); 
     526      link.href = '#'; 
     527      link.appendChild(document.createTextNode(text)); 
     528      link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; 
     529      link.className = 'editor_' + mode + '_link'; 
     530      if (extraClasses) 
     531        link.className += ' ' + extraClasses; 
     532      this._form.appendChild(link); 
     533      this._controls[mode] = link; 
     534    } 
     535  }, 
     536  createEditField: function() { 
     537    var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); 
     538    var fld; 
     539    if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { 
     540      fld = document.createElement('input'); 
     541      fld.type = 'text'; 
     542      var size = this.options.size || this.options.cols || 0; 
     543      if (0 < size) fld.size = size; 
     544    } else { 
     545      fld = document.createElement('textarea'); 
     546      fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); 
     547      fld.cols = this.options.cols || 40; 
     548    } 
     549    fld.name = this.options.paramName; 
     550    fld.value = text; // No HTML breaks conversion anymore 
     551    fld.className = 'editor_field'; 
     552    if (this.options.submitOnBlur) 
     553      fld.onblur = this._boundSubmitHandler; 
     554    this._controls.editor = fld; 
     555    if (this.options.loadTextURL) 
     556      this.loadExternalText(); 
     557    this._form.appendChild(this._controls.editor); 
     558  }, 
     559  createForm: function() { 
     560    var ipe = this; 
     561    function addText(mode, condition) { 
     562      var text = ipe.options['text' + mode + 'Controls']; 
     563      if (!text || condition === false) return; 
     564      ipe._form.appendChild(document.createTextNode(text)); 
     565    }; 
     566    this._form = $(document.createElement('form')); 
     567    this._form.id = this.options.formId; 
     568    this._form.addClassName(this.options.formClassName); 
     569    this._form.onsubmit = this._boundSubmitHandler; 
     570    this.createEditField(); 
     571    if ('textarea' == this._controls.editor.tagName.toLowerCase()) 
     572      this._form.appendChild(document.createElement('br')); 
     573    if (this.options.onFormCustomization) 
     574      this.options.onFormCustomization(this, this._form); 
     575    addText('Before', this.options.okControl || this.options.cancelControl); 
     576    this.createControl('ok', this._boundSubmitHandler); 
     577    addText('Between', this.options.okControl && this.options.cancelControl); 
     578    this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); 
     579    addText('After', this.options.okControl || this.options.cancelControl); 
     580  }, 
     581  destroy: function() { 
     582    if (this._oldInnerHTML) 
     583      this.element.innerHTML = this._oldInnerHTML; 
     584    this.leaveEditMode(); 
     585    this.unregisterListeners(); 
     586  }, 
     587  enterEditMode: function(e) { 
     588    if (this._saving || this._editing) return; 
     589    this._editing = true; 
     590    this.triggerCallback('onEnterEditMode'); 
     591    if (this.options.externalControl) 
     592      this.options.externalControl.hide(); 
     593    this.element.hide(); 
    558594    this.createForm(); 
    559     this.element.parentNode.insertBefore(this.form, this.element); 
    560     if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField); 
    561     // stop the event to avoid a page refresh in Safari 
    562     if (evt) { 
    563       Event.stop(evt); 
    564     } 
    565     return false; 
    566   }, 
    567   createForm: function() { 
    568     this.form = document.createElement("form"); 
    569     this.form.id = this.options.formId; 
    570     Element.addClassName(this.form, this.options.formClassName) 
    571     this.form.onsubmit = this.onSubmit.bind(this); 
    572  
    573     this.createEditField(); 
    574  
    575     if (this.options.textarea) { 
    576       var br = document.createElement("br"); 
    577       this.form.appendChild(br); 
    578     } 
    579      
    580     if (this.options.textBeforeControls) 
    581       this.form.appendChild(document.createTextNode(this.options.textBeforeControls)); 
    582  
    583     if (this.options.okButton) { 
    584       var okButton = document.createElement("input"); 
    585       okButton.type = "submit"; 
    586       okButton.value = this.options.okText; 
    587       okButton.className = 'editor_ok_button'; 
    588       this.form.appendChild(okButton); 
    589     } 
    590      
    591     if (this.options.okLink) { 
    592       var okLink = document.createElement("a"); 
    593       okLink.href = "#"; 
    594       okLink.appendChild(document.createTextNode(this.options.okText)); 
    595       okLink.onclick = this.onSubmit.bind(this); 
    596       okLink.className = 'editor_ok_link'; 
    597       this.form.appendChild(okLink); 
    598     } 
    599      
    600     if (this.options.textBetweenControls &&  
    601       (this.options.okLink || this.options.okButton) &&  
    602       (this.options.cancelLink || this.options.cancelButton)) 
    603       this.form.appendChild(document.createTextNode(this.options.textBetweenControls)); 
    604        
    605     if (this.options.cancelButton) { 
    606       var cancelButton = document.createElement("input"); 
    607       cancelButton.type = "submit"; 
    608       cancelButton.value = this.options.cancelText; 
    609       cancelButton.onclick = this.onclickCancel.bind(this); 
    610       cancelButton.className = 'editor_cancel_button'; 
    611       this.form.appendChild(cancelButton); 
    612     } 
    613  
    614     if (this.options.cancelLink) { 
    615       var cancelLink = document.createElement("a"); 
    616       cancelLink.href = "#"; 
    617       cancelLink.appendChild(document.createTextNode(this.options.cancelText)); 
    618       cancelLink.onclick = this.onclickCancel.bind(this); 
    619       cancelLink.className = 'editor_cancel editor_cancel_link';       
    620       this.form.appendChild(cancelLink); 
    621     } 
    622      
    623     if (this.options.textAfterControls) 
    624       this.form.appendChild(document.createTextNode(this.options.textAfterControls)); 
    625   }, 
    626   hasHTMLLineBreaks: function(string) { 
    627     if (!this.options.handleLineBreaks) return false; 
    628     return string.match(/<br/i) || string.match(/<p>/i); 
    629   }, 
    630   convertHTMLLineBreaks: function(string) { 
    631     return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, ""); 
    632   }, 
    633   createEditField: function() { 
    634     var text; 
    635     if(this.options.loadTextURL) { 
    636       text = this.options.loadingText; 
    637     } else { 
    638       text = this.getText(); 
    639     } 
    640  
    641     var obj = this; 
    642      
    643     if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { 
    644       this.options.textarea = false; 
    645       var textField = document.createElement("input"); 
    646       textField.obj = this; 
    647       textField.type = "text"; 
    648       textField.name = this.options.paramName; 
    649       textField.value = text; 
    650       textField.style.backgroundColor = this.options.highlightcolor; 
    651       textField.className = 'editor_field'; 
    652       var size = this.options.size || this.options.cols || 0; 
    653       if (size != 0) textField.size = size; 
    654       if (this.options.submitOnBlur) 
    655         textField.onblur = this.onSubmit.bind(this); 
    656       this.editField = textField; 
    657     } else { 
    658       this.options.textarea = true; 
    659       var textArea = document.createElement("textarea"); 
    660       textArea.obj = this; 
    661       textArea.name = this.options.paramName; 
    662       textArea.value = this.convertHTMLLineBreaks(text); 
    663       textArea.rows = this.options.rows; 
    664       textArea.cols = this.options.cols || 40; 
    665       textArea.className = 'editor_field';       
    666       if (this.options.submitOnBlur) 
    667         textArea.onblur = this.onSubmit.bind(this); 
    668       this.editField = textArea; 
    669     } 
    670      
    671     if(this.options.loadTextURL) { 
    672       this.loadExternalText(); 
    673     } 
    674     this.form.appendChild(this.editField); 
     595    this.element.parentNode.insertBefore(this._form, this.element); 
     596    if (!this.options.loadTextURL) 
     597      this.postProcessEditField(); 
     598    if (e) Event.stop(e); 
     599  }, 
     600  enterHover: function(e) { 
     601    if (this.options.hoverClassName) 
     602      this.element.addClassName(this.options.hoverClassName); 
     603    if (this._saving) return; 
     604    this.triggerCallback('onEnterHover'); 
    675605  }, 
    676606  getText: function() { 
    677607    return this.element.innerHTML; 
    678608  }, 
     609  handleAJAXFailure: function(transport) { 
     610    this.triggerCallback('onFailure', transport); 
     611    if (this._oldInnerHTML) { 
     612      this.element.innerHTML = this._oldInnerHTML; 
     613      this._oldInnerHTML = null; 
     614    } 
     615  }, 
     616  handleFormCancellation: function(e) { 
     617    this.wrapUp(); 
     618    if (e) Event.stop(e); 
     619  }, 
     620  handleFormSubmission: function(e) { 
     621    var form = this._form; 
     622    var value = $F(this._controls.editor); 
     623    this.prepareSubmission(); 
     624    var params = this.options.callback(form, value) || ''; 
     625    if (Object.isString(params)) 
     626      params = params.toQueryParams(); 
     627    params.editorId = this.element.id; 
     628    if (this.options.htmlResponse) { 
     629      var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); 
     630      Object.extend(options, { 
     631        parameters: params, 
     632        onComplete: this._boundWrapperHandler, 
     633        onFailure: this._boundFailureHandler 
     634      }); 
     635      new Ajax.Updater({ success: this.element }, this.url, options); 
     636    } else { 
     637      var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); 
     638      Object.extend(options, { 
     639        parameters: params, 
     640        onComplete: this._boundWrapperHandler, 
     641        onFailure: this._boundFailureHandler 
     642      }); 
     643      new Ajax.Request(this.url, options); 
     644    } 
     645    if (e) Event.stop(e); 
     646  }, 
     647  leaveEditMode: function() { 
     648    this.element.removeClassName(this.options.savingClassName); 
     649    this.removeForm(); 
     650    this.leaveHover(); 
     651    this.element.style.backgroundColor = this._originalBackground; 
     652    this.element.show(); 
     653    if (this.options.externalControl) 
     654      this.options.externalControl.show(); 
     655    this._saving = false; 
     656    this._editing = false; 
     657    this._oldInnerHTML = null; 
     658    this.triggerCallback('onLeaveEditMode'); 
     659  }, 
     660  leaveHover: function(e) { 
     661    if (this.options.hoverClassName) 
     662      this.element.removeClassName(this.options.hoverClassName); 
     663    if (this._saving) return; 
     664    this.triggerCallback('onLeaveHover'); 
     665  }, 
    679666  loadExternalText: function() { 
    680     Element.addClassName(this.form, this.options.loadingClassName); 
    681     this.editField.disabled = true; 
    682     new Ajax.Request( 
    683       this.options.loadTextURL, 
    684       Object.extend({ 
    685         asynchronous: true, 
    686         onComplete: this.onLoadedExternalText.bind(this) 
    687       }, this.options.ajaxOptions) 
    688     ); 
    689   }, 
    690   onLoadedExternalText: function(transport) { 
    691     Element.removeClassName(this.form, this.options.loadingClassName); 
    692     this.editField.disabled = false; 
    693     this.editField.value = transport.responseText.stripTags(); 
    694     Field.scrollFreeActivate(this.editField); 
    695   }, 
    696   onclickCancel: function() { 
    697     this.onComplete(); 
    698     this.leaveEditMode(); 
    699     return false; 
    700   }, 
    701   onFailure: function(transport) { 
    702     this.options.onFailure(transport); 
    703     if (this.oldInnerHTML) { 
    704       this.element.innerHTML = this.oldInnerHTML; 
    705       this.oldInnerHTML = null; 
    706     } 
    707     return false; 
    708   }, 
    709   onSubmit: function() { 
    710     // onLoading resets these so we need to save them away for the Ajax call 
    711     var form = this.form; 
    712     var value = this.editField.value; 
    713      
    714     // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... 
    715     // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... 
    716     // to be displayed indefinitely 
    717     this.onLoading(); 
    718      
    719     if (this.options.evalScripts) { 
    720       new Ajax.Request( 
    721         this.url, Object.extend({ 
    722           parameters: this.options.callback(form, value), 
    723           onComplete: this.onComplete.bind(this), 
    724           onFailure: this.onFailure.bind(this), 
    725           asynchronous:true,  
    726           evalScripts:true 
    727         }, this.options.ajaxOptions)); 
    728     } else  { 
    729       new Ajax.Updater( 
    730         { success: this.element, 
    731           // don't update on failure (this could be an option) 
    732           failure: null },  
    733         this.url, Object.extend({ 
    734           parameters: this.options.callback(form, value), 
    735           onComplete: this.onComplete.bind(this), 
    736           onFailure: this.onFailure.bind(this) 
    737         }, this.options.ajaxOptions)); 
    738     } 
    739     // stop the event to avoid a page refresh in Safari 
    740     if (arguments.length > 1) { 
    741       Event.stop(arguments[0]); 
    742     } 
    743     return false; 
    744   }, 
    745   onLoading: function() { 
    746     this.saving = true; 
     667    this._form.addClassName(this.options.loadingClassName); 
     668    this._controls.editor.disabled = true; 
     669    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); 
     670    Object.extend(options, { 
     671      parameters: 'editorId=' + encodeURIComponent(this.element.id), 
     672      onComplete: Prototype.emptyFunction, 
     673      onSuccess: function(transport) { 
     674        this._form.removeClassName(this.options.loadingClassName); 
     675        var text = transport.responseText; 
     676        if (this.options.stripLoadedTextTags) 
     677          text = text.stripTags(); 
     678        this._controls.editor.value = text; 
     679        this._controls.editor.disabled = false; 
     680        this.postProcessEditField(); 
     681      }.bind(this), 
     682      onFailure: this._boundFailureHandler 
     683    }); 
     684    new Ajax.Request(this.options.loadTextURL, options); 
     685  }, 
     686  postProcessEditField: function() { 
     687    var fpc = this.options.fieldPostCreation; 
     688    if (fpc) 
     689      $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); 
     690  }, 
     691  prepareOptions: function() { 
     692    this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); 
     693    Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); 
     694    [this._extraDefaultOptions].flatten().compact().each(function(defs) { 
     695      Object.extend(this.options, defs); 
     696    }.bind(this)); 
     697  }, 
     698  prepareSubmission: function() { 
     699    this._saving = true; 
    747700    this.removeForm(); 
    748701    this.leaveHover(); 
    749702    this.showSaving(); 
    750703  }, 
     704  registerListeners: function() { 
     705    this._listeners = { }; 
     706    var listener; 
     707    $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { 
     708      listener = this[pair.value].bind(this); 
     709      this._listeners[pair.key] = listener; 
     710      if (!this.options.externalControlOnly) 
     711        this.element.observe(pair.key, listener); 
     712      if (this.options.externalControl) 
     713        this.options.externalControl.observe(pair.key, listener); 
     714    }.bind(this)); 
     715  }, 
     716  removeForm: function() { 
     717    if (!this._form) return; 
     718    this._form.remove(); 
     719    this._form = null; 
     720    this._controls = { }; 
     721  }, 
    751722  showSaving: function() { 
    752     this.oldInnerHTML = this.element.innerHTML; 
     723    this._oldInnerHTML = this.element.innerHTML; 
    753724    this.element.innerHTML = this.options.savingText; 
    754     Element.addClassName(this.element, this.options.savingClassName); 
    755     this.element.style.backgroundColor = this.originalBackground; 
    756     Element.show(this.element); 
    757   }, 
    758   removeForm: function() { 
    759     if(this.form) { 
    760       if (this.form.parentNode) Element.remove(this.form); 
    761       this.form = null; 
    762     } 
    763   }, 
    764   enterHover: function() { 
    765     if (this.saving) return; 
    766     this.element.style.backgroundColor = this.options.highlightcolor; 
    767     if (this.effect) { 
    768