1. #31
    Ext User
    Join Date
    Mar 2008
    Posts
    41
    Vote Rating
    0
    jonx is on a distinguished road

      0  

    Question Can I have a sample please?

    Can I have a sample please?


    @jsakalos: this is exactly what I was looking for but unfortunately I don't have the required skills to use it. You are right when you say that it's nothing visual but this doesn't mean it's more easy for me to use You affered to provide a demo if enought people would request it. I'm pretty tall. Do you think I can count as two people requesting for a demo
    Even a simple sample would be nice. That way I could see where to refer to your code, where I shall call it to save state, to restore state. And if I may suggest a type of demo... hum, maybe you could take the portal sample and show how to save and restore the portlets columns and positions... H

  2. #32
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    379
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    OK, I'll prepare a demo but be patient please as I'm pretty busy these day (months? ) and this is not very high in my priorities...

    Thank you for nice words.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  3. #33
    Ext User
    Join Date
    Mar 2008
    Posts
    41
    Vote Rating
    0
    jonx is on a distinguished road

      0  

    Thumbs up No problem

    No problem


    Those are the rules... I fully understand...
    Thanks a lot in advance,
    Ahoj !

  4. #34
    Sencha Premium Member
    Join Date
    Oct 2007
    Location
    Germany
    Posts
    70
    Vote Rating
    0
    dyndan is on a distinguished road

      0  

    Default


    Hi jsakalos,

    thanks for your state provider, it saved me a lot of work. But before I could use it, I had to make a couple of changes cause your implementation is

    not thread-safe.

    Please see my commented changes in your code:

    Code:
    // vim: ts=4:sw=4:nu:fdc=2:nospell
    /**
     * Ext.ux.HttpProvider extension
     *
     * @author    Ing. Jozef Sakalos
     * @copyright (c) 2008, Ing. Jozef Sakalos
     * @version $Id: Ext.ux.HttpProvider.js 734 2008-02-21 16:04:24Z jozo $
     *
     * @license Ext.ux.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.
     * 
     * License details: http://www.gnu.org/licenses/lgpl.html
     */
    
    /**
     * @class Ext.ux.HttpProvider
     * @extends Ext.state.Provider
     * @constructor
     * @param {Object} config Configuration object
     */
    // {{{
    Ext.ux.HttpProvider = function(config) {
    
        this.addEvents('readsuccess', 'readfailure', 'savesuccess', 'savefailure');
    
        // call parent 
        Ext.ux.HttpProvider.superclass.constructor.call(this);
    
        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
            //Here I use an object instead of an array. (Reason will be explained)
    
            ,queue:{}
            ,queueLength:0
            //,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 = new Ext.util.DelayedTask(this.submitState, this);
        if(this.autoStart) {
            this.start();
        }
    }; // eo constructor
    // }}}
    
    Ext.extend(Ext.ux.HttpProvider, Ext.state.Provider, {
    
        // localizable texts
         saveSuccessText:'Save Success'
        ,saveFailureText:'Save Failure'
        ,readSuccessText:'Read Success'
        ,readFailureText:'Read Failure'
        ,dataErrorText:'Data Error'
    
        // {{{
        ,initState:function(state) {
            if(state instanceof Array) {
                Ext.each(state, function(item) {
                    this.state[item.name] = this.decodeValue(item.value);
                }, this);
            }
            else {
                this.state = state ? state : {};
            }
        } // eo function initState
        // }}}
        // {{{
        ,set:function(name, value) {
            if(!name) {
                return;
            }
    
            this.queueChange(name, value);
    
        } // eo function set
        // }}}
        // {{{
        ,start:function() {
            this.dt.delay(this.delay);
            this.started = true;
        } // eo function start
        // }}}
        // {{{
        ,stop:function() {
            this.dt.cancel();
            this.started = false;
        } // eo function stop
        // }}}
        // {{{
        ,queueChange:function(name, value) {
            var changed = undefined === this.state[name] || this.state[name] !== value;
            var o = {};
            var i;
            var found = false;
            if(changed) {
                o[this.paramNames.name] = name;
                o[this.paramNames.value] = this.encodeValue(value);
    
                //Using an object as queue simplifies things here:
    
                if (!this.queue[name]) this.queueLength++;
                this.queue[name]=o;
                //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;
            }
            return changed;
        } // eo function bufferChange
        // }}}
        // {{{
        ,submitState:function() {
            if(!this.dirty) {
                this.dt.delay(this.delay);
                return;
            }
            this.dt.cancel();
            
            //Copy queue (Reason will be explained)
    
            var queueCopy={};
            for (var p in this.queue) {
                if (typeof this.queue[p]=="object" && this.queue[p]!=null) {
                     queueCopy[p]=this.queue[p];
                };
            };
    
            var o = {
                 url:this.saveUrl || this.url
                ,method:this.method
                ,scope:this
                ,success:this.onSaveSuccess
                ,failure:this.onSaveFailure
                  //For later comparison purposes I pass a copy of this.queue here instead of a 
                //reference to the queue itself cause the queue possibly changes during the
                //remote server call.
    
                ,queue:this.queueCopy
                //,queue:this.queue
                ,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(this.queue);
    
            Ext.apply(o.params, params);
            Ext.Ajax.request(o);
        } // eo function submitState
        // }}}
        // {{{
        ,clear:function(name) {
            this.set(name, undefined);
        } // eo function clear
        // }}}
        // {{{
        ,onSaveSuccess:function(response, options) {
            if(this.started) {
                this.start();
            }
            var o = {};
            try {o = Ext.decode(response.responseText);}
            catch(e) {
                if(true === this.logFailure) {
                    this.log(this.saveFailureText, e, response);
                }
                return;
            }
            if(true !== o.success) {
                if(true === this.logFailure) {
                    this.log(this.saveFailureText, o, response);
                }
            }
            else {
                //If you loop over options.queue without having passed a queue copy but a 
                //reference to the queue itself (options.queue==this.queue) you possibly loop
                //over entries that were written during the time it took the server to answer the      
                //state submit.
    
                 //Ext.each(options.queue, function(item) {
    
                //Looping over my copy of queue
    
                for (var p in options.queue) {
                    var item=options.queue[p];
    
                    var name = item[this.paramNames.name];
                    var value = this.decodeValue(item[this.paramNames.value]);
    
                    //Here only these queue entries are deleted, which are found in the queue copy 
                    //created by the time the call was sent to the server.
                    //Cause I use a object as queue identifing the corresponding entry is easy.
    
                    this.queue[name]=null;
                    this.queueLength--;
    
                    if(undefined === value || null === value) {
                        Ext.ux.HttpProvider.superclass.clear.call(this, name);
                    }
                    else {
                        // parent sets value and fires event
                        Ext.ux.HttpProvider.superclass.set.call(this, name, value);
                    }
    
                };
    
                //}, this);
    
                //Throwing away the queue like this leads to all kind of strange state saving effects
                //cause by the time the server returns a state saving cycle there can be a whole
                //bunch of new entries in the queue which possibly were not sent to server yet.
                
                //this.queue = [];
                //this.dirty = false;
    
                //Instead, only if the queueLength appears to be 0 I initialise the queue  
                //and remove the dirty flag:
    
                if (this.queueLength==0) {
                    this.queue={};
                    this.dirty=false;
                }
                
    
                if(true === this.logSuccess) {
                    this.log(this.saveSuccessText, o, response);
                }
                this.fireEvent('savesuccess', this);
            }
        } // eo function onSaveSuccess
        // }}}
        // {{{
        ,onSaveFailure:function(response, options) {
            if(true === this.logFailure) {
                this.log(this.saveFailureText, response);
            }
            if(this.started) {
                this.start();
            }
            this.fireEvent('savefailure', this);
        } // eo function onSaveFailure
        // }}}
        // {{{
        ,onReadFailure:function(response, options) {
            if(true === this.logFailure) {
                this.log(this.readFailureText, response);
            }
            this.fireEvent('readfailure', this);
    
        } // eo function onReadFailure
        // }}}
        // {{{
        ,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 {
                try {data = Ext.decode(o[this.paramNames.data]);}
                catch(ex) {
                    if(true === this.logFailure) {
                        this.log(this.dataErrorText, o, response);
                    }
                    return;
                }
                if(!(data instanceof Array) && true === this.logFailure) {
                    this.log(this.dataErrorText, data, response);
                    return;
                }
                Ext.each(data, function(item) {
                    this.state[item[this.paramNames.name]] = this.decodeValue(item[this.paramNames.value]);
                }, this);
    
                //Queue changed to object
    
                this.queue={}:
    
                //this.queue = [];
    
                this.dirty = false;
                if(true === this.logSuccess) {
                    this.log(this.readSuccessText, data, response);
                }
                this.fireEvent('readsuccess', this);
            }
        } // eo function onReadSuccess
        // }}}
        //
    
        // {{{
        ,readState:function() {
            var o = {
                 url:this.readUrl || this.url
                ,method:this.method
                ,scope:this
                ,success:this.onReadSuccess
                ,failure:this.onReadFailure
                ,params:{}
            };
    
            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
        // }}}
        // {{{
        ,log:function() {
            if(console) {
                console.log.apply(console, arguments);
            }
        } // eo log
        // }}}
    
    }); // eo extend
    
    // eof
    dyndan

  5. #35
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    379
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    Thanks for pointing out.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  6. #36
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    379
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    I was looking a bit into it (not very high on my priority list) and your implementation changes the server api as you haven't done anything with submitState routine. Server expects that it will receive array of objects and after your changes it will receive nested objects keyed by name.

    I'll take another look at it, as you're right that it is not thread-safe, to find out an implementation that would keep api.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  7. #37
    Sencha Premium Member
    Join Date
    Oct 2007
    Location
    Germany
    Posts
    70
    Vote Rating
    0
    dyndan is on a distinguished road

      0  

    Default


    You're right,

    I forgot this part cause I use a different server implementation which requires that every state is postet as "param". The server then recognises the relevant arguments by naming convention.

    I did not want to mix these changes in here.

    To solve the problem and keep the server api, the following line of code

    Code:
    params[this.paramNames.data] = Ext.encode(this.queue);
    has to be replaced as follows:


    Code:
    var a = [];
    var aIdx=0;
    for (var p in this.queue) a[aIdx++]= this.queue[p];
    params[this.paramNames.data] = Ext.encode(a);
    dyndan
    Last edited by dyndan; 17 Mar 2008 at 5:01 AM. Reason: spelling

  8. #38
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    379
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    Hi dyndan,

    would you please take a look at the code now? I found a spare hour so I fixed it to be thread-safe. The logic is that I'm optimistic in the first place so I reset dirty flag before submitting. In callback, if the flag is still reset, I just clear old queue (this.queue = [] and I do a special processing (deleting unchanged entries) only if the queue dirtied meanwhile.

    I guess this is of best performance as complex part of the code (finding an clearing unchanged entries) is executed only if needed. Also, server API stays same.

    I haven't had an opportunity to thoroughly check the new logic so all your inputs are welcome.

    Thanks.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  9. #39
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    379
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    Quote Originally Posted by galdaka View Post
    Sound interesting!!

    Will be a demo in future?

    Thanks in advance,
    There is no demo dedicated to HttpProvider but http://rowactions.extjs.eu uses HttpProvider to keep state of window and grid.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  10. #40
    Ext User
    Join Date
    Mar 2008
    Posts
    41
    Vote Rating
    0
    jonx is on a distinguished road

      0  

    Thumbs up


    Quote Originally Posted by jsakalos View Post
    There is demo dedicated to HttpProvider but http://rowactions.extjs.eu uses HttpProvider to keep state of window and grid.
    Hello jsakalos
    thank you for providing a demo. I have still not finished adapting it to my code as I'm using asp.net and I'm trying to persist the state of the portal sample. I made some progresses but this still needs work

    Thanks again...