/** * Provides for repetitive polling of the server at distinct {@link #interval intervals}. * The initial request for data originates from the client, and then is responded to by the * server. * * Configuration for the PollingProvider can be generated by the server-side * API portion of the Ext Direct stack. * * An instance of PollingProvider may be created directly via the new keyword or by simply * specifying `type = 'polling'`. For example: * * var pollA = new Ext.direct.PollingProvider({ * type:'polling', * url: 'php/pollA.php', * }); * Ext.direct.Manager.addProvider(pollA); * pollA.disconnect(); * * Ext.direct.Manager.addProvider({ * type:'polling', * url: 'php/pollB.php', * id: 'pollB-provider' * }); * var pollB = Ext.direct.Manager.getProvider('pollB-provider'); * */Ext.define('Ext.direct.PollingProvider', { extend: 'Ext.direct.JsonProvider', alias: 'direct.pollingprovider', requires: [ 'Ext.Ajax', 'Ext.util.TaskRunner', 'Ext.direct.ExceptionEvent' ], type: 'polling', /** * @cfg {Number} [interval=3000] * How often to poll the server-side in milliseconds. Defaults to every 3 seconds. */ interval: 3000, /** * @cfg {Object} [baseParams] * An object containing properties which are to be sent as parameters on every * polling request. Note that if baseParams are set and {@link #url} parameter * is an URL string, poll requests will use POST method instead of default GET. */ /** * @cfg {String/Function} url * The url which the PollingProvider should contact with each request. This can also be * an imported Ext Direct method which will be passed baseParams as named arguments. * * @deprecated 5.1.0 Using Function `url` is deprecated, please use {@link #pollFn} instead */ /** * @cfg {String/Function} pollFn * * Ext Direct method to use for polling. If a method name is provided as a string, * the actual function will not be resolved until the first time this provider * is connected. * * The method should accept named arguments and will be passed {@link #baseParams} * if set. */ /** * @cfg {Number} [timeout] * * The timeout to use for each request. */ /** * @event beforepoll * @preventable * Fired immediately before a poll takes place. * * @param {Ext.direct.PollingProvider} this */ /** * @event poll * Fired immediately after a poll takes place. * * @param {Ext.direct.PollingProvider} this */ constructor: function(config) { var me = this; me.callParent([config]); me.pollTask = Ext.TaskManager.newTask({ run: me.runPoll, interval: me.interval, scope: me }); }, destroy: function() { this.pollTask.stop(true); this.callParent(); }, doConnect: function() { var me = this, url = me.url, pollFn = me.pollFn; // It is important that pollFn resolution happens at the time when // Provider is first connected, and not at construction time. If // pollFn is configured as a string, the API stub may not exist yet // when PollingProvider is constructed. if (pollFn && Ext.isString(pollFn)) { //<debug> var fnName = pollFn; // eslint-disable-line vars-on-top, one-var //</debug> me.pollFn = pollFn = Ext.direct.Manager.parseMethod(pollFn); //<debug> if (!Ext.isFunction(pollFn)) { Ext.raise("Cannot resolve Ext Direct API method " + fnName + " for PollingProvider"); } //</debug> } else if (Ext.isFunction(url)) { //<debug> Ext.log.warn('Using a function for url is deprecated, use pollFn instead.'); //</debug> me.pollFn = pollFn = url; me.url = url = null; } if (url || pollFn) { me.setInterval(me.interval); me.pollTask.start(); } }, doDisconnect: function() { if (this.pollTask) { this.pollTask.stop(); } }, getInterval: function() { return this.pollTask && this.pollTask.interval; }, setInterval: function(interval) { var me = this, pollTask = me.pollTask; //<debug> if (interval < 100) { Ext.raise("Attempting to configure PollProvider " + me.id + " with interval that is less than 100ms."); } //</debug> me.interval = pollTask.interval = interval; if (me.isConnected()) { pollTask.restart(interval); } }, /** * @private */ runPoll: function() { var me = this, url = me.url, pollFn = me.pollFn, baseParams = me.baseParams, args, request; if (me.fireEvent('beforepoll', me) !== false) { if (pollFn) { args = pollFn.directCfg.method.getArgs({ params: baseParams !== undefined ? baseParams : {}, callback: me.onPollFn, scope: me }); pollFn.apply(window, args); } else { request = { url: url, callback: me.onData, scope: me, params: baseParams, headers: me.getHeaders() }; if (me.timeout != null) { request.timeout = me.timeout; } me.sendAjaxRequest(request); } me.fireEvent('poll', me); } }, /** * @private */ onData: function(opt, success, response) { var me = this, i, len, events, event; if (success) { events = me.createEvents(response); for (i = 0, len = events.length; i < len; ++i) { event = events[i]; me.fireEvent('data', me, event); if (!event.status) { me.fireEvent('exception', me, event); } } } else { event = new Ext.direct.ExceptionEvent({ data: null, code: Ext.direct.Manager.exceptions.TRANSPORT, message: 'Unable to connect to the server.', xhr: response }); me.fireEvent('data', me, event); me.fireEvent('exception', me, event); } me.callParent([opt, success, response]); }, /** * @private */ onPollFn: function(result, event, success, options) { this.onData(null, success, { responseText: result }); }, inheritableStatics: { /** * @private * @static * @inheritable */ checkConfig: function(config) { // Polling provider needs either URI or pollFn return config && config.type === 'polling' && (config.url || config.pollFn); } }});