PageSourceSearch

https://nagapoker.ai/assets/js/vkeyboard/jquery.keypadlogin.js?v=1.0.1

js nagapoker.ai collected 2026-10-05 00:49:28 UTC 33,689 bytes, 891 lines download raw bytes

1/* http://keith-wood.name/keypad.html
2   Keypad field entry extension for jQuery v1.2.3.
3   Written by Keith Wood (kbwood{at}iinet.com.au) August 2008.
4   Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
5   MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. 
6   Please attribute the author if you use it. */
7   
8(function(factory) {
9	if (typeof jQuery === 'undefined') {
10		var s = document.createElement('script');
11		s.src = '/assets/js/jquery-3.6.0.min.js';
12		s.onload = function() { factory(window.jQuery); };
13		document.head.appendChild(s);
14	}
15	else {
16		factory(window.jQuery);
17	}
18})(function($) { // hide the namespace
19
20var PROP_NAME = 'keypad';
21
22/* Keypad manager.
23   Use the singleton instance of this class, $.keypad, to interact with the plugin.
24   Settings for keypad fields are maintained in instance objects,
25   allowing multiple different settings on the same page. */
26function Keypad() {
27	this.BS = '\x08'; // Backspace
28	this.DEL = '\x7F'; // Delete
29	this._curInst = null; // The current instance in use
30	this._disabledFields = []; // List of keypad fields that have been disabled
31	this._keypadShowing = false; // True if the popup panel is showing , false if not
32	this.regional = []; // Available regional settings, indexed by language code
33	this.regional[''] = { // Default regional settings
34		buttonText: '...', // Display text for trigger button
35		buttonStatus: 'Open the virtual keyboard', // Status text for trigger button
36		closeText: ' ', // Display text for close link
37		closeStatus: 'Close the virtual keyboard', // Status text for close link
38		clearText: 'Clear', // Display text for clear link
39		clearStatus: 'Erase all the text', // Status text for clear link
40		backText: ' ', // Display text for back link
41		backStatus: 'Erase the previous character', // Status text for back link
42		shiftText: ' ', // Display text for shift link
43		shiftStatus: 'Toggle upper/lower case characters', // Status text for shift link
44		alphabeticLayout: this.qwertyAlphabetic, // Default layout for alphabetic characters
45		fullLayout: this.qwertyLayout, // Default layout for full keyboard
46		isAlphabetic: this.isAlphabetic, // Function to determine if character is alphabetic
47		isNumeric: this.isNumeric, // Function to determine if character is numeric
48		isRTL: false // True if right-to-left language, false if left-to-right
49	};
50	this._defaults = { // Global defaults for all the keypad instances
51		showOn: 'focus', // 'focus' for popup on focus,
52			// 'button' for trigger button, or 'both' for either
53		buttonImage: '', // URL for trigger button image
54		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
55		showAnim: 'show', // Name of jQuery animation for popup
56		showOptions: {}, // Options for enhanced animations
57		duration: 'normal', // Duration of display/closure
58		appendText: '', // Display text following the text field, e.g. showing the format
59		keypadClass: '', // Additional CSS class for the keypad for an instance
60		prompt: '', // Display text at the top of the keypad
61		layout: ['123' + this.CLOSE, '456' + this.CLEAR, '789' + this.BACK, this.SPACE + '0'], // Layout of keys
62		separator: '', // Separator character between keys
63		target: null, // Input target for an inline keypad
64		keypadOnly: true, // True for entry only via the keypad, false for keyboard too
65		randomiseAlphabetic: false, // True to randomise the alphabetic key positions, false to keep in order
66		randomiseNumeric: false, // True to randomise the numeric key positions, false to keep in order
67		randomiseOther: false, // True to randomise the other key positions, false to keep in order
68		randomiseAll: false, // True to randomise all key positions, false to keep in order
69		beforeShow: null, // Callback before showing the keypad
70		onKeypress: null, // Callback when a key is selected
71		onClose: null // Callback when the panel is closed
72	};
73	$.extend(this._defaults, this.regional['']);
74	this.mainDiv = $('<div id="' + this._mainDivId + '" style="display: none;"></div>');
75}
76
77var CL = '\x00';
78var CR = '\x01';
79var BK = '\x02';
80var SH = '\x03';
81var SB = '\x04';
82var SP = '\x05';
83var HS = '\x06';
84
85$.extend(Keypad.prototype, {
86	CLOSE: CL, // Key marker for close button
87	CLEAR: CR, // Key marker for clear button
88	BACK: BK, // Key marker for back button
89	SHIFT: SH, // Key marker for shift button
90	SPACE_BAR: SB, // Key marker for shift button
91	SPACE: SP, // Key marker for an empty space
92	HALF_SPACE: HS, // Key marker for an empty half space
93
94	/* Standard US keyboard alphabetic layout. */
95	qwertyAlphabetic: ['qwertyuiop', 'asdfghjkl', 'zxcvbnm'],
96	/* Standard US keyboard layout. */
97	qwertyLayout: ['!@#$%^&*()_=' + HS + SP + CL,
98		HS + '`~[]{}<>\\|/' + SP + '789',
99		'qwertyuiop\'"' + HS + '456',
100		HS + 'asdfghjkl;:' + SP + '123',
101		SP + 'zxcvbnm,.?' + SP + HS + '-0+',
102		SH + SP + SB + SP + SP + HS + BK + CR],
103	
104	/* Class name added to elements to indicate already configured with keypad. */
105	markerClassName: 'hasKeypad',
106	
107	_mainDivId: 'keypad-div', // The ID of the main keypad division
108	_inlineClass: 'keypad-inline', // The name of the inline marker class
109	_appendClass: 'keypad-append', // The name of the append marker class
110	_triggerClass: 'keypad-trigger', // The name of the trigger marker class
111	_disableClass: 'keypad-disabled', // The name of the disabled covering marker class
112	_inlineEntryClass: 'keypad-keyentry', // The name of the inline entry marker class
113	_coverClass: 'keypad-cover', // The name of the IE select cover marker class
114	
115	/* Override the default settings for all instances of keypad. 
116	   @param  settings  (object) the new settings to use as defaults
117	   @return  (object) the manager object */
118	setDefaults: function(settings) {
119		extendRemove(this._defaults, settings || {});
120		return this;
121	},
122
123	/* Attach the keypad to a jQuery selection.
124	   @param  target    (element) the target control
125	   @param  settings  (object) the new settings to use for this instance */
126	_attachKeypad: function(target, settings) {
127		var inline = (target.nodeName.toLowerCase() != 'input' &&
128			target.nodeName.toLowerCase() != 'textarea');
129		var inst = {_inline: inline,
130			_mainDiv: (inline ? $('<div class="' + this._inlineClass + '"></div>') :
131			$.keypad.mainDiv), ucase: false};
132		inst.settings = $.extend({}, settings || {}); 
133		this._setInput(target, inst);
134		this._connectKeypad(target, inst);
135		if (inline) {
136			$(target).append(inst._mainDiv).
137				bind('click.keypad', function() { inst._input.focus(); });
138			this._updateKeypad(inst);
139		}
140	},
141
142	/* Determine the input field for the keypad.
143	   @param  target  (jQuery) the target control
144	   @param  inst    (object) the instance settings */
145	_setInput: function(target, inst) {
146		inst._input = $(!inst._inline ? target : this._get(inst, 'target') ||
147			'<input type="text" class="' + this._inlineEntryClass + '" disabled="disabled"/>');
148		if (inst._inline) {
149			target = $(target);
150			target.find('input').remove();
151			if (!this._get(inst, 'target')) {
152				target.append(inst._input);
153			}
154		}
155	},
156
157	/* Attach the keypad to a text field.
158	   @param  target  (element) the target text field
159	   @param  inst    (object) the instance settings */
160	_connectKeypad: function(target, inst) {
161		var field = $(target);
162		if (field.hasClass(this.markerClassName)) {
163			return;
164		}
165		var appendText = this._get(inst, 'appendText');
166		var isRTL = this._get(inst, 'isRTL');
167		if (appendText) {
168			field[isRTL ? 'before' : 'after'](
169				'<span class="' + this._appendClass + '">' + appendText + '</span>');
170		}
171		if (!inst._inline) {
172			var showOn = this._get(inst, 'showOn');
173			if (showOn == 'focus' || showOn == 'both') { // pop-up keypad when in the marked field
174				field.focus(this._showKeypad).keydown(this._doKeyDown);
175			}
176			if (showOn == 'button' || showOn == 'both') { // pop-up keypad when button clicked
177				var buttonText = this._get(inst, 'buttonText');
178				var buttonStatus = this._get(inst, 'buttonStatus');
179				var buttonImage = this._get(inst, 'buttonImage');
180				var trigger = $(this._get(inst, 'buttonImageOnly') ? 
181					$('<img src="' + buttonImage + '" alt="' +
182					buttonStatus + '" title="' + buttonStatus + '"/>') :
183				$('<button type="button" title="' + buttonStatus + '"></button>').
184					html(buttonImage == '' ? buttonText :
185					$('<img src="' + buttonImage + '" alt="' +
186					buttonStatus + '" title="' + buttonStatus + '"/>')));
187				field[isRTL ? 'before' : 'after'](trigger);
188				trigger.addClass(this._triggerClass).click(function() {
189					if ($.keypad._keypadShowing && $.keypad._lastField == target) {
190						$.keypad._hideKeypad();
191					}
192					else {
193						$.keypad._showKeypad(target);
194					}
195					return false;
196				});
197			}
198		}
199		//inst.saveReadonly = field.attr('readonly');
200		field.addClass(this.markerClassName).
201			//attr('readonly', (this._get(inst, 'keypadOnly') ? 'readonly' : '')).
202			bind('setData.keypad', function(event, key, value) {
203				inst.settings[key] = value;
204			}).bind('getData.keypad', function(event, key) {
205				return this._get(inst, key);
206			});
207		$.data(target, PROP_NAME, inst);
208	},
209
210	/* Detach keypad from its control.
211	   @param  target  (element) the target text field */
212	_destroyKeypad: function(target) {
213		var $target = $(target);
214		if (!$target.hasClass(this.markerClassName)) {
215			return;
216		}
217		var inst = $.data(target, PROP_NAME);
218		if (this._curInst == inst) {
219			this._hideKeypad();
220		}
221		$target.siblings('.' + this._appendClass).remove().end().
222			siblings('.' + this._triggerClass).remove().end().
223			prev('.' + this._inlineEntryClass).remove();
224		$target.empty().unbind('focus', this._showKeypad).
225			removeClass(this.markerClassName).
226			attr('readonly', inst.saveReadonly);
227		$.removeData(inst._input[0], PROP_NAME);
228		$.removeData(target, PROP_NAME);
229	},
230
231	/* Enable the keypad for a jQuery selection.
232	   @param  target  (element) the target text field */
233	_enableKeypad: function(target) {
234		var control = $(target);
235		if (!control.hasClass(this.markerClassName)) {
236			return;
237		}
238		var nodeName = target.nodeName.toLowerCase();
239		if (nodeName == 'input' || nodeName == 'textarea') {
240			target.disabled = false;
241			control.siblings('button.' + this._triggerClass).
242				each(function() { this.disabled = false; }).end().
243				siblings('img.' + this._triggerClass).
244				css({opacity: '1.0', cursor: ''});
245		}
246		else if (nodeName == 'div' || nodeName == 'span') {
247			control.children('.' + this._disableClass).remove();
248			var inst = $.data(target, PROP_NAME);
249			inst._mainDiv.find('button').attr('disabled', '');
250		}
251		this._disabledFields = $.map(this._disabledFields,
252			function(value) { return (value == target ? null : value); }); // delete entry
253	},
254
255	/* Disable the keypad for a jQuery selection.
256	   @param  target  (element) the target text field */
257	_disableKeypad: function(target) {
258		var control = $(target);
259		if (!control.hasClass(this.markerClassName)) {
260			return;
261		}
262		var nodeName = target.nodeName.toLowerCase();
263		if (nodeName == 'input' || nodeName == 'textarea') {
264		target.disabled = true;
265			control.siblings('button.' + this._triggerClass).
266			each(function() { this.disabled = true; }).end().
267			siblings('img.' + this._triggerClass).
268			css({opacity: '0.5', cursor: 'default'});
269		}
270		else if (nodeName == 'div' || nodeName == 'span') {
271			var inline = control.children('.' + this._inlineClass);
272			var offset = inline.offset();
273			var relOffset = {left: 0, top: 0};
274			inline.parents().each(function() {
275				if ($(this).css('position') == 'relative') {
276					relOffset = $(this).offset();
277					return false;
278				}
279			});
280			control.prepend('<div class="' + this._disableClass + '" style="width: ' +
281				inline.outerWidth() + 'px; height: ' + inline.outerHeight() +
282				'px; left: ' + (offset.left - relOffset.left) +
283				'px; top: ' + (offset.top - relOffset.top) + 'px;"></div>');
284			var inst = $.data(target, PROP_NAME);
285			inst._mainDiv.find('button').attr('disabled', 'disabled');
286		}
287		this._disabledFields = $.map(this._disabledFields,
288			function(value) { return (value == target ? null : value); }); // delete entry
289		this._disabledFields[this._disabledFields.length] = target;
290	},
291
292	/* Is the text field disabled as a keypad?
293	   @param  target  (element) the target text field
294	   @return  (boolean) true if disabled, false if enabled */
295	_isDisabledKeypad: function(target) {
296		return (target && $.inArray(target, this._disabledFields) > -1);
297	},
298
299	/* Update the settings for keypad attached to a text field
300	   @param  target  (element) the target text field
301	   @param  name    (object) the new settings to update or
302	                   (string) the name of the setting to change
303	   @param  value   (any) the new value for the setting (omit if above is an object) */
304	_changeKeypad: function(target, name, value) {
305		var settings = name || {};
306		if (typeof name == 'string') {
307			settings = {};
308			settings[name] = value;
309		}
310		var inst = $.data(target, PROP_NAME);
311		if (inst) {
312			if (this._curInst == inst) {
313				this._hideKeypad();
314			}
315			extendRemove(inst.settings, settings);
316			this._setInput($(target), inst);
317			this._updateKeypad(inst);
318		}
319	},
320
321	/* Pop-up the keypad for a given text field.
322	   @param  field  (element) the text field attached to the keypad or
323	                  (event) if triggered by focus */
324	_showKeypad: function(field) {
325		field = field.target || field;
326		if ($.keypad._isDisabledKeypad(field) ||
327				$.keypad._lastField == field) { // already here
328			return;
329		}
330		var inst = $.data(field, PROP_NAME);
331		$.keypad._hideKeypad(null, '');
332		$.keypad._lastField = field;
333		$.keypad._pos = $.keypad._findPos(field);
334		$.keypad._pos[1] += field.offsetHeight; // add the height
335		var isFixed = false;
336		$(field).parents().each(function() {
337			isFixed |= $(this).css('position') == 'fixed';
338			return !isFixed;
339		});
340		/*if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
341			$.keypad._pos[0] -= document.documentElement.scrollLeft;
342			$.keypad._pos[1] -= document.documentElement.scrollTop;
343		}*/
344		var offset = {left: $.keypad._pos[0], top: $.keypad._pos[1]};
345		$.keypad._pos = null;
346		// determine sizing offscreen
347		inst._mainDiv.css({
348			position: 'absolute', 
349			display: 'block', 
350			top: '-1000px',
351			width: (/*$.browser.opera ? '1000px' : */'auto')
352		});
353		$.keypad._updateKeypad(inst);
354		// and adjust position before showing
355		offset = $.keypad._checkOffset(inst, offset, isFixed);
356		inst._mainDiv.css({//keyboard position
357			position: (isFixed ? 'fixed' : 'absolute'), 
358			display: 'none',
359			//left: (offset.left+10) + 'px',
360			//top: (/*($.browser.msie) ? */'360px'/* : '342px'*/)
361            right: '10%',
362			top: '90px'
363		});
364		var showAnim = $.keypad._get(inst, 'showAnim');
365		var duration = $.keypad._get(inst, 'duration');
366		duration = (duration == 'normal' && $.ui && $.ui.version >= '1.8' ? '_default' : duration);
367		var postProcess = function() {
368			$.keypad._keypadShowing = true;
369			var borders = $.keypad._getBorders(inst._mainDiv);
370			inst._mainDiv.find('iframe.' + $.keypad._coverClass). // IE6- only
371				css({left: -borders[0], top: -borders[1] + '20px',
372					width: inst._mainDiv.outerWidth(), height: inst._mainDiv.outerHeight()});
373		};
374		if ($.effects && $.effects[showAnim]) {
375			inst._mainDiv.show(showAnim, $.keypad._get(inst, 'showOptions'),
376				duration, postProcess);
377		}
378		else {
379			inst._mainDiv[showAnim || 'show']((showAnim ? duration : ''), postProcess);
380		}
381		if (!showAnim) {
382			postProcess();
383		}
384		if (inst._input[0].type != 'hidden') {
385			inst._input[0].focus();
386		}
387		$.keypad._curInst = inst;
388	},
389
390	/* Generate the keypad content.
391	   @param  inst  (object) the instance settings */
392	_updateKeypad: function(inst) {
393		var borders = this._getBorders(inst._mainDiv);
394		inst._mainDiv.empty().append(this._generateHTML(inst)).
395			find('iframe.' + this._coverClass). // IE6- only
396			css({left: -borders[0], top: -borders[1]+ '20px',
397				width: inst._mainDiv.outerWidth(), height: inst._mainDiv.outerHeight()});
398		inst._mainDiv.removeClass().addClass(this._get(inst, 'keypadClass') +
399			(this._get(inst, 'isRTL') ? ' keypad-rtl' : '') +
400			(inst._inline ? this._inlineClass : ''));
401		var beforeShow = this._get(inst, 'beforeShow');
402		if (beforeShow) {
403			beforeShow.apply((inst._input ? inst._input[0] : null),
404				[inst._mainDiv, inst]);
405		}
406	},
407
408	/* Retrieve the size of left and top borders for an element.
409	   @param  elem  (jQuery object) the element of interest
410	   @return  (number[2]) the left and top borders */
411	_getBorders: function(elem) {
412		var convert = function(value) {
413			var extra = (/*$.browser.msie ? */1/* : 0*/);
414			return {thin: 1 + extra, medium: 3 + extra, thick: 5 + extra}[value] || value;
415		};
416		return [parseFloat(convert(elem.css('border-left-width'))),
417			parseFloat(convert(elem.css('border-top-width')))];
418	},
419
420	/* Check positioning to remain on screen.
421	   @param  inst    (object) the instance settings
422	   @param  offset  (object) the current offset
423	   @param  isFixed  (boolean) true if the text field is fixed in position
424	   @return  (object) the updated offset */
425	_checkOffset: function(inst, offset, isFixed) {
426		var pos = inst._input ? this._findPos(inst._input[0]) : null;
427		var browserWidth = window.innerWidth || document.documentElement.clientWidth;
428		var browserHeight = window.innerHeight || document.documentElement.clientHeight;
429		var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
430		var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
431		/*if (($.browser.msie && parseInt($.browser.version, 10) < 7) || $.browser.opera) {
432			// recalculate width as otherwise set to 100%
433			var width = 0;
434			inst._mainDiv.find(':not(div,iframe)').each(function() {
435				width = Math.max(width, this.offsetLeft + $(this).outerWidth() +
436					parseInt($(this).css('margin-right'), 10));
437			});
438			inst._mainDiv.css('width', width);
439		}*/
440		// reposition keypad panel horizontally if outside the browser window
441		if (this._get(inst, 'isRTL') ||
442				(offset.left + inst._mainDiv.outerWidth() - scrollX) > browserWidth) {
443			offset.left = Math.max((isFixed ? 0 : scrollX),
444				pos[0] + (inst._input ? inst._input.outerWidth() : 0) -
445				(isFixed ? scrollX : 0) - inst._mainDiv.outerWidth() -
446				(/*isFixed && $.browser.opera ? document.documentElement.scrollLeft : */0));
447		}
448		else {
449			offset.left -= (isFixed ? scrollX : 0);
450		}
451		// reposition keypad panel vertically if outside the browser window
452		if ((offset.top + inst._mainDiv.outerHeight() - scrollY) > browserHeight) {
453			offset.top = Math.max((isFixed ? 0 : scrollY),
454				pos[1] - (isFixed ? scrollY : 0) - inst._mainDiv.outerHeight() -
455				(/*isFixed && $.browser.opera ? document.documentElement.scrollTop : */0));
456		}
457		else {
458			offset.top -= (isFixed ? scrollY : 0);
459		}
460		return offset;
461	},
462	
463	/* Find an object's position on the screen.
464	   @param  obj  (element) the element to find the position for
465	   @return  (int[2]) the element's position */
466	_findPos: function(obj) {
467        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
468            obj = obj.nextSibling;
469        }
470        var position = $(obj).offset();
471	    return [position.left, position.top];
472	},
473
474	/* Hide the keypad from view.
475	   @param  field     (element) the text field attached to the keypad
476	   @param  duration  (string) the duration over which to close the keypad */
477	_hideKeypad: function(field, duration) {
478		var inst = this._curInst;
479		if (!inst || (field && inst != $.data(field, PROP_NAME))) {
480			return;
481		}
482		if (this._keypadShowing) {
483			duration = (duration != null ? duration : this._get(inst, 'duration'));
484			duration = (duration == 'normal' && $.ui && $.ui.version >= '1.8' ? '_default' : duration);
485			var showAnim = this._get(inst, 'showAnim');
486			if ($.effects && $.effects[showAnim]) {
487				inst._mainDiv.hide(showAnim, this._get(inst, 'showOptions'), duration);
488			}
489			else {
490				inst._mainDiv[(showAnim == 'slideDown' ? 'slideUp' :
491					(showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))](showAnim ? duration : '');
492			}
493		}
494		var onClose = this._get(inst, 'onClose');
495		if (onClose) {
496			onClose.apply((inst._input ? inst._input[0] : null),  // trigger custom callback
497				[inst._input.val(), inst]);
498		}
499		if (this._keypadShowing) {
500			this._keypadShowing = false;
501			this._lastField = null;
502		}
503		if (inst._inline) {
504			inst._input.val('');
505		}
506		this._curInst = null;
507	},
508
509	/* Handle keystrokes.
510	   @param  e  (event) the key event */
511	_doKeyDown: function(e) {
512		if (e.keyCode == 9) { // Tab out
513			$.keypad.mainDiv.stop(true, true);
514			$.keypad._hideKeypad(null, '');
515		}
516	},
517
518	/* Close keypad if clicked elsewhere.
519	   @param  event  (event) the mouseclick details */
520	_checkExternalClick: function(event) {
521		if (!$.keypad._curInst) {
522			return;
523		}
524		var target = $(event.target);
525		if (!target.parents().andSelf().is('#' + $.keypad._mainDivId) &&
526				!target.hasClass($.keypad.markerClassName) &&
527				!target.parents().andSelf().hasClass($.keypad._triggerClass) &&
528				$.keypad._keypadShowing) {
529			$.keypad._hideKeypad(null, '');
530		}
531	},
532
533	/* Toggle between upper and lower case.
534	   @param  inst  (object) the instance settings */
535	_shiftKeypad: function(inst) {
536		inst.ucase = !inst.ucase;
537		this._updateKeypad(inst);
538		inst._input.focus(); // for further typing
539	},
540
541	/* Erase the text field.
542	   @param  inst  (object) the instance settings */
543	_clearValue: function(inst) {
544		this._setValue(inst, '', 0);
545		this._notifyKeypress(inst, $.keypad.DEL);
546	},
547
548	/* Erase the last character.
549	   @param  inst  (object) the instance settings */
550	_backValue: function(inst) {
551		var field = inst._input[0];
552		var value = inst._input.val();
553		var range = [value.length, value.length];
554		if (field.setSelectionRange) { // Mozilla
555			range = (inst._input.attr('readonly') || inst._input.attr('disabled') ?
556				range : [field.selectionStart, field.selectionEnd]);
557		}
558		else if (field.createTextRange) { // IE
559			range = (inst._input.attr('readonly') || inst._input.attr('disabled') ?
560				range : this._getIERange(field));
561		}
562		this._setValue(inst, (value.length == 0 ? '' :
563			value.substr(0, range[0] - 1) + value.substr(range[1])), range[0] - 1);
564		this._notifyKeypress(inst, $.keypad.BS);
565	},
566
567	/* Update the text field with the selected value.
568	   @param  inst   (object) the instance settings
569	   @param  value  (string) the new character to add */
570	_selectValue: function(inst, value) {
571		this.insertValue(inst._input[0], value);
572		this._setValue(inst, inst._input.val());
573		this._notifyKeypress(inst, value);
574	},
575
576	/* Update the text field with the selected value.
577	   @param  input  (element) the input field or
578	                  (jQuery) jQuery collection
579	   @param  value  (string) the new character to add */
580	insertValue: function(input, value) {
581		input = (input.jquery ? input : $(input));
582		var field = input[0];
583		var newValue = input.val();
584		var range = [newValue.length, newValue.length];
585		if (field.setSelectionRange) { // Mozilla
586			range = (input.attr('readonly') || input.attr('disabled') ?
587				range : [field.selectionStart, field.selectionEnd]);
588		}
589		else if (field.createTextRange) { // IE
590			range = (input.attr('readonly') || input.attr('disabled') ?
591				range : this._getIERange(field));
592		}
593		input.val(newValue.substr(0, range[0]) + value + newValue.substr(range[1]));
594		pos = range[0] + value.length;
595		if (input.css('display') != 'none') {
596			input.focus(); // for further typing
597		}
598		if (field.setSelectionRange) { // Mozilla
599			if (input.css('display') != 'none') {
600				field.setSelectionRange(pos, pos);
601			}
602		}
603		else if (field.createTextRange) { // IE
604			var range = field.createTextRange();
605			range.move('character', pos);
606			range.select();
607		}
608	},
609
610	/* Get the coordinates for the selected area in the text field in IE.
611	   @param  field  (element) the target text field
612	   @return  (int[2]) the start and end positions of the selection */
613	_getIERange: function(field) {
614		field.focus();
615		var selectionRange = document.selection.createRange().duplicate();
616		// Use two ranges: before and selection
617		var beforeRange = this._getIETextRange(field);
618		beforeRange.setEndPoint('EndToStart', selectionRange);
619		// Check each range for trimmed newlines by shrinking the range by one
620		// character and seeing if the text property has changed. If it has not
621		// changed then we know that IE has trimmed a \r\n from the end.
622		var checkCRLF = function(range) {
623			var origText = range.text;
624			var text = origText;
625			var finished = false;
626			while (true) {
627				if (range.compareEndPoints('StartToEnd', range) == 0) {
628					break;
629				} 
630				else {
631					range.moveEnd('character', -1);
632					if (range.text == origText) {
633						text += '\r\n';
634					} 
635					else {
636						break;
637					}
638				}
639			}
640			return text;
641		};
642		var beforeText = checkCRLF(beforeRange);
643		var selectionText = checkCRLF(selectionRange);
644		return [beforeText.length, beforeText.length + selectionText.length];
645	},
646
647	/* Create an IE text range for the text field.
648	   @param  field  (element) the target text field
649	   @return  (object) the corresponding text range */
650	_getIETextRange: function(field) {
651		var isInput = (field.nodeName.toLowerCase() == 'input');
652		var range = (isInput ? field.createTextRange() : document.body.createTextRange());
653		if (!isInput) {
654			range.moveToElementText(field); // Selects all the text for a textarea
655		}
656		return range;
657	},
658
659	/* Set the text field to the selected value,
660	   and trigger any on change event.
661	   @param  inst   (object) the instance settings
662	   @param  value  (string) the new value for the text field */
663	_setValue: function(inst, value) {
664		var maxlen = inst._input.attr('maxlength');
665		if (maxlen > -1) {
666			value = value.substr(0, maxlen);
667		}
668		inst._input.val(value);
669		if (!this._get(inst, 'onKeypress')) {
670			inst._input.trigger('change'); // fire the change event
671		}
672	},
673
674	_notifyKeypress: function(inst, key) {
675		var onKeypress = this._get(inst, 'onKeypress');
676		if (onKeypress) { // trigger custom callback
677			onKeypress.apply((inst._input ? inst._input[0] : null),
678				[key, inst._input.val(), inst]);
679		}
680	},
681
682	/* Get a setting value, defaulting if necessary.
683	   @param  inst  (object) the instance settings
684	   @param  name  (string) the name of the setting
685	   @return  (any) the value of the setting, or its default if not set explicitly */
686	_get: function(inst, name) {
687		return inst.settings[name] !== undefined ?
688			inst.settings[name] : this._defaults[name];
689	},
690
691	/* Generate the HTML for the current state of the keypad.
692	   @param  inst  (object) the instance settings
693	   @return  (jQuery) the HTML for this keypad */
694	_generateHTML: function(inst) {
695		var isRTL = this._get(inst, 'isRTL');
696		var prompt = this._get(inst, 'prompt');
697		var separator = this._get(inst, 'separator');
698		var html = (!prompt ? '' :
699			'<div class="keypad-prompt">' + prompt + '</div>');
700		var layout = this._randomiseLayout(inst);
701		for (var i = 0; i < layout.length; i++) {
702			html += '<div class="keypad-row">';
703			var keys = layout[i].split(separator);
704			for (var j = 0; j < keys.length; j++) {
705				if (inst.ucase) {
706					keys[j] = keys[j].toUpperCase();
707				}
708				html += (keys[j] == this.SPACE ? '<div class="keypad-space"></div>' :
709					(keys[j] == this.HALF_SPACE ? '<div class="keypad-half-space"></div>' :
710					'<button type="button" class="keypad-key' +
711					(keys[j] == this.CLEAR ? ' keypad-clear' :
712					(keys[j] == this.BACK ? ' keypad-back' :
713					(keys[j] == this.CLOSE ? ' keypad-close' :
714					(keys[j] == this.SHIFT ? ' keypad-shift' :
715					(keys[j] == this.SPACE_BAR ? ' keypad-spacebar' : ''))))) + '" ' + 
716					'title="' + (keys[j] == this.CLEAR ? this._get(inst, 'clearStatus') :
717					(keys[j] == this.BACK ? this._get(inst, 'backStatus') :
718					(keys[j] == this.CLOSE ? this._get(inst, 'closeStatus') :
719					(keys[j] == this.SHIFT ? this._get(inst, 'shiftStatus') : '')))) + '">' +
720					(keys[j] == this.CLEAR ? this._get(inst, 'clearText') :
721					(keys[j] == this.BACK ? this._get(inst, 'backText') :
722					(keys[j] == this.CLOSE ? this._get(inst, 'closeText') :
723					(keys[j] == this.SHIFT ? this._get(inst, 'shiftText') :
724					(keys[j] == this.SPACE_BAR ? '&nbsp;' :
725					(keys[j] == ' ' ? '&nbsp;' : keys[j])))))) + '</button>'));
726			}
727			html += '</div>';
728		}
729		html += '<div style="clear: both;"></div>' + 
730			(/*!inst._inline && $.browser.msie && parseInt($.browser.version, 10) < 7 ? 
731			'<iframe src="javascript:false;" class="' + $.keypad._coverClass + '"></iframe>' :*/ '');
732		html = $(html);
733		var thisInst = inst;
734		html.find('button').mousedown(function() { $(this).addClass('keypad-key-down'); }).
735			mouseup(function() { $(this).removeClass('keypad-key-down'); }).
736			mouseout(function() { $(this).removeClass('keypad-key-down'); }).
737			filter('.keypad-clear').click(function() { $.keypad._clearValue(thisInst); }).end().
738			filter('.keypad-back').click(function() { $.keypad._backValue(thisInst); }).end().
739			filter('.keypad-close').click(function() {
740				$.keypad._curInst = (thisInst._inline ? thisInst : $.keypad._curInst);
741				$.keypad._hideKeypad();
742			}).end().
743			filter('.keypad-shift').click(function() { $.keypad._shiftKeypad(thisInst); }).end().
744			not('.keypad-clear').not('.keypad-back').not('.keypad-close').not('.keypad-shift').
745			click(function() { $.keypad._selectValue(thisInst, $(this).text()); });
746		return html;
747	},
748
749	/* Check whether characters should be randomised,
750	   and, if so, produce the randomised layout.
751	   @param  inst  (object) the instance settings
752	   @return  (string[]) the layout with any requested randomisations applied */
753	_randomiseLayout: function(inst) {
754		var randomiseNumeric = this._get(inst, 'randomiseNumeric');
755		var randomiseAlpha = this._get(inst, 'randomiseAlphabetic');
756		var randomiseOther = this._get(inst, 'randomiseOther');
757		var randomiseAll = this._get(inst, 'randomiseAll');
758		var layout = this._get(inst, 'layout');
759		if (!randomiseNumeric && !randomiseAlpha && !randomiseOther && !randomiseAll) {
760			return layout;
761		}
762		var isNumeric = this._get(inst, 'isNumeric');
763		var isAlphabetic = this._get(inst, 'isAlphabetic');
764		var separator = this._get(inst, 'separator');
765		var numerics = [];
766		var alphas = [];
767		var others = [];
768		var newLayout = [];
769		// Find characters of different types
770		for (var i = 0; i < layout.length; i++) {
771			newLayout[i] = '';
772			var keys = layout[i].split(separator);
773			for (var j = 0; j < keys.length; j++) {
774				if (this._isControl(keys[j])) {
775					continue;
776				}
777				if (randomiseAll) {
778					others.push(keys[j]);
779				}
780				else if (isNumeric(keys[j])) {
781					numerics.push(keys[j]);
782				}
783				else if (isAlphabetic(keys[j])) {
784					alphas.push(keys[j]);
785				}
786				else {
787					others.push(keys[j]);
788				}
789			}
790		}
791		// Shuffle them
792		if (randomiseNumeric) {
793			this._shuffle(numerics);
794		}
795		if (randomiseAlpha) {
796			this._shuffle(alphas);
797		}
798		if (randomiseOther || randomiseAll) {
799			this._shuffle(others);
800		}
801		var n = 0;
802		var a = 0;
803		var o = 0;
804		// And replace them in the layout
805		for (var i = 0; i < layout.length; i++) {
806			var keys = layout[i].split(separator);
807			for (var j = 0; j < keys.length; j++) {
808				newLayout[i] += (this._isControl(keys[j]) ? keys[j] :
809					(randomiseAll ? others[o++] :
810					(isNumeric(keys[j]) ? numerics[n++] :
811					(isAlphabetic(keys[j]) ? alphas[a++] :
812					others[o++])))) + separator;
813			}
814		}
815		return newLayout;
816	},
817
818	/* Is a given character a control character?
819	   @param  ch  (char) the character to test
820	   @return  (boolean) true if a control character, false if not */
821	_isControl: function(ch) {
822		return ch < ' ';
823	},
824
825	/* Is a given character alphabetic?
826	   @param  ch  (char) the character to test
827	   @return  (boolean) true if alphabetic, false if not */
828	isAlphabetic: function(ch) {
829		return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
830	},
831
832	/* Is a given character numeric?
833	   @param  ch  (char) the character to test
834	   @return  (boolean) true if numeric, false if not */
835	isNumeric: function(ch) {
836		return (ch >= '0' && ch <= '9');
837	},
838
839	/* Randomise the contents of an array.
840	   @param  values  (string[]) the array to rearrange */
841	_shuffle: function(values) {
842		for (var i = values.length - 1; i > 0; i--) {
843			var j = Math.floor(Math.random() * values.length);
844			var ch = values[i];
845			values[i] = values[j];
846			values[j] = ch;
847		}
848	}
849});
850
851/* jQuery extend now ignores nulls!
852   @param  target  (object) the object to extend
853   @param  props   (object) the new settings
854   @return  (object) the updated target */
855function extendRemove(target, props) {
856	$.extend(target, props);
857	for (var name in props) {
858		if (props[name] == null || props[name] == undefined) {
859			target[name] = props[name];
860		}
861	}
862	return target;
863};
864
865/* Invoke the keypad functionality.
866   @param  options  (string) a command, optionally followed by additional parameters or
867                    (object) settings for attaching new keypad functionality
868   @return  (object) the jQuery object */
869$.fn.keypad = function(options) {
870	var otherArgs = Array.prototype.slice.call(arguments, 1);
871	if (options == 'isDisabled') {
872		return $.keypad['_' + options + 'Keypad'].
873			apply($.keypad, [this[0]].concat(otherArgs));
874	}
875	return this.each(function() {
876		typeof options == 'string' ?
877			$.keypad['_' + options + 'Keypad'].
878				apply($.keypad, [this].concat(otherArgs)) :
879			$.keypad._attachKeypad(this, options);
880	});
881};
882
883$.keypad = new Keypad(); // singleton instance
884
885// Add the keypad division and external click check
886$(function() {
887	$(document.body).append($.keypad.mainDiv).
888		mousedown($.keypad._checkExternalClick);
889});
890
891});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.