All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.primefaces.keyboard.0-jquery.keypad.js Maven / Gradle / Ivy

Go to download

PrimeFaces is one of the most popular UI libraries in Java EE Ecosystem and widely used by software companies, world renowned brands, banks, financial institutions, insurance companies, universities and more.

There is a newer version: 14.0.0-RC3
Show newest version
/* http://keith-wood.name/keypad.html
   Keypad field entry extension for jQuery v2.1.0.
   Written by Keith Wood (kbwood{at}iinet.com.au) August 2008.
   Available under the MIT (http://keith-wood.name/licence.html) license.
   Please attribute the author if you use it. */

/* globals JQClass */
/*! Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
	'use strict';
	var initializing = false;

	// The base JQClass implementation (does nothing)
	window.JQClass = function(){};

	// Collection of derived classes
	JQClass.classes = {};

	// Create a new JQClass that inherits from this class
	JQClass.extend = function extender(prop) {
		var base = this.prototype;

		// Instantiate a base class (but only create the instance, don't run the init constructor)
		initializing = true;
		var prototype = new this();
		initializing = false;

		// Copy the properties over onto the new prototype
		for (var name in prop) { // jshint loopfunc:true
			// Check if we're overwriting an existing function
			if (typeof prop[name] === 'function' && typeof base[name] === 'function') {
				prototype[name] = (function (name, fn) {
					return function () {
						var __super = this._super;
						// Add a new ._super() method that is the same method but on the super-class
						this._super = function (args) {
							return base[name].apply(this, args || []);
						};
						var ret = fn.apply(this, arguments);
						// The method only needs to be bound temporarily, so we remove it when we're done executing
						this._super = __super;
						return ret;
					};
				})(name, prop[name]);
			// Check if we're overwriting existing default options.
			} else if (typeof prop[name] === 'object' && typeof base[name] === 'object' && name === 'defaultOptions') {
				var obj1 = base[name];
				var obj2 = prop[name];
				var obj3 = {};
				var key;
				for (key in obj1) { // jshint forin:false
					obj3[key] = obj1[key];
				}
				for (key in obj2) { // jshint forin:false
					obj3[key] = obj2[key];
				}
				prototype[name] = obj3;
			} else {
				prototype[name] = prop[name];
			}
		}

		// The dummy class constructor
		function JQClass() {
			// All construction is actually done in the init method
			if (!initializing && this._init) {
				this._init.apply(this, arguments);
			}
		}

		// Populate our constructed prototype object
		JQClass.prototype = prototype;

		// Enforce the constructor to be what we expect
		JQClass.prototype.constructor = JQClass;

		// And make this class extendable
		JQClass.extend = extender;

		return JQClass;
	};
})();
/*! Abstract base class for collection plugins v1.0.2.
	Written by Keith Wood (wood.keith{at}optusnet.com.au) December 2013.
	Licensed under the MIT license (http://keith-wood.name/licence.html). */
(function($) { // Ensure $, encapsulate
	'use strict';

	/** 

Abstract base class for collection plugins v1.0.2.

Written by Keith Wood (wood.keith{at}optusnet.com.au) December 2013.

Licensed under the MIT license (http://keith-wood.name/licence.html).

Use {@link $.JQPlugin.createPlugin} to create new plugins using this framework.

This base class provides common functionality such as:

  • Creates jQuery bridge - allowing you to invoke your plugin on a collection of elements.
  • Handles initialisation including reading settings from metadata - an instance object is attached to the affected element(s) containing all the necessary data.
  • Handles option retrieval and update - options can be set through default values, through inline metadata, or through instantiation settings.
    Metadata is specified as an attribute on the element: data-<pluginName>="<option name>: '<value>', ...". Dates should be specified as strings in this format: 'new Date(y, m-1, d)'.
  • Handles method calling - inner functions starting with '_'are inaccessible, whereas others can be called via $(selector).pluginName('functionName').
  • Handles plugin destruction - removing all trace of the plugin.
@module JQPlugin @abstract */ JQClass.classes.JQPlugin = JQClass.extend({ /** Name to identify this plugin. @example name: 'tabs' */ name: 'plugin', /** Default options for instances of this plugin (default: {}). @example defaultOptions: { selectedClass: 'selected', triggers: 'click' } */ defaultOptions: {}, /** Options dependent on the locale. Indexed by language and (optional) country code, with '' denoting the default language (English/US). Normally additional languages would be provided as separate files to all them to be included as needed. @example regionalOptions: { '': { greeting: 'Hi' } } */ regionalOptions: {}, /** Whether or not a deep merge should be performed when accumulating options. The default is true but can be overridden in a sub-class. */ deepMerge: true, /** Retrieve a marker class for affected elements. In the format: is-<pluginName>. @protected @return {string} The marker class. */ _getMarker: function() { return 'is-' + this.name; }, /** Initialise the plugin. Create the jQuery bridge - plugin name xyz produces singleton $.xyz and collection function $.fn.xyz. @protected */ _init: function() { // Apply default localisations $.extend(this.defaultOptions, (this.regionalOptions && this.regionalOptions['']) || {}); // Camel-case the name var jqName = camelCase(this.name); // Expose jQuery singleton manager $[jqName] = this; // Expose jQuery collection plugin $.fn[jqName] = function(options) { var otherArgs = Array.prototype.slice.call(arguments, 1); var inst = this; var returnValue = this; this.each(function () { if (typeof options === 'string') { if (options[0] === '_' || !$[jqName][options]) { throw 'Unknown method: ' + options; } var methodValue = $[jqName][options].apply($[jqName], [this].concat(otherArgs)); if (methodValue !== inst && methodValue !== undefined) { returnValue = methodValue; return false; } } else { $[jqName]._attach(this, options); } }); return returnValue; }; }, /** Set default options for all subsequent instances. @param {object} options The new default options. @example $.pluginName.setDefaults({name: value, ...}) */ setDefaults: function(options) { $.extend(this.defaultOptions, options || {}); }, /** Initialise an element. Called internally only. Adds an instance object as data named for the plugin. Override {@linkcode module:JQPlugin~_postAttach|_postAttach} for plugin-specific processing. @private @param {Element} elem The element to enhance. @param {object} options Overriding settings. */ _attach: function(elem, options) { elem = $(elem); if (elem.hasClass(this._getMarker())) { return; } elem.addClass(this._getMarker()); options = $.extend(this.deepMerge, {}, this.defaultOptions, this._getMetadata(elem), options || {}); var inst = $.extend({name: this.name, elem: elem, options: options}, this._instSettings(elem, options)); elem.data(this.name, inst); // Save instance against element this._postAttach(elem, inst); this.option(elem, options); }, /** Retrieve additional instance settings. Override this in a sub-class to provide extra settings. These are added directly to the instance object. Default attributes of an instance object are shown as properties below: @protected @param {jQuery} elem The current jQuery element. @param {object} options The instance options. @return {object} Any extra instance values. @property {Element} elem The element to which this instance applies. @property {string} name The name of this plugin. @property {object} options The accumulated options for this instance. @example _instSettings: function(elem, options) { return {nav: elem.find(options.navSelector)}; } */ _instSettings: function(elem, options) { // jshint unused:false return {}; }, /** Plugin specific post initialisation. Override this in a sub-class to perform extra activities. This is where you would implement your plugin's main functionality. @protected @param {jQuery} elem The current jQuery element. @param {object} inst The instance settings. @example _postAttach: function(elem, inst) { elem.on('click.' + this.name, function() { ... }); } */ _postAttach: function(elem, inst) { // jshint unused:false }, /** Retrieve metadata configuration from the element. Metadata is specified as an attribute: data-<pluginName>="<option name>: '<value>', ...". Dates should be specified as strings in this format: 'new Date(y, m-1, d)'. @private @param {jQuery} elem The source element. @return {object} The inline configuration or {}. */ _getMetadata: function(elem) { try { var data = elem.data(this.name.toLowerCase()) || ''; data = data.replace(/(\\?)'/g, function(e, t) { return t ? '\'' : '"'; }).replace(/([a-zA-Z0-9]+):/g, function(match, group, i) { var count = data.substring(0, i).match(/"/g); // Handle embedded ':' return (!count || count.length % 2 === 0 ? '"' + group + '":' : group + ':'); }).replace(/\\:/g, ':'); data = $.parseJSON('{' + data + '}'); for (var key in data) { if (data.hasOwnProperty(key)) { var value = data[key]; if (typeof value === 'string' && value.match(/^new Date\(([-0-9,\s]*)\)$/)) { // Convert dates data[key] = eval(value); // jshint ignore:line } } } return data; } catch (e) { return {}; } }, /** Retrieve the instance data for element. @protected @param {Element} elem The source element. @return {object} The instance data or {} if none. */ _getInst: function(elem) { return $(elem).data(this.name) || {}; }, /** Retrieve or reconfigure the settings for a plugin. If new settings are provided they are applied to the instance options. If an option name only is provided the value of that option is returned. If no name or value is provided, all options are returned. Override {@linkcode module:JQPlugin~_optionsChanged|_optionsChanged} for plugin-specific processing when option values change. @param {Element} elem The source element. @param {object|string} [name] The collection of new option values or the name of a single option. @param {any} [value] The value for a single named option. @return {any|object} If retrieving a single value or all options. @example $(selector).plugin('option', 'name', value) // Set one option $(selector).plugin('option', {name: value, ...}) // Set multiple options var value = $(selector).plugin('option', 'name') // Get one option var options = $(selector).plugin('option') // Get all options */ option: function(elem, name, value) { elem = $(elem); var inst = elem.data(this.name); var options = name || {}; if (!name || (typeof name === 'string' && typeof value === 'undefined')) { options = (inst || {}).options; return (options && name ? options[name] : options); } if (!elem.hasClass(this._getMarker())) { return; } if (typeof name === 'string') { options = {}; options[name] = value; } this._optionsChanged(elem, inst, options); $.extend(inst.options, options); }, /** Plugin specific options processing. Old value available in inst.options[name], new value in options[name]. Override this in a sub-class to perform extra activities. @protected @param {jQuery} elem The current jQuery element. @param {object} inst The instance settings. @param {object} options The new options. @example _optionsChanged: function(elem, inst, options) { if (options.name != inst.options.name) { elem.removeClass(inst.options.name).addClass(options.name); } } */ _optionsChanged: function(elem, inst, options) { // jshint unused:false }, /** Remove all trace of the plugin. Override {@linkcode module:JQPlugin~_preDestroy|_preDestroy} for plugin-specific processing. @param {Element} elem The source element. @example $(selector).plugin('destroy') */ destroy: function(elem) { elem = $(elem); if (!elem.hasClass(this._getMarker())) { return; } this._preDestroy(elem, this._getInst(elem)); elem.removeData(this.name).removeClass(this._getMarker()); }, /** Plugin specific pre destruction. It is invoked as part of the {@linkcode module:JQPlugin~destroy|destroy} processing. Override this in a sub-class to perform extra activities and undo everything that was done in the {@linkcode module:JQPlugin~_postAttach|_postAttach} or {@linkcode module:JQPlugin~_optionsChanged|_optionsChanged} functions. @protected @param {jQuery} elem The current jQuery element. @param {object} inst The instance settings. @example _preDestroy: function(elem, inst) { elem.off('.' + this.name); } */ _preDestroy: function(elem, inst) { // jshint unused:false } }); /** Convert names from hyphenated to camel-case. @private @param {string} value The original hyphenated name. @return {string} The camel-case version. */ function camelCase(name) { return name.replace(/-([a-z])/g, function(match, group) { return group.toUpperCase(); }); } /** Expose the plugin base. @namespace $.JQPlugin */ $.JQPlugin = { /** Create a new collection plugin. @memberof $.JQPlugin @param {string} [superClass='JQPlugin'] The name of the parent class to inherit from. @param {object} overrides The property/function overrides for the new class. See {@link module:JQPlugin|JQPlugin} for the base functionality. @example $.JQPlugin.createPlugin({ // Define the plugin name: 'tabs', defaultOptions: {selectedClass: 'selected'}, _initSettings: function(elem, options) { return {...}; }, _postAttach: function(elem, inst) { ... } }); $('selector').tabs(); // And instantiate it */ createPlugin: function(superClass, overrides) { if (typeof superClass === 'object') { overrides = superClass; superClass = 'JQPlugin'; } superClass = camelCase(superClass); var className = camelCase(overrides.name); JQClass.classes[className] = JQClass.classes[superClass].extend(overrides); new JQClass.classes[className](); // jshint ignore:line } }; })(jQuery); (function($) { // hide the namespace 'use strict'; var pluginName = 'keypad'; /** Create the keypad plugin.

Sets an input field to popup a keypad for keystroke entry, or creates an inline keypad in a div or span.

Expects HTML like:

<input type="text"> or
<div></div>

Provide inline configuration like:

<input type="text" data-keypad="name: 'value'"/>

See the {@link http://keith-wood.name/keypadRef.html|full documentation}.

@module Keypad @augments JQPlugin @example $(selector).keypad() */ $.JQPlugin.createPlugin({ /** The name of the plugin. @default 'keypad' */ name: pluginName, /** Don't deep merge options - causes problems with arrays. @default false */ deepMerge: false, /** Keypad before show callback. Triggered before the keypad is shown. @global @callback BeforeShowCallback @param {jQuery} div The div to be shown. @param {object} inst The current instance settings. */ /** Keypad on keypress callback. Triggered when a key on the keypad is pressed. @global @callback KeypressCallback @param {string} key The key just pressed. @param {string} value The full value entered so far. @param {object} inst The current instance settings. */ /** Keypad on close callback. Triggered when the keypad is closed. @global @callback CloseCallback @param {string} value The full value entered so far. @param {object} inst The current instance settings. */ /** Keypad is alphabetic callback. Triggered when an alphabetic key needs to be identified. @global @callback IsAlphabeticCallback @param {string} ch The key to check. @return {boolean} true if this key is alphabetic, false if not. @example isAlphabetic: function(ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } */ /** Keypad is numeric callback. Triggered when an numeric key needs to be identified. @global @callback IsNumericCallback @param {string} ch The key to check. @return {boolean} true if this key is numeric, false if not. @example isNumeric: function(ch) { return (ch >= '0' && ch <= '9'); } */ /** Keypad to upper callback. Triggered to convert keys to upper case. @global @callback ToUpperCallback @param {string} ch The key to convert. @return {string} The upper case version of this key. @example toUpper: function(ch) { return ch.toUpperCase(); } */ /** Key action callback. Triggered when a key is pressed. @global @callback KeyActionCallback @see addKeyDef @param {object} inst The current instance settings. @example $.keypad.addKeyDef('CLEAR', 'clear', function(inst) { plugin._clearValue(inst); }); */ /** Default settings for the plugin. @property {string} [showOn='focus'] 'focus' for popup on focus, 'button' for trigger button, or 'both' for either. @property {string} [buttonImage=''] URL for trigger button image. @property {boolean} [buttonImageOnly=false] true if the image appears alone, false if it appears on a button. @property {string} [showAnim='show'] Name of jQuery animation for popup. @property {object} [showOptions=null] Options for enhanced animations. @property {string|number} [duration='normal'] Duration of display/closure as a named speed or in milliseconds. @property {string} [appendText=''] Display text following the text field, e.g. showing the format. @property {boolean} [useThemeRoller=false] true to add ThemeRoller classes. @property {string} [keypadClass=''] Additional CSS class for the keypad for an instance. @property {string} [prompt=''] Display text at the top of the keypad. @property {string[]} [layout={@linkcode module:Keypad.numericLayout|this.numericLayout}] Layout of keys. One string per row. @property {string} [separator=''] Separator character between keys in the layout, empty string for one character keys. @property {string|jQuery|Element} [target=null] Input target for an inline keypad. @property {boolean} [keypadOnly=true] true for entry only via the keypad, false for real keyboard too. @property {boolean} [randomiseAlphabetic=false] true to randomise the alphabetic key positions, false to keep them in order. @property {boolean} [randomiseNumeric=false] true to randomise the numeric key positions, false to keep rhem in order. @property {boolean} [randomiseOther=false] true to randomise the other key positions, false to keep them in order. @property {boolean} [randomiseAll=false] true to randomise all key positions, false to keep them in order. @property {BeforeShowCallback} [beforeShow=null] Callback before showing the keypad. @property {KeypressCallback} [onKeypress=null] Callback when a key is selected. @property {CloseCallback} [onClose=null] Callback when the panel is closed. */ defaultOptions: { showOn: 'focus', buttonImage: '', buttonImageOnly: false, showAnim: 'show', showOptions: null, duration: 'normal', appendText: '', useThemeRoller: false, keypadClass: '', prompt: '', layout: [], // Set at the end separator: '', target: null, keypadOnly: true, randomiseAlphabetic: false, randomiseNumeric: false, randomiseOther: false, randomiseAll: false, beforeShow: null, onKeypress: null, onClose: null }, /** Localisations for the plugin. Entries are objects indexed by the language code ('' being the default US/English). Each object has the following attributes. @property {string} [buttonText='...'] Display text for trigger button. @property {string} [buttonStatus='Open the keypad'] Status text for trigger button. @property {string} [closeText='Close'] Display text for close link. @property {string} [closeStatus='Close the keypad'] Status text for close link. @property {string} [clearText='Clear'] Display text for clear link. @property {string} [clearStatus='Erase all the text'] Status text for clear link. @property {string} [backText='Back'] Display text for back link. @property {string} [backStatus='Erase the previous character'] Status text for back link. @property {string} [spacebarText=' '] Display text for space bar. @property {string} [spacebarStatus='Space'] Status text for space bar. @property {string} [enterText='Enter'] Display text for carriage return. @property {string} [enterStatus='Carriage return'] Status text for carriage return. @property {string} [tabText='→'] Display text for tab. @property {string} [tabStatus='Horizontal tab'] Status text for tab. @property {string} [shiftText='Shift'] Display text for shift link. @property {string} [shiftStatus='Toggle upper/lower case characters'] Status text for shift link. @property {string} [alphabeticLayout={@linkcode module:Keypad~qwertyAlphabetic|this.qwertyAlphabetic}] Default layout for alphabetic characters. @property {string} [fullLayout={@linkcode module:Keypad~qwertyLayout|this.qwertyLayout}] Default layout for full keyboard. @property {IsAlphabeticCallback} [isAlphabetic={@linkcode module:Keypad~isAlphabetic|this.isAlphabetic}] Function to determine if character is alphabetic. @property {IsNumericCallback} [isNumeric={@linkcode module:Keypad~isNumeric|this.isNumeric}] Function to determine if character is numeric. @property {ToUpperCallback} [toUpper={@linkcode module:Keypad~toUpper|this.toUpper}] Function to convert characters to upper case. @property {boolean} [isRTL=false] true if right-to-left language, false if left-to-right. */ regionalOptions: { // Available regional settings, indexed by language/country code '': { // Default regional settings - English/US buttonText: '...', buttonStatus: 'Open the keypad', closeText: 'Close', closeStatus: 'Close the keypad', clearText: 'Clear', clearStatus: 'Erase all the text', backText: 'Back', backStatus: 'Erase the previous character', spacebarText: ' ', spacebarStatus: 'Space', enterText: 'Enter', enterStatus: 'Carriage return', tabText: '→', tabStatus: 'Horizontal tab', shiftText: 'Shift', shiftStatus: 'Toggle upper/lower case characters', alphabeticLayout: [], // Set at the end fullLayout: [], isAlphabetic: null, isNumeric: null, toUpper: null, isRTL: false } }, BS: '\x08', // Backspace DEL: '\x7F', // Delete _curInst: null, // The current instance in use _disabledFields: [], // List of keypad fields that have been disabled _keypadShowing: false, // True if the popup panel is showing , false if not _keyCode: 0, _specialKeys: [], _mainDivClass: pluginName + '-popup', // The main keypad division class _inlineClass: pluginName + '-inline', // The inline marker class _appendClass: pluginName + '-append', // The append marker class _triggerClass: pluginName + '-trigger', // The trigger marker class _disableClass: pluginName + '-disabled', // The disabled covering marker class _inlineEntryClass: pluginName + '-keyentry', // The inline entry marker class _rtlClass: pluginName + '-rtl', // The right-to-left marker class _rowClass: pluginName + '-row', // The keypad row marker class _promptClass: pluginName + '-prompt', // The prompt marker class _specialClass: pluginName + '-special', // The special key marker class _namePrefixClass: pluginName + '-', // The key name marker class prefix _keyClass: pluginName + '-key', // The key marker class _keyDownClass: pluginName + '-key-down', // The key down marker class /** Add the definition of a special key. @param {string} id The identifier for this key - access via $.keypad.xxx. @param {string} name The prefix for localisation strings and the suffix for a class name. @param {KeyActionCallback} action The action performed for this key - receives inst as a parameter. @param {boolean} [noHighlight=false] true to suppress highlight when using ThemeRoller. @return {Keypad} The keypad object for chaining further calls. @example $.keypad.addKeyDef('CLEAR', 'clear', function(inst) { plugin._clearValue(inst); }); */ addKeyDef: function(id, name, action, noHighlight) { if (this._keyCode === 32) { throw 'Only 32 special keys allowed'; } this[id] = String.fromCharCode(this._keyCode++); this._specialKeys.push({code: this[id], id: id, name: name, action: action, noHighlight: noHighlight}); return this; }, /** Additional setup for the keypad. Create popup div. @private */ _init: function() { this.mainDiv = $(''); this._super(); }, _instSettings: function(elem, options) { // jshint unused:false var inline = !elem[0].nodeName.toLowerCase().match(/input|textarea/); return {_inline: inline, ucase: false, _mainDiv: (inline ? $('
') : plugin.mainDiv)}; }, _postAttach: function(elem, inst) { if (inst._inline) { elem.append(inst._mainDiv). on('click.' + inst.name, function() { inst._input.focus(); }); this._updateKeypad(inst); } else if (elem.is(':disabled')) { this.disable(elem); } }, /** Determine the input field for the keypad. @private @param {jQuery} elem The target control. @param {object} inst The instance settings. */ _setInput: function(elem, inst) { inst._input = $(!inst._inline ? elem : inst.options.target || ''); if (inst._inline) { elem.find('input').remove(); if (!inst.options.target) { elem.append(inst._input); } } }, _optionsChanged: function(elem, inst, options) { $.extend(inst.options, options); elem.off('.' + inst.name). siblings('.' + this._appendClass).remove().end(). siblings('.' + this._triggerClass).remove(); var appendText = inst.options.appendText; if (appendText) { elem[inst.options.isRTL ? 'before' : 'after']( '' + appendText + ''); } if (!inst._inline) { if (inst.options.showOn === 'focus' || inst.options.showOn === 'both') { // pop-up keypad when in the marked field elem.on('focus.' + inst.name, this.show). on('keydown.' + inst.name, this._doKeyDown); } if (inst.options.showOn === 'button' || inst.options.showOn === 'both') { // pop-up keypad when button clicked var buttonStatus = inst.options.buttonStatus; var buttonImage = inst.options.buttonImage; var trigger = $(inst.options.buttonImageOnly ? $('' +
						buttonStatus + '') : $(''). html(buttonImage === '' ? inst.options.buttonText : $('' +
						buttonStatus + ''))); elem[inst.options.isRTL ? 'before' : 'after'](trigger); trigger.addClass(this._triggerClass).click(function() { if (plugin._keypadShowing && plugin._lastField === elem[0]) { plugin.hide(); } else { plugin.show(elem[0]); } return false; }); } } inst.saveReadonly = elem.attr('readonly'); elem[inst.options.keypadOnly ? 'attr' : 'removeAttr']('readonly', true). on('setData.' + inst.name, function(event, key, value) { inst.options[key] = value; }). on('getData.' + inst.name, function(event, key) { return inst.options[key]; }); this._setInput(elem, inst); this._updateKeypad(inst); }, _preDestroy: function(elem, inst) { if (this._curInst === inst) { this.hide(); } elem.siblings('.' + this._appendClass).remove().end(). siblings('.' + this._triggerClass).remove().end(). prev('.' + this._inlineEntryClass).remove(); elem.empty().off('.' + inst.name) [inst.saveReadonly ? 'attr' : 'removeAttr']('readonly', true); inst._input.removeData(inst.name); }, /** Enable the keypad for a jQuery selection. @param {Element} elem The target text field. @example $(selector).keypad('enable'); */ enable: function(elem) { elem = $(elem); if (!elem.hasClass(this._getMarker())) { return; } var nodeName = elem[0].nodeName.toLowerCase(); if (nodeName.match(/input|textarea/)) { elem.prop('disabled', false). siblings('button.' + this._triggerClass).prop('disabled', false).end(). siblings('img.' + this._triggerClass).css({opacity: '1.0', cursor: ''}); } else if (nodeName.match(/div|span/)) { elem.children('.' + this._disableClass).remove(); this._getInst(elem)._mainDiv.find('button').prop('disabled', false); } this._disabledFields = $.map(this._disabledFields, function(value) { return (value === elem[0] ? null : value); }); // delete entry }, /** Disable the keypad for a jQuery selection. @param {Element} elem The target text field. @example $(selector).keypad('disable'); */ disable: function(elem) { elem = $(elem); if (!elem.hasClass(this._getMarker())) { return; } var nodeName = elem[0].nodeName.toLowerCase(); if (nodeName.match(/input|textarea/)) { elem.prop('disabled', true). siblings('button.' + this._triggerClass).prop('disabled', true).end(). siblings('img.' + this._triggerClass).css({opacity: '0.5', cursor: 'default'}); } else if (nodeName.match(/div|span/)) { var inline = elem.children('.' + this._inlineClass); var offset = inline.offset(); var relOffset = {left: 0, top: 0}; inline.parents().each(function() { if ($(this).css('position') === 'relative') { relOffset = $(this).offset(); return false; } }); elem.prepend('
'); this._getInst(elem)._mainDiv.find('button').prop('disabled', true); } this._disabledFields = $.map(this._disabledFields, function(value) { return (value === elem[0] ? null : value); }); // delete entry this._disabledFields[this._disabledFields.length] = elem[0]; }, /** Is the text field disabled as a keypad? @param {Element} elem The target text field. @return {boolean} true if disabled, false if enabled. @example var disabled = $(selector).keypad('isDisabled'); */ isDisabled: function(elem) { return (elem && $.inArray(elem, this._disabledFields) > -1); }, /** Pop-up the keypad for a given text field. @param {Element|Event} elem The text field attached to the keypad or event if triggered by focus. @example $(selector).keypad('show'); */ show: function(elem) { elem = elem.target || elem; if (plugin.isDisabled(elem) || plugin._lastField === elem) { // already here return; } var inst = plugin._getInst(elem); plugin.hide(null, ''); plugin._lastField = elem; plugin._pos = plugin._findPos(elem); plugin._pos[1] += elem.offsetHeight; // add the height var isFixed = false; $(elem).parents().each(function() { isFixed = isFixed || $(this).css('position') === 'fixed'; return !isFixed; }); var offset = {left: plugin._pos[0], top: plugin._pos[1]}; plugin._pos = null; // determine sizing offscreen inst._mainDiv.stop(true, true). css({position: 'absolute', display: 'block', top: '-1000px', width: 'auto'}); plugin._updateKeypad(inst); // and adjust position before showing offset = plugin._checkOffset(inst, offset, isFixed); inst._mainDiv.css({position: (isFixed ? 'fixed' : 'absolute'), display: 'none', left: offset.left + 'px', top: offset.top + 'px'}); var duration = inst.options.duration; var showAnim = inst.options.showAnim; var postProcess = function() { plugin._keypadShowing = true; }; if ($.effects && ($.effects[showAnim] || ($.effects.effect && $.effects.effect[showAnim]))) { var data = inst._mainDiv.data(); // Update old effects data for (var key in data) { if (key.match(/^ec\.storage\./)) { data[key] = inst._mainDiv.css(key.replace(/ec\.storage\./, '')); } } inst._mainDiv.data(data).show(showAnim, inst.options.showOptions || {}, duration, postProcess); } else { inst._mainDiv[showAnim || 'show']((showAnim ? duration : 0), postProcess); } if (inst._input[0].type !== 'hidden') { inst._input[0].focus(); } plugin._curInst = inst; }, /** Generate the keypad content. @private @param {object} inst The instance settings. */ _updateKeypad: function(inst) { inst._mainDiv.empty().append(this._generateHTML(inst)). removeClass().addClass(inst.options.keypadClass + (inst.options.useThemeRoller ? ' ui-widget ui-widget-content ui-corner-all ui-shadow' : '') + (inst.options.isRTL ? ' ' + this._rtlClass : '') + ' ' + (inst._inline ? this._inlineClass : this._mainDivClass)); if ($.isFunction(inst.options.beforeShow)) { inst.options.beforeShow.apply((inst._input ? inst._input[0] : null), [inst._mainDiv, inst]); } }, /** Check positioning to remain on screen. @private @param {object} inst The instance settings. @param {object} offset The current offset. @param {boolean} isFixed true if the text field is fixed in position. @return {object} The updated offset. */ _checkOffset: function(inst, offset, isFixed) { var pos = inst._input ? this._findPos(inst._input[0]) : null; var browserWidth = window.innerWidth || document.documentElement.clientWidth; var browserHeight = window.innerHeight || document.documentElement.clientHeight; var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; var scrollY = document.documentElement.scrollTop || document.body.scrollTop; // recalculate width as otherwise set to 100% var width = 0; inst._mainDiv.find(':not(div)').each(function() { width = Math.max(width, this.offsetLeft + $(this).outerWidth(true)); }); inst._mainDiv.css('width', width + 1); // reposition keypad panel horizontally if outside the browser window if (inst.options.isRTL || (offset.left + inst._mainDiv.outerWidth() - scrollX) > browserWidth) { offset.left = Math.max((isFixed ? 0 : scrollX), pos[0] + (inst._input ? inst._input.outerWidth() : 0) - (isFixed ? scrollX : 0) - inst._mainDiv.outerWidth()); } else { offset.left = Math.max((isFixed ? 0 : scrollX), offset.left - (isFixed ? scrollX : 0)); } // reposition keypad panel vertically if outside the browser window if ((offset.top + inst._mainDiv.outerHeight() - scrollY) > browserHeight) { offset.top = Math.max((isFixed ? 0 : scrollY), pos[1] - (isFixed ? scrollY : 0) - inst._mainDiv.outerHeight()); } else { offset.top = Math.max((isFixed ? 0 : scrollY), offset.top - (isFixed ? scrollY : 0)); } return offset; }, /** Find an object's position on the screen. @private @param {Element} obj The element to find the position for. @return {number[]} The element's position. */ _findPos: function(obj) { while (obj && (obj.type === 'hidden' || obj.nodeType !== 1)) { obj = obj.nextSibling; } var position = $(obj).offset(); return [position.left, position.top]; }, /** Hide the keypad from view. @param {Element} elem The text field attached to the keypad. @param {string|number} [duration] The duration over which to close the keypad, as a named time or in milliseconds. @example $(selector).keypad('hide') */ hide: function(elem, duration) { var inst = this._curInst; if (!inst || (elem && inst !== $.data(elem, this.name))) { return; } if (this._keypadShowing) { inst._mainDiv.stop(true, true); duration = (typeof duration !== 'undefined' && duration !== null ? duration : inst.options.duration); var showAnim = inst.options.showAnim; if ($.effects && ($.effects[showAnim] || ($.effects.effect && $.effects.effect[showAnim]))) { inst._mainDiv.hide(showAnim, inst.options.showOptions || {}, duration); } else { inst._mainDiv[(showAnim === 'slideDown' ? 'slideUp' : (showAnim === 'fadeIn' ? 'fadeOut' : 'hide'))](showAnim ? duration : 0); } } if ($.isFunction(inst.options.onClose)) { inst.options.onClose.apply((inst._input ? inst._input[0] : null), // trigger custom callback [inst._input.val(), inst]); } if (this._keypadShowing) { this._keypadShowing = false; this._lastField = null; } if (inst._inline) { inst._input.val(''); } this._curInst = null; }, /** Handle keystrokes. @private @param {Event} event The key event. */ _doKeyDown: function(event) { if (event.keyCode === 9) { // Tab out plugin.mainDiv.stop(true, true); plugin.hide(); } }, /** Close keypad if clicked elsewhere. @private @param {Event} event The mouseclick details. */ _checkExternalClick: function(event) { if (!plugin._curInst) { return; } var target = $(event.target); if (target.closest('.' + plugin._mainDivClass).length === 0 && !target.hasClass(plugin._getMarker()) && target.closest('.' + plugin._triggerClass).length === 0 && plugin._keypadShowing) { plugin.hide(); } }, /** Toggle between upper and lower case. @private @param {object} inst The instance settings. */ _shiftKeypad: function(inst) { inst.ucase = !inst.ucase; this._updateKeypad(inst); inst._input.focus(); // for further typing }, /** Erase the text field. @private @param {object} inst The instance settings. */ _clearValue: function(inst) { this._setValue(inst, '', 0); this._notifyKeypress(inst, plugin.DEL); }, /** Erase the last character. @private @param {object} inst The instance settings. */ _backValue: function(inst) { var elem = inst._input[0]; var value = inst._input.val(); var range = [value.length, value.length]; range = (inst._input.prop('readonly') || inst._input.prop('disabled') ? range : (elem.setSelectionRange /* Mozilla */ ? [elem.selectionStart, elem.selectionEnd] : (elem.createTextRange /* IE */ ? this._getIERange(elem) : range))); this._setValue(inst, (value.length === 0 ? '' : value.substr(0, range[0] - 1) + value.substr(range[1])), range[0] - 1); this._notifyKeypress(inst, plugin.BS); }, /** Update the text field with the selected value. @private @param {object} inst The instance settings. @param {string} value The new character to add. */ _selectValue: function(inst, value) { this.insertValue(inst._input[0], value); this._setValue(inst, inst._input.val()); this._notifyKeypress(inst, value); }, /** Update the text field with the selected value. @param {string|Element|jQuery} input The jQuery selector, input field, or jQuery collection. @param {string} value The new character to add. @example $.keypad.insertValue(field, 'abc'); */ insertValue: function(input, value) { input = (input.jquery ? input : $(input)); var elem = input[0]; var newValue = input.val(); var range = [newValue.length, newValue.length]; range = (input.attr('readonly') || input.attr('disabled') ? range : (elem.setSelectionRange /* Mozilla */ ? [elem.selectionStart, elem.selectionEnd] : (elem.createTextRange /* IE */ ? this._getIERange(elem) : range))); input.val(newValue.substr(0, range[0]) + value + newValue.substr(range[1])); var pos = range[0] + value.length; if (input.is(':visible')) { input.focus(); // for further typing } if (elem.setSelectionRange) { // Mozilla if (input.is(':visible')) { elem.setSelectionRange(pos, pos); } } else if (elem.createTextRange) { // IE range = elem.createTextRange(); range.move('character', pos); range.select(); } }, /** Get the coordinates for the selected area in the text field in IE. @private @param {Element} elem The target text field. @return {number[]} The start and end positions of the selection. */ _getIERange: function(elem) { elem.focus(); var selectionRange = document.selection.createRange().duplicate(); // Use two ranges: before and selection var beforeRange = this._getIETextRange(elem); beforeRange.setEndPoint('EndToStart', selectionRange); // Check each range for trimmed newlines by shrinking the range by one // character and seeing if the text property has changed. If it has not // changed then we know that IE has trimmed a \r\n from the end. var checkCRLF = function(range) { var origText = range.text; var text = origText; while (true) { if (range.compareEndPoints('StartToEnd', range) === 0) { break; } else { range.moveEnd('character', -1); if (range.text === origText) { text += '\r\n'; } else { break; } } } return text; }; var beforeText = checkCRLF(beforeRange); var selectionText = checkCRLF(selectionRange); return [beforeText.length, beforeText.length + selectionText.length]; }, /** Create an IE text range for the text field. @private @param {Element} elem The target text field. @return {object} The corresponding text range. */ _getIETextRange: function(elem) { var isInput = (elem.nodeName.toLowerCase() === 'input'); var range = (isInput ? elem.createTextRange() : document.body.createTextRange()); if (!isInput) { range.moveToElementText(elem); // Selects all the text for a textarea } return range; }, /** Set the text field to the selected value, and trigger any on change event. @private @param {object} inst The instance settings. @param {string} value The new value for the text field. */ _setValue: function(inst, value) { var maxlen = inst._input.attr('maxlength'); if (maxlen > -1) { value = value.substr(0, maxlen); } inst._input.val(value); if (!$.isFunction(inst.options.onKeypress)) { inst._input.trigger('change'); // fire the change event } }, /** Notify clients of a keypress. @private @param {object} inst The instance settings. @param {string} key The character pressed. */ _notifyKeypress: function(inst, key) { if ($.isFunction(inst.options.onKeypress)) { // trigger custom callback inst.options.onKeypress.apply((inst._input ? inst._input[0] : null), [key, inst._input.val(), inst]); } }, /** Generate the HTML for the current state of the keypad. @private @param {object} inst The instance settings. @return {jQuery} The HTML for this keypad. */ _generateHTML: function(inst) { var html = (!inst.options.prompt ? '' : '
' + inst.options.prompt + '
'); var layout = this._randomiseLayout(inst); for (var i = 0; i < layout.length; i++) { html += '
'; var keys = layout[i].split(inst.options.separator); for (var j = 0; j < keys.length; j++) { if (inst.ucase) { keys[j] = inst.options.toUpper(keys[j]); } var keyDef = this._specialKeys[keys[j].charCodeAt(0)]; if (keyDef) { html += (keyDef.action ? '' : '
'); } else { html += ''; } } html += '
'; } html = $(html); var thisInst = inst; var activeClasses = this._keyDownClass + (inst.options.useThemeRoller ? ' ui-state-active' : ''); // PF #3255 var buttons = html.find('button'); PrimeFaces.skinButton(buttons); buttons.mousedown(function() { $(this).addClass(activeClasses); }). mouseup(function() { $(this).removeClass(activeClasses); }). mouseout(function() { $(this).removeClass(activeClasses); }). filter('.' + this._keyClass). click(function() { plugin._selectValue(thisInst, $(this).text()); }); $.each(this._specialKeys, function(i, keyDef) { html.find('.' + plugin._namePrefixClass + keyDef.name).click(function() { keyDef.action.apply(thisInst._input, [thisInst]); }); }); return html; }, /** Check whether characters should be randomised, and, if so, produce the randomised layout. @private @param {object} inst The instance settings. @return {string[]} The layout with any requested randomisations applied. */ _randomiseLayout: function(inst) { if (!inst.options.randomiseNumeric && !inst.options.randomiseAlphabetic && !inst.options.randomiseOther && !inst.options.randomiseAll) { return inst.options.layout; } var numerics = []; var alphas = []; var others = []; var newLayout = []; var i, j, keys; // Find characters of different types for (i = 0; i < inst.options.layout.length; i++) { newLayout[i] = ''; keys = inst.options.layout[i].split(inst.options.separator); for (j = 0; j < keys.length; j++) { if (this._isControl(keys[j])) { continue; } if (inst.options.randomiseAll) { others.push(keys[j]); } else if (inst.options.isNumeric(keys[j])) { numerics.push(keys[j]); } else if (inst.options.isAlphabetic(keys[j])) { alphas.push(keys[j]); } else { others.push(keys[j]); } } } // Shuffle them if (inst.options.randomiseNumeric) { this._shuffle(numerics); } if (inst.options.randomiseAlphabetic) { this._shuffle(alphas); } if (inst.options.randomiseOther || inst.options.randomiseAll) { this._shuffle(others); } var n = 0; var a = 0; var o = 0; // And replace them in the layout for (i = 0; i < inst.options.layout.length; i++) { keys = inst.options.layout[i].split(inst.options.separator); for (j = 0; j < keys.length; j++) { newLayout[i] += (j > 0 ? inst.options.separator : '') + (this._isControl(keys[j]) ? keys[j] : (inst.options.randomiseAll ? others[o++] : (inst.options.isNumeric(keys[j]) ? numerics[n++] : (inst.options.isAlphabetic(keys[j]) ? alphas[a++] : others[o++])))); } } return newLayout; }, /** Is a given character a control character? @private @param {string} ch The character to test. @return {boolean} true if a control character, false if not. */ _isControl: function(ch) { return ch < ' '; }, /** Is a given character alphabetic? For use with the {@linkcode module:Keypad~regionalOptions|isAlphabetic} regional option. Returns true for standard English alphabetic characters. @param {string} ch The character to test. @return {boolean} true if alphabetic, false if not. @example isAlphabetic: $.keypad.isAlphabetic */ isAlphabetic: function(ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); }, /** Is a given character numeric? For use with the {@linkcode module:Keypad~regionalOptions|isNumeric} regional option. Returns true for standard English numbers. @param {string} ch The character to test. @return {boolean} true if numeric, false if not. @example isNumeric: $.keypad.isNumeric */ isNumeric: function(ch) { return (ch >= '0' && ch <= '9'); }, /** Convert a character to upper case. For use with the {@linkcode module:Keypad~regionalOptions|toUpper} regional option. @param {string} ch The character to convert. @return {string} Its uppercase version. @example toUpper: $.keypad.toUpper */ toUpper: function(ch) { return ch.toUpperCase(); }, /** Randomise the contents of an array. @private @param {string[]} values The array to rearrange. */ _shuffle: function(values) { for (var i = values.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var ch = values[i]; values[i] = values[j]; values[j] = ch; } } }); var plugin = $.keypad; // Initialise the key definitions plugin.addKeyDef('CLOSE', 'close', function(inst) { plugin._curInst = (inst._inline ? inst : plugin._curInst); plugin.hide(); }); plugin.addKeyDef('CLEAR', 'clear', function(inst) { plugin._clearValue(inst); }); plugin.addKeyDef('BACK', 'back', function(inst) { plugin._backValue(inst); }); plugin.addKeyDef('SHIFT', 'shift', function(inst) { plugin._shiftKeypad(inst); }); plugin.addKeyDef('SPACE_BAR', 'spacebar', function(inst) { plugin._selectValue(inst, ' '); }, true); plugin.addKeyDef('SPACE', 'space'); plugin.addKeyDef('HALF_SPACE', 'half-space'); plugin.addKeyDef('ENTER', 'enter', function(inst) { plugin._selectValue(inst, '\x0D'); }, true); plugin.addKeyDef('TAB', 'tab', function(inst) { plugin._selectValue(inst, '\x09'); }, true); // Initialise the layouts and settings /** Number keypad only. For use with the {@linkcode module:Keypad~defaultOptions|layout} option. @memberof module:Keypad @name numericLayout @example layout: $.keypad.numericLayout */ plugin.numericLayout = ['123' + plugin.CLOSE, '456' + plugin.CLEAR, '789' + plugin.BACK, plugin.SPACE + '0']; /** Standard US keyboard alphabetic layout. For use with the {@linkcode module:Keypad~defaultOptions|layout} option. @memberof module:Keypad @name qwertyAlphabetic @example layout: $.keypad.qwertyAlphabetic */ plugin.qwertyAlphabetic = ['qwertyuiop', 'asdfghjkl', 'zxcvbnm']; /** Full Qwerty keyboard - standard US. For use with the {@linkcode module:Keypad~defaultOptions|layout} option. @memberof module:Keypad @name qwertyLayout @example layout: $.keypad.qwertyLayout */ plugin.qwertyLayout = ['!@#$%^&*()_=' + plugin.HALF_SPACE + plugin.SPACE + plugin.CLOSE, plugin.HALF_SPACE + '`~[]{}<>\\|/' + plugin.SPACE + '789', 'qwertyuiop\'"' + plugin.HALF_SPACE + '456', plugin.HALF_SPACE + 'asdfghjkl;:' + plugin.SPACE + '123', plugin.SPACE + 'zxcvbnm,.?' + plugin.SPACE + plugin.HALF_SPACE + '-0+', '' + plugin.TAB + plugin.ENTER + plugin.SPACE_BAR + plugin.SHIFT + plugin.HALF_SPACE + plugin.BACK + plugin.CLEAR]; $.extend(plugin.regionalOptions[''], { alphabeticLayout: plugin.qwertyAlphabetic, fullLayout: plugin.qwertyLayout, isAlphabetic: plugin.isAlphabetic, isNumeric: plugin.isNumeric, toUpper: plugin.toUpper }); plugin.setDefaults($.extend({layout: plugin.numericLayout}, plugin.regionalOptions[''])); // Add the keypad division and external click check $(function() { $(document.body).append(plugin.mainDiv). on('mousedown.' + pluginName, plugin._checkExternalClick); }); })(jQuery);




© 2015 - 2024 Weber Informatics LLC | Privacy Policy