+ /**
+ * Decode a json response from server.
+ * @param {String} action [{@link Ext.data.Api#actions} create|read|update|destroy]
+ * @param {Object} response HTTP Response object from browser.
+ * @return {Ext.data.Response} response Returns an instance of {@link Ext.data.Response}
+ */
+ readResponse : function(action, response) {
+ var q = Ext.DomQuery,
+ doc = response.responseXML;
+
+ // create general Response instance.
+ var res = new Ext.data.Response({
+ action: action,
+ success : this.getSuccess(doc),
+ message: this.getMessage(doc),
+ data: this.extractData(q.select(this.meta.record, doc) || q.select(this.meta.root, doc), false),
+ raw: doc
+ });
+
+ if (Ext.isEmpty(res.success)) {
+ throw new Ext.data.DataReader.Error('successProperty-response', this.meta.successProperty);
+ }
+
+ // Create actions from a response having status 200 must return pk
+ if (action === Ext.data.Api.actions.create) {
+ var def = Ext.isDefined(res.data);
+ if (def && Ext.isEmpty(res.data)) {
+ throw new Ext.data.JsonReader.Error('root-empty', this.meta.root);
+ }
+ else if (!def) {
+ throw new Ext.data.JsonReader.Error('root-undefined-response', this.meta.root);
+ }
+ }
+ return res;
+ },
+
+ getSuccess : function() {
+ return true;
+ },
+
+ /**
+ * build response-data extractor functions.
+ * @private
+ * @ignore
+ */
+ buildExtractors : function() {
+ if(this.ef){
+ return;
+ }
+ var s = this.meta,
+ Record = this.recordType,
+ f = Record.prototype.fields,
+ fi = f.items,
+ fl = f.length;
+
+ if(s.totalProperty) {
+ this.getTotal = this.createAccessor(s.totalProperty);
+ }
+ if(s.successProperty) {
+ this.getSuccess = this.createAccessor(s.successProperty);
+ }
+ if (s.messageProperty) {
+ this.getMessage = this.createAccessor(s.messageProperty);
+ }
+ this.getRoot = function(res) {
+ return (!Ext.isEmpty(res[this.meta.record])) ? res[this.meta.record] : res[this.meta.root];
+ }
+ if (s.idPath || s.idProperty) {
+ var g = this.createAccessor(s.idPath || s.idProperty);
+ this.getId = function(rec) {
+ var id = g(rec) || rec.id;
+ return (id === undefined || id === '') ? null : id;
+ };
+ } else {
+ this.getId = function(){return null;};
+ }
+ var ef = [];
+ for(var i = 0; i < fl; i++){
+ f = fi[i];
+ var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
+ ef.push(this.createAccessor(map));
+ }
+ this.ef = ef;
+ },
+
+ /**
+ * Creates a function to return some particular key of data from a response.
+ * @param {String} key
+ * @return {Function}
+ * @private
+ * @ignore
+ */
+ createAccessor : function(){
+ var q = Ext.DomQuery;
+ return function(key) {
+ switch(key) {
+ case this.meta.totalProperty:
+ return function(root, def){
+ return q.selectNumber(key, root, def);
+ }
+ break;
+ case this.meta.successProperty:
+ return function(root, def) {
+ var sv = q.selectValue(key, root, true);
+ var success = sv !== false && sv !== 'false';
+ return success;
+ }
+ break;
+ default:
+ return function(root, def) {
+ return q.selectValue(key, root, def);
+ }
+ break;
+ }
+ };
+ }(),
+
+ /**
+ * extracts values and type-casts a row of data from server, extracted by #extractData
+ * @param {Hash} data
+ * @param {Ext.data.Field[]} items
+ * @param {Number} len
+ * @private
+ * @ignore
+ */
+ extractValues : function(data, items, len) {
+ var f, values = {};
+ for(var j = 0; j < len; j++){
+ f = items[j];
+ var v = this.ef[j](data);
+ values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue, data);
+ }
+ return values;
+ }