    /** * Base Writer class used by most subclasses of {@link Ext.data.proxy.Server}. This class * is responsible for taking a set of {@link Ext.data.operation.Operation} objects and a * {@link Ext.data.Request} object and modifying that request based on the Operations. * * For example a Ext.data.writer.Json would format the Operations and their * {@link Ext.data.Model} instances based on the config options passed to the JsonWriter's * constructor. * * Writers are not needed for any kind of local storage - whether via a * {@link Ext.data.proxy.WebStorage Web Storage proxy} (see * {@link Ext.data.proxy.LocalStorage localStorage} and * {@link Ext.data.proxy.SessionStorage sessionStorage}) * or just in memory via a {@link Ext.data.proxy.Memory MemoryProxy}. *  * # Dates * * Before sending dates to the server, they can be formatted using an {@link Ext.Date} * format. These formats can be specified both on the field and the writer itself. In terms * of precedence, from highest to lowest: *  * - {@link #dateFormat Writer.dateFormat} The writer `dateFormat` will always have the *   highest precedence. * - {@link Ext.data.field.Date#dateWriteFormat} The `dateWriteFormat` given to the field *   instance. This is handled by {@link Ext.data.field.Date#method-serialize}. * - {@link Ext.data.field.Date#dateFormat Field.dateFormat} This is handled by the field's *   `serialize` method. * - {@link Ext.data.field.Date#dateReadFormat Field.dateReadFormat} Also handled by the *   field's `serialize` method. */Ext.define('Ext.data.writer.Writer', {    mixins: [        'Ext.mixin.Factoryable'    ],     alias: 'writer.base',    factoryConfig: {        defaultType: null    },     alternateClassName: [        'Ext.data.DataWriter',        'Ext.data.Writer'    ],     config: {        /**         * @cfg {String} clientIdProperty          * When specified this property causes the `{@link Ext.data.Model#idProperty}` of         * newly created records to be sent to the server as this name instead of the         * value of the `idProperty`.         *         * For example, by default, the following code:         *         *      Ext.define('Person', {         *          idProperty: 'id',  // this is the default value (for clarity)         *         *          fields: [ 'name' ]         *      });         *         *      var person = new Person({         *          // no id provided, so one is generated         *          name: 'Clark Kent'         *      });         *         * Will send this to the server:         *         *      {         *          id: 'Person-1',         *          name: 'Clark Kent'         *      }         *         * This can be an issue if the server expects an integer for the "id" property.         * You can use `{@link Ext.data.Model#identifier}` to produce identifiers that         * the server would recognize or use this config to send the client's id in a         * different property.         *         *      Ext.define('Person', {         *          idProperty: 'id',  // this is the default value (for clarity)         *         *          proxy: {         *              writer: {         *                  clientIdProperty: 'clientId'         *              }         *          },         *         *          fields: [ 'name' ]         *      });         *         * Given the above, the server is sent this data now:         *         *      {         *          clientId: 'Person-1',         *          name: 'Clark Kent'         *      }         *         * While this config provides the behavior of `{@link Ext.data.Model#clientIdProperty}`         * from previous releases, this property is not as useful as a suitable         * `{@link Ext.data.Model#identifier}` due to id's appearing in foreign-key fields         * and in `{@link Ext.data.Model#manyToMany}` associations.         *         * See `{@link Ext.data.Model#identifier}` for more on id generation.         */        clientIdProperty: null,         /**         * @cfg {Object} allDataOptions          * This object contains the options passed to `{@link Ext.data.Model#getData}` when         * writing `{@link Ext.data.Model#phantom}` records or when `writeAllFields` is set         * to `true`.         *         * *NOTE:* The `serialize` option cannot be used here.         */        allDataOptions: {            persist: true        },         /**         * @cfg {Object} partialDataOptions          * This object contains the options passed to `{@link Ext.data.Model#getData}` when         * writing non `{@link Ext.data.Model#phantom}` records or when `writeAllFields` is         * set to `false`.         *         * *NOTE:* The `serialize` option cannot be used here.         */        partialDataOptions: {            changes: true,            critical: true        },         /**         * @cfg {Boolean} writeAllFields `true` to write all fields from the record to the         * server. If set to `false` it will only send the fields that were modified. Note         * that any fields that have `{@link Ext.data.field.Field#persist}` set to `false`         * will still be ignored while those with `{@link Ext.data.field.Field#critical}`         * set to `true` will be included.         *         * The exact set of fields written is determined by `allDataOptions` (when `true`)         * or `partialDataOptions` (when `false`). This option is ignored and treated as         * `true` when writing `{@link Ext.data.Model#phantom}` records.         *         * It is seldom a good idea to use this config. Rather use `allDataOptions` or         * `partialDataOptions` to control what fields are sent for records based on their         * `{@link Ext.data.Model#phantom}` state.         *         * In the previous release, this was default `true`.         */        writeAllFields: false,            /**         * @cfg {String} dateFormat          * This is used for each field of type date in the model to format the value before         * it is sent to the server.         */        dateFormat: null,            /**         * @cfg {String} nameProperty          * This property is used to read the key for each value that will be sent to the         * server.         *         * For example:         *         *     Ext.define('Person', {         *         extend: 'Ext.data.Model',         *         fields: [{         *             name: 'first',         *             mapping: 'firstName'         *         }, {         *             name: 'last',         *             mapping: 'lastName'         *         }, {         *             name: 'age'         *         }]         *     });         *         *     new Ext.data.writer.Writer({         *         nameProperty: 'mapping'         *     });         *         *     // This will be sent to the server         *     {         *         firstName: 'first name value',         *         lastName: 'last name value',         *         age: 1         *     }         *         * If the value is not present, the field name will always be used.         */        nameProperty: 'name',            /**         * @cfg {Boolean} [writeRecordId]         * By default, each record's id is always included in the output for non-phantom         * records since in most cases the id will be required on the server to process         * the record action. This is helpful since the id will normally not be modified,         * and so would not be sent to the server unless {@link #writeAllFields} was         * explicitly enabled.         *          * However, there are cases where it is not desirable for the record id to be passed         * in the data directly. For example, when using a RESTful API the record id would         * typically be appended to the url instead.         */        writeRecordId: true,                /**         * @cfg {Function|Object} [transform]         * If a transform function is set, it will be invoked just before {@link #writeRecords}          * executes. It is passed the unserialized data object and the {@link Ext.data.Request request}         * object. The transform function returns a data object, which can be a modified version of the original          * data object, or a completely new data object. The transform can be a function, or an object          * with a 'fn' key and an optional 'scope' key. Example usage:         *         *     Ext.create('Ext.data.Store', {         *         model: 'User',         *         proxy: {         *             type: 'ajax',         *             url : 'users.json',         *             writer: {         *                 type: 'json',         *                 transform: {         *                     fn: function(data, request) {         *                         // do some manipulation of the unserialized data object         *                         return data;         *                     },         *                     scope: this         *                 }         *             }         *         },         *     });         *         */         transform: null    },     /**     * @property {Boolean} isWriter      * `true` in this class to identify an object as an instantiated Writer, or subclass thereof.     **/    isWriter: true,     /**     * Creates new Writer.     * @param {Object} [config] Config object.     */    constructor: function(config) {        this.initConfig(config);    },        applyTransform: function(transform) {        if (transform) {            if (Ext.isFunction(transform)) {                transform = {fn:transform};            }            return transform.fn.bind(transform.scope || this);        }        return transform;    },     /**     * Prepares a Proxy's Ext.data.Request object.     * @param {Ext.data.Request} request The request object.     * @return {Ext.data.Request} The modified request object.     */    write: function(request) {        var operation = request.getOperation(),            records = operation.getRecords() || [],            len = records.length,            data = [],            i;         for (i = 0; i < len; i++) {            data.push(this.getRecordData(records[i], operation));        }         return this.writeRecords(request, data);    },        /**     * @method     *     * Write the record data to the request in the appropriate format.     * @protected     * @param {Ext.data.Request} request The request.     * @param {Array} data An array of objects containing data.     * @return {Ext.data.Request} The request.     */    writeRecords: Ext.emptyFn,     /**     * Formats the data for each record before sending it to the server. This method should     * be overridden to format the data in a way that differs from the default.     *     * @param {Ext.data.Model} record The record that we are writing to the server.     * @param {Ext.data.operation.Operation} [operation] An operation object.     * @return {Object} An object literal of name/value keys to be written to the server.     * By default this method returns the data property on the record.     */    getRecordData: function (record, operation) {        var me = this,            nameProperty = me.getNameProperty(),            mapping = nameProperty !== 'name',            idField = record.self.idField,            key = idField[nameProperty] || idField.name, // setup for idField first             value = record.id,            writeAll = me.getWriteAllFields(),            ret, dateFormat, phantom,            options, clientIdProperty,            fieldsMap, data, field;         if (idField.serialize) {            value = idField.serialize(value);        }         if (!writeAll && operation && operation.isDestroyOperation) {            ret = {};            ret[key] = value;        } else {            dateFormat = me.getDateFormat();            phantom = record.phantom;            options = (phantom || writeAll) ? me.getAllDataOptions() : me.getPartialDataOptions();            clientIdProperty = phantom && me.getClientIdProperty();            fieldsMap = record.getFieldsMap();             options.serialize = false; // we must take over this here             data = record.getData(options);             // If we are mapping we need to pour data into a new object, otherwise we do             // our work in-place:             ret = mapping ? {} : data;             if (clientIdProperty) { // if (phantom and have clientIdProperty)                 ret[clientIdProperty] = value; // must read data and write ret                 delete data[key];  // in case ret === data (must not send "id")             }            else if (!me.getWriteRecordId()) {                delete data[key];            }             for (key in data) {                value = data[key];                 if (!(field = fieldsMap[key])) {                    // No defined field, so clearly no nameProperty to look up for this field                     // but if we are mapping we need to copy over the value. Also there is no                     // serializer to call in this case.                     if (mapping) {                        ret[key] = value;                    }                } else {                    // Allow this Writer to take over formatting date values if it has a                     // dateFormat specified. Only check isDate on fields declared as dates                     // for efficiency.                     if (field.isDateField && dateFormat && Ext.isDate(value)) {                        value = Ext.Date.format(value, dateFormat);                    } else if (field.serialize) {                        value = field.serialize(value, record);                    }                     if (mapping) {                        key = field[nameProperty] || key;                    }                     ret[key] = value;                }            }        }         return ret;    }});