client/js/models.js
author ymh <ymh.work@gmail.com>
Tue, 10 Jan 2017 17:36:30 +0100
changeset 649 2b9c120dba55
parent 622 02e3c464223f
permissions -rw-r--r--
first implementation of node title size and color

(function(root) {
    'use strict';

    var Backbone = root.Backbone;

    var Models = root.Rkns.Models = {};

    Models.getUID = function(obj) {
        var guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
            .replace(/[xy]/g,
                     function(c) {
                         var r = Math.random() * 16 | 0, v = c === 'x' ? r
                             : (r & 0x3 | 0x8);
                         return v.toString(16);
                     });
        if (typeof obj !== 'undefined') {
            return obj.type + '-' + guid;
        }
        else {
            return guid;
        }
    };

    var RenkanModel = Backbone.RelationalModel.extend({
        idAttribute : '_id',
        constructor : function(options) {

            if (typeof options !== 'undefined') {
                options._id = options._id || options.id || Models.getUID(this);
                options.title = options.title || '';
                options.description = options.description || '';
                options.uri = options.uri || '';

                if (typeof this.prepare === 'function') {
                    options = this.prepare(options);
                }
            }
            Backbone.RelationalModel.prototype.constructor.call(this, options);
        },
        validate : function() {
            if (!this.type) {
                return 'object has no type';
            }
        },
        addReference : function(_options, _propName, _list, _id, _default) {
            var _element = _list.get(_id);
            if (typeof _element === 'undefined' &&
                typeof _default !== 'undefined') {
                _options[_propName] = _default;
            }
            else {
                _options[_propName] = _element;
            }
        }
    });

    // USER
    var User = Models.User = RenkanModel.extend({
        type : 'user',
        prepare : function(options) {
            options.color = options.color || '#666666';
            return options;
        },
        toJSON : function() {
            return {
                _id : this.get('_id'),
                title : this.get('title'),
                uri : this.get('uri'),
                description : this.get('description'),
                color : this.get('color')
            };
        }
    });

    // NODE
    var Node = Models.Node = RenkanModel.extend({
        type : 'node',
        relations : [ {
            type : Backbone.HasOne,
            key : 'created_by',
            relatedModel : User
        } ],
        prepare : function(options) {
            var project = options.project;
            this.addReference(options, 'created_by', project.get('users'),
                              options.created_by, project.current_user);
            options.description = options.description || '';
            return options;
        },
        toJSON : function() {
            return {
                _id : this.get('_id'),
                title : this.get('title'),
                uri : this.get('uri'),
                description : this.get('description'),
                position : this.get('position'),
                image : this.get('image'),
                style : this.get('style'),
                created_by : this.get('created_by') ? this.get('created_by')
                    .get('_id') : null,
                size : this.get('size'),
                clip_path : this.get('clip_path'),
                shape : this.get('shape'),
                type : this.get('type')
            };
        }
    });

    // EDGE
    var Edge = Models.Edge = RenkanModel.extend({
        type : 'edge',
        relations : [ {
            type : Backbone.HasOne,
            key : 'created_by',
            relatedModel : User
        }, {
            type : Backbone.HasOne,
            key : 'from',
            relatedModel : Node
        }, {
            type : Backbone.HasOne,
            key : 'to',
            relatedModel : Node
        } ],
        prepare : function(options) {
            var project = options.project;
            this.addReference(options, 'created_by', project.get('users'),
                              options.created_by, project.current_user);
            this.addReference(options, 'from', project.get('nodes'),
                              options.from);
            this.addReference(options, 'to', project.get('nodes'), options.to);
            return options;
        },
        toJSON : function() {
            return {
                _id : this.get('_id'),
                title : this.get('title'),
                uri : this.get('uri'),
                description : this.get('description'),
                from : this.get('from') ? this.get('from').get('_id') : null,
                to : this.get('to') ? this.get('to').get('_id') : null,
                style : this.get('style'),
                created_by : this.get('created_by') ? this.get('created_by')
                    .get('_id') : null
            };
        }
    });

    // View
    var View = Models.View = RenkanModel.extend({
        type : 'view',
        relations : [ {
            type : Backbone.HasOne,
            key : 'created_by',
            relatedModel : User
        } ],
        prepare : function(options) {
            var project = options.project;
            this.addReference(options, 'created_by', project.get('users'),
                              options.created_by, project.current_user);
            options.description = options.description || '';
            if (typeof options.offset !== 'undefined') {
                var offset = {};
                if (Array.isArray(options.offset)) {
                    offset.x = options.offset[0];
                    offset.y = options.offset.length > 1 ? options.offset[1]
                        : options.offset[0];
                }
                else if (options.offset.x != null) {
                    offset.x = options.offset.x;
                    offset.y = options.offset.y;
                }
                options.offset = offset;
            }
            return options;
        },
        toJSON : function() {
            return {
                _id : this.get('_id'),
                zoom_level : this.get('zoom_level'),
                offset : this.get('offset'),
                title : this.get('title'),
                description : this.get('description'),
                created_by : this.get('created_by') ? this.get('created_by')
                    .get('_id') : null,
                hidden_nodes: this.get('hidden_nodes')
                // Don't need project id
            };
        }
    });

    // PROJECT
    var Project = Models.Project = RenkanModel.extend({
        schema_version : '2',
        type : 'project',
        blacklist : [ 'saveStatus', 'loadingStatus'],
        relations : [ {
            type : Backbone.HasMany,
            key : 'users',
            relatedModel : User,
            reverseRelation : {
                key : 'project',
                includeInJSON : '_id'
            }
        }, {
            type : Backbone.HasMany,
            key : 'nodes',
            relatedModel : Node,
            reverseRelation : {
                key : 'project',
                includeInJSON : '_id'
            }
        }, {
            type : Backbone.HasMany,
            key : 'edges',
            relatedModel : Edge,
            reverseRelation : {
                key : 'project',
                includeInJSON : '_id'
            }
        }, {
            type : Backbone.HasMany,
            key : 'views',
            relatedModel : View,
            reverseRelation : {
                key : 'project',
                includeInJSON : '_id'
            }
        } ],
        addUser : function(_props, _options) {
            _props.project = this;
            var _user = User.findOrCreate(_props);
            this.get('users').push(_user, _options);
            return _user;
        },
        addNode : function(_props, _options) {
            _props.project = this;
            var _node = Node.findOrCreate(_props);
            this.get('nodes').push(_node, _options);
            return _node;
        },
        addEdge : function(_props, _options) {
            _props.project = this;
            var _edge = Edge.findOrCreate(_props);
            this.get('edges').push(_edge, _options);
            return _edge;
        },
        addView : function(_props, _options) {
            _props.project = this;
            // TODO: check if need to replace with create only
            var _view = View.findOrCreate(_props);
            // TODO: Should we remember only one view?
            this.get('views').push(_view, _options);
            return _view;
        },
        removeNode : function(_model) {
            this.get('nodes').remove(_model);
        },
        removeEdge : function(_model) {
            this.get('edges').remove(_model);
        },
        validate : function(options) {
            var _project = this;
            _.each(
                [].concat(options.users, options.nodes, options.edges,options.views),
                function(_item) {
                    if (_item) {
                        _item.project = _project;
                    }
                }
            );
        },
        getSchemaVersion : function(data) {
            var t = data;
            if(typeof(t) === 'undefined') {
                t = this;
            }
            var version = t.schema_version;
            if(!version) {
                return 1;
            }
            else {
                return version;
            }
        },
        // Add event handler to remove edges when a node is removed
        initialize : function() {
            var _this = this;
            this.on('remove:nodes', function(_node) {
                _this.get('edges').remove(
                    _this.get('edges').filter(
                        function(_edge) {
                            return _edge.get('from') === _node ||
                                _edge.get('to') === _node;
                        }));
            });
        },
        toJSON : function() {
            var json = _.clone(this.attributes);
            for ( var attr in json) {
                if ((json[attr] instanceof Backbone.Model) ||
                    (json[attr] instanceof Backbone.Collection) ||
                    (json[attr] instanceof RenkanModel)) {
                    json[attr] = json[attr].toJSON();
                }
            }
            return _.omit(json, this.blacklist);
        }
    });

    var RosterUser = Models.RosterUser = Backbone.Model
        .extend({
            type : 'roster_user',
            idAttribute : '_id',

            constructor : function(options) {

                if (typeof options !== 'undefined') {
                    options._id = options._id ||
                        options.id ||
                        Models.getUID(this);
                    options.title = options.title || '(untitled ' + this.type + ')';
                    options.description = options.description || '';
                    options.uri = options.uri || '';
                    options.project = options.project || null;
                    options.site_id = options.site_id || 0;

                    if (typeof this.prepare === 'function') {
                        options = this.prepare(options);
                    }
                }
                Backbone.Model.prototype.constructor.call(this, options);
            },

            validate : function() {
                if (!this.type) {
                    return 'object has no type';
                }
            },

            prepare : function(options) {
                options.color = options.color || '#666666';
                return options;
            },

            toJSON : function() {
                return {
                    _id : this.get('_id'),
                    title : this.get('title'),
                    uri : this.get('uri'),
                    description : this.get('description'),
                    color : this.get('color'),
                    project : (this.get('project') != null) ? this.get(
                        'project').get('id') : null,
                    site_id : this.get('site_id')
                };
            }
        });

    var UsersList = Models.UsersList = Backbone.Collection.extend({
        model : RosterUser
    });

})(window);