source: trunk/web/addons/job_monarch/lib/extjs-30/pkgs/data-json-debug.js @ 625

Last change on this file since 625 was 625, checked in by ramonb, 15 years ago

lib/extjs-30:

  • new ExtJS 3.0
File size: 23.1 KB
Line 
1/*!
2 * Ext JS Library 3.0.0
3 * Copyright(c) 2006-2009 Ext JS, LLC
4 * licensing@extjs.com
5 * http://www.extjs.com/license
6 */
7/**
8 * @class Ext.data.JsonWriter
9 * @extends Ext.data.DataWriter
10 * DataWriter extension for writing an array or single {@link Ext.data.Record} object(s) in preparation for executing a remote CRUD action.
11 */
12Ext.data.JsonWriter = function(config) {
13    Ext.data.JsonWriter.superclass.constructor.call(this, config);
14    // careful to respect "returnJson", renamed to "encode"
15    if (this.returnJson != undefined) {
16        this.encode = this.returnJson;
17    }
18}
19Ext.extend(Ext.data.JsonWriter, Ext.data.DataWriter, {
20    /**
21     * @cfg {Boolean} returnJson <b>Deprecated.  Use {@link Ext.data.JsonWriter#encode} instead.
22     */
23    returnJson : undefined,
24    /**
25     * @cfg {Boolean} encode <tt>true</tt> to {@link Ext.util.JSON#encode encode} the
26     * {@link Ext.data.DataWriter#toHash hashed data}. Defaults to <tt>true</tt>.  When using
27     * {@link Ext.data.DirectProxy}, set this to <tt>false</tt> since Ext.Direct.JsonProvider will perform
28     * its own json-encoding.  In addition, if you're using {@link Ext.data.HttpProxy}, setting to <tt>false</tt>
29     * will cause HttpProxy to transmit data using the <b>jsonData</b> configuration-params of {@link Ext.Ajax#request}
30     * instead of <b>params</b>.  When using a {@link Ext.data.Store#restful} Store, some serverside frameworks are
31     * tuned to expect data through the jsonData mechanism.  In those cases, one will want to set <b>encode: <tt>false</tt></b>
32     */
33    encode : true,
34
35    /**
36     * Final action of a write event.  Apply the written data-object to params.
37     * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
38     * @param {Record[]} rs
39     * @param {Object} http params
40     * @param {Object} data object populated according to DataReader meta-data "root" and "idProperty"
41     */
42    render : function(action, rs, params, data) {
43        Ext.apply(params, data);
44
45        if (this.encode === true) { // <-- @deprecated returnJson
46            if (Ext.isArray(rs) && data[this.meta.idProperty]) {
47                params[this.meta.idProperty] = Ext.encode(params[this.meta.idProperty]);
48            }
49            params[this.meta.root] = Ext.encode(params[this.meta.root]);
50        }
51    },
52    /**
53     * createRecord
54     * @protected
55     * @param {Ext.data.Record} rec
56     */
57    createRecord : function(rec) {
58        return this.toHash(rec);
59    },
60    /**
61     * updateRecord
62     * @protected
63     * @param {Ext.data.Record} rec
64     */
65    updateRecord : function(rec) {
66        return this.toHash(rec);
67
68    },
69    /**
70     * destroyRecord
71     * @protected
72     * @param {Ext.data.Record} rec
73     */
74    destroyRecord : function(rec) {
75        return rec.id;
76    }
77});/**
78 * @class Ext.data.JsonReader
79 * @extends Ext.data.DataReader
80 * <p>Data reader class to create an Array of {@link Ext.data.Record} objects from a JSON response
81 * based on mappings in a provided {@link Ext.data.Record} constructor.</p>
82 * <p>Example code:</p>
83 * <pre><code>
84var Employee = Ext.data.Record.create([
85    {name: 'firstname'},                  // map the Record's "firstname" field to the row object's key of the same name
86    {name: 'job', mapping: 'occupation'}  // map the Record's "job" field to the row object's "occupation" key
87]);
88var myReader = new Ext.data.JsonReader(
89    {                             // The metadata property, with configuration options:
90        totalProperty: "results", //   the property which contains the total dataset size (optional)
91        root: "rows",             //   the property which contains an Array of record data objects
92        idProperty: "id"          //   the property within each row object that provides an ID for the record (optional)
93    },
94    Employee  // {@link Ext.data.Record} constructor that provides mapping for JSON object
95);
96</code></pre>
97 * <p>This would consume a JSON data object of the form:</p><pre><code>
98{
99    results: 2,  // Reader's configured totalProperty
100    rows: [      // Reader's configured root
101        { id: 1, firstname: 'Bill', occupation: 'Gardener' },         // a row object
102        { id: 2, firstname: 'Ben' , occupation: 'Horticulturalist' }  // another row object
103    ]
104}
105</code></pre>
106 * <p><b><u>Automatic configuration using metaData</u></b></p>
107 * <p>It is possible to change a JsonReader's metadata at any time by including a <b><tt>metaData</tt></b>
108 * property in the JSON data object. If the JSON data object has a <b><tt>metaData</tt></b> property, a
109 * {@link Ext.data.Store Store} object using this Reader will reconfigure itself to use the newly provided
110 * field definition and fire its {@link Ext.data.Store#metachange metachange} event. The metachange event
111 * handler may interrogate the <b><tt>metaData</tt></b> property to perform any configuration required.
112 * Note that reconfiguring a Store potentially invalidates objects which may refer to Fields or Records
113 * which no longer exist.</p>
114 * <p>The <b><tt>metaData</tt></b> property in the JSON data object may contain:</p>
115 * <div class="mdetail-params"><ul>
116 * <li>any of the configuration options for this class</li>
117 * <li>a <b><tt>{@link Ext.data.Record#fields fields}</tt></b> property which the JsonReader will
118 * use as an argument to the {@link Ext.data.Record#create data Record create method} in order to
119 * configure the layout of the Records it will produce.</li>
120 * <li>a <b><tt>{@link Ext.data.Store#sortInfo sortInfo}</tt></b> property which the JsonReader will
121 * use to set the {@link Ext.data.Store}'s {@link Ext.data.Store#sortInfo sortInfo} property</li>
122 * <li>any user-defined properties needed</li>
123 * </ul></div>
124 * <p>To use this facility to send the same data as the example above (without having to code the creation
125 * of the Record constructor), you would create the JsonReader like this:</p><pre><code>
126var myReader = new Ext.data.JsonReader();
127</code></pre>
128 * <p>The first data packet from the server would configure the reader by containing a
129 * <b><tt>metaData</tt></b> property <b>and</b> the data. For example, the JSON data object might take
130 * the form:</p>
131<pre><code>
132{
133    metaData: {
134        idProperty: 'id',
135        root: 'rows',
136        totalProperty: 'results',
137        fields: [
138            {name: 'name'},
139            {name: 'job', mapping: 'occupation'}
140        ],
141        sortInfo: {field: 'name', direction:'ASC'}, // used by store to set its sortInfo
142        foo: 'bar' // custom property
143    },
144    results: 2,
145    rows: [ // an Array
146        { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
147        { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' }
148    ]
149}
150</code></pre>
151 * @cfg {String} totalProperty [total] Name of the property from which to retrieve the total number of records
152 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
153 * paged from the remote server.  Defaults to <tt>total</tt>.
154 * @cfg {String} successProperty [success] Name of the property from which to
155 * retrieve the success attribute. Defaults to <tt>success</tt>.  See
156 * {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}
157 * for additional information.
158 * @cfg {String} root [undefined] <b>Required</b>.  The name of the property
159 * which contains the Array of row objects.  Defaults to <tt>undefined</tt>.
160 * An exception will be thrown if the root property is undefined. The data packet
161 * value for this property should be an empty array to clear the data or show
162 * no data.
163 * @cfg {String} idProperty [id] Name of the property within a row object that contains a record identifier value.  Defaults to <tt>id</tt>
164 * @constructor
165 * Create a new JsonReader
166 * @param {Object} meta Metadata configuration options.
167 * @param {Array/Object} recordType
168 * <p>Either an Array of {@link Ext.data.Field Field} definition objects (which
169 * will be passed to {@link Ext.data.Record#create}, or a {@link Ext.data.Record Record}
170 * constructor created from {@link Ext.data.Record#create}.</p>
171 */
172Ext.data.JsonReader = function(meta, recordType){
173    meta = meta || {};
174
175    // default idProperty, successProperty & totalProperty -> "id", "success", "total"
176    Ext.applyIf(meta, {
177        idProperty: 'id',
178        successProperty: 'success',
179        totalProperty: 'total'
180    });
181
182    Ext.data.JsonReader.superclass.constructor.call(this, meta, recordType || meta.fields);
183};
184Ext.extend(Ext.data.JsonReader, Ext.data.DataReader, {
185    /**
186     * This JsonReader's metadata as passed to the constructor, or as passed in
187     * the last data packet's <b><tt>metaData</tt></b> property.
188     * @type Mixed
189     * @property meta
190     */
191    /**
192     * This method is only used by a DataProxy which has retrieved data from a remote server.
193     * @param {Object} response The XHR object which contains the JSON data in its responseText.
194     * @return {Object} data A data block which is used by an Ext.data.Store object as
195     * a cache of Ext.data.Records.
196     */
197    read : function(response){
198        var json = response.responseText;
199        var o = Ext.decode(json);
200        if(!o) {
201            throw {message: "JsonReader.read: Json object not found"};
202        }
203        return this.readRecords(o);
204    },
205
206    // private function a store will implement
207    onMetaChange : function(meta, recordType, o){
208
209    },
210
211    /**
212     * @ignore
213     */
214    simpleAccess: function(obj, subsc) {
215        return obj[subsc];
216    },
217
218    /**
219     * @ignore
220     */
221    getJsonAccessor: function(){
222        var re = /[\[\.]/;
223        return function(expr) {
224            try {
225                return(re.test(expr)) ?
226                new Function("obj", "return obj." + expr) :
227                function(obj){
228                    return obj[expr];
229                };
230            } catch(e){}
231            return Ext.emptyFn;
232        };
233    }(),
234
235    /**
236     * Create a data block containing Ext.data.Records from a JSON object.
237     * @param {Object} o An object which contains an Array of row objects in the property specified
238     * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
239     * which contains the total size of the dataset.
240     * @return {Object} data A data block which is used by an Ext.data.Store object as
241     * a cache of Ext.data.Records.
242     */
243    readRecords : function(o){
244        /**
245         * After any data loads, the raw JSON data is available for further custom processing.  If no data is
246         * loaded or there is a load exception this property will be undefined.
247         * @type Object
248         */
249        this.jsonData = o;
250        if(o.metaData){
251            delete this.ef;
252            this.meta = o.metaData;
253            this.recordType = Ext.data.Record.create(o.metaData.fields);
254            this.onMetaChange(this.meta, this.recordType, o);
255        }
256        var s = this.meta, Record = this.recordType,
257            f = Record.prototype.fields, fi = f.items, fl = f.length, v;
258
259        // Generate extraction functions for the totalProperty, the root, the id, and for each field
260        this.buildExtractors();
261        var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
262        if(s.totalProperty){
263            v = parseInt(this.getTotal(o), 10);
264            if(!isNaN(v)){
265                totalRecords = v;
266            }
267        }
268        if(s.successProperty){
269            v = this.getSuccess(o);
270            if(v === false || v === 'false'){
271                success = false;
272            }
273        }
274
275        var records = [];
276        for(var i = 0; i < c; i++){
277            var n = root[i];
278            var record = new Record(this.extractValues(n, fi, fl), this.getId(n));
279            record.json = n;
280            records[i] = record;
281        }
282        return {
283            success : success,
284            records : records,
285            totalRecords : totalRecords
286        };
287    },
288
289    // private
290    buildExtractors : function() {
291        if(this.ef){
292            return;
293        }
294        var s = this.meta, Record = this.recordType,
295            f = Record.prototype.fields, fi = f.items, fl = f.length;
296
297        if(s.totalProperty) {
298            this.getTotal = this.getJsonAccessor(s.totalProperty);
299        }
300        if(s.successProperty) {
301            this.getSuccess = this.getJsonAccessor(s.successProperty);
302        }
303        this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
304        if (s.id || s.idProperty) {
305            var g = this.getJsonAccessor(s.id || s.idProperty);
306            this.getId = function(rec) {
307                var r = g(rec);
308                return (r === undefined || r === "") ? null : r;
309            };
310        } else {
311            this.getId = function(){return null;};
312        }
313        var ef = [];
314        for(var i = 0; i < fl; i++){
315            f = fi[i];
316            var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
317            ef.push(this.getJsonAccessor(map));
318        }
319        this.ef = ef;
320    },
321
322    // private extractValues
323    extractValues: function(data, items, len) {
324        var f, values = {};
325        for(var j = 0; j < len; j++){
326            f = items[j];
327            var v = this.ef[j](data);
328            values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue, data);
329        }
330        return values;
331    },
332
333    /**
334     * Decode a json response from server.
335     * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
336     * @param {Object} response
337     */
338    readResponse : function(action, response) {
339        var o = (response.responseText !== undefined) ? Ext.decode(response.responseText) : response;
340        if(!o) {
341            throw new Ext.data.JsonReader.Error('response');
342        }
343        if (Ext.isEmpty(o[this.meta.successProperty])) {
344            throw new Ext.data.JsonReader.Error('successProperty-response', this.meta.successProperty);
345        }
346        // TODO, separate empty and undefined exceptions.
347        if ((action === Ext.data.Api.actions.create || action === Ext.data.Api.actions.update)) {
348            if (Ext.isEmpty(o[this.meta.root])) {
349                throw new Ext.data.JsonReader.Error('root-emtpy', this.meta.root);
350            }
351            else if (o[this.meta.root] === undefined) {
352                throw new Ext.data.JsonReader.Error('root-undefined-response', this.meta.root);
353            }
354        }
355        // make sure extraction functions are defined.
356        this.ef = this.buildExtractors();
357        return o;
358    }
359});
360
361/**
362 * @class Ext.data.JsonReader.Error
363 * Error class for JsonReader
364 */
365Ext.data.JsonReader.Error = Ext.extend(Ext.Error, {
366    constructor : function(message, arg) {
367        this.arg = arg;
368        Ext.Error.call(this, message);
369    },
370    name : 'Ext.data.JsonReader'
371});
372Ext.apply(Ext.data.JsonReader.Error.prototype, {
373    lang: {
374        'response': "An error occurred while json-decoding your server response",
375        'successProperty-response': 'Could not locate your "successProperty" in your server response.  Please review your JsonReader config to ensure the config-property "successProperty" matches the property in your server-response.  See the JsonReader docs.',
376        'root-undefined-response': 'Could not locate your "root" property in your server response.  Please review your JsonReader config to ensure the config-property "root" matches the property your server-response.  See the JsonReader docs.',
377        'root-undefined-config': 'Your JsonReader was configured without a "root" property.  Please review your JsonReader config and make sure to define the root property.  See the JsonReader docs.',
378        'idProperty-undefined' : 'Your JsonReader was configured without an "idProperty"  Please review your JsonReader configuration and ensure the "idProperty" is set (e.g.: "id").  See the JsonReader docs.',
379        'root-emtpy': 'Data was expected to be returned by the server in the "root" property of the response.  Please review your JsonReader configuration to ensure the "root" property matches that returned in the server-response.  See JsonReader docs.'
380    }
381});
382/**
383 * @class Ext.data.ArrayReader
384 * @extends Ext.data.JsonReader
385 * <p>Data reader class to create an Array of {@link Ext.data.Record} objects from an Array.
386 * Each element of that Array represents a row of data fields. The
387 * fields are pulled into a Record object using as a subscript, the <code>mapping</code> property
388 * of the field definition if it exists, or the field's ordinal position in the definition.</p>
389 * <p>Example code:</p>
390 * <pre><code>
391var Employee = Ext.data.Record.create([
392    {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
393    {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
394]);
395var myReader = new Ext.data.ArrayReader({
396    {@link #idIndex}: 0
397}, Employee);
398</code></pre>
399 * <p>This would consume an Array like this:</p>
400 * <pre><code>
401[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
402 * </code></pre>
403 * @constructor
404 * Create a new ArrayReader
405 * @param {Object} meta Metadata configuration options.
406 * @param {Array/Object} recordType
407 * <p>Either an Array of {@link Ext.data.Field Field} definition objects (which
408 * will be passed to {@link Ext.data.Record#create}, or a {@link Ext.data.Record Record}
409 * constructor created from {@link Ext.data.Record#create}.</p>
410 */
411Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
412    /**
413     * @cfg {String} successProperty
414     * @hide
415     */
416    /**
417     * @cfg {Number} id (optional) The subscript within row Array that provides an ID for the Record.
418     * Deprecated. Use {@link #idIndex} instead.
419     */
420    /**
421     * @cfg {Number} idIndex (optional) The subscript within row Array that provides an ID for the Record.
422     */
423    /**
424     * Create a data block containing Ext.data.Records from an Array.
425     * @param {Object} o An Array of row objects which represents the dataset.
426     * @return {Object} data A data block which is used by an Ext.data.Store object as
427     * a cache of Ext.data.Records.
428     */
429    readRecords : function(o){
430        this.arrayData = o;
431        var s = this.meta,
432            sid = s ? Ext.num(s.idIndex, s.id) : null,
433            recordType = this.recordType, 
434            fields = recordType.prototype.fields,
435            records = [],
436            v;
437
438        if(!this.getRoot) {
439            this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p) {return p;};
440            if(s.totalProperty) {
441                this.getTotal = this.getJsonAccessor(s.totalProperty);
442            }
443        }
444
445        var root = this.getRoot(o);
446
447        for(var i = 0; i < root.length; i++) {
448            var n = root[i];
449            var values = {};
450            var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
451            for(var j = 0, jlen = fields.length; j < jlen; j++) {
452                var f = fields.items[j];
453                var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
454                v = n[k] !== undefined ? n[k] : f.defaultValue;
455                v = f.convert(v, n);
456                values[f.name] = v;
457            }
458            var record = new recordType(values, id);
459            record.json = n;
460            records[records.length] = record;
461        }
462
463        var totalRecords = records.length;
464
465        if(s.totalProperty) {
466            v = parseInt(this.getTotal(o), 10);
467            if(!isNaN(v)) {
468                totalRecords = v;
469            }
470        }
471
472        return {
473            records : records,
474            totalRecords : totalRecords
475        };
476    }
477});/**
478 * @class Ext.data.ArrayStore
479 * @extends Ext.data.Store
480 * <p>Formerly known as "SimpleStore".</p>
481 * <p>Small helper class to make creating {@link Ext.data.Store}s from Array data easier.
482 * An ArrayStore will be automatically configured with a {@link Ext.data.ArrayReader}.</p>
483 * <p>A store configuration would be something like:<pre><code>
484var store = new Ext.data.ArrayStore({
485    // store configs
486    autoDestroy: true,
487    storeId: 'myStore',
488    // reader configs
489    idIndex: 0, 
490    fields: [
491       'company',
492       {name: 'price', type: 'float'},
493       {name: 'change', type: 'float'},
494       {name: 'pctChange', type: 'float'},
495       {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
496    ]
497});
498 * </code></pre></p>
499 * <p>This store is configured to consume a returned object of the form:<pre><code>
500var myData = [
501    ['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
502    ['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
503    ['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am'],
504    ['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
505    ['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am']
506];
507 * </code></pre>
508 * An object literal of this form could also be used as the {@link #data} config option.</p>
509 * <p><b>*Note:</b> Although not listed here, this class accepts all of the configuration options of
510 * <b>{@link Ext.data.ArrayReader ArrayReader}</b>.</p>
511 * @constructor
512 * @param {Object} config
513 * @xtype arraystore
514 */
515Ext.data.ArrayStore = Ext.extend(Ext.data.Store, {
516    /**
517     * @cfg {Ext.data.DataReader} reader @hide
518     */
519    constructor: function(config){
520        Ext.data.ArrayStore.superclass.constructor.call(this, Ext.apply(config, {
521            reader: new Ext.data.ArrayReader(config)
522        }));
523    },
524
525    loadData : function(data, append){
526        if(this.expandData === true){
527            var r = [];
528            for(var i = 0, len = data.length; i < len; i++){
529                r[r.length] = [data[i]];
530            }
531            data = r;
532        }
533        Ext.data.ArrayStore.superclass.loadData.call(this, data, append);
534    }
535});
536Ext.reg('arraystore', Ext.data.ArrayStore);
537
538// backwards compat
539Ext.data.SimpleStore = Ext.data.ArrayStore;
540Ext.reg('simplestore', Ext.data.SimpleStore);/**
541 * @class Ext.data.JsonStore
542 * @extends Ext.data.Store
543 * <p>Small helper class to make creating {@link Ext.data.Store}s from JSON data easier.
544 * A JsonStore will be automatically configured with a {@link Ext.data.JsonReader}.</p>
545 * <p>A store configuration would be something like:<pre><code>
546var store = new Ext.data.JsonStore({
547    // store configs
548    autoDestroy: true,
549    url: 'get-images.php',
550    storeId: 'myStore',
551    // reader configs
552    root: 'images',
553    idProperty: 'name', 
554    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
555});
556 * </code></pre></p>
557 * <p>This store is configured to consume a returned object of the form:<pre><code>
558{
559    images: [
560        {name: 'Image one', url:'/GetImage.php?id=1', size:46.5, lastmod: new Date(2007, 10, 29)},
561        {name: 'Image Two', url:'/GetImage.php?id=2', size:43.2, lastmod: new Date(2007, 10, 30)}
562    ]
563}
564 * </code></pre>
565 * An object literal of this form could also be used as the {@link #data} config option.</p>
566 * <p><b>*Note:</b> Although not listed here, this class accepts all of the configuration options of
567 * <b>{@link Ext.data.JsonReader JsonReader}</b>.</p>
568 * @constructor
569 * @param {Object} config
570 * @xtype jsonstore
571 */
572Ext.data.JsonStore = Ext.extend(Ext.data.Store, {
573    /**
574     * @cfg {Ext.data.DataReader} reader @hide
575     */
576    constructor: function(config){
577        Ext.data.JsonStore.superclass.constructor.call(this, Ext.apply(config, {
578            reader: new Ext.data.JsonReader(config)
579        }));
580    }
581});
582Ext.reg('jsonstore', Ext.data.JsonStore);
Note: See TracBrowser for help on using the repository browser.