define("dijit/typematic", [ "dojo/_base/array", // array.forEach "dojo/_base/connect", // connect.connect "dojo/_base/event", // event.stop "dojo/_base/kernel", // kernel.deprecated "dojo/_base/lang", // lang.mixin, lang.hitch "dojo/on", "dojo/_base/sniff", // has("ie") "." // setting dijit.typematic global ], function(array, connect, event, kernel, lang, on, has, dijit){ // module: // dijit/typematic // summary: // These functions are used to repetitively call a user specified callback // method when a specific key or mouse click over a specific DOM node is // held down for a specific amount of time. // Only 1 such event is allowed to occur on the browser page at 1 time. var typematic = (dijit.typematic = { // summary: // These functions are used to repetitively call a user specified callback // method when a specific key or mouse click over a specific DOM node is // held down for a specific amount of time. // Only 1 such event is allowed to occur on the browser page at 1 time. _fireEventAndReload: function(){ this._timer = null; this._callback(++this._count, this._node, this._evt); // Schedule next event, timer is at most minDelay (default 10ms) to avoid // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup) this._currentTimeout = Math.max( this._currentTimeout < 0 ? this._initialDelay : (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)), this._minDelay); this._timer = setTimeout(lang.hitch(this, "_fireEventAndReload"), this._currentTimeout); }, trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start a timed, repeating callback sequence. // If already started, the function call is ignored. // This method is not normally called by the user but can be // when the normal listener code is insufficient. // evt: // key or mouse event object to pass to the user callback // _this: // pointer to the user's widget space. // node: // the DOM node object to pass the the callback function // callback: // function to call until the sequence is stopped called with 3 parameters: // count: // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped // node: // the DOM node object passed in // evt: // key or mouse event object // obj: // user space object used to uniquely identify each typematic sequence // subsequentDelay (optional): // if > 1, the number of milliseconds until the 3->n events occur // or else the fractional time multiplier for the next event's delay, default=0.9 // initialDelay (optional): // the number of milliseconds until the 2nd event occurs, default=500ms // minDelay (optional): // the maximum delay in milliseconds for event to fire, default=10ms if(obj != this._obj){ this.stop(); this._initialDelay = initialDelay || 500; this._subsequentDelay = subsequentDelay || 0.90; this._minDelay = minDelay || 10; this._obj = obj; this._evt = evt; this._node = node; this._currentTimeout = -1; this._count = -1; this._callback = lang.hitch(_this, callback); this._fireEventAndReload(); this._evt = lang.mixin({faux: true}, evt); } }, stop: function(){ // summary: // Stop an ongoing timed, repeating callback sequence. if(this._timer){ clearTimeout(this._timer); this._timer = null; } if(this._obj){ this._callback(-1, this._node, this._evt); this._obj = null; } }, addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start listening for a specific typematic key. // See also the trigger method for other parameters. // keyObject: // an object defining the key to listen for: // charOrCode: // the printable character (string) or keyCode (number) to listen for. // keyCode: // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0). // charCode: // (deprecated - use charOrCode) the charCode (number) to listen for. // ctrlKey: // desired ctrl key state to initiate the callback sequence: // - pressed (true) // - released (false) // - either (unspecified) // altKey: // same as ctrlKey but for the alt key // shiftKey: // same as ctrlKey but for the shift key // returns: // a connection handle if(keyObject.keyCode){ keyObject.charOrCode = keyObject.keyCode; kernel.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); }else if(keyObject.charCode){ keyObject.charOrCode = String.fromCharCode(keyObject.charCode); kernel.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); } var handles = [ on(node, connect._keypress, lang.hitch(this, function(evt){ if(evt.charOrCode == keyObject.charOrCode && (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) && (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) && (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){ event.stop(evt); typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay); }else if(typematic._obj == keyObject){ typematic.stop(); } })), on(node, "keyup", lang.hitch(this, function(){ if(typematic._obj == keyObject){ typematic.stop(); } })) ]; return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } }; }, addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start listening for a typematic mouse click. // See the trigger method for other parameters. // returns: // a connection handle var handles = [ on(node, "mousedown", lang.hitch(this, function(evt){ event.stop(evt); typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay); })), on(node, "mouseup", lang.hitch(this, function(evt){ if(this._obj){ event.stop(evt); } typematic.stop(); })), on(node, "mouseout", lang.hitch(this, function(evt){ event.stop(evt); typematic.stop(); })), on(node, "mousemove", lang.hitch(this, function(evt){ evt.preventDefault(); })), on(node, "dblclick", lang.hitch(this, function(evt){ event.stop(evt); if(has("ie")){ typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay); setTimeout(lang.hitch(this, typematic.stop), 50); } })) ]; return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } }; }, addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start listening for a specific typematic key and mouseclick. // This is a thin wrapper to addKeyListener and addMouseListener. // See the addMouseListener and addKeyListener methods for other parameters. // mouseNode: // the DOM node object to listen on for mouse events. // keyNode: // the DOM node object to listen on for key events. // returns: // a connection handle var handles = [ this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay), this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay) ]; return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } }; } }); return typematic; });