// EditInPlace.js - enable editing a text field right on the page
//
// Using this object is very easy.
//
// 1) In your HTML, put the text you want to make editable into an
//    identifiable HTML element.  You can use an id, a name, or
//    whatever identification method you like.  For example:
//
//        <div id="text">Here is the text.</div>
//
//    The element should have only text inside it, not other HTML elements.
//
// 2) Load the routines into your code:
//
//        <script src="http://www.acme.com/javascript/EditInPlace.js" type="text/javascript"></script>
//
// 3) Find the element you want to edit.  For example, if you specified an
//    id in the HTML then you could say:
//
//        var element = document.getElementById( 'text' );
//
// 4) Create an EditInPlace object, passing it the HTML element, the number
//    of lines you want in the editable field, and a callback function:
//
//        var eip = new EditInPlace( element, lines, callback );
//
//    If lines is one you get a text input field for editing; if lines is
//    greater than one you get a textarea.
//
// 5) The callback will probably a closure that you create, that knows
//    which element it is getting called on.  For example you might say:
//
//        function () { RealCallback( element ); }
//
//    That creates a closure that calls the real callback with the text
//    element as argument.
//
//    When the callback is called, the contents of the text element have
//    already been changed to the new value.  If you don't need to do
//    anything else, feel free to pass null as the callback.
//
// That's it!  Everything else happens automatically.
//
//
// The current version of this code is always available at:
// http://www.acme.com/javascript/
//
//
// Copyright © 2006 by Jef Poskanzer <jef@mail.acme.com>.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// For commentary on this license please see http://www.acme.com/license.html


// August 30, 2006 - Andrew M DIetz
// Hacked the hell out of this to work with the new functions I made so that
// this whole class is more flexible. Changelog someday...


//EditInPlace = function ( element, lines, width, callback )
EditInPlace = function ( element, callback )
{
    	
    this.element = element;
    this.inputName = '';
    this.lines = '';
    this.width = '';
    this.type = '';
    this.value = '';
    this.options = '';
    this.modified = false;
    
    this.callback = callback;
    
    if( !callback && inlineEditCallback )
    	this.callback = inlineEditCallback;

    this.savedBackgroundColor = element.style.backgroundColor;
    if ( element.title == null || element.title == '' )
	element.title = 'Click to edit';
    else
	element.title += ' - click to edit';

    element.onmouseover = EditInPlace.MakeCaller( EditInPlace.Yellowfy, this );
    element.onmouseout = EditInPlace.MakeCaller( EditInPlace.DeYellowfy, this );
    element.onclick = EditInPlace.MakeCaller( EditInPlace.Edit, this );
};


EditInPlace.yellow = '#ffffcc';


EditInPlace.Yellowfy = function ( eip )
    {
    	eip.element.className = 'inline_edit_mover';
    	//eip.element.style.backgroundColor = EditInPlace.yellow;
    };


EditInPlace.DeYellowfy = function ( eip )
    {
    	eip.element.className = 'inline_edit_mout';
   		//eip.element.style.backgroundColor = eip.savedBackgroundColor;
    };


EditInPlace.Edit = function ( eip )
    {
    if ( eip.editElement == null )
	{
	// Create editElement.  Structure is as follows:
	// <form>
	//   <table border="0">
	//     <tbody>
	//       <tr>
	//         <td>
	//           <input type="text">
	//         </td>
	//       </tr>
	//       <tr>
	//         <td align="right">
	//           <input type="submit" value="Save">
	//           <span>&nbsp;</span>
	//           <input type="submit" value="Cancel">
	//         </td>
	//       </tr>
	//     </tbody>
	//   </table>
	// </form>


	eip.editElement = document.createElement( 'form' );
	eip.editElement.method = 'get';
	eip.editElement.action = 'javascript:void(0);';
	eip.editElement.style.marginTop = '0';
	eip.editElement.style.marginBottom = '0';
	eip.element.parentNode.insertBefore( eip.editElement, eip.element );

	var tableElement = document.createElement( 'table' );
	tableElement.border = 0;
	eip.editElement.appendChild( tableElement );

	var tbodyElement = document.createElement( 'tbody' );
	tableElement.appendChild( tbodyElement );

	var tr1Element = document.createElement( 'tr' );
	tbodyElement.appendChild( tr1Element );

	var td1Element = document.createElement( 'td' );
	tr1Element.appendChild( td1Element );
	

	if( eip.type == 'text' )
	{
		eip.inputElement = document.createElement( 'input' );
		eip.inputElement.value = eip.element.innerHTML;
		eip.inputElement.type = 'text';
	}
	else if( eip.type == 'textarea' )
	{
		eip.inputElement = document.createElement( 'textarea' );
		eip.inputElement.value = removeBreaks(eip.element.innerHTML);
	}
	else if( eip.type == 'select' )
	{
		eip.inputElement = document.createElement( 'select' );
		eip.inputElement.options.length = 0;
		
		i = 0;

		for( value in eip.options )
		{
			eip.inputElement.options[i] = eip.options[i];
			
			i++;
		}

		eip.inputElement.value = this.value;
			
	}
	
	
	eip.inputElement.setAttribute( "name", eip.inputName );
	
	
	if( eip.width )
		eip.inputElement.style.width = eip.width;
	else
		eip.inputElement.style.width = eip.element.style.width;

	eip.inputElement.style.height = ( eip.lines * 1.6 ).toFixed(1) + 'em';
	//eip.inputElement.style.backgroundColor = EditInPlace.yellow;
	eip.inputElement.className = 'inline_edit';
	eip.inputElement.onkeypress = EditInPlace.MakeCaller( EditInPlace.KeyPress, eip );
	td1Element.appendChild( eip.inputElement );

	var tr2Element = document.createElement( 'tr' );
	tbodyElement.appendChild( tr2Element );

	var td2Element = document.createElement( 'td' );
	td2Element.align = "right";
	tr2Element.appendChild( td2Element );

	var saveElement = document.createElement( 'input' );
	saveElement.type = 'submit';
	saveElement.value = 'Done';
	saveElement.onclick = EditInPlace.MakeCaller( EditInPlace.Save, eip );
	td2Element.appendChild( saveElement );

	var spanElement = document.createElement( 'span' );
	spanElement.innerHTML = '&nbsp;';
	td2Element.appendChild( spanElement );

	var cancelElement = document.createElement( 'input' );
	cancelElement.type = 'submit';
	cancelElement.value = 'Cancel';
	cancelElement.onclick = EditInPlace.MakeCaller( EditInPlace.Cancel, eip );
	td2Element.appendChild( cancelElement );
	}
    eip.element.style.display = 'none';
    eip.editElement.style.display = '';
    
    if( eip.type != 'select' )
   		eip.inputElement.select();
};


EditInPlace.KeyPress = function ( eip )
    {
    // This only works in MSIE, but it's also only needed in MSIE.
    // In Firefox, hitting Enter in the input field automatically
    // triggers the onsubmit action of the first button.
    if ( window.event && window.event.keyCode == 13 )
      EditInPlace.Save( eip );
    };


EditInPlace.Save = function ( eip )
    {
    	// Check to see if the new value is different from the old, and if so,
    	// set the element as modified for saving later
    	if ( eip.type == 'select' && eip.element.innerHTML != eip.inputElement.options[eip.inputElement.selectedIndex].value )
    		eip.modified = true;
    	else if( eip.element.innerHTML != eip.inputElement.value )
    		eip.modified = true;
    	
    	if( eip.type == 'select' )
    	{
    		eip.element.innerHTML = eip.inputElement.options[eip.inputElement.selectedIndex].text;
    		eip.inputElement.value = eip.inputElement.options[eip.inputElement.selectedIndex].value;
    	}
    	else if( eip.type == 'textarea')
    		eip.element.innerHTML = restoreBreaks(eip.inputElement.value);
    	else
	   	eip.element.innerHTML = eip.inputElement.value;
	   	 
	    eip.editElement.style.display = 'none';
	    eip.element.style.display = '';
	    EditInPlace.DeYellowfy( eip );
	    
	    // May as well only check it if the data has been modified
	    if ( eip.callback != null && eip.modified )
			eip.callback( eip.element );

    };

EditInPlace.Cancel = function ( eip )
    {
    eip.editElement.style.display = 'none';
    eip.element.style.display = '';
    EditInPlace.DeYellowfy( eip );
    };


// This returns a function closure that calls the given routine with the
// specified arg.
EditInPlace.MakeCaller = function ( func, arg )
    {
    return function () { func( arg ); };
    };


function removeBreaks(newString)
{
	return newString.replace(/<BR>/gi,"\r");
}

function restoreBreaks(newString)
{
	newString = newString.replace(/\r/g,"\n");
	return newString.replace(/\n/g,"<BR>");
}