typematic.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. define("dijit/typematic", [
  2. "dojo/_base/array", // array.forEach
  3. "dojo/_base/connect", // connect.connect
  4. "dojo/_base/event", // event.stop
  5. "dojo/_base/kernel", // kernel.deprecated
  6. "dojo/_base/lang", // lang.mixin, lang.hitch
  7. "dojo/on",
  8. "dojo/_base/sniff", // has("ie")
  9. "." // setting dijit.typematic global
  10. ], function(array, connect, event, kernel, lang, on, has, dijit){
  11. // module:
  12. // dijit/typematic
  13. // summary:
  14. // These functions are used to repetitively call a user specified callback
  15. // method when a specific key or mouse click over a specific DOM node is
  16. // held down for a specific amount of time.
  17. // Only 1 such event is allowed to occur on the browser page at 1 time.
  18. var typematic = (dijit.typematic = {
  19. // summary:
  20. // These functions are used to repetitively call a user specified callback
  21. // method when a specific key or mouse click over a specific DOM node is
  22. // held down for a specific amount of time.
  23. // Only 1 such event is allowed to occur on the browser page at 1 time.
  24. _fireEventAndReload: function(){
  25. this._timer = null;
  26. this._callback(++this._count, this._node, this._evt);
  27. // Schedule next event, timer is at most minDelay (default 10ms) to avoid
  28. // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup)
  29. this._currentTimeout = Math.max(
  30. this._currentTimeout < 0 ? this._initialDelay :
  31. (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)),
  32. this._minDelay);
  33. this._timer = setTimeout(lang.hitch(this, "_fireEventAndReload"), this._currentTimeout);
  34. },
  35. trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  36. // summary:
  37. // Start a timed, repeating callback sequence.
  38. // If already started, the function call is ignored.
  39. // This method is not normally called by the user but can be
  40. // when the normal listener code is insufficient.
  41. // evt:
  42. // key or mouse event object to pass to the user callback
  43. // _this:
  44. // pointer to the user's widget space.
  45. // node:
  46. // the DOM node object to pass the the callback function
  47. // callback:
  48. // function to call until the sequence is stopped called with 3 parameters:
  49. // count:
  50. // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped
  51. // node:
  52. // the DOM node object passed in
  53. // evt:
  54. // key or mouse event object
  55. // obj:
  56. // user space object used to uniquely identify each typematic sequence
  57. // subsequentDelay (optional):
  58. // if > 1, the number of milliseconds until the 3->n events occur
  59. // or else the fractional time multiplier for the next event's delay, default=0.9
  60. // initialDelay (optional):
  61. // the number of milliseconds until the 2nd event occurs, default=500ms
  62. // minDelay (optional):
  63. // the maximum delay in milliseconds for event to fire, default=10ms
  64. if(obj != this._obj){
  65. this.stop();
  66. this._initialDelay = initialDelay || 500;
  67. this._subsequentDelay = subsequentDelay || 0.90;
  68. this._minDelay = minDelay || 10;
  69. this._obj = obj;
  70. this._evt = evt;
  71. this._node = node;
  72. this._currentTimeout = -1;
  73. this._count = -1;
  74. this._callback = lang.hitch(_this, callback);
  75. this._fireEventAndReload();
  76. this._evt = lang.mixin({faux: true}, evt);
  77. }
  78. },
  79. stop: function(){
  80. // summary:
  81. // Stop an ongoing timed, repeating callback sequence.
  82. if(this._timer){
  83. clearTimeout(this._timer);
  84. this._timer = null;
  85. }
  86. if(this._obj){
  87. this._callback(-1, this._node, this._evt);
  88. this._obj = null;
  89. }
  90. },
  91. addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  92. // summary:
  93. // Start listening for a specific typematic key.
  94. // See also the trigger method for other parameters.
  95. // keyObject:
  96. // an object defining the key to listen for:
  97. // charOrCode:
  98. // the printable character (string) or keyCode (number) to listen for.
  99. // keyCode:
  100. // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
  101. // charCode:
  102. // (deprecated - use charOrCode) the charCode (number) to listen for.
  103. // ctrlKey:
  104. // desired ctrl key state to initiate the callback sequence:
  105. // - pressed (true)
  106. // - released (false)
  107. // - either (unspecified)
  108. // altKey:
  109. // same as ctrlKey but for the alt key
  110. // shiftKey:
  111. // same as ctrlKey but for the shift key
  112. // returns:
  113. // a connection handle
  114. if(keyObject.keyCode){
  115. keyObject.charOrCode = keyObject.keyCode;
  116. kernel.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
  117. }else if(keyObject.charCode){
  118. keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
  119. kernel.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
  120. }
  121. var handles = [
  122. on(node, connect._keypress, lang.hitch(this, function(evt){
  123. if(evt.charOrCode == keyObject.charOrCode &&
  124. (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
  125. (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) &&
  126. (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey
  127. (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){
  128. event.stop(evt);
  129. typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay);
  130. }else if(typematic._obj == keyObject){
  131. typematic.stop();
  132. }
  133. })),
  134. on(node, "keyup", lang.hitch(this, function(){
  135. if(typematic._obj == keyObject){
  136. typematic.stop();
  137. }
  138. }))
  139. ];
  140. return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } };
  141. },
  142. addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  143. // summary:
  144. // Start listening for a typematic mouse click.
  145. // See the trigger method for other parameters.
  146. // returns:
  147. // a connection handle
  148. var handles = [
  149. on(node, "mousedown", lang.hitch(this, function(evt){
  150. event.stop(evt);
  151. typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
  152. })),
  153. on(node, "mouseup", lang.hitch(this, function(evt){
  154. if(this._obj){
  155. event.stop(evt);
  156. }
  157. typematic.stop();
  158. })),
  159. on(node, "mouseout", lang.hitch(this, function(evt){
  160. event.stop(evt);
  161. typematic.stop();
  162. })),
  163. on(node, "mousemove", lang.hitch(this, function(evt){
  164. evt.preventDefault();
  165. })),
  166. on(node, "dblclick", lang.hitch(this, function(evt){
  167. event.stop(evt);
  168. if(has("ie") < 9){
  169. typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
  170. setTimeout(lang.hitch(this, typematic.stop), 50);
  171. }
  172. }))
  173. ];
  174. return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } };
  175. },
  176. addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  177. // summary:
  178. // Start listening for a specific typematic key and mouseclick.
  179. // This is a thin wrapper to addKeyListener and addMouseListener.
  180. // See the addMouseListener and addKeyListener methods for other parameters.
  181. // mouseNode:
  182. // the DOM node object to listen on for mouse events.
  183. // keyNode:
  184. // the DOM node object to listen on for key events.
  185. // returns:
  186. // a connection handle
  187. var handles = [
  188. this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay),
  189. this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay)
  190. ];
  191. return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } };
  192. }
  193. });
  194. return typematic;
  195. });