Luxbum.net - Script de galerie photo

Changeset 305

Show
Ignore:
Timestamp:
03/09/08 20:56:18 (9 months ago)
Author:
nicolas
Message:

mise à jour de scriptaculous vers la dernière version
intégration de lightbox 2
utilisation de lightbox 2 pour agrandir les photos dans le manager

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/luxbum-0.6/_fonctions_manager/galerie.php

    r303 r305  
    426426      $name = $file->getImageName (); 
    427427 
    428       $page->MxImage ('liste.photo', $file->getThumbLink(), $name,  
    429                       'id="'.$name.'" onclick="toggleBigImage(\''.$name.'\', \''.$file->getPreviewLink().'\');" '); 
    430       //$page->MxAttribut ('liste.id_photo', $name); 
     428      $page->MxImage ('liste.photo', $file->getThumbLink(), $name, 'id="'.$name.'"'); 
     429      $page->MxUrl('liste.lightbox', $file->getPreviewLink()); 
    431430      $page->MxAttribut ('liste.action_date_desc', $str_critere.'&img='.$name.'&f=date_desc#'.$name); 
    432431 
  • branches/luxbum-0.6/_javascript/scriptaculous/builder.js

    r68 r305  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     1// script.aculo.us builder.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008 
     2 
     3// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    24// 
    3 // See scriptaculous.js for full license. 
     5// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     6// For details, see the script.aculo.us web site: http://script.aculo.us/ 
    47 
    58var Builder = { 
     
    3437       
    3538    // see if browser added wrapping tags 
    36     if(element && (element.tagName != elementName)) 
     39    if(element && (element.tagName.toUpperCase() != elementName)) 
    3740      element = element.getElementsByTagName(elementName)[0]; 
    3841     
     
    4649    if(arguments[1]) 
    4750      if(this._isStringOrNumber(arguments[1]) || 
    48         (arguments[1] instanceof Array)) { 
     51        (arguments[1] instanceof Array) || 
     52        arguments[1].tagName) { 
    4953          this._children(element, arguments[1]); 
    5054        } else { 
     
    6266                element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; 
    6367            } 
    64             if(element.tagName != elementName) 
     68            if(element.tagName.toUpperCase() != elementName) 
    6569              element = parentElement.getElementsByTagName(elementName)[0]; 
    66            
     70         
    6771        }  
    6872 
     
    7680     return document.createTextNode(text); 
    7781  }, 
     82 
     83  ATTR_MAP: { 
     84    'className': 'class', 
     85    'htmlFor': 'for' 
     86  }, 
     87 
    7888  _attributes: function(attributes) { 
    7989    var attrs = []; 
    8090    for(attribute in attributes) 
    81       attrs.push((attribute=='className' ? 'class' : attribute) + 
    82           '="' + attributes[attribute].toString().escapeHTML() + '"'); 
     91      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + 
     92          '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"'); 
    8393    return attrs.join(" "); 
    8494  }, 
    8595  _children: function(element, children) { 
     96    if(children.tagName) { 
     97      element.appendChild(children); 
     98      return; 
     99    } 
    86100    if(typeof children=='object') { // array can hold nodes and text 
    87101      children.flatten().each( function(e) { 
     
    93107      }); 
    94108    } else 
    95       if(Builder._isStringOrNumber(children))  
    96         element.appendChild(Builder._text(children)); 
     109      if(Builder._isStringOrNumber(children)) 
     110        element.appendChild(Builder._text(children)); 
    97111  }, 
    98112  _isStringOrNumber: function(param) { 
    99113    return(typeof param=='string' || typeof param=='number'); 
     114  }, 
     115  build: function(html) { 
     116    var element = this.node('div'); 
     117    $(element).update(html.strip()); 
     118    return element.down(); 
     119  }, 
     120  dump: function(scope) {  
     121    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope  
     122   
     123    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + 
     124      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + 
     125      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ 
     126      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ 
     127      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ 
     128      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); 
     129   
     130    tags.each( function(tag){  
     131      scope[tag] = function() {  
     132        return Builder.node.apply(Builder, [tag].concat($A(arguments)));   
     133      }  
     134    }); 
    100135  } 
    101136} 
  • branches/luxbum-0.6/_javascript/scriptaculous/controls.js

    r68 r305  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    2 //           (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan) 
    3 //           (c) 2005 Jon Tirsen (http://www.tirsen.com) 
     1// script.aculo.us controls.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008 
     2 
     3// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     4//           (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan) 
     5//           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com) 
    46// Contributors: 
    57//  Richard Livsey 
     
    79//  Rob Wills 
    810//  
    9 // See scriptaculous.js for full license. 
     11// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     12// For details, see the script.aculo.us web site: http://script.aculo.us/ 
    1013 
    1114// Autocompleter.Base handles all the autocompletion functionality  
     
    3437// allows smart autocompletion after linebreaks. 
    3538 
    36 var Autocompleter = {} 
    37 Autocompleter.Base = function() {}; 
    38 Autocompleter.Base.prototype = { 
     39if(typeof Effect == 'undefined') 
     40  throw("controls.js requires including script.aculo.us' effects.js library"); 
     41 
     42var Autocompleter = { } 
     43Autocompleter.Base = Class.create({ 
    3944  baseInitialize: function(element, update, options) { 
    40     this.element     = $(element);  
     45    element          = $(element) 
     46    this.element     = element;  
    4147    this.update      = $(update);   
    4248    this.hasFocus    = false;  
     
    4551    this.index       = 0;      
    4652    this.entryCount  = 0; 
    47  
    48     if (this.setOptions) 
     53    this.oldElementValue = this.element.value; 
     54 
     55    if(this.setOptions) 
    4956      this.setOptions(options); 
    5057    else 
    51       this.options = options || {}; 
     58      this.options = options || { }; 
    5259 
    5360    this.options.paramName    = this.options.paramName || this.element.name; 
     
    5663    this.options.minChars     = this.options.minChars || 1; 
    5764    this.options.onShow       = this.options.onShow ||  
    58     function(element, update){  
    59       if(!update.style.position || update.style.position=='absolute') { 
    60         update.style.position = 'absolute'; 
    61         Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight}); 
    62       } 
    63       Effect.Appear(update,{duration:0.15}); 
    64     }; 
     65      function(element, update){  
     66        if(!update.style.position || update.style.position=='absolute') { 
     67          update.style.position = 'absolute'; 
     68          Position.clone(element, update, { 
     69            setHeight: false,  
     70            offsetTop: element.offsetHeight 
     71          }); 
     72        } 
     73        Effect.Appear(update,{duration:0.15}); 
     74      }; 
    6575    this.options.onHide = this.options.onHide ||  
    66     function(element, update){ new Effect.Fade(update,{duration:0.15}) }; 
    67  
    68     if (typeof(this.options.tokens) == 'string')  
     76      function(element, update){ new Effect.Fade(update,{duration:0.15}) }; 
     77 
     78    if(typeof(this.options.tokens) == 'string')  
    6979      this.options.tokens = new Array(this.options.tokens); 
     80    // Force carriage returns as token delimiters anyway 
     81    if (!this.options.tokens.include('\n')) 
     82      this.options.tokens.push('\n'); 
    7083 
    7184    this.observer = null; 
     
    7588    Element.hide(this.update); 
    7689 
    77     Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this)); 
    78     Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); 
     90    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); 
     91    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); 
    7992  }, 
    8093 
     
    8295    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); 
    8396    if(!this.iefix &&  
    84       (navigator.appVersion.indexOf('MSIE')>0) && 
    85       (navigator.userAgent.indexOf('Opera')<0) && 
     97      (Prototype.Browser.IE) && 
    8698      (Element.getStyle(this.update, 'position')=='absolute')) { 
    8799      new Insertion.After(this.update,  
     
    95107   
    96108  fixIEOverlapping: function() { 
    97     Position.clone(this.update, this.iefix); 
     109    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); 
    98110    this.iefix.style.zIndex = 1; 
    99111    this.update.style.zIndex = 2; 
     
    133145         this.markPrevious(); 
    134146         this.render(); 
    135          if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); 
     147         Event.stop(event); 
    136148         return; 
    137149       case Event.KEY_DOWN: 
    138150         this.markNext(); 
    139151         this.render(); 
    140          if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); 
     152         Event.stop(event); 
    141153         return; 
    142154      } 
    143155     else  
    144       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)  
    145         return; 
     156      if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||  
     157        (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; 
    146158 
    147159    this.changed = true; 
     
    151163      this.observer =  
    152164        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); 
     165  }, 
     166 
     167  activate: function() { 
     168    this.changed = false; 
     169    this.hasFocus = true; 
     170    this.getUpdatedChoices(); 
    153171  }, 
    154172 
     
    183201          Element.addClassName(this.getEntry(i),"selected") :  
    184202          Element.removeClassName(this.getEntry(i),"selected"); 
    185          
    186203      if(this.hasFocus) {  
    187204        this.show(); 
     
    197214    if(this.index > 0) this.index-- 
    198215      else this.index = this.entryCount-1; 
     216    this.getEntry(this.index).scrollIntoView(true); 
    199217  }, 
    200218   
     
    202220    if(this.index < this.entryCount-1) this.index++ 
    203221      else this.index = 0; 
     222    this.getEntry(this.index).scrollIntoView(false); 
    204223  }, 
    205224   
     
    224243    var value = ''; 
    225244    if (this.options.select) { 
    226       var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; 
     245      var nodes = $(selectedElement).select('.' + this.options.select) || []; 
    227246      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); 
    228247    } else 
    229248      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); 
    230249     
    231     var lastTokenPos = this.findLastToken(); 
    232     if (lastTokenPos != -1) { 
    233       var newValue = this.element.value.substr(0, lastTokenPos + 1); 
    234       var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); 
     250    var bounds = this.getTokenBounds(); 
     251    if (bounds[0] != -1) { 
     252      var newValue = this.element.value.substr(0, bounds[0]); 
     253      var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); 
    235254      if (whitespace) 
    236255        newValue += whitespace[0]; 
    237       this.element.value = newValue + value
     256      this.element.value = newValue + value + this.element.value.substr(bounds[1])
    238257    } else { 
    239258      this.element.value = value; 
    240259    } 
     260    this.oldElementValue = this.element.value; 
    241261    this.element.focus(); 
    242262     
     
    249269      this.update.innerHTML = choices; 
    250270      Element.cleanWhitespace(this.update); 
    251       Element.cleanWhitespace(this.update.firstChild); 
    252  
    253       if(this.update.firstChild && this.update.firstChild.childNodes) { 
     271      Element.cleanWhitespace(this.update.down()); 
     272 
     273      if(this.update.firstChild && this.update.down().childNodes) { 
    254274        this.entryCount =  
    255           this.update.firstChild.childNodes.length; 
     275          this.update.down().childNodes.length; 
    256276        for (var i = 0; i < this.entryCount; i++) { 
    257277          var entry = this.getEntry(i); 
     
    264284 
    265285      this.stopIndicator(); 
    266  
    267286      this.index = 0; 
    268       this.render(); 
     287       
     288      if(this.entryCount==1 && this.options.autoSelect) { 
     289        this.selectEntry(); 
     290        this.hide(); 
     291      } else { 
     292        this.render(); 
     293      } 
    269294    } 
    270295  }, 
     
    277302  onObserverEvent: function() { 
    278303    this.changed = false;    
     304    this.tokenBounds = null; 
    279305    if(this.getToken().length>=this.options.minChars) { 
    280       this.startIndicator(); 
    281306      this.getUpdatedChoices(); 
    282307    } else { 
     
    284309      this.hide(); 
    285310    } 
     311    this.oldElementValue = this.element.value; 
    286312  }, 
    287313 
    288314  getToken: function() { 
    289     var tokenPos = this.findLastToken(); 
    290     if (tokenPos != -1) 
    291       var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); 
    292     else 
    293       var ret = this.element.value; 
    294  
    295     return /\n/.test(ret) ? '' : ret; 
    296   }, 
    297  
    298   findLastToken: function() { 
    299     var lastTokenPos = -1; 
    300  
    301     for (var i=0; i<this.options.tokens.length; i++) { 
    302       var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]); 
    303       if (thisTokenPos > lastTokenPos) 
    304         lastTokenPos = thisTokenPos; 
    305     } 
    306     return lastTokenPos; 
     315    var bounds = this.getTokenBounds(); 
     316    return this.element.value.substring(bounds[0], bounds[1]).strip(); 
     317  }, 
     318 
     319  getTokenBounds: function() { 
     320    if (null != this.tokenBounds) return this.tokenBounds; 
     321    var value = this.element.value; 
     322    if (value.strip().empty()) return [-1, 0]; 
     323    var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); 
     324    var offset = (diff == this.oldElementValue.length ? 1 : 0); 
     325    var prevTokenPos = -1, nextTokenPos = value.length; 
     326    var tp; 
     327    for (var index = 0, l = this.options.tokens.length; index < l; ++index) { 
     328      tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); 
     329      if (tp > prevTokenPos) prevTokenPos = tp; 
     330      tp = value.indexOf(this.options.tokens[index], diff + offset); 
     331      if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; 
     332    } 
     333    return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); 
    307334  } 
    308 
    309  
    310 Ajax.Autocompleter = Class.create(); 
    311 Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { 
     335}); 
     336 
     337Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { 
     338  var boundary = Math.min(newS.length, oldS.length); 
     339  for (var index = 0; index < boundary; ++index) 
     340    if (newS[index] != oldS[index]) 
     341      return index; 
     342  return boundary; 
     343}; 
     344 
     345Ajax.Autocompleter = Class.create(Autocompleter.Base, { 
    312346  initialize: function(element, update, url, options) { 
    313          this.baseInitialize(element, update, options); 
     347    this.baseInitialize(element, update, options); 
    314348    this.options.asynchronous  = true; 
    315349    this.options.onComplete    = this.onComplete.bind(this); 
     
    319353 
    320354  getUpdatedChoices: function() { 
    321     entry = encodeURIComponent(this.options.paramName) + '=' +  
     355    this.startIndicator(); 
     356     
     357    var entry = encodeURIComponent(this.options.paramName) + '=' +  
    322358      encodeURIComponent(this.getToken()); 
    323359 
     
    327363    if(this.options.defaultParams)  
    328364      this.options.parameters += '&' + this.options.defaultParams; 
    329  
     365     
    330366    new Ajax.Request(this.url, this.options); 
    331367  }, 
     
    334370    this.updateChoices(request.responseText); 
    335371  } 
    336  
    337372}); 
    338373 
     
    372407// you support them. 
    373408 
    374 Autocompleter.Local = Class.create(); 
    375 Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { 
     409Autocompleter.Local = Class.create(Autocompleter.Base, { 
    376410  initialize: function(element, update, array, options) { 
    377411    this.baseInitialize(element, update, options); 
     
    429463        return "<ul>" + ret.join('') + "</ul>"; 
    430464      } 
    431     }, options || {}); 
     465    }, options || { }); 
    432466  } 
    433467}); 
    434468 
    435 // AJAX in-place editor 
    436 // 
    437 // see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor 
     469// AJAX in-place editor and collection editor 
     470// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007). 
    438471 
    439472// Use this if you notice weird scrolling problems on some browsers, 
     
    446479} 
    447480 
    448 Ajax.InPlaceEditor = Class.create(); 
    449 Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; 
    450 Ajax.InPlaceEditor.prototype = { 
     481Ajax.InPlaceEditor = Class.create({ 
    451482  initialize: function(element, url, options) { 
    452483    this.url = url; 
    453     this.element = $(element); 
    454  
    455     this.options = Object.extend({ 
    456       okButton: true, 
    457       okText: "ok", 
    458       cancelLink: true, 
    459       cancelText: "cancel", 
    460       savingText: "Saving...", 
    461       clickToEditText: "Click to edit", 
    462       okText: "ok", 
    463       rows: 1, 
    464       onComplete: function(transport, element) { 
    465         new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); 
    466       }, 
    467       onFailure: function(transport) { 
    468         alert("Error communicating with the server: " + transport.responseText.stripTags()); 
    469       }, 
    470       callback: function(form) { 
    471         return Form.serialize(form); 
    472       }, 
    473       handleLineBreaks: true, 
    474       loadingText: 'Loading...', 
    475       savingClassName: 'inplaceeditor-saving', 
    476       loadingClassName: 'inplaceeditor-loading', 
    477       formClassName: 'inplaceeditor-form', 
    478       highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, 
    479       highlightendcolor: "#FFFFFF", 
    480       externalControl:  null, 
    481       submitOnBlur: false, 
    482       ajaxOptions: {} 
    483     }, options || {}); 
    484  
    485     if(!this.options.formId && this.element.id) { 
    486       this.options.formId = this.element.id + "-inplaceeditor"; 
    487       if ($(this.options.formId)) { 
    488         // there's already a form with that name, don't specify an id 
    489         this.options.formId = null; 
    490       } 
    491     } 
    492      
    493     if (this.options.externalControl) { 
     484    this.element = element = $(element); 
     485    this.prepareOptions(); 
     486    this._controls = { }; 
     487    arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! 
     488    Object.extend(this.options, options || { }); 
     489    if (!this.options.formId && this.element.id) { 
     490      this.options.formId = this.element.id + '-inplaceeditor'; 
     491      if ($(this.options.formId)) 
     492        this.options.formId = ''; 
     493    } 
     494    if (this.options.externalControl) 
    494495      this.options.externalControl = $(this.options.externalControl); 
    495     } 
    496      
    497     this.originalBackground = Element.getStyle(this.element, 'background-color'); 
    498     if (!this.originalBackground) { 
    499       this.originalBackground = "transparent"; 
    500     } 
    501      
     496    if (!this.options.externalControl) 
     497      this.options.externalControlOnly = false; 
     498    this._originalBackground = this.element.getStyle('background-color') || 'transparent'; 
    502499    this.element.title = this.options.clickToEditText; 
    503      
    504     this.onclickListener = this.enterEditMode.bindAsEventListener(this); 
    505     this.mouseoverListener = this.enterHover.bindAsEventListener(this); 
    506     this.mouseoutListener = this.leaveHover.bindAsEventListener(this); 
    507     Event.observe(this.element, 'click', this.onclickListener); 
    508     Event.observe(this.element, 'mouseover', this.mouseoverListener); 
    509     Event.observe(this.element, 'mouseout', this.mouseoutListener); 
    510     if (this.options.externalControl) { 
    511       Event.observe(this.options.externalControl, 'click', this.onclickListener); 
    512       Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); 
    513       Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); 
    514     } 
    515   }, 
    516   enterEditMode: function(evt) { 
    517     if (this.saving) return; 
    518     if (this.editing) return; 
    519     this.editing = true; 
    520     this.onEnterEditMode(); 
    521     if (this.options.externalControl) { 
    522       Element.hide(this.options.externalControl); 
    523     } 
    524     Element.hide(this.element); 
     500    this._boundCancelHandler = this.handleFormCancellation.bind(this); 
     501    this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); 
     502    this._boundFailureHandler = this.handleAJAXFailure.bind(this); 
     503    this._boundSubmitHandler = this.handleFormSubmission.bind(this); 
     504    this._boundWrapperHandler = this.wrapUp.bind(this); 
     505    this.registerListeners(); 
     506  }, 
     507  checkForEscapeOrReturn: function(e) { 
     508    if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; 
     509    if (Event.KEY_ESC == e.keyCode) 
     510      this.handleFormCancellation(e); 
     511    else if (Event.KEY_RETURN == e.keyCode) 
     512      this.handleFormSubmission(e); 
     513  }, 
     514  createControl: function(mode, handler, extraClasses) { 
     515    var control = this.options[mode + 'Control']; 
     516    var text = this.options[mode + 'Text']; 
     517    if ('button' == control) { 
     518      var btn = document.createElement('input'); 
     519      btn.type = 'submit'; 
     520      btn.value = text; 
     521      btn.className = 'editor_' + mode + '_button'; 
     522      if ('cancel' == mode) 
     523        btn.onclick = this._boundCancelHandler; 
     524      this._form.appendChild(btn); 
     525      this._controls[mode] = btn; 
     526    } else if ('link' == control) { 
     527      var link = document.createElement('a'); 
     528      link.href = '#'; 
     529      link.appendChild(document.createTextNode(text)); 
     530      link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; 
     531      link.className = 'editor_' + mode + '_link'; 
     532      if (extraClasses) 
     533        link.className += ' ' + extraClasses; 
     534      this._form.appendChild(link); 
     535      this._controls[mode] = link; 
     536    } 
     537  }, 
     538  createEditField: function() { 
     539    var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); 
     540    var fld; 
     541    if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { 
     542      fld = document.createElement('input'); 
     543      fld.type = 'text'; 
     544      var size = this.options.size || this.options.cols || 0; 
     545      if (0 < size) fld.size = size; 
     546    } else { 
     547      fld = document.createElement('textarea'); 
     548      fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); 
     549      fld.cols = this.options.cols || 40; 
     550    } 
     551    fld.name = this.options.paramName; 
     552    fld.value = text; // No HTML breaks conversion anymore 
     553    fld.className = 'editor_field'; 
     554    if (this.options.submitOnBlur) 
     555      fld.onblur = this._boundSubmitHandler; 
     556    this._controls.editor = fld; 
     557    if (this.options.loadTextURL) 
     558      this.loadExternalText(); 
     559    this._form.appendChild(this._controls.editor); 
     560  }, 
     561  createForm: function() { 
     562    var ipe = this; 
     563    function addText(mode, condition) { 
     564      var text = ipe.options['text' + mode + 'Controls']; 
     565      if (!text || condition === false) return; 
     566      ipe._form.appendChild(document.createTextNode(text)); 
     567    }; 
     568    this._form = $(document.createElement('form')); 
     569    this._form.id = this.options.formId; 
     570    this._form.addClassName(this.options.formClassName); 
     571    this._form.onsubmit = this._boundSubmitHandler; 
     572    this.createEditField(); 
     573    if ('textarea' == this._controls.editor.tagName.toLowerCase()) 
     574      this._form.appendChild(document.createElement('br')); 
     575    if (this.options.onFormCustomization) 
     576      this.options.onFormCustomization(this, this._form); 
     577    addText('Before', this.options.okControl || this.options.cancelControl); 
     578    this.createControl('ok', this._boundSubmitHandler); 
     579    addText('Between', this.options.okControl && this.options.cancelControl); 
     580    this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); 
     581    addText('After', this.options.okControl || this.options.cancelControl); 
     582  }, 
     583  destroy: function() { 
     584    if (this._oldInnerHTML) 
     585      this.element.innerHTML = this._oldInnerHTML; 
     586    this.leaveEditMode(); 
     587    this.unregisterListeners(); 
     588  }, 
     589  enterEditMode: function(e) { 
     590    if (this._saving || this._editing) return; 
     591    this._editing = true; 
     592    this.triggerCallback('onEnterEditMode'); 
     593    if (this.options.externalControl) 
     594      this.options.externalControl.hide(); 
     595    this.element.hide(); 
    525596    this.createForm(); 
    526     this.element.parentNode.insertBefore(this.form, this.element); 
    527     Field.scrollFreeActivate(this.editField); 
    528     // stop the event to avoid a page refresh in Safari 
    529     if (evt) { 
    530       Event.stop(evt); 
    531     } 
    532     return false; 
    533   }, 
    534   createForm: function() { 
    535     this.form = document.createElement("form"); 
    536     this.form.id = this.options.formId; 
    537     Element.addClassName(this.form, this.options.formClassName) 
    538     this.form.onsubmit = this.onSubmit.bind(this); 
    539  
    540     this.createEditField(); 
    541  
    542     if (this.options.textarea) { 
    543       var br = document.createElement("br"); 
    544       this.form.appendChild(br); 
    545     } 
    546  
    547     if (this.options.okButton) { 
    548       okButton = document.createElement("input"); 
    549       okButton.type = "submit"; 
    550       okButton.value = this.options.okText; 
    551       this.form.appendChild(okButton); 
    552     } 
    553  
    554     if (this.options.cancelLink) { 
    555       cancelLink = document.createElement("a"); 
    556       cancelLink.href = "#"; 
    557       cancelLink.appendChild(document.createTextNode(this.options.cancelText)); 
    558       cancelLink.onclick = this.onclickCancel.bind(this); 
    559       this.form.appendChild(cancelLink); 
    560     } 
    561   }, 
    562   hasHTMLLineBreaks: function(string) { 
    563     if (!this.options.handleLineBreaks) return false; 
    564     return string.match(/<br/i) || string.match(/<p>/i); 
    565   }, 
    566   convertHTMLLineBreaks: function(string) { 
    567     return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, ""); 
    568   }, 
    569   createEditField: function() { 
    570     var text; 
    571     if(this.options.loadTextURL) { 
    572       text = this.options.loadingText; 
    573     } else { 
    574       text = this.getText(); 
    575     } 
    576  
    577     var obj = this; 
    578      
    579     if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { 
    580       this.options.textarea = false; 
    581       var textField = document.createElement("input"); 
    582       textField.obj = this; 
    583       textField.type = "text"; 
    584       textField.name = "value"; 
    585       textField.value = text; 
    586       textField.style.backgroundColor = this.options.highlightcolor; 
    587       var size = this.options.size || this.options.cols || 0; 
    588       if (size != 0) textField.size = size; 
    589       if (this.options.submitOnBlur) 
    590         textField.onblur = this.onSubmit.bind(this); 
    591       this.editField = textField; 
    592     } else { 
    593       this.options.textarea = true; 
    594       var textArea = document.createElement("textarea"); 
    595       textArea.obj = this; 
    596       textArea.name = "value"; 
    597       textArea.value = this.convertHTMLLineBreaks(text); 
    598       textArea.rows = this.options.rows; 
    599       textArea.cols = this.options.cols || 40; 
    600       if (this.options.submitOnBlur) 
    601         textArea.onblur = this.onSubmit.bind(this); 
    602       this.editField = textArea; 
    603     } 
    604      
    605     if(this.options.loadTextURL) { 
    606       this.loadExternalText(); 
    607     } 
    608     this.form.appendChild(this.editField); 
     597    this.element.parentNode.insertBefore(this._form, this.element); 
     598    if (!this.options.loadTextURL) 
     599      this.postProcessEditField(); 
     600    if (e) Event.stop(e); 
     601  }, 
     602  enterHover: function(e) { 
     603    if (this.options.hoverClassName) 
     604      this.element.addClassName(this.options.hoverClassName); 
     605    if (this._saving) return; 
     606    this.triggerCallback('onEnterHover'); 
    609607  }, 
    610608  getText: function() { 
    611609    return this.element.innerHTML; 
    612610  }, 
     611  handleAJAXFailure: function(transport) { 
     612    this.triggerCallback('onFailure', transport); 
     613    if (this._oldInnerHTML) { 
     614      this.element.innerHTML = this._oldInnerHTML; 
     615      this._oldInnerHTML = null; 
     616    } 
     617  }, 
     618  handleFormCancellation: function(e) { 
     619    this.wrapUp(); 
     620    if (e) Event.stop(e); 
     621  }, 
     622  handleFormSubmission: function(e) { 
     623    var form = this._form; 
     624    var value = $F(this._controls.editor); 
     625    this.prepareSubmission(); 
     626    var params = this.options.callback(form, value) || ''; 
     627    if (Object.isString(params)) 
     628      params = params.toQueryParams(); 
     629    params.editorId = this.element.id; 
     630    if (this.options.htmlResponse) { 
     631      var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); 
     632      Object.extend(options, { 
     633        parameters: params, 
     634        onComplete: this._boundWrapperHandler, 
     635        onFailure: this._boundFailureHandler 
     636      }); 
     637      new Ajax.Updater({ success: this.element }, this.url, options); 
     638    } else { 
     639      var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); 
     640      Object.extend(options, { 
     641        parameters: params, 
     642        onComplete: this._boundWrapperHandler, 
     643        onFailure: this._boundFailureHandler 
     644      }); 
     645      new Ajax.Request(this.url, options); 
     646    } 
     647    if (e) Event.stop(e); 
     648  }, 
     649  leaveEditMode: function() { 
     650    this.element.removeClassName(this.options.savingClassName); 
     651    this.removeForm(); 
     652    this.leaveHover(); 
     653    this.element.style.backgroundColor = this._originalBackground; 
     654    this.element.show(); 
     655    if (this.options.externalControl) 
     656      this.options.externalControl.show(); 
     657    this._saving = false; 
     658    this._editing = false; 
     659    this._oldInnerHTML = null; 
     660    this.triggerCallback('onLeaveEditMode'); 
     661  }, 
     662  leaveHover: function(e) { 
     663    if (this.options.hoverClassName) 
     664      this.element.removeClassName(this.options.hoverClassName); 
     665    if (this._saving) return; 
     666    this.triggerCallback('onLeaveHover'); 
     667  }, 
    613668  loadExternalText: function() { 
    614     Element.addClassName(this.form, this.options.loadingClassName); 
    615     this.editField.disabled = true; 
    616     new Ajax.Request( 
    617       this.options.loadTextURL, 
    618       Object.extend({ 
    619         asynchronous: true, 
    620         onComplete: this.onLoadedExternalText.bind(this) 
    621       }, this.options.ajaxOptions) 
    622     ); 
    623   }, 
    624   onLoadedExternalText: function(transport) { 
    625     Element.removeClassName(this.form, this.options.loadingClassName); 
    626     this.editField.disabled = false; 
    627     this.editField.value = transport.responseText.stripTags(); 
    628   }, 
    629   onclickCancel: function() { 
    630     this.onComplete(); 
    631     this.leaveEditMode(); 
    632     return false; 
    633   }, 
    634   onFailure: function(transport) { 
    635     this.options.onFailure(transport); 
    636     if (this.oldInnerHTML) { 
    637       this.element.innerHTML = this.oldInnerHTML; 
    638       this.oldInnerHTML = null; 
    639     } 
    640     return false; 
    641   }, 
    642   onSubmit: function() { 
    643     // onLoading resets these so we need to save them away for the Ajax call 
    644     var form = this.form; 
    645     var value = this.editField.value; 
    646      
    647     // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... 
    648     // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... 
    649     // to be displayed indefinitely 
    650     this.onLoading(); 
    651      
    652     new Ajax.Updater( 
    653       {  
    654         success: this.element, 
    655          // don't update on failure (this could be an option) 
    656         failure: null 
    657       }, 
    658       this.url, 
    659       Object.extend({ 
    660         parameters: this.options.callback(form, value), 
    661         onComplete: this.onComplete.bind(this), 
    662         onFailure: this.onFailure.bind(this) 
    663       }, this.options.ajaxOptions) 
    664     ); 
    665     // stop the event to avoid a page refresh in Safari 
    666     if (arguments.length > 1) { 
    667       Event.stop(arguments[0]); 
    668     } 
    669     return false; 
    670   }, 
    671   onLoading: function() { 
    672     this.saving = true; 
     669    this._form.addClassName(this.options.loadingClassName); 
     670    this._controls.editor.disabled = true; 
     671    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); 
     672    Object.extend(options, { 
     673      parameters: 'editorId=' + encodeURIComponent(this.element.id), 
     674      onComplete: Prototype.emptyFunction, 
     675      onSuccess: function(transport) { 
     676        this._form.removeClassName(this.options.loadingClassName); 
     677        var text = transport.responseText; 
     678        if (this.options.stripLoadedTextTags) 
     679          text = text.stripTags(); 
     680        this._controls.editor.value = text; 
     681        this._controls.editor.disabled = false; 
     682        this.postProcessEditField(); 
     683      }.bind(this), 
     684      onFailure: this._boundFailureHandler 
     685    }); 
     686    new Ajax.Request(this.options.loadTextURL, options); 
     687  }, 
     688  postProcessEditField: function() { 
     689    var fpc = this.options.fieldPostCreation; 
     690    if (fpc) 
     691      $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); 
     692  }, 
     693  prepareOptions: function() { 
     694    this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); 
     695    Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); 
     696    [this._extraDefaultOptions].flatten().compact().each(function(defs) { 
     697      Object.extend(this.options, defs); 
     698    }.bind(this)); 
     699  }, 
     700  prepareSubmission: function() { 
     701    this._saving = true; 
    673702    this.removeForm(); 
    674703    this.leaveHover(); 
    675704    this.showSaving(); 
    676705  }, 
     706  registerListeners: function() { 
     707    this._listeners = { }; 
     708    var listener; 
     709    $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { 
     710      listener = this[pair.value].bind(this); 
     711      this._listeners[pair.key] = listener; 
     712      if (!this.options.externalControlOnly) 
     713        this.element.observe(pair.key, listener); 
     714      if (this.options.externalControl) 
     715        this.options.externalControl.observe(pair.key, listener); 
     716    }.bind(this)); 
     717  }, 
     718  removeForm: function() { 
     719    if (!this._form) return; 
     720    this._form.remove(); 
     721    this._form = null; 
     722    this._controls = { }; 
     723  }, 
    677724  showSaving: function() { 
    678     this.oldInnerHTML = this.element.innerHTML; 
     725    this._oldInnerHTML = this.element.innerHTML; 
    679726    this.element.innerHTML = this.options.savingText; 
    680     Element.addClassName(this.element, this.options.savingClassName); 
    681     this.element.style.backgroundColor = this.originalBackground; 
    682     Element.show(this.element); 
    683   }, 
    684   removeForm: function() { 
    685     if(this.form) { 
    686       if (this.form.parentNode) Element.remove(this.form); 
    687       this.form = null; 
    688     } 
    689   }, 
    690   enterHover: function() { 
    691     if (this.saving) return; 
    692     this.element.style.backgroundColor = this.options.highlightcolor; 
    693     if (this.effect) { 
    694       this.effect.cancel(); 
    695     } 
    696     Element.addClassName(this.element, this.options.hoverClassName) 
    697   }, 
    698   leaveHover: function() { 
    699     if (this.options.backgroundColor) { 
    700       this.element.style.backgroundColor = this.oldBackground; 
    701     } 
    702     Element.removeClassName(this.element, this.options.hoverClassName) 
    703     if (this.saving) return; 
    704     this.effect = new Effect.Highlight(this.element, { 
    705       startcolor: this.options.highlightcolor, 
    706       endcolor: this.options.highlightendcolor, 
    707       restorecolor: this.originalBackground 
     727    this.element.addClassName(this.options.savingClassName); 
     728    this.element.style.backgroundColor = this._originalBackground; 
     729    this.element.show(); 
     730  }, 
     731  triggerCallback: function(cbName, arg) { 
     732    if ('function' == typeof this.options[cbName]) { 
     733      this.options[cbName](this, arg); 
     734    } 
     735  }, 
     736  unregisterListeners: function() { 
     737    $H(this._listeners).each(function(pair) { 
     738      if (!this.options.externalControlOnly) 
     739        this.element.stopObserving(pair.key, pair.value); 
     740      if (this.options.externalControl) 
     741        this.options.externalControl.stopObserving(pair.key, pair.value); 
     742    }.bind(this)); 
     743  }, 
     744  wrapUp: function(transport) { 
     745    this.leaveEditMode(); 
     746    // Can't use triggerCallback due to backward compatibility: requires 
     747    // binding + direct element 
     748    this._boundComplete(transport, this.element); 
     749  } 
     750}); 
     751 </