Home Reference Source Repository

js/Models/BaseModel.js

import Backbone from 'backbone';
import RODAN_EVENTS from 'js/Shared/RODAN_EVENTS';
import Radio from 'backbone.radio';

/**
 * Base model.
 */
export default class BaseModel extends Backbone.Model
{
///////////////////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
///////////////////////////////////////////////////////////////////////////////////////
    /**
     * Constructor.
     *
     * @param {object} options initialization parameters for Backbone.Model
     */
    constructor(options)
    {
        super(options);
        this.on('change', (model, options) => this._onChange(model, options));
        this.on('sync', (model, response, options) => this._onSync(model, response, options));
    }

    /**
     * URL override to add trailing slash. Also, the URL will depend if this model instance has been saved or not. 
     * If not saved, we have to use the plural route for the model to save it.
     * That's the way Rodan works. :)
     *
     * @return {string} URL of Resource with trailing slash
     */
    url()
    {
        var original_url = Radio.channel('rodan').request(RODAN_EVENTS.REQUEST__SERVER_GET_ROUTE, this.routeName);
        if (typeof this.get('uuid') !== 'undefined')
        {
            original_url = this.get('url');
        }
        var parsed_url = original_url + ( original_url.charAt( original_url.length - 1 ) === '/' ? '' : '/' );
        return parsed_url;
    }

    /**
     * Override of destroy to allow for generic handling.
     *
     * @param {object} options Backbone.Model.destroy options object
     */
    destroy(options)
    {
        options = this._applyResponseHandlers(options);
        options.task = 'destroy';
        super.destroy(options);
    }

    /**
     * Override of save to allow for generic handling.
     *
     * @param {object} attributes attributes to change in model
     * @param {object} options Backbone.Model.save options object
     */
    save(attributes, options)
    {
        options = this._applyResponseHandlers(options);
        options.task = 'save';
        return super.save(attributes, options);
    }

    /**
     * Override of fetch to allow for generic handling.
     *
     * @param {object} options Backbone.Model.fetch options object
     */
    fetch(options)
    {
        options = this._applyResponseHandlers(options);
        options.task = 'fetch';
        super.fetch(options);
    }

    /**
     * Returns descriptive string for model. This should be overridden by sub-classes.
     *
     * @return {string} returns 'no description available' unless overridden by subclass
     */
    getDescription()
    {
        return 'no description available';
    }

    /**
     * Parses ID out of resource type URL.
     *
     * @param {string} url URL with UUID at end
     * @return {string} UUID
     * @todo this should be in a utility file
     */
    parseIdFromUrl(url)
    {
        var lastSlash = url.lastIndexOf('/');
        var subString = url.substring(0, lastSlash);
        var secondLastSlash = subString.lastIndexOf('/');
        return url.substring(secondLastSlash + 1, lastSlash);
    }

///////////////////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
///////////////////////////////////////////////////////////////////////////////////////
    /**
     * On change handler.
     */
    _onChange(model, response, options)
    {
        Radio.channel('rodan').trigger(RODAN_EVENTS.EVENT__MODEL_CHANGE, {model: model, options: options});
        Radio.channel('rodan').trigger(RODAN_EVENTS.EVENT__MODEL_CHANGE + model.get('url'), {model: model, options: options});
    }

    /**
     * On sync handler.
     */
    _onSync(model, response, options)
    {
        Radio.channel('rodan').trigger(RODAN_EVENTS.EVENT__MODEL_SYNC, {model: model, response: response, options: options});
        Radio.channel('rodan').trigger(RODAN_EVENTS.EVENT__MODEL_SYNC + model.get('url'), {model: model, response: response, options: options});
    }

    /**
     * Applies response handlers.
     */
    _applyResponseHandlers(options)
    {
        // Check if options are defined.
        if (options === undefined)
        {
            options = {};
        }

        // Success.
        var genericSuccessFunction = (model, response, options) => this._handleSuccessResponse(model, response, options);
        if (!options.hasOwnProperty('success'))
        {
            options.success = (model, response, options) => this._handleSuccessResponse(model, response, options);
        }
        else
        {
            var customSuccessFunction = options.success;
            options.success = function(model, response, options)
            {
                customSuccessFunction(model, response, options);
                genericSuccessFunction(model, response, options);
            };
        }

        // Error.
        var genericErrorFunction = (model, response, options) => this._handleErrorResponse(model, response, options);
        if (!options.hasOwnProperty('error'))
        {
            options.error = (model, response, options) => this._handleErrorResponse(model, response, options);
        }
        else
        {
            var customErrorFunction = options.error;
            options.error = function(model, response, options)
            {
                customErrorFunction(model, response, options);
                genericErrorFunction(model, response, options);
            };
        }

        return options;
    }

    /**
     * Handle success response.
     */
    _handleSuccessResponse(model, response, options)
    {
    }

    /**
     * Handle error response.
     */
    _handleErrorResponse(model, response, options)
    {
        Radio.channel('rodan').request(RODAN_EVENTS.REQUEST__SYSTEM_HANDLE_ERROR, {model: model,
                                                                  response: response,
                                                                  options: options});
    }
}
BaseModel.prototype.idAttribute = 'uuid';