Пример jquery-ui виджета

Виджет добавляет инпуту кнопки, упрощающие генерацию маски, и строку для показа сгенерированного по маске значения.
Виджет выложен исключительно для примера.
Использовать напрямую нельзя (только с моего письменного разрешения). К сожалению так, прошу извинить.

Для работы нужен jquery.caret

(function( $ ) {
	$.widget( "ui.numerationMaskGenerator", {
		options:
		{
			"buttonsData":
			{
				"Day":
				{
					"value": "%D",
					"isPressed": false,
					"example": "01"
				},
				"Month":
				{
					"value": "%M",
					"isPressed": false,
					"example": "01"
				},
				"Year":
				{
					"value": "%Y",
					"isPressed": false,
					"example": "1970"
				},
				"Number":
				{
					"value": "%N",
					"isPressed": false,
					"example": "1",
					"required": true
				}
			}
		},
	//{{{ _init
	/**
	 * Инициализация виджета
	 */
		_init: function()
		{
			var self = this;
		// обкладывающий див
			this.buttonsParent = $( "<div></div>" )
				.addClass( "numeration-mask-parent" )
				.addClass( "ui-helper-clearfix" );
			this.buttons = [];
			this.valuesExamples = [];
			this.required = [];
		// инитим все кнопки
			for ( var buttonName in this.options.buttonsData ) {
				this._initiateButton( buttonName, this.options.buttonsData[buttonName] )
					.appendTo( this.buttonsParent );
			}
			this.element.before( this.buttonsParent )
				.addClass( "numeration-mask" );
		// вывод примера сгенерированного значения
			this.exampleElement = $( "<div></div>" )
				.addClass( "numeration-mask-example" );
			this.element.after( this.exampleElement );
			this.element.bind( "keyup", function(){ self._generateExample(); } );
			this._generateExample();
		},
	/**
	 * Инициализация кнопки
	 */
		_initiateButton: function( ButtonName, ButtonData )
		{
			var self = this,
				button;
			button = this.buttons[ButtonName] = $( "<div></div>" );
			button
			// запрещаем выделение текста
				.disableSelection()
				.addClass( "numeration-mask-button " + ButtonName )
				.text( ButtonName )
				.bind( "click", function( Event ) {
					self.buttonClick( self.buttons[ButtonName] );
				})
				.data( "name", ButtonName )
				.data( "value", ButtonData["value"] )
				.data( "isPressed", this.element.val().indexOf( ButtonData["value"] ) > -1 ? true : ButtonData["isPressed"] )
				.data( "example", ButtonData["example"] )
			// если уже введён текст - делаем кнопку нажатой
				.toggleClass( "pressed", button.data( "isPressed" ) );
			this.valuesExamples[ButtonData["value"]] = ButtonData["example"];
		// сюда складываем названия обязательных кнопок
			if ( "required" in ButtonData && ButtonData.required ) {
				this.required.push( ButtonName );
			}
			return this.buttons[ButtonName];
		},
	/**
	 * Нажатие на кнопку
	 */
		buttonClick: function( Button )
		{
			var button = Button;
			button
				.data( "isPressed", ! button.data( "isPressed" ) )
				.toggleClass( "pressed", button.data( "isPressed" ) );
		// при нажатии на кнопку вставляем значение кнопки в позицию курсора
			if ( button.data( "isPressed" ) ) {
				$( this.element ).insertAtCaret( Button.data( "value" ) );
			}
		// иначе - удаляем все вхождения значения кнопки
			else {
				this._clearButtonValue( Button.data( "value" ) );
			}
		// перегенерируем пример
			this._generateExample();
			$( this.element ).focus();
		},
	/**
	 * Меняем текст в строке
	 */
		_replace: function( String, Value, Replace )
		{
			var re = new RegExp( Value, "g" );
			return String.replace( re, Replace );
		},
	/**
	 * Убираем из значения инпута все вхождения значения кнопки
	 */
		_clearButtonValue: function( Value )
		{
			$( this.element ).val( this._replace( $( this.element ).val(), Value, "" ) );
		},
	/**
	 * Генерация примера
	 */
		_generateExample: function()
		{
			var maskString = $( this.element ).val();
			maskString = this._appendRequiredParamsToExampleString( maskString );
			for ( var val in this.valuesExamples ) {
				maskString = this._replace( maskString, val, this.valuesExamples[val] );
			}
			$( this.exampleElement ).text( maskString );
		},

	/**
	 * Добавляем значения требуемых кнопок
	 */
		_appendRequiredParamsToExampleString: function( String )
		{
			if ( this.required.length )
			{
				for ( var i =0; i < this.required.length; i++ )
				{
					var name = this.required[i];
					var value = this.buttons[name].data( "value" );
					if ( String.indexOf( value ) == -1 ) {
						String += value;
					}
				}
			}
			return String;
		}
	});

}( jQuery ));


$.fn.extend({
	insertAtCaret: function( Value )
	{
		var $element =  $( this );
		var caretPosition = $element.caret();
		var value = $element.val();
		$element.val( value.substr( 0, caretPosition.start ) + Value + value.substr( caretPosition.end, value.length ) );
		var pos = caretPosition.start + Value.length;
		$element.caret( pos, pos );
	}
});

Ещё пример, попроще:


	/**
	 * Виджет редактирования текста на странице (использует уже существующий DOM для формы редактирования)
	 */
		jQuery.widget( "ui.simpleInlineEditor",
		{
			options:
			{
				selectorForm: null,
				selectorText: null,
				selectorSwitchToForm: null,
				selectorSave: null,
				selectorCancel: null,
				messageSuccess: 'Данные сохранены',
				messageError: 'Не удалось сохранить данные. Попробуйте ещё раз.',
				messagePositionTop: 30,
				eventsNs: 'simpleInlineEditor'
			},
			_init: function()
			{
				var $ = jQuery,
					me = this;
				var $el = me.element;
				if ( ! me.options.selectorForm || ! me.options.selectorText || ! me.options.selectorSwitchToForm || ! me.options.selectorSave || ! me.options.selectorCancel ) {
					throw new Error( 'not enough params' );
				}
				$( me.options.selectorSwitchToForm, $el ).bind( 'click.' + me.options.eventsNs, function() {
					me._toggle( true );
				} );
				$( me.options.selectorCancel, $el ).bind( 'click.' + me.options.eventsNs, function( Event ) {
					Event.stopPropagation();
					Event.preventDefault();
					me._toggle( false );
				} );
				$( me.options.selectorSave, $el ).bind( 'click.' + me.options.eventsNs, function( Event ) {
					Event.stopPropagation();
					Event.preventDefault();
					me._submit();
				} );
			},
		//переключатель текст/форма
			_toggle: function( ShowForm )
			{
				var $ = jQuery,
					me = this;
				var $el = me.element;
				$( me.options.selectorForm, $el ).toggle( ShowForm );
				$( me.options.selectorText, $el ).toggle( ! ShowForm );
			},
		// сохранение данных формы
			_submit: function()
			{
				var me = this,
					$ = jQuery;
				var $el = me.element;
				var $form = $( me.options.selectorForm, me.element );
				$.post( $form.attr( 'action' ), $form.serialize(), function( Answer )
					{
						if ( Answer.done )
						{
							me._showMessage( me.options.messageSuccess );
							me._toggle( false );
							if ( 'text' in Answer ) {
								$( me.options.selectorText, $el ).text( Answer.text );
							}
						}
						else {
							me._showMessage( me.options.messageError );
						}
					}, 'json');
			},
		// показ сообщения об ошибке или о сохранении
			_showMessage: function( Text )
			{
				var me = this;
				showPopupMessage( me.element, Text, { top: me.options.messagePositionTop } );
			}
		} );

// вызов:
			$( '.js-collection-name' ).simpleInlineEditor( {
				selectorForm: 'form',
				selectorText: '#collection-name',
				selectorSwitchToForm: '#collection-name',
				selectorSave: 'input[type="submit"]',
				selectorCancel: 'input[type="reset"]'
			} );

LEAVE A COMMENT