PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/assets/plugins/timepicker/spec/js/libs/autotype/index.js

https://gitlab.com/jjgomez/Navicu
JavaScript | 283 lines | 215 code | 18 blank | 50 comment | 49 complexity | f97a18bfaeeb9eff4e7f348d0b68226c MD5 | raw file
  1. /**
  2. * jQuery.autotype - Simple, accurate, typing simulation for jQuery
  3. *
  4. * version 0.5.0
  5. *
  6. * http://michaelmonteleone.net/projects/autotype
  7. * http://github.com/mmonteleone/jquery.autotype
  8. *
  9. * Copyright (c) 2009 Michael Monteleone
  10. * Licensed under terms of the MIT License (README.markdown)
  11. */
  12. (function($){
  13. // code type constants
  14. var CHARACTER = 1,
  15. NON_CHARACTER = 2,
  16. MODIFIER_BEGIN = 3,
  17. MODIFIER_END = 4,
  18. isNullOrEmpty = function(val) { return val === null || val.length === 0; },
  19. isUpper = function(char) { return char.toUpperCase() === char; },
  20. isLower = function(char) { return char.toLowerCase() === char; },
  21. areDifferentlyCased = function(char1,char2) {
  22. return (isUpper(char1) && isLower(char2)) ||
  23. (isLower(char1) && isUpper(char2));
  24. },
  25. convertCase = function(char) {
  26. return isUpper(char) ? char.toLowerCase() : char.toUpperCase();
  27. },
  28. parseCodes = function(value, codeMap) {
  29. // buffer to hold a collection of key/char code pairs corresponding to input string value
  30. var codes = [],
  31. // buffer to hold the name of a control key as it's being parsed
  32. definingControlKey = false,
  33. // hold a collection of currently pushed modifier keys
  34. activeModifiers = {
  35. alt: false,
  36. meta: false,
  37. shift: false,
  38. ctrl: false
  39. },
  40. explicitModifiers = $.extend({}, activeModifiers),
  41. // buffer to hold construction of current control key
  42. currentControlKey = '',
  43. previousChar = '',
  44. pushCode = function(opts) {
  45. codes.push($.extend({}, opts, activeModifiers));
  46. },
  47. pushModifierBeginCode = function(modifierName) {
  48. activeModifiers[modifierName] = true;
  49. pushCode({
  50. keyCode: codeMap[modifierName],
  51. charCode: 0,
  52. char: '',
  53. type: MODIFIER_BEGIN
  54. });
  55. },
  56. pushModifierEndCode = function(modifierName) {
  57. activeModifiers[modifierName] = false;
  58. pushCode({
  59. keyCode: codeMap[modifierName],
  60. charCode: 0,
  61. char: '',
  62. type: MODIFIER_END
  63. });
  64. };
  65. for(var i=0;i<value.length;i++) {
  66. // if the character is about to define a control key
  67. if(!definingControlKey &&
  68. i <= value.length - 5 &&
  69. value.charAt(i) === '{' &&
  70. value.charAt(i+1) === '{')
  71. {
  72. // skip the next "{"
  73. i++;
  74. definingControlKey = true;
  75. }
  76. // if the character is about to end definition of control key
  77. else if (definingControlKey &&
  78. i <= value.length - 2 &&
  79. value.charAt(i) === '}' &&
  80. value.charAt(i+1) === '}')
  81. {
  82. // skip the next "}"
  83. i++;
  84. // check if this key is a modifier-opener (is a ctrl,alt,del,shift)
  85. if(activeModifiers[currentControlKey] !== undefined)
  86. {
  87. explicitModifiers[currentControlKey] = true;
  88. pushModifierBeginCode(currentControlKey);
  89. }
  90. // check if this key is a modifier-closer (is a /ctrl,/alt,/del,.shift)
  91. else if(activeModifiers[currentControlKey.substring(1)] !== undefined)
  92. {
  93. explicitModifiers[currentControlKey] = false;
  94. pushModifierEndCode(currentControlKey.substring(1));
  95. }
  96. // otherwise is some other kind of non-modifier control key
  97. else
  98. {
  99. pushCode({
  100. keyCode: codeMap[currentControlKey],
  101. charCode: 0,
  102. char: '',
  103. type: NON_CHARACTER,
  104. controlKeyName: currentControlKey
  105. });
  106. }
  107. definingControlKey = false;
  108. currentControlKey = '';
  109. }
  110. // currently defining control key
  111. else if (definingControlKey)
  112. {
  113. currentControlKey += value.charAt(i);
  114. }
  115. // otherwise is just a text character
  116. else
  117. {
  118. var character = value.charAt(i);
  119. // check for any implicitly changing of cases, and register presses/releases
  120. // of the shift key in accord with them.
  121. if(
  122. (!isNullOrEmpty(previousChar) && areDifferentlyCased(previousChar, character)) ||
  123. (isNullOrEmpty(previousChar) && isUpper(character))
  124. )
  125. {
  126. if(isUpper(character) && !activeModifiers.shift) {
  127. pushModifierBeginCode("shift");
  128. } else if (isLower(character) && activeModifiers.shift && !explicitModifiers.shift){
  129. pushModifierEndCode("shift");
  130. }
  131. }
  132. // modify the current character if there are active modifiers
  133. if((activeModifiers.shift && isLower(character)) ||
  134. (!activeModifiers.shift && isUpper(character))) {
  135. // shift converts case
  136. character = convertCase(character);
  137. }
  138. var code = {
  139. // if can't identify a keycode, just fudge with the char code.
  140. // nope, this isn't ideal by any means.
  141. keyCode: codeMap[character] || character.charCodeAt(0),
  142. charCode: character.charCodeAt(0),
  143. char: character,
  144. type: CHARACTER
  145. };
  146. // modify the current character if there are active modifiers
  147. if(activeModifiers.alt ||
  148. activeModifiers.ctrl ||
  149. activeModifiers.meta) {
  150. // alt, ctrl, meta make it so nothing is typed
  151. code.char = '';
  152. }
  153. pushCode(code);
  154. if(code.char !== '') { previousChar = code.char; }
  155. }
  156. }
  157. return codes;
  158. },
  159. triggerCodeOnField = function(code, field) {
  160. // build up base content that every event should contain
  161. // with information about whether certain chord keys are
  162. // simulated as being pressed
  163. var evnt = {
  164. altKey: code.alt,
  165. metaKey: code.meta,
  166. shiftKey: code.shift,
  167. ctrlKey: code.ctrl
  168. };
  169. // build out 3 event instances for all the steps of a key entry
  170. var keyDownEvent = $.extend($.Event(), evnt, {type:'keydown', keyCode: code.keyCode, charCode: 0, which: code.keyCode});
  171. var keyPressEvent = $.extend($.Event(), evnt, {type:'keypress', keyCode: 0, charCode: code.charCode, which: code.charCode || code.keyCode});
  172. var keyUpEvent = $.extend($.Event(), evnt, {type:'keyup', keyCode: code.keyCode, charCode: 0, which: code.keyCode});
  173. // go ahead and trigger the first 2 (down and press)
  174. // a keyup of a modifier shouldn't also re-trigger a keydown
  175. if(code.type !== MODIFIER_END) {
  176. field.trigger(keyDownEvent);
  177. }
  178. // modifier keys don't have a keypress event, only down or up
  179. if(code.type !== MODIFIER_BEGIN && code.type !== MODIFIER_END) {
  180. field.trigger(keyPressEvent);
  181. }
  182. // only actually add the new character to the input if the keydown or keypress events
  183. // weren't cancelled by any consuming event handlers
  184. if(!keyDownEvent.isPropagationStopped() &&
  185. !keyPressEvent.isPropagationStopped()) {
  186. if(code.type === NON_CHARACTER) {
  187. switch(code.controlKeyName) {
  188. case 'enter':
  189. field.val(field.val() + "\n");
  190. break;
  191. case 'back':
  192. field.val(field.val().substring(0,field.val().length-1));
  193. break;
  194. }
  195. } else {
  196. field.val(field.val() + code.char);
  197. }
  198. }
  199. // then also trigger the 3rd event (up)
  200. // a keydown of a modifier shouldn't also trigger a keyup until coded
  201. if(code.type !== MODIFIER_BEGIN) {
  202. field.trigger(keyUpEvent);
  203. }
  204. },
  205. triggerCodesOnField = function(codes, field, delay, global) {
  206. if(delay > 0) {
  207. codes = codes.reverse();
  208. var keyInterval = global.setInterval(function(){
  209. var code = codes.pop();
  210. triggerCodeOnField(code, field);
  211. if(codes.length === 0) {
  212. global.clearInterval(keyInterval);
  213. field.trigger('autotyped');
  214. }
  215. }, delay);
  216. } else {
  217. $.each(codes,function(){
  218. triggerCodeOnField(this, field);
  219. });
  220. field.trigger('autotyped');
  221. }
  222. };
  223. $.fn.autotype = function(value, options) {
  224. if(value === undefined || value === null) { throw("Value is required by jQuery.autotype plugin"); }
  225. var settings = $.extend({}, $.fn.autotype.defaults, options);
  226. // 1st Pass
  227. // step through the input string and convert it into
  228. // a logical sequence of steps, key, and charcodes to apply to the inputs
  229. var codes = parseCodes(value, settings.keyCodes[settings.keyBoard]);
  230. // 2nd Pass
  231. // Run the translated codes against each input through a realistic
  232. // and cancelable series of key down/press/up events
  233. return this.each(function(){ triggerCodesOnField(codes, $(this), settings.delay, settings.global); });
  234. };
  235. $.fn.autotype.defaults = {
  236. version: '0.5.0',
  237. keyBoard: 'enUs',
  238. delay: 0,
  239. global: window,
  240. keyCodes: {
  241. enUs: { 'back':8,'ins':45,'del':46,'enter':13,'shift':16,'ctrl':17,'meta':224,
  242. 'alt':18,'pause':19,'caps':20,'esc':27,'pgup':33,'pgdn':34,
  243. 'end':35,'home':36,'left':37,'up':38,'right':39,'down':40,
  244. 'printscr':44,'num0':96,'num1':97,'num2':98,'num3':99,'num4':100,
  245. 'num5':101,'num6':102,'num7':103,'num8':104,'num9':105,
  246. 'multiply':106,'add':107,'subtract':109,'decimal':110,
  247. 'divide':111,'f1':112,'f2':113,'f3':114,'f4':115,'f5':116,
  248. 'f6':117,'f7':118,'f8':119,'f9':120,'f10':121,'f11':122,
  249. 'f12':123,'numlock':144,'scrolllock':145,' ':9,' ':32,
  250. 'tab':9,'space':32,'0':48,'1':49,'2':50,'3':51,'4':52,
  251. '5':53,'6':54,'7':55,'8':56,'9':57,')':48,'!':49,'@':50,
  252. '#':51,'$':52,'%':53,'^':54,'&':55,'*':56,'(':57,';':186,
  253. '=':187,',':188,'-':189,'.':190,'/':191,'[':219,'\\':220,
  254. ']':221,"'":222,':':186,'+':187,'<':188,'_':189,'>':190,
  255. '?':191,'{':219,'|':220,'}':221,'"':222,'a':65,'b':66,'c':67,
  256. 'd':68,'e':69,'f':70,'g':71,'h':72,'i':73,'j':74,'k':75,
  257. 'l':76,'m':77,'n':78,'o':79,'p':80,'q':81,'r':82,'s':83,
  258. 't':84,'u':85,'v':86,'w':87,'x':88,'y':89,'z':90,'A':65,
  259. 'B':66,'C':67,'D':68,'E':69,'F':70,'G':71,'H':72,'I':73,
  260. 'J':74,'K':75,'L':76,'M':77,'N':78,'O':79,'P':80,'Q':81,
  261. 'R':82,'S':83,'T':84,'U':85,'V':86,'W':87,'X':88,'Y':89,'Z':90 }
  262. }
  263. };
  264. })(jQuery);