/* * GxUI Library 2.0.1 * Copyright (c) 2009, Artech * All rights reserved. * * GxUI Library is freely distributable under the terms of the BSD license. * */ // vim: ts=4:sw=4:nu:fdc=2:nospell /*global Ext, console */ /** * @class Ext.ux.state.HttpProvider * @extends Ext.state.Provider * * Buffering state provider that sends and receives state information to/from server * * @author Ing. Jozef Sak�lo� * @copyright (c) 2008, Ing. Jozef Sak�lo� * @version 1.2 * @revision $Id: Ext.ux.state.HttpProvider.js 728 2009-06-16 16:31:16Z jozo $ * * @license Ext.ux.state.HttpProvider is licensed under the terms of * the Open Source LGPL 3.0 license. Commercial use is permitted to the extent * that the code/component(s) do NOT become part of another Open Source or Commercially * licensed development library or toolkit without explicit permission. * * <p>License details: <a href="http://www.gnu.org/licenses/lgpl.html" * target="_blank">http://www.gnu.org/licenses/lgpl.html</a></p> * * @forum 24970 * @demo http://cellactions.extjs.eu * * @donate * <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank"> * <input type="hidden" name="cmd" value="_s-xclick"> * <input type="hidden" name="hosted_button_id" value="3430419"> * <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" * border="0" name="submit" alt="PayPal - The safer, easier way to pay online."> * <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"> * </form> * @ignore */ Ext.define('Ext.ux.state.HttpProvider', { extend: 'Ext.state.Provider' /** * @cfg {Boolean} async * Force the request to be syncronous by setting to false. * Default is true. */ , async: true /** * @cfg {Boolean} flushCache * Indicates if the state data should be flushed before loading new records. * False indicates that new records returned from a read request will be appended to the cache. * Defaults to false. */ , flushCache: false // localizable texts , saveSuccessText: 'Save Success' , saveFailureText: 'Save Failure' , readSuccessText: 'Read Success' , readFailureText: 'Read Failure' , dataErrorText: 'Data Error' //private , constructor: function (config) { this.addEvents( /** * @event readsuccess * Fires after state has been successfully received from server and restored * @param {HttpProvider} this */ 'readsuccess' /** * @event readfailure * Fires in the case of an error when attempting to read state from server * @param {HttpProvider} this */ , 'readfailure' /** * @event savesuccess * Fires after the state has been successfully saved to server * @param {HttpProvider} this */ , 'savesuccess' /** * @event savefailure * Fires in the case of an error when attempting to save state to the server * @param {HttpProvider} this */ , 'savefailure' ); this.callParent(arguments); Ext.apply(this, config, { // defaults delay: 750 // buffer changes for 750 ms , dirty: false , started: false , autoStart: true , autoRead: true , user: 'user' , id: 1 , session: 'session' , logFailure: false , logSuccess: false , queue: [] , url: '.' , readUrl: undefined , saveUrl: undefined , method: 'POST' , saveBaseParams: {} , readBaseParams: {} , paramNames: { id: 'id' , name: 'name' , value: 'value' , user: 'user' , session: 'session' , data: 'data' } }); // eo apply if (this.autoRead) { this.readState(); } this.dt = Ext.create('Ext.util.DelayedTask', this.submitState, this); if (this.autoStart) { this.start(); } } //eof constructor // {{{ /** * Initializes state from the passed state object or array. * This method can be called early during page load having the state Array/Object * retrieved from database by server. * @param {Array/Object} state State to initialize state manager with */ , initState: function (state) { if (state instanceof Array) { Ext.each(state, function (item) { this.state[item.name] = this.decodeValue(item[this.paramNames.value]); }, this); } else { this.state = state ? state : {}; } } // eo function initState // }}} // {{{ /** * Sets the passed state variable name to the passed value and queues the change * @param {String} name Name of the state variable * @param {Mixed} value Value of the state variable */ , set: function (name, value) { if (!name) { return; } this.queueChange(name, value); } // eo function set // }}} // {{{ /** * Starts submitting state changes to server */ , start: function () { this.dt.delay(this.delay); this.started = true; } // eo function start // }}} // {{{ /** * Stops submitting state changes */ , stop: function () { this.dt.cancel(); this.started = false; } // eo function stop // }}} // {{{ /** * private, queues the state change if the value has changed */ , queueChange: function (name, value) { var o = {} , i = 0 , found = false // see http://extjs.com/forum/showthread.php?p=344233 , oldValue = this.state[name] , newValue , changed; for (; i < this.queue.length; i++) { if (this.queue[i].name === name) { oldValue = this.decodeValue(this.queue[i].value); } } //changed = undefined === oldValue || oldValue !== value; //http://www.sencha.com/forum/showthread.php?24970-Buffering-Http-State-Provider&p=581091&viewfull=1#post581091 changed = undefined === oldValue || this.encodeValue(oldValue) !== this.encodeValue(value); if (changed) { newValue = this.encodeValue(value); o[this.paramNames.name] = name; o[this.paramNames.value] = newValue; for (i = 0; i < this.queue.length; i++) { if (this.queue[i].name === o.name) { this.queue[i] = o; found = true; } } if (false === found) { this.queue.push(o); } this.dirty = true; } if (this.started) { this.start(); } return changed; } // eo function bufferChange // }}} // {{{ /** * private, submits state to server by asynchronous Ajax request */ , submitState: function () { if (!this.dirty || Ext.isEmpty(this.queue)) { this.dt.delay(this.delay); return; } this.dt.cancel(); var o = { url: this.saveUrl || this.url , method: this.method , scope: this , success: this.onSaveSuccess , failure: this.onSaveFailure //,queue:Ext.ux.util.clone(this.queue) , queueCopy: Ext.Array.clone(this.queue) //don't use 'queue', conflicts with ext-basex QueueManager , params: {} }; var params = Ext.apply({}, this.saveBaseParams); params[this.paramNames.id] = this.id; params[this.paramNames.user] = this.user; params[this.paramNames.session] = this.session; params[this.paramNames.data] = Ext.encode(o.queueCopy); Ext.apply(o.params, params); // be optimistic this.dirty = false; Ext.Ajax.request(o); } // eo function submitState // }}} // {{{ /** * Clears the state variable * @param {String} name Name of the variable to clear */ , clear: function (name) { this.set(name, undefined); } // eo function clear // }}} // {{{ /** * private, save success callback */ , onSaveSuccess: function (response, options) { var o = {}; try { o = Ext.decode(response.responseText); } catch (e) { if (true === this.logFailure) { this.log(this.saveFailureText, e, response); } this.dirty = true; return; } if (true !== o.success) { if (true === this.logFailure) { this.log(this.saveFailureText, o, response); } this.dirty = true; } else { Ext.each(options.queueCopy, function (item) { if (!item) { return; } var name = item[this.paramNames.name]; var value = this.decodeValue(item[this.paramNames.value]); if (undefined === value || null === value) { Ext.ux.state.HttpProvider.superclass.clear.call(this, name); } else { // parent sets value and fires event Ext.ux.state.HttpProvider.superclass.set.call(this, name, value); } }, this); if (false === this.dirty) { this.queue = []; } else { var i, j, found; for (i = 0; i < options.queueCopy.length; i++) { found = false; for (j = 0; j < this.queue.length; j++) { if (options.queueCopy[i].name === this.queue[j].name) { found = true; break; } } if (true === found && this.encodeValue(options.queueCopy[i].value) === this.encodeValue(this.queue[j].value)) { Ext.Array.remove(this.queue, this.queue[j]); } } } if (true === this.logSuccess) { this.log(this.saveSuccessText, o, response); } this.fireEvent('savesuccess', this); } } // eo function onSaveSuccess // }}} // {{{ /** * private, save failure callback */ , onSaveFailure: function (response, options) { if (true === this.logFailure) { this.log(this.saveFailureText, response); } this.dirty = true; this.fireEvent('savefailure', this); } // eo function onSaveFailure // }}} // {{{ /** * private, read state callback */ , onReadFailure: function (response, options) { if (true === this.logFailure) { this.log(this.readFailureText, response); } this.fireEvent('readfailure', this); } // eo function onReadFailure // }}} // {{{ /** * private, read success callback */ , onReadSuccess: function (response, options) { var o = {}, data; try { o = Ext.decode(response.responseText); } catch (e) { if (true === this.logFailure) { this.log(this.readFailureText, e, response); } return; } if (true !== o.success) { if (true === this.logFailure) { this.log(this.readFailureText, o, response); } } else { data = o[this.paramNames.data]; if (!(data instanceof Array) && true === this.logFailure) { this.log(this.dataErrorText, data, response); return; } //flush cache if not appending if (this.flushCache) { this.state = {}; } Ext.each(data, function (item) { this.state[item[this.paramNames.name]] = this.decodeValue(item[this.paramNames.value]); }, this); this.queue = []; this.dirty = false; if (true === this.logSuccess) { this.log(this.readSuccessText, data, response); } this.fireEvent('readsuccess', this); } } // eo function onReadSuccess // }}} // {{{ /** * Reads saved state from server by sending asynchronous Ajax request and processing the response */ , readState: function () { var o = { url: this.readUrl || this.url , method: this.method , scope: this , success: this.onReadSuccess , failure: this.onReadFailure , params: {} , async: this.async }; var params = Ext.apply({}, this.readBaseParams); params[this.paramNames.id] = this.id; params[this.paramNames.user] = this.user; params[this.paramNames.session] = this.session; Ext.apply(o.params, params); Ext.Ajax.request(o); } // eo function readState // }}} // {{{ /** * private, logs errors or successes */ , log: function () { if (console) { console.log.apply(console, arguments); } } // eo log // }}} }); // eo extend // eof