/* * jQuery inlineEdit * * Copyright (c) 2009 Ca-Phun Ung * Licensed under the MIT (MIT-LICENSE.txt) license. * * http://github.com/caphun/jquery.inlineedit/ * * Inline (in-place) editing. */ (function($) { // cached values var namespace = '.inlineedit', placeholderClass = 'inlineEdit-placeholder'; // define inlineEdit method $.fn.inlineEdit = function( options ) { var self = this; return this .each( function() { $.inlineEdit.getInstance( this, options ).initValue(); }) .live( ['click', 'mouseenter','mouseleave'].join(namespace+' '), function( event ) { var widget = $.inlineEdit.getInstance( this, options ), editableElement = widget.element.find( widget.options.control ), mutated = !!editableElement.length; if ( event.target !== editableElement[0] ) { switch ( event.type ) { case 'click': widget[ mutated ? 'mutate' : 'init' ](); break; case 'mouseover': case 'mouseout': if ( !mutated ) { widget.hoverClassChange( event ); } break; } } }); } // plugin constructor $.inlineEdit = function( elem, options ) { // deep extend this.options = $.extend( true, {}, $.inlineEdit.defaults, options ); // the original element this.element = $( elem ); } // plugin instance $.inlineEdit.getInstance = function( elem, options ) { return ( $.inlineEdit.initialised( elem ) ) ? $( elem ).data( 'widget' + namespace ) : new $.inlineEdit( elem, options ); } // check if plugin initialised $.inlineEdit.initialised = function( elem ) { var init = $( elem ).data( 'init' + namespace ); return init !== undefined && init !== null ? true : false; } // plugin defaults $.inlineEdit.defaults = { hover: 'ui-state-hover', value: '', save: '', buttons: ' ', placeholder: 'Click to edit', control: 'input', cancelOnBlur: false }; // plugin prototypes $.inlineEdit.prototype = { // initialisation init: function() { // set initialise flag this.element.data( 'init' + namespace, true ); // initialise value this.initValue(); // mutate this.mutate(); // save widget data this.element.data( 'widget' + namespace, this ); }, initValue: function() { this.value( $.trim( this.element.text() ) || this.options.value ); if ( !this.value() ) { this.element.html( $( this.placeholderHtml() ) ); } else if ( this.options.value ) { this.element.html( this.options.value ); } }, mutate: function() { var self = this; return self .element .html( self.mutatedHtml( self.value() ) ) .find( 'button.save' ) .bind( 'click', function( event ) { self.save( self.element, event ); self.change( self.element, event ); return false; }) .end() .find( 'button.cancel' ) .bind( 'click', function( event ) { self.change( self.element, event ); return false; }) .end() .find( self.options.control ) .bind( 'blur', function( event ) { if (self.options.cancelOnBlur === true) self.change( self.element, event ); }) .bind( 'keyup', function( event ) { switch ( event.keyCode ) { case 13: // save on ENTER if (self.options.control !== 'textarea') { self.save( self.element, event ); self.change( self.element, event ); } break; case 27: // cancel on ESC self.change( self.element, event ); break; } }) .focus() .end(); }, value: function( newValue ) { if ( arguments.length ) { this.element.data( 'value' + namespace, $( '.' + placeholderClass, this ).length ? '' : newValue && newValue.replace( /\n/g,"
" ) ); } return this.element.data( 'value' + namespace ); }, mutatedHtml: function( value ) { return this.controls[ this.options.control ].call( this, value ); }, placeholderHtml: function() { return ''+ this.options.placeholder +''; }, buttonHtml: function( options ) { var o = $.extend({}, { before: ' ', buttons: this.options.buttons, after: '' }, options); return o.before + o.buttons + o.after; }, save: function( elem, event ) { var hash = { value: this.element.find( this.options.control ).val() }; if ( ( $.isFunction( this.options.save ) && this.options.save.call( this.element[0], event, hash ) ) !== false || !this.options.save ) { this.value( hash.value ); } }, change: function( elem, event ) { var self = this; if ( this.timer ) { window.clearTimeout( this.timer ); } this.timer = window.setTimeout( function() { self.element.html( self.value() || self.placeholderHtml() ); self.element.removeClass( self.options.hover ); }, 200 ); }, controls: { textarea: function( value ) { return '' + this.buttonHtml( { before: '
' } ); }, input: function( value ) { return '' + this.buttonHtml(); } }, hoverClassChange: function( event ) { $( event.target )[event.type === 'mouseover' ? 'addClass':'removeClass']( this.options.hover ); } }; })(jQuery);