Skip to main content

Here is a demo... jsfiddle.net/JFDee/

// Here is another plugin that I have written for yousound.co.uk. It allows 
// the user to just select the text they want to edit and change it instantly 
// in it's place.
// 
// You can initialise the plugin simply like this:
// $('.editable').inplaceTextEdit();
// 
// There are a few options you can specify as well. You can have placeholder 
// text (on by default) which will fill the target element with some text that 
// by default says "Click here to edit...", this text is also an option you 
// can change.
// 
// The plugin also shows a hint to the user underneath the element that they are 
// editing, that by default says "Hit enter to save". This can be turned off 
// and the text can be changed.
// 
// Another option allows you to specify what kind of text edit field you want 
// to use, this is currently limited to input and textarea by the 
// validInputTypes array.
// 
// Finally you can specify some functions to be invoked on certain 
// events: onEditBegin, onSave and onExitWithoutSave. These are very useful, 
// especially the onSave function as this is passed the new text that the user 
// entered and can be used to store the new value.
// 
// Here is a demo: jsfiddle.net/JFDee/
// 
// Hope you enjoy this plugin, let me know your thoughts! :)

/**
 * inplaceTextEdit - edit text in place.
 *
 */ 
(function ($) {
  $.fn.inplaceTextEdit = function (options) {

    options = $.extend({
      showPlaceholder: true,
      showHints: true,
      hintText: 'Hit enter to save',
      hintId: 'editable_text_hint',
      placeholderText: 'Click here to edit...',
      textInputType: 'input',
      textInputId: 'editable_text_input',
      onEditBegin: null,
      onSave: null,
      onExitWithoutSave: null
    }, options);

    $(this).each(function () {
      var that = $(this),
        currentText = '',
        validInputTypes = ['input', 'textarea'],
        inEditMode = false;

      // Validate the given input type.
      options.textInputType = ($.inArray(options.textInputType, validInputTypes)) ? options.textInputType : 'textarea';

      // If there is no current editable value then show the placeholder if allowed.
      if (that.html() === '' && options.showPlaceholder) {
        that.html(options.placeholderText);
      }

      /**
       * Function to handle the saving of the editable text.
       *
       * @method saveEditableText
       * @private
       * @void
       *
       */
      var saveEditableText = function () {
        var input = that.find(options.textInputType);

        if (input.val() !== currentText) {
          currentText = input.val();
          input.remove();
          if (options.showHints) {
            $('#' + options.hintId).remove();
          }
          that.html(((currentText !== '') ? currentText : options.placeholderText));
          inEditMode = false;
          executeCallback(options.onSave, currentText);
        } else {
          exitWithoutSave();
        }
      };

      /**
       * Function to handle the exit without save functionallity.
       *
       * @method exitWithoutSave
       * @private
       * @void
       *
       */
      var exitWithoutSave = function () {
        that.find(options.textInputType).remove();
        that.html(currentText);
        inEditMode = false;
        executeCallback(options.onExitWithoutSave, currentText);
      };

      /**
       * Function to execute a callback if it is of type function.
       *
       * @method executeCallback
       * @private
       * @void
       *
       */
      var executeCallback = function (callback, params) {
        if (callback && typeof callback === 'function') {
          callback(params);
        }
      };

      // Event for when user clicks on the editable text intending to edit it.
      that.bind('click', function (e) {
        e.preventDefault();

        if (!inEditMode) {
          inEditMode = true;

          // Store the current value.
          currentText = that.html();

          // Edit has begun.
          executeCallback(options.onEditBegin, currentText);

          // Build an input field to get the new value.
          var input = $('<' + options.textInputType + '>').attr('id', options.textInputId).css('width', parseInt(that.width() - 10) + 'px').val(currentText);

          // Set up a couple of 'save' events.
          input.bind('keypress', function (e) {
            // If the user hit enter then call the onSave delegate and return the new content to the editable element.
            switch (e.keyCode) {
            case 13:
              if (!e.shiftKey) {
                saveEditableText();
              }
              break;

            case 27:
              exitWithoutSave();
              break;
            }
          });

          // Cancel the edit on blur.
          input.bind('blur', function () {
            exitWithoutSave();
          });

          // Inject the input field and select the text within it ready for editing.
          that.html(input);

          // Show hints for how to save/cancel if allowed.
          if (options.showHints) {
            // Create the hint element.
            var hintElement = $('<span>').attr('id', options.hintId).html('<p>' + options.hintText + '</p>');

            // Inject the hint element.
            that.append(hintElement);
          }

          // Highlight all the text in the edit input.
          input.focus();
          input.select();
        }
      });
    });
  }
})(jQuery);

// How to use the plugin.
$('.editable').inplaceTextEdit({
  onSave: function (newText) {
    alert('New text: ' + newText);
  }
});