Page 1 of 3 123 LastLast
Results 1 to 10 of 25

Thread: [FIXED][3.0rc3] Cannot use native JSON without patching ExtJS

    You found a bug! We've classified it as a bug in our system. We encourage you to continue the discussion and to find an acceptable workaround while we work on a permanent fix.
  1. #1
    Ext JS Premium Member
    Join Date
    Feb 2009
    Posts
    57
    Vote Rating
    0
      0  

    Default [FIXED] [3.0rc3] Cannot use native JSON without patching ExtJS

    The way Ext.util.JSON is declared makes it useless to set Ext.USE_NATIVE_JSON to true (and expect it to have an effect) after Ext.util.JSON has been defined:

    Code:
    Ext.util.JSON = new (function(){
        var useHasOwn = !!{}.hasOwnProperty,
            isNative = Ext.USE_NATIVE_JSON && JSON && JSON.toString() == '[object JSON]';
    
        [...]
    
        this.encode = isNative ? JSON.stringify : function(o){[...]};
    
        [...]
    
        this.decode = isNative ? JSON.parse : function(json){
            return eval("(" + json + ')');    
        };
    })();
    The documentation of Ext.USE_NATIVE_JSON makes no notice of this limitation, so I guess this is a bug.

    Best regards,
    Papandreou

  2. #2
    Sencha Premium User evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    19,215
    Vote Rating
    1008
      0  

    Default

    I don't know how common it would be for people to be regularly changing the json encoding/decode inside an application. The reason it's done that way is to stop repeated calculation over and over when 99.9% of the time it will be the same.
    Twitter - @evantrimboli
    Former Sencha framework engineer, available for consulting.
    As of 2017-09-22 I am not employed by Sencha, all subsequent posts are my own and do not represent Sencha in any way.

  3. #3
    Sencha User Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    132
      0  

    Default

    The docs should mention that you need to set Ext.USE_NATIVE_JSON before including ext-all.js (in contrast to any other global Ext setting).

    Code:
    <script type="text/javascript" src="adapter/ext/ext-base.js"></script>
    <script type="text/javascript">
    Ext.USE_NATIVE_JSON = true;
    </script>
    <script type="text/javascript" src="ext-all.js"></script>
    ps. Shouldn't USE_NATIVE_JSON be the default?
    Code:
    var useHasOwn = !!{}.hasOwnProperty,
        isNative = (Ext.USE_NATIVE_JSON !== false) && JSON && JSON.toString() == '[object JSON]';

  4. #4
    Ext JS Premium Member
    Join Date
    Feb 2009
    Posts
    57
    Vote Rating
    0
      0  

    Default

    Quote Originally Posted by evant View Post
    I don't know how common it would be for people to be regularly changing the json encoding/decode inside an application. The reason it's done that way is to stop repeated calculation over and over when 99.9% of the time it will be the same.
    I appreciate the efficiency of the singleton = new (function(){[...]})(); construct in cases like this. I'm just looking for a way to enable the use of the native JSON object that doesn't involve patching the ExtJS code or shoehorning a script in between the inclusions of ext-base and ext-all (that would seem rather inelegant).

    And you're right -- of course I don't need to be able to change my mind afterwards.

    Best regards,
    Papandreou
    Last edited by papandreou; 2 Jul 2009 at 4:16 AM. Reason: typo

  5. #5
    Sencha Premium User evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    19,215
    Vote Rating
    1008
      0  

    Default

    @Condor

    No, for a few reasons, mainly that native JSON encode/decode require property values to be quoted, which I know isn't necessarily common amongst users.

    @papandreou

    You make a good point, we'll look into it.
    Twitter - @evantrimboli
    Former Sencha framework engineer, available for consulting.
    As of 2017-09-22 I am not employed by Sencha, all subsequent posts are my own and do not represent Sencha in any way.

  6. #6
    Sencha User mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
      0  

    Default

    how about changing isNative, JSON.encode and JSON.decode to functions which set themselves up on initial access?
    Code:
    Ext.util.JSON = new (function(){
        var useHasOwn = !!{}.hasOwnProperty,
            isNative = function() {
                var native;
    
                return function() {
                    if (native === null) {
                        native = Ext.USE_NATIVE_JSON && JSON && JSON.toString() == '[object JSON]';
                    }
            
                    return native;
                };
            }();
    
        // ... SNIP
    
        this.encode = function() {
            var ec;
            
            return function(obj) {
                if (!ec) {
                    // setup encoding function on first access
                    ec = isNative() ? JSON.stringify : function(o) { /* ... SNIP ... */ };
                }
                
                return ec(obj);
            };
        }();
    
        // ... SNIP
    
        this.decode = function() {
            var dc;
            
            return function(str) {
                if (!dc) {
                    // setup decoding function on first access
                    dc = isNative() ? JSON.parse : function(json) {
                        return eval("(" + json + ')');    
                    };
                }
                
                return dc(str);
            };
        }();
    })();
    Last edited by mystix; 2 Jul 2009 at 4:55 AM. Reason: edit -- i was braindead for a moment

  7. #7
    Ext JS Premium Member
    Join Date
    Feb 2009
    Posts
    57
    Vote Rating
    0
      0  

    Default

    @mystix: Did you mean like this?

    Code:
    Ext.util.JSON = new (function() {
        var useHasOwn = !!{}.hasOwnProperty,
            isNative = function() {return Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';};
    
        [...]
    
        this.encode = function(o) {
            return (this.encode = isNative() ? JSON.stringify : function(o) {
                [...]
            })(o);
        };
    
        [...]
    
        this.decode = function(o) {
            return (this.decode = isNative() ? JSON.parse : function(json) {
                return eval("(" + json + ')');
            })(o);
        };
    })();
    Edit: Ah, I see your edit and raise you one clever, but unreadable hack

  8. #8
    Sencha User mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
      0  

    Default

    ah, yes. that's the idea.

    p.s. does your code work?

  9. #9
    Ext JS Premium Member
    Join Date
    Feb 2009
    Posts
    57
    Vote Rating
    0
      0  

    Default

    Quote Originally Posted by mystix View Post
    p.s. does your code work?
    Of course it does -- does it seem too good to be true?

    Here's the complete JSON.js with my patch:

    Code:
    /**
     * @class Ext.util.JSON
     * Modified version of Douglas Crockford's json.js that doesn't
     * mess with the Object prototype
     * http://www.json.org/js.html
     * @singleton
     */
    Ext.util.JSON = new (function() {
        var useHasOwn = !!{}.hasOwnProperty,
            isNative = function() {return Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';};
     
        // crashes Safari in some instances
        //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
    
        var pad = function(n) {
            return n < 10 ? "0" + n : n;
        };
    
        var m = {
            "\b": '\\b',
            "\t": '\\t',
            "\n": '\\n',
            "\f": '\\f',
            "\r": '\\r',
            '"' : '\\"',
            "\\": '\\\\'
        };
    
        var encodeString = function(s){
            if (/["\\\x00-\x1f]/.test(s)) {
                return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                    var c = m[b];
                    if(c){
                        return c;
                    }
                    c = b.charCodeAt();
                    return "\\u00" +
                        Math.floor(c / 16).toString(16) +
                        (c % 16).toString(16);
                }) + '"';
            }
            return '"' + s + '"';
        };
    
        var encodeArray = function(o){
            var a = ["["], b, i, l = o.length, v;
                for (i = 0; i < l; i += 1) {
                    v = o[i];
                    switch (typeof v) {
                        case "undefined":
                        case "function":
                        case "unknown":
                            break;
                        default:
                            if (b) {
                                a.push(',');
                            }
                            a.push(v === null ? "null" : Ext.util.JSON.encode(v));
                            b = true;
                    }
                }
                a.push("]");
                return a.join("");
        };
    
        this.encodeDate = function(o){
            return '"' + o.getFullYear() + "-" +
                    pad(o.getMonth() + 1) + "-" +
                    pad(o.getDate()) + "T" +
                    pad(o.getHours()) + ":" +
                    pad(o.getMinutes()) + ":" +
                    pad(o.getSeconds()) + '"';
        };
    
        /**
         * Encodes an Object, Array or other value
         * @param {Mixed} o The variable to encode
         * @return {String} The JSON string
         */
        this.encode = function(o) {
            return (this.encode = isNative() ? JSON.stringify : function(o) {
                if(typeof o == "undefined" || o === null){
                    return "null";
                }else if(Ext.isArray(o)){
                    return encodeArray(o);
                }else if(Object.prototype.toString.apply(o) === '[object Date]'){
                    return Ext.util.JSON.encodeDate(o);
                }else if(typeof o == "string"){
                    return encodeString(o);
                }else if(typeof o == "number"){
                    return isFinite(o) ? String(o) : "null";
                }else if(typeof o == "boolean"){
                    return String(o);
                }else {
                    var a = ["{"], b, i, v;
                    for (i in o) {
                        if(!useHasOwn || o.hasOwnProperty(i)) {
                            v = o[i];
                            switch (typeof v) {
                            case "undefined":
                            case "function":
                            case "unknown":
                                break;
                            default:
                                if(b){
                                    a.push(',');
                                }
                                a.push(this.encode(i), ":",
                                        v === null ? "null" : this.encode(v));
                                b = true;
                            }
                        }
                    }
                    a.push("}");
                    return a.join("");
                }
            })(o);
        };
     
        /**
         * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
         * @param {String} json The JSON string
         * @return {Object} The resulting object
         */
        this.decode = function(o) {
            return (this.decode = isNative() ? JSON.parse : function(json) {
                return eval("(" + json + ')');
            })(o);
        };
    })();
    /**
     * Shorthand for {@link Ext.util.JSON#encode}
     * @param {Mixed} o The variable to encode
     * @return {String} The JSON string
     * @member Ext
     * @method encode
     */
    Ext.encode = Ext.util.JSON.encode;
    /**
     * Shorthand for {@link Ext.util.JSON#decode}
     * @param {String} json The JSON string
     * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
     * @return {Object} The resulting object
     * @member Ext
     * @method decode
     */
    Ext.decode = Ext.util.JSON.decode;
    Last edited by papandreou; 2 Jul 2009 at 5:34 AM. Reason: Highlighted changes in red

  10. #10
    Sencha User mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
      0  

    Default

    great! learnt something new today. thanks for that

    p.s. you might want to highlight your changes in red for easy reading

Page 1 of 3 123 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •