/** * The DelayedTask class provides a convenient way to "buffer" the execution of a method, * performing `setTimeout` where a new timeout cancels the old timeout. When called, the * task will wait the specified time period before executing. If during that time period, * the task is called again, the original call will be canceled. This continues so that * the function is only called a single time for each iteration. * * This method is especially useful for things like detecting whether a user has finished * typing in a text field. An example would be performing validation on a keypress. You can * use this class to buffer the keypress events for a certain number of milliseconds, and * perform only if they stop for that amount of time. * * Using {@link Ext.util.DelayedTask} is very simple: * * //create the delayed task instance with our callback * var task = Ext.create('Ext.util.DelayedTask', { * fn: function() { * console.log('callback!'); * } * }); * * task.delay(1500); //the callback function will now be called after 1500ms * * task.cancel(); //the callback function will never be called now, unless we call delay() again * * ## Example * * @example * //create a textfield where we can listen to text * var field = Ext.create('Ext.field.Text', { * xtype: 'textfield', * label: 'Length: 0' * }); * * //add the textfield into a fieldset * Ext.Viewport.add({ * xtype: 'formpanel', * items: [{ * xtype: 'fieldset', * items: [field], * instructions: 'Type into the field and watch the count go up after 500ms.' * }] * }); * * //create our delayed task with a function that returns the fields length as the fields label * var task = Ext.create('Ext.util.DelayedTask', function() { * field.setLabel('Length: ' + field.getValue().length); * }); * * // Wait 500ms before calling our function. If the user presses another key * // during that 500ms, it will be canceled and we'll wait another 500ms. * field.on('keyup', function() { * task.delay(500); * }); * * @constructor * The parameters to this constructor serve as defaults and are not required. * @param {Function} fn The default function to call. * @param {Object} scope The default scope (The `this` reference) in which the function is called. If * not specified, `this` will refer to the browser window. * @param {Array} args The default Array of arguments. */ Ext.define('Ext.util.DelayedTask', { config: { interval: null, delay: null, fn: null, scope: null, args: null }, constructor: function(fn, scope, args) { var config = { fn: fn, scope: scope, args: args }; this.initConfig(config); }, /** * Cancels any pending timeout and queues a new one. * @param {Number} delay The milliseconds to delay * @param {Function} newFn Overrides the original function passed when instantiated. * @param {Object} newScope Overrides the original `scope` passed when instantiated. Remember that if no scope * is specified, `this` will refer to the browser window. * @param {Array} newArgs Overrides the original `args` passed when instantiated. */ delay: function(delay, newFn, newScope, newArgs) { var me = this; //cancel any existing queued functions me.cancel(); //set all the new configurations if (Ext.isNumber(delay)) { me.setDelay(delay); } if (Ext.isFunction(newFn)) { me.setFn(newFn); } if (newScope) { me.setScope(newScope); } if (newScope) { me.setArgs(newArgs); } //create the callback method for this delayed task var call = function() { me.getFn().apply(me.getScope(), me.getArgs() || []); me.cancel(); }; me.setInterval(setInterval(call, me.getDelay())); }, /** * Cancel the last queued timeout */ cancel: function() { this.setInterval(null); }, /** * @private * Clears the old interval */ updateInterval: function(newInterval, oldInterval) { if (oldInterval) { clearInterval(oldInterval); } }, /** * @private * Changes the value into an array if it isn't one. */ applyArgs: function(config) { if (!Ext.isArray(config)) { config = [config]; } return config; } });