jQuery Simulate Key-Sequence Plugin 1.3.0

jQuery Simulate Key-Sequence Plugin

Tính đến 22-11-2015. Xem phiên bản mới nhất.

Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta // @require https://update.greasyforks.org/scripts/14095/88783/jQuery%20Simulate%20Key-Sequence%20Plugin%20130.js

/*jshint camelcase:true, plusplus:true, forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, devel:true, maxerr:100, white:false, onevar:false */
/*global jQuery:true $:true bililiteRange:true */

/* jQuery Simulate Key-Sequence Plugin 1.3.0
 * http://github.com/j-ulrich/jquery-simulate-ext
 * 
 * Copyright (c) 2014 Jochen Ulrich
 * Licensed under the MIT license (MIT-LICENSE.txt).
 * 
 * The plugin is an extension and modification of the jQuery sendkeys plugin by Daniel Wachsstock.
 * Therefore, the original copyright notice and license follow below.
 */

// insert characters in a textarea or text input field
// special characters are enclosed in {}; use {{} for the { character itself
// documentation: http://bililite.com/blog/2008/08/20/the-fnsendkeys-plugin/
// Version: 2.0
// Copyright (c) 2010 Daniel Wachsstock
// MIT license:
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

;(function($, undefined){
	"use strict";
	
	$.simulate.prototype.quirks = $.simulate.prototype.quirks || {};
	
	$.extend($.simulate.prototype.quirks, 

	/**
	 * @lends $.simulate.prototype.quirks
	 */		
	{
		/**
		 * When simulating with delay in non-input elements,
		 * all spaces are simulated at the end of the sequence instead
		 * of the correct position.
		 * @see {@link https://github.com/j-ulrich/jquery-simulate-ext/issues/6|issues #6}
		 */
		delayedSpacesInNonInputGlitchToEnd: undefined

	});
	
	$.extend($.simulate.prototype,
			
	/**
	 * @lends $.simulate.prototype
	 */		
	{
		
		/**
		 * Simulates sequencial key strokes.
		 * 
		 * @see https://github.com/j-ulrich/jquery-simulate-ext/blob/master/doc/key-sequence.md
		 * @public
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		simulateKeySequence: function() {
			var target = this.target,
				$target = $(target),
				opts = $.extend({
					sequence: "",
					triggerKeyEvents: true,
					eventProps: {},
					delay: 0,
					callback: undefined
				}, this.options),
				sequence = opts.sequence;
			
			opts.delay = parseInt(opts.delay,10);

			var localkeys = {};

			// Fix for #6 (https://github.com/j-ulrich/jquery-simulate-ext/issues/6)
			if ($.simulate.prototype.quirks.delayedSpacesInNonInputGlitchToEnd && !$target.is('input,textarea')) {
				$.extend(localkeys, {
					' ': function(rng, s, opts) {
						var internalOpts = $.extend({}, opts, {
							triggerKeyEvents: false,
							delay: 0,
							callback: undefined
						});
						$.simulate.prototype.simulateKeySequence.defaults.simplechar(rng, '\xA0', internalOpts);
						$.simulate.prototype.simulateKeySequence.defaults['{leftarrow}'](rng, s, internalOpts);
						$.simulate.prototype.simulateKeySequence.defaults.simplechar(rng, s, opts);
						$.simulate.prototype.simulateKeySequence.defaults['{del}'](rng, s, internalOpts);
					}
				});
			}

			$.extend(localkeys, opts, $target.data('simulate-keySequence')); // allow for element-specific key functions

			// most elements to not keep track of their selection when they lose focus, so we have to do it for them
			var rng = $.data (target, 'simulate-keySequence.selection');
			if (!rng){
				rng = bililiteRange(target).bounds('selection');
				$.data(target, 'simulate-keySequence.selection', rng);
				$target.bind('mouseup.simulate-keySequence', function(){
					// we have to update the saved range. The routines here update the bounds with each press, but actual keypresses and mouseclicks do not
					$.data(target, 'simulate-keySequence.selection').bounds('selection');
				}).bind('keyup.simulate-keySequence', function(evt){
					// restore the selection if we got here with a tab (a click should select what was clicked on)
					if (evt.which === 9){
						// there's a flash of selection when we restore the focus, but I don't know how to avoid that.
						$.data(target, 'simulate-keySequence.selection').select();
					}else{
						$.data(target, 'simulate-keySequence.selection').bounds('selection');
					}	
				});
			}
			$target.focus();
			if (typeof sequence === 'undefined') { // no string, so we just set up the event handlers
				return;
			}
			sequence = sequence.replace(/\n/g, '{enter}'); // turn line feeds into explicit break insertions
			
			/**
			 * Informs the rest of the world that the sequences is finished.
			 * @fires simulate-keySequence
			 * @requires target
			 * @requires sequence
			 * @requires opts
			 * @inner
			 * @author julrich
			 * @since 1.0
			 */
			function sequenceFinished() {
				$target.trigger({type: 'simulate-keySequence', sequence: sequence});
				if ($.isFunction(opts.callback)) {
					opts.callback.apply(target, [{
						sequence: sequence
					}]);
				}
			}
			
			/**
			 * Simulates the key stroke for one character (or special sequence) and sleeps for
			 * <code>opts.delay</code> milliseconds.
			 * @requires lastTime
			 * @requires now()
			 * @requires tokenRegExp
			 * @requires opts
			 * @requires rng
			 * @inner
			 * @author julrich
			 * @since 1.0
			 */
			function processNextToken() {
				var timeElapsed = now() - lastTime; // Work-around for Firefox "bug": setTimeout can fire before the timeout
				if (timeElapsed >= opts.delay) {
					var match = tokenRegExp.exec(sequence);
					if ( match !== null ) {
						var s = match[0];
						(localkeys[s] || $.simulate.prototype.simulateKeySequence.defaults[s] || $.simulate.prototype.simulateKeySequence.defaults.simplechar)(rng, s, opts);
						setTimeout(processNextToken, opts.delay);
					}
					else {
						sequenceFinished();
					}
					lastTime = now();
				}
				else {
					setTimeout(processNextToken, opts.delay - timeElapsed);
				}
			}

			if (!opts.delay || opts.delay <= 0) {
				// Run as fast as possible
				sequence.replace(/\{[^}]*\}|[^{]+/g, function(s){
					(localkeys[s] || $.simulate.prototype.simulateKeySequence.defaults[s] || $.simulate.prototype.simulateKeySequence.defaults.simplechar)(rng, s, opts);
				});
				sequenceFinished();
			}
			else {
				var tokenRegExp = /\{[^}]*\}|[^{]/g; // This matches curly bracket expressions or single characters
				var now = Date.now || function() { return new Date().getTime(); },
					lastTime = now();
				
				processNextToken();
			}
			
		}
	});

	$.extend($.simulate.prototype.simulateKeySequence.prototype,
			
	/**
	 * @lends $.simulate.prototype.simulateKeySequence.prototype
	 */		
	{
		
			/**
			 * Maps special character char codes to IE key codes (covers IE and Webkit)
			 * @author julrich
			 * @since 1.0
			 */
			IEKeyCodeTable: {
				33: 49,	// ! -> 1
				64: 50,	// @ -> 2
				35: 51,	// # -> 3
				36: 52,	// $ -> 4
				37: 53,	// % -> 5
				94: 54,	// ^ -> 6
				38: 55,	// & -> 7
				42: 56,	// * -> 8
				40: 57,	// ( -> 9
				41: 48,	// ) -> 0
				
				59: 186,	// ; -> 186
				58: 186,	// : -> 186
				61: 187,	// = -> 187
				43: 187,	// + -> 187
				44: 188,	// , -> 188
				60: 188,	// < -> 188
				45: 189,	// - -> 189
				95: 189,	// _ -> 189
				46: 190,	// . -> 190
				62: 190,	// > -> 190
				47: 191,	// / -> 191
				63: 191,	// ? -> 191
				96: 192,	// ` -> 192
				126: 192,	// ~ -> 192
				91: 219,	// [ -> 219
				123: 219,	// { -> 219
				92: 220,	// \ -> 220
				124: 220,	// | -> 220
				93: 221,	// ] -> 221
				125: 221,	// } -> 221
				39: 222,	// ' -> 222
				34: 222		// " -> 222
			},
			
			/**
			 * Tries to convert character codes to key codes.
			 * @param {Numeric} character - A character code
			 * @returns {Numeric} The key code corresponding to the given character code,
			 * based on the key code table of InternetExplorer. If no corresponding key code
			 * could be found (which will be the case for all special characters except the common
			 * ones), the character code itself is returned. However, <code>keyCode === charCode</code>
			 * does not imply that no key code was found because some key codes are identical to the
			 * character codes (e.g. for uppercase characters).
			 * @requires $.simulate.prototype.simulateKeySequence.prototype.IEKeyCodeTable
			 * @see $.simulate.prototype.simulateKeySequence.prototype.IEKeyCodeTable
			 * @author julrich
			 * @since 1.0
			 */
			charToKeyCode: function(character) {
				var specialKeyCodeTable = $.simulate.prototype.simulateKeySequence.prototype.IEKeyCodeTable;
				var charCode = character.charCodeAt(0);
		
				if (charCode >= 64 && charCode <= 90 || charCode >= 48 && charCode <= 57) {
					// A-Z and 0-9
					return charCode;
				}
				else if (charCode >= 97 && charCode <= 122) {
					// a-z -> A-Z
					return character.toUpperCase().charCodeAt(0);
				}
				else if (specialKeyCodeTable[charCode] !== undefined) {
					return specialKeyCodeTable[charCode];
				}
				else {
					return charCode;
				}
			}
	});

	// add the functions publicly so they can be overridden
	$.simulate.prototype.simulateKeySequence.defaults = {
		
		/**
		 * Simulates key strokes of "normal" characters (i.e. non-special sequences).
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @param {String} s - String of (simple) characters to be simulated. 
		 * @param {Object} opts - The key-sequence options.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		simplechar: function (rng, s, opts){
			rng.text(s, 'end');
			if (opts.triggerKeyEvents) {
				for (var i =0; i < s.length; i += 1){
					var charCode = s.charCodeAt(i);
					var keyCode = $.simulate.prototype.simulateKeySequence.prototype.charToKeyCode(s.charAt(i));
					// a bit of cheating: rng._el is the element associated with rng.
					$(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: keyCode}));
					$(rng._el).simulate('keypress', $.extend({}, opts.eventProps,{keyCode: charCode, which: charCode, charCode: charCode}));
					$(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: keyCode}));
				}
			}
		},
		
		/**
		 * Simulates key strokes of a curly opening bracket. 
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @param {String} s - Ignored. 
		 * @param {Object} opts - The key-sequence options.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		'{{}': function (rng, s, opts){
			$.simulate.prototype.simulateKeySequence.defaults.simplechar(rng, '{', opts);
		},
		
		/**
		 * Simulates hitting the enter button.
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @param {String} s - Ignored. 
		 * @param {Object} opts - The key-sequence options.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		'{enter}': function (rng, s, opts){
			rng.insertEOL();
			rng.select();
			if (opts.triggerKeyEvents === true) {
				$(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 13}));
				$(rng._el).simulate('keypress', $.extend({}, opts.eventProps, {keyCode: 13, which: 13, charCode: 13}));
				$(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 13}));
			}
		},
		
		/**
		 * Simulates hitting the backspace button.
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @param {String} s - Ignored. 
		 * @param {Object} opts - The key-sequence options.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		'{backspace}': function (rng, s, opts){
			var b = rng.bounds();
			if (b[0] === b[1]) { rng.bounds([b[0]-1, b[0]]); } // no characters selected; it's just an insertion point. Remove the previous character
			rng.text('', 'end'); // delete the characters and update the selection
			if (opts.triggerKeyEvents === true) {
				$(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 8}));
				$(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 8}));
			}
		},
		
		/**
		 * Simulates hitting the delete button.
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @param {String} s - Ignored. 
		 * @param {Object} opts - The key-sequence options.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		'{del}': function (rng, s, opts){
			var b = rng.bounds();
			if (b[0] === b[1]) { rng.bounds([b[0], b[0]+1]); } // no characters selected; it's just an insertion point. Remove the next character
			rng.text('', 'end'); // delete the characters and update the selection
			if (opts.triggerKeyEvents === true) {
				$(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 46}));
				$(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 46}));
			}
		},
		
		/**
		 * Simulates hitting the right arrow button.
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @param {String} s - Ignored. 
		 * @param {Object} opts - The key-sequence options.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		'{rightarrow}':  function (rng, s, opts){
			var b = rng.bounds();
			if (b[0] === b[1]) { b[1] += 1; } // no characters selected; it's just an insertion point. Move to the right
			rng.bounds([b[1], b[1]]).select();
			if (opts.triggerKeyEvents === true) {
				$(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 39}));
				$(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 39}));
			}
		},
		
		/**
		 * Simulates hitting the left arrow button.
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @param {String} s - Ignored. 
		 * @param {Object} opts - The key-sequence options.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		'{leftarrow}': function (rng, s, opts){
			var b = rng.bounds();
			if (b[0] === b[1]) { b[0] -= 1; } // no characters selected; it's just an insertion point. Move to the left
			rng.bounds([b[0], b[0]]).select();
			if (opts.triggerKeyEvents === true) {
				$(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 37}));
				$(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 37}));
			}
		},
		
		/**
		 * Selects all characters in the target element.
		 * @param {Object} rng - bililiteRange object of the simulation target element.
		 * @author Daniel Wachsstock, julrich
		 * @since 1.0
		 */
		'{selectall}' : function (rng){
			rng.bounds('all').select();
		}
	};
	
	
		
	
	//####### Quirk detection #######
	if ($.simulate.ext_disableQuirkDetection !== true) { // Fixes issue #9 (https://github.com/j-ulrich/jquery-simulate-ext/issues/9)
		$(document).ready(function() {
			// delayedSpacesInNonInputGlitchToEnd
			// See issues #6 (https://github.com/j-ulrich/jquery-simulate-ext/issues/6)
			/* Append a div to the document (bililiteRange needs the element to be in the document), simulate
			 * a delayed sequence containing a space in the middle and check if the space moves to the end.
			 */
			var $testDiv = $('<div/>').css({height: 1, width: 1, position: 'absolute', left: -1000, top: -1000}).appendTo('body');
			$testDiv.simulate('key-sequence', {sequence: '\xA0 \xA0', delay:1, callback: function() {
				$.simulate.prototype.quirks.delayedSpacesInNonInputGlitchToEnd = ($testDiv.text() === '\xA0\xA0 ');
				$testDiv.remove();
			}});
		});
	}

})(jQuery);
长期地址
遇到问题?请前往 GitHub 提 Issues。