🏠 返回首頁 

Greasy Fork is available in English.

jQuery Simulate Key-Sequence Plugin 1.3.0

jQuery Simulate Key-Sequence Plugin

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.org/scripts/14095/88783/jQuery%20Simulate%20Key-Sequence%20Plugin%20130.js

  1. /*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 */
  2. /*global jQuery:true $:true bililiteRange:true */
  3. /* jQuery Simulate Key-Sequence Plugin 1.3.0
  4. * http://github.com/j-ulrich/jquery-simulate-ext
  5. *
  6. * Copyright (c) 2014 Jochen Ulrich
  7. * Licensed under the MIT license (MIT-LICENSE.txt).
  8. *
  9. * The plugin is an extension and modification of the jQuery sendkeys plugin by Daniel Wachsstock.
  10. * Therefore, the original copyright notice and license follow below.
  11. */
  12. // insert characters in a textarea or text input field
  13. // special characters are enclosed in {}; use {{} for the { character itself
  14. // documentation: http://bililite.com/blog/2008/08/20/the-fnsendkeys-plugin/
  15. // Version: 2.0
  16. // Copyright (c) 2010 Daniel Wachsstock
  17. // MIT license:
  18. // Permission is hereby granted, free of charge, to any person
  19. // obtaining a copy of this software and associated documentation
  20. // files (the "Software"), to deal in the Software without
  21. // restriction, including without limitation the rights to use,
  22. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  23. // copies of the Software, and to permit persons to whom the
  24. // Software is furnished to do so, subject to the following
  25. // conditions:
  26. //
  27. // The above copyright notice and this permission notice shall be
  28. // included in all copies or substantial portions of the Software.
  29. //
  30. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  31. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  32. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  33. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  34. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  35. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  36. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  37. // OTHER DEALINGS IN THE SOFTWARE.
  38. ;(function($, undefined){
  39. "use strict";
  40. $.simulate.prototype.quirks = $.simulate.prototype.quirks || {};
  41. $.extend($.simulate.prototype.quirks,
  42. /**
  43. * @lends $.simulate.prototype.quirks
  44. */
  45. {
  46. /**
  47. * When simulating with delay in non-input elements,
  48. * all spaces are simulated at the end of the sequence instead
  49. * of the correct position.
  50. * @see {@link https://github.com/j-ulrich/jquery-simulate-ext/issues/6|issues #6}
  51. */
  52. delayedSpacesInNonInputGlitchToEnd: undefined
  53. });
  54. $.extend($.simulate.prototype,
  55. /**
  56. * @lends $.simulate.prototype
  57. */
  58. {
  59. /**
  60. * Simulates sequencial key strokes.
  61. *
  62. * @see https://github.com/j-ulrich/jquery-simulate-ext/blob/master/doc/key-sequence.md
  63. * @public
  64. * @author Daniel Wachsstock, julrich
  65. * @since 1.0
  66. */
  67. simulateKeySequence: function() {
  68. var target = this.target,
  69. $target = $(target),
  70. opts = $.extend({
  71. sequence: "",
  72. triggerKeyEvents: true,
  73. eventProps: {},
  74. delay: 0,
  75. callback: undefined
  76. }, this.options),
  77. sequence = opts.sequence;
  78. opts.delay = parseInt(opts.delay,10);
  79. var localkeys = {};
  80. // Fix for #6 (https://github.com/j-ulrich/jquery-simulate-ext/issues/6)
  81. if ($.simulate.prototype.quirks.delayedSpacesInNonInputGlitchToEnd && !$target.is('input,textarea')) {
  82. $.extend(localkeys, {
  83. ' ': function(rng, s, opts) {
  84. var internalOpts = $.extend({}, opts, {
  85. triggerKeyEvents: false,
  86. delay: 0,
  87. callback: undefined
  88. });
  89. $.simulate.prototype.simulateKeySequence.defaults.simplechar(rng, '\xA0', internalOpts);
  90. $.simulate.prototype.simulateKeySequence.defaults['{leftarrow}'](rng, s, internalOpts);
  91. $.simulate.prototype.simulateKeySequence.defaults.simplechar(rng, s, opts);
  92. $.simulate.prototype.simulateKeySequence.defaults['{del}'](rng, s, internalOpts);
  93. }
  94. });
  95. }
  96. $.extend(localkeys, opts, $target.data('simulate-keySequence')); // allow for element-specific key functions
  97. // most elements to not keep track of their selection when they lose focus, so we have to do it for them
  98. var rng = $.data (target, 'simulate-keySequence.selection');
  99. if (!rng){
  100. rng = bililiteRange(target).bounds('selection');
  101. $.data(target, 'simulate-keySequence.selection', rng);
  102. $target.bind('mouseup.simulate-keySequence', function(){
  103. // we have to update the saved range. The routines here update the bounds with each press, but actual keypresses and mouseclicks do not
  104. $.data(target, 'simulate-keySequence.selection').bounds('selection');
  105. }).bind('keyup.simulate-keySequence', function(evt){
  106. // restore the selection if we got here with a tab (a click should select what was clicked on)
  107. if (evt.which === 9){
  108. // there's a flash of selection when we restore the focus, but I don't know how to avoid that.
  109. $.data(target, 'simulate-keySequence.selection').select();
  110. }else{
  111. $.data(target, 'simulate-keySequence.selection').bounds('selection');
  112. }
  113. });
  114. }
  115. $target.focus();
  116. if (typeof sequence === 'undefined') { // no string, so we just set up the event handlers
  117. return;
  118. }
  119. sequence = sequence.replace(/\n/g, '{enter}'); // turn line feeds into explicit break insertions
  120. /**
  121. * Informs the rest of the world that the sequences is finished.
  122. * @fires simulate-keySequence
  123. * @requires target
  124. * @requires sequence
  125. * @requires opts
  126. * @inner
  127. * @author julrich
  128. * @since 1.0
  129. */
  130. function sequenceFinished() {
  131. $target.trigger({type: 'simulate-keySequence', sequence: sequence});
  132. if ($.isFunction(opts.callback)) {
  133. opts.callback.apply(target, [{
  134. sequence: sequence
  135. }]);
  136. }
  137. }
  138. /**
  139. * Simulates the key stroke for one character (or special sequence) and sleeps for
  140. * <code>opts.delay</code> milliseconds.
  141. * @requires lastTime
  142. * @requires now()
  143. * @requires tokenRegExp
  144. * @requires opts
  145. * @requires rng
  146. * @inner
  147. * @author julrich
  148. * @since 1.0
  149. */
  150. function processNextToken() {
  151. var timeElapsed = now() - lastTime; // Work-around for Firefox "bug": setTimeout can fire before the timeout
  152. if (timeElapsed >= opts.delay) {
  153. var match = tokenRegExp.exec(sequence);
  154. if ( match !== null ) {
  155. var s = match[0];
  156. (localkeys[s] || $.simulate.prototype.simulateKeySequence.defaults[s] || $.simulate.prototype.simulateKeySequence.defaults.simplechar)(rng, s, opts);
  157. setTimeout(processNextToken, opts.delay);
  158. }
  159. else {
  160. sequenceFinished();
  161. }
  162. lastTime = now();
  163. }
  164. else {
  165. setTimeout(processNextToken, opts.delay - timeElapsed);
  166. }
  167. }
  168. if (!opts.delay || opts.delay <= 0) {
  169. // Run as fast as possible
  170. sequence.replace(/\{[^}]*\}|[^{]+/g, function(s){
  171. (localkeys[s] || $.simulate.prototype.simulateKeySequence.defaults[s] || $.simulate.prototype.simulateKeySequence.defaults.simplechar)(rng, s, opts);
  172. });
  173. sequenceFinished();
  174. }
  175. else {
  176. var tokenRegExp = /\{[^}]*\}|[^{]/g; // This matches curly bracket expressions or single characters
  177. var now = Date.now || function() { return new Date().getTime(); },
  178. lastTime = now();
  179. processNextToken();
  180. }
  181. }
  182. });
  183. $.extend($.simulate.prototype.simulateKeySequence.prototype,
  184. /**
  185. * @lends $.simulate.prototype.simulateKeySequence.prototype
  186. */
  187. {
  188. /**
  189. * Maps special character char codes to IE key codes (covers IE and Webkit)
  190. * @author julrich
  191. * @since 1.0
  192. */
  193. IEKeyCodeTable: {
  194. 33: 49, // ! -> 1
  195. 64: 50, // @ -> 2
  196. 35: 51, // # -> 3
  197. 36: 52, // $ -> 4
  198. 37: 53, // % -> 5
  199. 94: 54, // ^ -> 6
  200. 38: 55, // & -> 7
  201. 42: 56, // * -> 8
  202. 40: 57, // ( -> 9
  203. 41: 48, // ) -> 0
  204. 59: 186, // ; -> 186
  205. 58: 186, // : -> 186
  206. 61: 187, // = -> 187
  207. 43: 187, // + -> 187
  208. 44: 188, // , -> 188
  209. 60: 188, // < -> 188
  210. 45: 189, // - -> 189
  211. 95: 189, // _ -> 189
  212. 46: 190, // . -> 190
  213. 62: 190, // > -> 190
  214. 47: 191, // / -> 191
  215. 63: 191, // ? -> 191
  216. 96: 192, // ` -> 192
  217. 126: 192, // ~ -> 192
  218. 91: 219, // [ -> 219
  219. 123: 219, // { -> 219
  220. 92: 220, // \ -> 220
  221. 124: 220, // | -> 220
  222. 93: 221, // ] -> 221
  223. 125: 221, // } -> 221
  224. 39: 222, // ' -> 222
  225. 34: 222 // " -> 222
  226. },
  227. /**
  228. * Tries to convert character codes to key codes.
  229. * @param {Numeric} character - A character code
  230. * @returns {Numeric} The key code corresponding to the given character code,
  231. * based on the key code table of InternetExplorer. If no corresponding key code
  232. * could be found (which will be the case for all special characters except the common
  233. * ones), the character code itself is returned. However, <code>keyCode === charCode</code>
  234. * does not imply that no key code was found because some key codes are identical to the
  235. * character codes (e.g. for uppercase characters).
  236. * @requires $.simulate.prototype.simulateKeySequence.prototype.IEKeyCodeTable
  237. * @see $.simulate.prototype.simulateKeySequence.prototype.IEKeyCodeTable
  238. * @author julrich
  239. * @since 1.0
  240. */
  241. charToKeyCode: function(character) {
  242. var specialKeyCodeTable = $.simulate.prototype.simulateKeySequence.prototype.IEKeyCodeTable;
  243. var charCode = character.charCodeAt(0);
  244. if (charCode >= 64 && charCode <= 90 || charCode >= 48 && charCode <= 57) {
  245. // A-Z and 0-9
  246. return charCode;
  247. }
  248. else if (charCode >= 97 && charCode <= 122) {
  249. // a-z -> A-Z
  250. return character.toUpperCase().charCodeAt(0);
  251. }
  252. else if (specialKeyCodeTable[charCode] !== undefined) {
  253. return specialKeyCodeTable[charCode];
  254. }
  255. else {
  256. return charCode;
  257. }
  258. }
  259. });
  260. // add the functions publicly so they can be overridden
  261. $.simulate.prototype.simulateKeySequence.defaults = {
  262. /**
  263. * Simulates key strokes of "normal" characters (i.e. non-special sequences).
  264. * @param {Object} rng - bililiteRange object of the simulation target element.
  265. * @param {String} s - String of (simple) characters to be simulated.
  266. * @param {Object} opts - The key-sequence options.
  267. * @author Daniel Wachsstock, julrich
  268. * @since 1.0
  269. */
  270. simplechar: function (rng, s, opts){
  271. rng.text(s, 'end');
  272. if (opts.triggerKeyEvents) {
  273. for (var i =0; i < s.length; i += 1){
  274. var charCode = s.charCodeAt(i);
  275. var keyCode = $.simulate.prototype.simulateKeySequence.prototype.charToKeyCode(s.charAt(i));
  276. // a bit of cheating: rng._el is the element associated with rng.
  277. $(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: keyCode}));
  278. $(rng._el).simulate('keypress', $.extend({}, opts.eventProps,{keyCode: charCode, which: charCode, charCode: charCode}));
  279. $(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: keyCode}));
  280. }
  281. }
  282. },
  283. /**
  284. * Simulates key strokes of a curly opening bracket.
  285. * @param {Object} rng - bililiteRange object of the simulation target element.
  286. * @param {String} s - Ignored.
  287. * @param {Object} opts - The key-sequence options.
  288. * @author Daniel Wachsstock, julrich
  289. * @since 1.0
  290. */
  291. '{{}': function (rng, s, opts){
  292. $.simulate.prototype.simulateKeySequence.defaults.simplechar(rng, '{', opts);
  293. },
  294. /**
  295. * Simulates hitting the enter button.
  296. * @param {Object} rng - bililiteRange object of the simulation target element.
  297. * @param {String} s - Ignored.
  298. * @param {Object} opts - The key-sequence options.
  299. * @author Daniel Wachsstock, julrich
  300. * @since 1.0
  301. */
  302. '{enter}': function (rng, s, opts){
  303. rng.insertEOL();
  304. rng.select();
  305. if (opts.triggerKeyEvents === true) {
  306. $(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 13}));
  307. $(rng._el).simulate('keypress', $.extend({}, opts.eventProps, {keyCode: 13, which: 13, charCode: 13}));
  308. $(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 13}));
  309. }
  310. },
  311. /**
  312. * Simulates hitting the backspace button.
  313. * @param {Object} rng - bililiteRange object of the simulation target element.
  314. * @param {String} s - Ignored.
  315. * @param {Object} opts - The key-sequence options.
  316. * @author Daniel Wachsstock, julrich
  317. * @since 1.0
  318. */
  319. '{backspace}': function (rng, s, opts){
  320. var b = rng.bounds();
  321. 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
  322. rng.text('', 'end'); // delete the characters and update the selection
  323. if (opts.triggerKeyEvents === true) {
  324. $(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 8}));
  325. $(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 8}));
  326. }
  327. },
  328. /**
  329. * Simulates hitting the delete button.
  330. * @param {Object} rng - bililiteRange object of the simulation target element.
  331. * @param {String} s - Ignored.
  332. * @param {Object} opts - The key-sequence options.
  333. * @author Daniel Wachsstock, julrich
  334. * @since 1.0
  335. */
  336. '{del}': function (rng, s, opts){
  337. var b = rng.bounds();
  338. 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
  339. rng.text('', 'end'); // delete the characters and update the selection
  340. if (opts.triggerKeyEvents === true) {
  341. $(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 46}));
  342. $(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 46}));
  343. }
  344. },
  345. /**
  346. * Simulates hitting the right arrow button.
  347. * @param {Object} rng - bililiteRange object of the simulation target element.
  348. * @param {String} s - Ignored.
  349. * @param {Object} opts - The key-sequence options.
  350. * @author Daniel Wachsstock, julrich
  351. * @since 1.0
  352. */
  353. '{rightarrow}': function (rng, s, opts){
  354. var b = rng.bounds();
  355. if (b[0] === b[1]) { b[1] += 1; } // no characters selected; it's just an insertion point. Move to the right
  356. rng.bounds([b[1], b[1]]).select();
  357. if (opts.triggerKeyEvents === true) {
  358. $(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 39}));
  359. $(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 39}));
  360. }
  361. },
  362. /**
  363. * Simulates hitting the left arrow button.
  364. * @param {Object} rng - bililiteRange object of the simulation target element.
  365. * @param {String} s - Ignored.
  366. * @param {Object} opts - The key-sequence options.
  367. * @author Daniel Wachsstock, julrich
  368. * @since 1.0
  369. */
  370. '{leftarrow}': function (rng, s, opts){
  371. var b = rng.bounds();
  372. if (b[0] === b[1]) { b[0] -= 1; } // no characters selected; it's just an insertion point. Move to the left
  373. rng.bounds([b[0], b[0]]).select();
  374. if (opts.triggerKeyEvents === true) {
  375. $(rng._el).simulate('keydown', $.extend({}, opts.eventProps, {keyCode: 37}));
  376. $(rng._el).simulate('keyup', $.extend({}, opts.eventProps, {keyCode: 37}));
  377. }
  378. },
  379. /**
  380. * Selects all characters in the target element.
  381. * @param {Object} rng - bililiteRange object of the simulation target element.
  382. * @author Daniel Wachsstock, julrich
  383. * @since 1.0
  384. */
  385. '{selectall}' : function (rng){
  386. rng.bounds('all').select();
  387. }
  388. };
  389. //####### Quirk detection #######
  390. if ($.simulate.ext_disableQuirkDetection !== true) { // Fixes issue #9 (https://github.com/j-ulrich/jquery-simulate-ext/issues/9)
  391. $(document).ready(function() {
  392. // delayedSpacesInNonInputGlitchToEnd
  393. // See issues #6 (https://github.com/j-ulrich/jquery-simulate-ext/issues/6)
  394. /* Append a div to the document (bililiteRange needs the element to be in the document), simulate
  395. * a delayed sequence containing a space in the middle and check if the space moves to the end.
  396. */
  397. var $testDiv = $('<div/>').css({height: 1, width: 1, position: 'absolute', left: -1000, top: -1000}).appendTo('body');
  398. $testDiv.simulate('key-sequence', {sequence: '\xA0 \xA0', delay:1, callback: function() {
  399. $.simulate.prototype.quirks.delayedSpacesInNonInputGlitchToEnd = ($testDiv.text() === '\xA0\xA0 ');
  400. $testDiv.remove();
  401. }});
  402. });
  403. }
  404. })(jQuery);