<commit_before>/*global _ Backbone */

/*
 * Backbone.Siren
 *
 * Copyright (c) 2013 Kiva Microfunds
 * Licensed under the MIT license.
 * https://github.com/kiva/backbone.siren/blob/master/license.txt
 */

(function(root, factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['underscore', 'backbone'], function(_, Backbone) {
            Backbone.Siren = factory(_, Backbone);
        });
    } else {
        // Browser globals
        root.Backbone.Siren = factory(_, Backbone);
    }

}(this, function (_, Backbone, undefined) {
    'use strict';

    // The store
    var _store = {}
    , store = {
        add: function (model) {
            _store[model.url()] = model;
        }

        , exists: function (model) {
            return !!_store[model.url()];
        }

        , all: function () {
            return _store;
        }
    }
    , warn = function (msg) {
        if (Backbone.Siren.settings.showWarnings && console) {
            console.warn(msg);
        }
    };

    function Action(actionData) {
        _.extend(this, actionData);
    }

    Action.prototype = {
        field: function (name) {
            return _.find(this.fields, function (field) {
                return field.name == name;
            });
        }
    };

    /**
     *
     * @static
     * @param name
     * @return {String}
     */
    function toCamelCase(name) {
        return name.replace(/(\-[a-z])/g, function(match){return match.toUpperCase().replace('-','');});
    }

    /**
     *
     * @static
     * @param entity
     * @return {Object}
     */
    function getUrl(entity) {
        var link, url;

        if (entity.href) {
            url = entity.href;
        } else if (entity.links) {
            link = entity.links.filter(function (link) {
                return !!(link.rel && link.rel.filter(function (relType) {
                    return relType == 'self';
                }).length);
            })[0];

            if (link) {
                url = link.href;
            }
        } else {
            warn('Missing href or "self" link');
        }

        return url;
    }

    /**
     * Access to the representation's "self" url, or its "href" if there is one.
     *
     * @return {String}
     */
    function url() {
        return getUrl(this._data);
    }

    /**
     *
     * @static
     * @param {Object} sirenObj Can be a siren entity or siren action object
     * @return {Array}
     */
    function getClassNames(sirenObj) {
        return sirenObj['class'];
    }

    /**
     *
     * @static
     * @param {Array} entities
     * @param {Object} filters
     * @return {Array}
     */
    function filter(entities, filters) {
        return _.filter(entities, function (entity) {
            return hasProperties(entity, filters);
        });
    }

    /**
     *
     * @param {Backbone.Siren.Model|Backbone.Siren.Collection} bbSiren
     * @param {Object} filters
     * @return {Boolean}
     */
    function hasProperties(bbSiren, filters) {
        var hasProperties = true;

        if (filters.className) {
            hasProperties = bbSiren.hasClass(filters.className);
        }

        if (filters.rel) {
            hasProperties = bbSiren.rel() == filters.rel;
        }

        return hasProperties;
    }

    /**
     *
     * @param {Object} action
     * @param {Object} filters
     * @return {Boolean}
     */
    function actionHasProperties(action, filters) {
        var hasProperties = true;

        if (filters.className) {
            hasProperties = _hasClass(action, filters.className);
        }

        if (filters.name) {
            hasProperties = action.name == filters.name;
        }

        return hasProperties;
    }

    /**
     *
     * @static
     * @param sirenObj
     * @param className
     * @return {Boolean}
     */
    function _hasClass(sirenObj, className) {
        return _.indexOf(getClassNames(sirenObj), className) > -1;
    }

    /**
     *
     * @param className
     * @return {Boolean}
     */
    function hasClass(className) {
        return _hasClass(this._data, className);
    }

    /**
     * Accesses the "class" property of the Siren Object
     *
     * @return {Array}
     */
    function classes() {
        return getClassNames(this._data);
    }

    /**
     *
     * @static
     * @param sirenObj
     * @return {String}
     */
    function getRel(sirenObj) {
        var rel = sirenObj.rel;

        if (rel) {
            rel = rel[0]; // @todo, arbitrarily grabbing the first rel might be bad but I still don't understand the use case for many rels...
            rel = rel.slice(rel.lastIndexOf('/') + 1, rel.length);
        }

        return rel;
    }

    function rel() {
        return getRel(this._data);
    }

    function actions(filters) {
        var _actions = this._actions;

        if (filters) {
            _actions = _.filter(_actions, function (action) {
                return actionHasProperties(action, filters);
            });
        }
        return _actions;
    }

    function action(name) {
        return _.find(this._actions, function (action) {
            return action.name == name;
        });
    }

    /**
     * Access to the representation's "title"
     *
     * @return {String}
     */
    function title() {
        return this._data.title;
    }

    /**
     *
     * @param model
     * @param options
     */
    function parseActions(model, options) {
        var _actions = [];

        _.each(model._data.actions, function (action) {
            var bbSirenAction = new Backbone.Siren.Action(action);

            _actions.push(bbSirenAction);

            model[toCamelCase(action.name)] = function () {

                options.url = action.href;
                options.actionName = action.name;

                if (action.method) {
                    options.method = action.method;
                }

                if (action.type) {
                    options.type = action.type;
                }

                return model.save(arguments, options);
            };
        });

        model._actions = _actions;
    }

    return {
        settings: {
            showWarnings: true
        }

        , store: store

        , Action: Action

        , Model: Backbone.Model.extend({

            url: url
            , classes: classes
            , hasClass: hasClass
            , rel: rel
            , title: title
            , actions: actions
            , action: action

            /**
             * http://backbonejs.org/#Model-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj, options) {
                var self = this;

                this.resolveEntities()
                    .done(function (args) {
                        _.each(args, function (entity) {
                            var rel, bbSiren;

                            if (_hasClass(entity, 'collection')) {
                                // Its a collection
                                bbSiren = new Backbone.Siren.Collection(entity);
                            } else if (_hasClass(entity, 'error')) {
                                // @todo how should we represent errors?
                            } else {
                                // Its a model
                                bbSiren = new Backbone.Siren.Model(entity);
                                store.add(bbSiren);
                            }

                            rel = bbSiren.rel();
                            self.set(rel, bbSiren);
                            self._entities.push(rel);
                        });
                    });

                parseActions(this, options);

                return sirenObj.properties;
            }

            /**
             * http://backbonejs.org/#Model-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function () {
                var json = _.clone(this.attributes)
                , entities = this.entities();

                _.each(entities, function (entity) {
                    json[entity.rel()] = entity;
                });

                return json;
            }

            /**
             * Filters the entity's properties and returns only sub-entities
             *
             * @return {Array}
             */
            , entities: function (filters) {
                var self = this
                , entities = _.filter(this, function (val, name) {
                    return _.indexOf(self._entities, name) > -1;
                });

                if (filters) {
                    entities = filter(entities, filters);
                }

                return entities;
            }

            /**
             *
             * @return {jQuery.Deferred}
             */
            , resolveEntities: function () {
                var deferreds = [];

                _.each(this._data.entities, function (entity) {
                    var url = getUrl(entity);

                    if (entity.href && url) {
                        deferreds.push($.getJSON(url));
                    } else if (! entity.href) {
                        deferreds.push(entity);
                    }
                });

                return $.when(deferreds);
            }

            /**
             * http://backbonejs.org/#Model-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj; // Stores the entire siren object in raw json
                this._entities = []; // Stores sub-entity names

                Backbone.Model.call(this, sirenObj, options);
            }

        })

        , Collection: Backbone.Collection.extend({
            url: url
            , classes: classes
            , hasClass: hasClass
            , title: title
            , rel: rel
            , actions: actions
            , action: action

            /**
             * http://backbonejs.org/#Collection-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function (options) {
                return this.map(function(model){
                    return model.toJSON(options);
                });
            }

            /**
             *
             * @param {Function|Object} arg
             * @return {Array}
             */
            , filter: function (arg) {
                if (typeof arg ==  'function') {
                    return _.filter(this, arg);
                } else {
                    return filter(this, arg);
                }
            }

            /**
             * http://backbonejs.org/#Collection-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj, options) {
                var models = [];
                _.each(sirenObj.entities, function (entity) {
                    var model = new Backbone.Siren.Model(entity);
                    models.push(model);
                    store.add(model);
                });

                parseActions(this, options);

                return models;
            }

            /**
             * http://backbonejs.org/#Collection-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj;

                Backbone.Collection.call(this, sirenObj, options);
            }
        })
    };

}));<commit_msg>provide method for getting all attributes that correspond to a given siren action<commit_after>/*global _ Backbone */

/*
 * Backbone.Siren
 *
 * Copyright (c) 2013 Kiva Microfunds
 * Licensed under the MIT license.
 * https://github.com/kiva/backbone.siren/blob/master/license.txt
 */

(function(root, factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['underscore', 'backbone'], function(_, Backbone) {
            Backbone.Siren = factory(_, Backbone);
        });
    } else {
        // Browser globals
        root.Backbone.Siren = factory(_, Backbone);
    }

}(this, function (_, Backbone, undefined) {
    'use strict';

    // The store
    var _store = {}
    , store = {
        add: function (model) {
            _store[model.url()] = model;
        }

        , exists: function (model) {
            return !!_store[model.url()];
        }

        , all: function () {
            return _store;
        }
    }
    , warn = function (msg) {
        if (Backbone.Siren.settings.showWarnings && console) {
            console.warn(msg);
        }
    };

    function Action(actionData) {
        _.extend(this, actionData);
    }

    Action.prototype = {
        field: function (name) {
            return _.find(this.fields, function (field) {
                return field.name == name;
            });
        }
    };

    /**
     *
     * @static
     * @param name
     * @return {String}
     */
    function toCamelCase(name) {
        return name.replace(/(\-[a-z])/g, function(match){return match.toUpperCase().replace('-','');});
    }

    /**
     *
     * @static
     * @param entity
     * @return {Object}
     */
    function getUrl(entity) {
        var link, url;

        if (entity.href) {
            url = entity.href;
        } else if (entity.links) {
            link = entity.links.filter(function (link) {
                return !!(link.rel && link.rel.filter(function (relType) {
                    return relType == 'self';
                }).length);
            })[0];

            if (link) {
                url = link.href;
            }
        } else {
            warn('Missing href or "self" link');
        }

        return url;
    }

    /**
     * Access to the representation's "self" url, or its "href" if there is one.
     *
     * @return {String}
     */
    function url() {
        return getUrl(this._data);
    }

    /**
     *
     * @static
     * @param {Object} sirenObj Can be a siren entity or siren action object
     * @return {Array}
     */
    function getClassNames(sirenObj) {
        return sirenObj['class'];
    }

    /**
     *
     * @static
     * @param {Array} entities
     * @param {Object} filters
     * @return {Array}
     */
    function filter(entities, filters) {
        return _.filter(entities, function (entity) {
            return hasProperties(entity, filters);
        });
    }

    /**
     *
     * @param {Backbone.Siren.Model|Backbone.Siren.Collection} bbSiren
     * @param {Object} filters
     * @return {Boolean}
     */
    function hasProperties(bbSiren, filters) {
        var _hasProperties = true;

        if (filters.className) {
            _hasProperties = bbSiren.hasClass(filters.className);
        }

        if (filters.rel) {
            _hasProperties = bbSiren.rel() == filters.rel;
        }

        return _hasProperties;
    }

    /**
     *
     * @param {Object} action
     * @param {Object} filters
     * @return {Boolean}
     */
    function actionHasProperties(action, filters) {
        var hasProperties = true;

        if (filters.className) {
            hasProperties = _hasClass(action, filters.className);
        }

        if (filters.name) {
            hasProperties = action.name == filters.name;
        }

        return hasProperties;
    }

    /**
     *
     * @static
     * @param sirenObj
     * @param className
     * @return {Boolean}
     */
    function _hasClass(sirenObj, className) {
        return _.indexOf(getClassNames(sirenObj), className) > -1;
    }

    /**
     *
     * @param className
     * @return {Boolean}
     */
    function hasClass(className) {
        return _hasClass(this._data, className);
    }

    /**
     * Accesses the "class" property of the Siren Object
     *
     * @return {Array}
     */
    function classes() {
        return getClassNames(this._data);
    }

    /**
     *
     * @static
     * @param sirenObj
     * @return {String}
     */
    function getRel(sirenObj) {
        var rel = sirenObj.rel;

        if (rel) {
            rel = rel[0]; // @todo, arbitrarily grabbing the first rel might be bad but I still don't understand the use case for many rels...
            rel = rel.slice(rel.lastIndexOf('/') + 1, rel.length);
        }

        return rel;
    }

    function rel() {
        return getRel(this._data);
    }

    function actions(filters) {
        var _actions = this._actions;

        if (filters) {
            _actions = _.filter(_actions, function (action) {
                return actionHasProperties(action, filters);
            });
        }
        return _actions;
    }

    function getAllByAction(actionName) {
        var action = this.action(actionName)
        , values = {}
        , self = this;

        _.each(action.fields, function (field) {
            values[field.name] = self.get(field.name);
        });

        return values;
    }

    function action(name) {
        return _.find(this._actions, function (action) {
            return action.name == name;
        });
    }

    /**
     * Access to the representation's "title"
     *
     * @return {String}
     */
    function title() {
        return this._data.title;
    }

    /**
     *
     * @param model
     * @param options
     */
    function parseActions(model, options) {
        var _actions = [];

        _.each(model._data.actions, function (action) {
            var bbSirenAction = new Backbone.Siren.Action(action);

            _actions.push(bbSirenAction);

            model[toCamelCase(action.name)] = function () {

                options.url = action.href;
                options.actionName = action.name;

                if (action.method) {
                    options.method = action.method;
                }

                if (action.type) {
                    options.type = action.type;
                }

                return model.save(model.getAllByAction(action.name), options);
            };
        });

        model._actions = _actions;
    }

    return {
        settings: {
            showWarnings: true
        }

        , store: store

        , Action: Action

        , Model: Backbone.Model.extend({

            url: url
            , classes: classes
            , hasClass: hasClass
            , rel: rel
            , title: title
            , actions: actions
            , action: action
            , getAllByAction: getAllByAction

            /**
             * http://backbonejs.org/#Model-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj, options) {
                var self = this;

                this.resolveEntities()
                    .done(function (args) {
                        _.each(args, function (entity) {
                            var rel, bbSiren;

                            if (_hasClass(entity, 'collection')) {
                                // Its a collection
                                bbSiren = new Backbone.Siren.Collection(entity);
                            } else if (_hasClass(entity, 'error')) {
                                // @todo how should we represent errors?
                                warn('@todo - errors');
                            } else {
                                // Its a model
                                bbSiren = new Backbone.Siren.Model(entity);
                                store.add(bbSiren);
                            }

                            rel = bbSiren.rel();
                            self.set(rel, bbSiren);
                            self._entities.push(rel);
                        });
                    });

                parseActions(this, options);

                return sirenObj.properties;
            }

            /**
             * http://backbonejs.org/#Model-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function () {
                var json = _.clone(this.attributes)
                , entities = this.entities();

                _.each(entities, function (entity) {
                    json[entity.rel()] = entity;
                });

                return json;
            }

            /**
             * Filters the entity's properties and returns only sub-entities
             *
             * @return {Array}
             */
            , entities: function (filters) {
                var self = this
                , entities = _.filter(this, function (val, name) {
                    return _.indexOf(self._entities, name) > -1;
                });

                if (filters) {
                    entities = filter(entities, filters);
                }

                return entities;
            }

            /**
             *
             * @return {jQuery.Deferred}
             */
            , resolveEntities: function () {
                var deferreds = [];

                _.each(this._data.entities, function (entity) {
                    var url = getUrl(entity);

                    if (entity.href && url) {
                        deferreds.push($.getJSON(url));
                    } else if (! entity.href) {
                        deferreds.push(entity);
                    }
                });

                return $.when(deferreds);
            }

            /**
             * http://backbonejs.org/#Model-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj; // Stores the entire siren object in raw json
                this._entities = []; // Stores sub-entity names

                Backbone.Model.call(this, sirenObj, options);
            }

        })

        , Collection: Backbone.Collection.extend({
            url: url
            , classes: classes
            , hasClass: hasClass
            , title: title
            , rel: rel
            , actions: actions
            , action: action
            , getAllByAction: getAllByAction

            /**
             * http://backbonejs.org/#Collection-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function (options) {
                return this.map(function(model){
                    return model.toJSON(options);
                });
            }

            /**
             *
             * @param {Function|Object} arg
             * @return {Array}
             */
            , filter: function (arg) {
                if (typeof arg ==  'function') {
                    return _.filter(this, arg);
                } else {
                    return filter(this, arg);
                }
            }

            /**
             * http://backbonejs.org/#Collection-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj, options) {
                var models = [];
                _.each(sirenObj.entities, function (entity) {
                    var model = new Backbone.Siren.Model(entity);
                    models.push(model);
                    store.add(model);
                });

                parseActions(this, options);

                return models;
            }

            /**
             * http://backbonejs.org/#Collection-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj;

                Backbone.Collection.call(this, sirenObj, options);
            }
        })
    };

}));<|endoftext|>


<commit_before>/*global _ Backbone */

/*
 * Backbone.Siren
 *
 * Copyright (c) 2013 Kiva Microfunds
 * Licensed under the MIT license.
 * https://github.com/kiva/backbone.siren/blob/master/license.txt
 */

(function(root, factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['underscore', 'backbone', 'backbone-relational'], function(_, Backbone) {
            Backbone.Siren = factory(_, Backbone);
        });
    } else {
        // Browser globals
        root.Backbone.Siren = factory(_, Backbone);
    }

}(this, function (_, Backbone, undefined) {
    'use strict';

    // The store
    var _store = {}
    , store = {
        key: function (model) {
            return model.url() + '-' +  model.cid;
        }

        , add: function (model) {
            _store[this.key(model)] = model;
        }

        , exists: function (model) {
            return !!_store[this.key(model)];
        }

        , all: function () {
            return _store;
        }
    }
    , warn = function (msg) {
        if (Backbone.Siren.settings.showWarnings && console) {
            console.warn(msg);
        }
    };

    /**
     *
     * @static
     * @param name
     * @param lowercaseFirstChar
     * @return {String}
     */
    function toCamelCase(name, lowercaseFirstChar) {
        return ((lowercaseFirstChar ? '' : '-') + name).replace(/(\-[a-z])/g, function(match){return match.toUpperCase().replace('-','');});
    }

    /**
     *
     * @static
     * @param entity
     * @return {Object}
     */
    function getUrl(entity) {
        var link, url;

        if (entity.href) {
            url = entity.href;
        } else if (entity.links) {
            link = entity.links.filter(function (link) {
                return !!(link.rel && link.rel.filter(function (relType) {
                    return relType == 'self';
                }).length);
            })[0];

            if (link) {
                url = link.href;
            }
        } else {
            warn('Missing href or "self" link');
        }

        return url;
    }

    /**
     * Access to the representation's "self" url, or its "href" if there is one.
     *
     * @return {String}
     */
    function url() {
        return getUrl(this._data);
    }

    /**
     *
     * @static
     * @return {Array}
     */
    function getClasses(entity) {
        return entity['class'];
    }

    /**
     * Accesses the "class" property of the Siren Object
     *
     * @return {Array}
     */
    function classes() {
        return getClasses(this._data);
    }

    /**
     * By default returns characters after the last '/'.  Set to `verbose` to true to return the entire rel string.
     *
     * @param {Boolean} verbose
     * @return {String}
     */
    function rel(verbose) {
        var _rel = this._data.rel;

        if (_rel) {
            _rel = _rel[0];

            if (! verbose) {
                _rel = _rel.slice(_rel.lastIndexOf('/') + 1, _rel.length);
            }
        } else {
            warn('Missing "rel" attribute');
        }

        return _rel;
    }

    /**
     * Access to the representation's "title"
     *
     * @return {String}
     */
    function title() {
        return this._data.title;
    }

    /**
     * Access to the representation's "actions"
     *
     * @return {Array}
     */
    function actions() {
        return this._data.actions;
    }

    return {
        store: store

        , settings: {
            showWarnings: true
        }

        , Model: Backbone.Model.extend({

            url: url
            , classes: classes
            , rel: rel
            , title: title
            , actions: actions

            /**
             * http://backbonejs.org/#Model-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj) {
                var self = this;

                this.resolveEntities()
                    .done(function (args) {
                        _.each(args, function (entity) {
                            if (_.indexOf(getClasses(entity), 'collection') == -1) {
                                // Its a model
                                var model = new Backbone.Siren.Model(entity);

                                self[toCamelCase(model.rel())] = model;
                                self._entities.push(model);
                                store.add(model);
                            } else {
                                // Its a collection
                                var collection = new Backbone.Siren.Collection(entity);

                                self[toCamelCase(collection.rel())] = collection;
                                self._entities.push(collection);
                            }
                        });
                    });

                return sirenObj.properties;
            }

            /**
             * http://backbonejs.org/#Model-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function () {
                var json = _.clone(this.attributes)
                , entities = this.entities();

                _.each(entities, function (entity) {
                    json[entity.rel()] = entity;
                });

                return json;
            }

            /**
             * Access to the representation's "actions"
             *
             */
            , entities: function () {
                return this._entities;
            }

            /**
             *
             * @param {Object} options
             * @param {Boolean} options.force forces an ajax request
             * @param {Array} options.range See http://underscorejs.org/#range
             *
             * @returns {jQuery.Deferred}
             */
            , resolveEntities: function (filters, options) {
                options = options || {};

                var deferreds = []
                , entities = this._data.entities;

                if (filters) {
                    // @todo Currently only have a filter for "rel"
                    entities = entities.filter(function (el) {
                        var rel = el.rel;

                        rel = rel.slice(rel.lastIndexOf('/') + 1, rel.length);
                        return _.indexOf(rel, filters.rel) > -1;
                    });
                }

                if (options.range) {
                    entities = entities.slice(options.range[0], options.range[1]);
                }

                _.each(entities, function (entity) {
                    var url = getUrl(entity);

                    if ((entity.href || options.force) && url) {
                        deferreds.push($.getJSON(url));
                    } else if (! entity.href) {
                        deferreds.push(entity);
                    }
                });

                return $.when(deferreds);
            }

            /**
             * http://backbonejs.org/#Model-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj; // Stores the entire siren object in raw json
                this._entities = []; // Stores sub-entity models

                Backbone.Model.call(this, sirenObj, options);
            }

        })

        , Collection: Backbone.Collection.extend({
            url: url
            , classes: classes
            , title: title
            , rel: rel

            /**
             * http://backbonejs.org/#Collection-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function (options) {
                return this.map(function(model){
                    return model.toJSON(options);
                });
            }

            /**
             * http://backbonejs.org/#Collection-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj) {
                var models = [];
                _.each(sirenObj.entities, function (entity) {
                    var model = new Backbone.Siren.Model(entity);
                    models.push(model);
                    store.add(model);
                });

                return models;
            }

            /**
             * http://backbonejs.org/#Collection-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj;

                Backbone.Collection.call(this, sirenObj, options);
            }
        })
    };

}));<commit_msg>have the ._entities array store entity names instead of the entire object.  If someone wants all entities they call .entities(), however if they just need a reference to what Model properties are entities they can reference the ._entities property<commit_after>/*global _ Backbone */

/*
 * Backbone.Siren
 *
 * Copyright (c) 2013 Kiva Microfunds
 * Licensed under the MIT license.
 * https://github.com/kiva/backbone.siren/blob/master/license.txt
 */

(function(root, factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['underscore', 'backbone', 'backbone-relational'], function(_, Backbone) {
            Backbone.Siren = factory(_, Backbone);
        });
    } else {
        // Browser globals
        root.Backbone.Siren = factory(_, Backbone);
    }

}(this, function (_, Backbone, undefined) {
    'use strict';

    // The store
    var _store = {}
    , store = {
        key: function (model) {
            return model.url() + '-' +  model.cid;
        }

        , add: function (model) {
            _store[this.key(model)] = model;
        }

        , exists: function (model) {
            return !!_store[this.key(model)];
        }

        , all: function () {
            return _store;
        }
    }
    , warn = function (msg) {
        if (Backbone.Siren.settings.showWarnings && console) {
            console.warn(msg);
        }
    };

    /**
     *
     * @static
     * @param name
     * @param lowercaseFirstChar
     * @return {String}
     */
    function toCamelCase(name, lowercaseFirstChar) {
        return ((lowercaseFirstChar ? '' : '-') + name).replace(/(\-[a-z])/g, function(match){return match.toUpperCase().replace('-','');});
    }

    /**
     *
     * @static
     * @param entity
     * @return {Object}
     */
    function getUrl(entity) {
        var link, url;

        if (entity.href) {
            url = entity.href;
        } else if (entity.links) {
            link = entity.links.filter(function (link) {
                return !!(link.rel && link.rel.filter(function (relType) {
                    return relType == 'self';
                }).length);
            })[0];

            if (link) {
                url = link.href;
            }
        } else {
            warn('Missing href or "self" link');
        }

        return url;
    }

    /**
     * Access to the representation's "self" url, or its "href" if there is one.
     *
     * @return {String}
     */
    function url() {
        return getUrl(this._data);
    }

    /**
     *
     * @static
     * @return {Array}
     */
    function getClasses(entity) {
        return entity['class'];
    }

    /**
     * Accesses the "class" property of the Siren Object
     *
     * @return {Array}
     */
    function classes() {
        return getClasses(this._data);
    }

    /**
     * By default returns characters after the last '/'.  Set to `verbose` to true to return the entire rel string.
     *
     * @param {Boolean} verbose
     * @return {String}
     */
    function rel(verbose) {
        var _rel = this._data.rel;

        if (_rel) {
            _rel = _rel[0];

            if (! verbose) {
                _rel = _rel.slice(_rel.lastIndexOf('/') + 1, _rel.length);
            }
        } else {
            warn('Missing "rel" attribute');
        }

        return _rel;
    }

    /**
     * Access to the representation's "title"
     *
     * @return {String}
     */
    function title() {
        return this._data.title;
    }

    /**
     * Access to the representation's "actions"
     *
     * @return {Array}
     */
    function actions() {
        return this._data.actions;
    }

    return {
        store: store

        , settings: {
            showWarnings: true
        }

        , Model: Backbone.Model.extend({

            url: url
            , classes: classes
            , rel: rel
            , title: title
            , actions: actions

            /**
             * http://backbonejs.org/#Model-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj) {
                var self = this;

                this.resolveEntities()
                    .done(function (args) {
                        _.each(args, function (entity) {
                            var camelCaseRel, model, collection;

                            if (_.indexOf(getClasses(entity), 'collection') == -1) {
                                // Its a model
                                model = new Backbone.Siren.Model(entity);
                                camelCaseRel = toCamelCase(model.rel());

                                self[camelCaseRel] = model;
                                self._entities.push(camelCaseRel);
                                store.add(model);
                            } else {
                                // Its a collection
                                collection = new Backbone.Siren.Collection(entity);
                                camelCaseRel = toCamelCase(collection.rel());

                                self[camelCaseRel] = collection;
                                self._entities.push(camelCaseRel);
                            }
                        });
                    });

                return sirenObj.properties;
            }

            /**
             * http://backbonejs.org/#Model-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function () {
                var json = _.clone(this.attributes)
                , entities = this.entities();

                _.each(entities, function (entity) {
                    json[entity.rel()] = entity;
                });

                return json;
            }

            /**
             * Filters the entitie's properties and returns only sub-entities
             *
             */
            , entities: function () {
                var self = this;
                return _.filter(this, function (val, name) {
                    return _.indexOf(self._entities, name) > -1;
                });
            }

            /**
             *
             * @param {Object} options
             * @param {Boolean} options.force forces an ajax request
             * @param {Array} options.range See http://underscorejs.org/#range
             *
             * @returns {jQuery.Deferred}
             */
            , resolveEntities: function (filters, options) {
                options = options || {};

                var deferreds = []
                , entities = this._data.entities;

                if (filters) {
                    // @todo Currently only have a filter for "rel"
                    entities = entities.filter(function (el) {
                        var rel = el.rel;

                        rel = rel.slice(rel.lastIndexOf('/') + 1, rel.length);
                        return _.indexOf(rel, filters.rel) > -1;
                    });
                }

                if (options.range) {
                    entities = entities.slice(options.range[0], options.range[1]);
                }

                _.each(entities, function (entity) {
                    var url = getUrl(entity);

                    if ((entity.href || options.force) && url) {
                        deferreds.push($.getJSON(url));
                    } else if (! entity.href) {
                        deferreds.push(entity);
                    }
                });

                return $.when(deferreds);
            }

            /**
             * http://backbonejs.org/#Model-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj; // Stores the entire siren object in raw json
                this._entities = []; // Stores sub-entity models

                Backbone.Model.call(this, sirenObj, options);
            }

        })

        , Collection: Backbone.Collection.extend({
            url: url
            , classes: classes
            , title: title
            , rel: rel

            /**
             * http://backbonejs.org/#Collection-toJSON
             *
             * @param {Object} options
             */
            , toJSON: function (options) {
                return this.map(function(model){
                    return model.toJSON(options);
                });
            }

            /**
             * http://backbonejs.org/#Collection-parse
             *
             * @param {Object} sirenObj
             */
            , parse: function (sirenObj) {
                var models = [];
                _.each(sirenObj.entities, function (entity) {
                    var model = new Backbone.Siren.Model(entity);
                    models.push(model);
                    store.add(model);
                });

                return models;
            }

            /**
             * http://backbonejs.org/#Collection-constructor
             *
             * @param {Object} attributes
             * @param {Object} options
             */
            , constructor: function (sirenObj, options) {
                options = options || {};
                options.parse = true; // Force "parse" to be called on instantiation: http://stackoverflow.com/questions/11068989/backbone-js-using-parse-without-calling-fetch/14950519#14950519

                this._data = sirenObj;

                Backbone.Collection.call(this, sirenObj, options);
            }
        })
    };

}));<|endoftext|>


<commit_before>"use strict";

/*globals
	YUI: true,
*/

YUI.add('Bucket', function (Y) {

	Y.Bucket = {

		// Properties
		bucketId: 0,

		// Methods
		init: function () {
			this.bucketId = new Date().getTime();
			//console.log("Bucket {" + this.bucketId + "} created");
			return this;
		},

		asHtml: function () {
			var html = [];

			html.push("
");
			html.push("
");
			html.push("

");
			html.push("
");
			html.push("
");

			return html.join('').supplant({
				bucketId: this.bucketId
			});
		},

		getTweets: function (request, params) {
			Y.Twitter.call(request, function (Tweets, Bucket) {
				Bucket.addTweets(Tweets);
			}, params, this);
		},

		addTweets: function (Tweets) {
			var html, i;

			html = [];

			if (Tweets.length > 0) {
				for (i in Tweets) {
					if (Tweets.hasOwnProperty(i)) {
						html.push(Tweets[i].asHtml());
					}
				}
			}
			else if (Y.all(".bucket").size() === 1) {
				html.push("
No tweets found
");
			}

			html = html.join('');

			Y.one("#bucketId-" + this.bucketId + ' .inner').set("innerHTML", html);
		}

	}; // End of Bucket

}, '0.0.1', { requires: ['node'] });<commit_msg>bug fix for image path<commit_after>"use strict";

/*globals
	YUI: true,
*/

YUI.add('Bucket', function (Y) {

	Y.Bucket = {

		// Properties
		bucketId: 0,

		// Methods
		init: function () {
			this.bucketId = new Date().getTime();
			//console.log("Bucket {" + this.bucketId + "} created");
			return this;
		},

		asHtml: function () {
			var html = [];

			html.push("
");
			html.push("
");
			html.push("

");
			html.push("
");
			html.push("
");

			return html.join('').supplant({
				bucketId: this.bucketId
			});
		},

		getTweets: function (request, params) {
			Y.Twitter.call(request, function (Tweets, Bucket) {
				Bucket.addTweets(Tweets);
			}, params, this);
		},

		addTweets: function (Tweets) {
			var html, i;

			html = [];

			if (Tweets.length > 0) {
				for (i in Tweets) {
					if (Tweets.hasOwnProperty(i)) {
						html.push(Tweets[i].asHtml());
					}
				}
			}
			else if (Y.all(".bucket").size() === 1) {
				html.push("
No tweets found
");
			}

			html = html.join('');

			Y.one("#bucketId-" + this.bucketId + ' .inner').set("innerHTML", html);
		}

	}; // End of Bucket

}, '0.0.1', { requires: ['node'] });<|endoftext|>


<commit_before>openerp.base_kanban = function (openerp) {
QWeb.add_template('/base_kanban/static/src/xml/base_kanban.xml');
openerp.base.views.add('kanban', 'openerp.base_kanban.KanbanView');
openerp.base_kanban.KanbanView = openerp.base.View.extend({

    init: function(parent, element_id, dataset, view_id) {
        this._super(parent, element_id);
        this.view_manager = parent;
        this.dataset = dataset;
        this.domain = dataset.domain;
        this.context = dataset.context;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.group_by_field = false;
        this.source_index = {};
        this.all_display_data = false;
        this.groups = [];
    },

    start: function() {
        this.rpc("/base_kanban/kanbanview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function(data) {
        var self = this;
        this.template_xml = '';
        this.columns = data.all_fields;
        _.each(data.fields_view.arch.children, function(child) {
            if (child.tag == "template"){
                self.template_xml = openerp.base.json_node_to_xml(child, true)
            }
        });
        if(this.template_xml){
            self.dataset.read_slice({
                context: self.dataset.get_context(),
                domain: self.dataset.get_domain()}, function (records) {
                self.all_display_data = [{'records': records, 'value':false, 'header': false, 'ids': self.dataset.ids}];
                self.on_show_data(self.all_display_data);
            });
        }
    },

    on_show_data: function(datas) {
        var self = this;
        var new_qweb = new QWeb2.Engine();
        self.$element.html(QWeb.render("KanbanBiew", {"datas" :datas}));

        this.on_reload_kanban();
        this.$element.find(".oe_column").sortable({
            connectWith: ".oe_column",
            start: function(event, ui) {
                self.source_index['index'] = ui.item.index();
                self.source_index['column'] = ui.item.parent().attr('id');
            },
            stop: self.on_recieve_record,
        });
        this.$element.find(".record").addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
            .find(".record-header")
                .addClass("ui-widget-header ui-corner-all")
                .prepend( "")
                .end()
            .find( ".record-content" );

        this.$element.find(".record-header .ui-icon").click(function() {
            $(this).toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
            $(this).parents(".record:first").find(".record-content").toggle();
        });
        this.$element.find('.record .ui-icon-closethick').click(this.on_close_action);
        this.$element.find(".oe_column").disableSelection();
    },

    on_button_click: function(button_attrs, record_id){
        var self = this;
        if(this.groups.length){
            _.each(this.groups, function (group) {
                group.list([],
                    function (groups) {},
                    function (dataset) {
                        dataset.read_slice({}, function(records) {
                            var index = parseInt(_.indexOf(dataset.ids, record_id));
                            if(index >= 0) {
                                self.on_confirm_click(dataset, button_attrs, index, record_id);
                            }
                        });
                    }
                );
            });
        } else{
            var index = parseInt(_.indexOf(self.dataset.ids, record_id));
            if(index >= 0) {
                _.extend(self.dataset, {domain: self.domain, context: self.context})
                self.on_confirm_click(self.dataset, button_attrs, index, record_id)
            }
        }
    },

    on_confirm_click: function(dataset, button_attrs, index, record_id){
        if(button_attrs.type == 'edit') {
            this.do_edit_record(dataset, index);
        } else{
            this.on_execute_button_click(dataset, button_attrs, record_id)
        }
    },

    do_edit_record: function (dataset, index) {
        var self = this;
        _.extend(this.dataset, {
            domain: dataset.domain,
            context: dataset.get_context()
        }).read_slice({}, function () {
            self.dataset.index = index;
            self.do_switch_view('form');
        });
    },

    do_delete: function (id) {
        var self = this;
        return $.when(this.dataset.unlink([id])).then(function () {
            self.drop_records(id);
        });
    },

    drop_records: function (id) {
        var self = this;
        _.each(self.all_display_data, function(data, index) {
            _.each(data.records, function(record, index_row) {
                if(parseInt(record.id) == id) {
                    self.all_display_data[index]['records'].splice(index_row, 1)
                    return false;
                }
            });
        });
        self.$element.find("#main_" + id).remove()
    },

    on_execute_button_click: function(dataset, button_attrs, record_id) {
        var self = this;
        this.execute_action(
            button_attrs, dataset,
            record_id, function () {
                var count = 1;
                _.each(self.all_display_data, function(data, index) {
                    self.dataset.read_ids( data.ids, [], function(records){
                        self.all_display_data[index].records = records;
                        if(self.all_display_data.length == count) {
                            self.on_reload_kanban();
                        }
                        count++;
                    });
                });
            }
        );
    },

    on_close_action: function(e) {
        var record_id = $(e.currentTarget).parents('.record:first').attr("id")
        if(record_id) {
            record_id = parseInt(record_id.split("_")[1])
            if(record_id) {
                this.do_delete(record_id);
            }
        }
    },

    on_recieve_record: function(event, ui) {
        var self = this;
        var from = ui.item.index();
        var search_action = false;
        var to = ui.item.prev().index() || 0;
        if(!ui.item.attr("id")){
            return false;
        }
        if(self.columns.sequence && (self.source_index.index >= 0 && self.source_index.index != from) ||
                (self.source_index.column && self.source_index.column != ui.item.parent().attr('id'))) {
            var child_record = ui.item.parent().children();
            var data, sequence = 1, index = to;
            child_record.splice(0, to);
            if(to >= 0 && child_record) {
                var record_id = parseInt($(child_record).attr("id").split("_")[1]);
                if(record_id) {
                    var flag = false;
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
	                        if(record_id == record.id && record.sequence) {
	                            sequence = record.sequence;
	                            flag = true;
	                            return false;
	                        }
                        });
                        if(flag) {return false;}
                    });
                }
            }
            _.each(child_record, function (child) {
                var child_id = parseInt($(child).attr("id").split("_")[1]);
                if(child_id) {
                    var flag = false;
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
                            if(parseInt(record.id) == child_id) {
                                self.all_display_data[index]['records'][index_row]['sequence'] = sequence;
                                flag = true;
                                return false;
                            }
                        });
                        if(flag) {return false;}
                    });
                    self.dataset.write(child_id, {sequence: sequence});
                    sequence++;
                    search_action = true;
                }
            });
        }
        if(self.group_by_field && self.source_index.column && self.source_index.column != ui.item.parent().attr('id')) {
            var value = ui.item.closest("td").attr("id")
            if(value) {
                var data_val = {};
                var wirte_id = parseInt(ui.item.attr("id").split("_")[1]);
                value = value.split("_")[1];
                if(value == 'false') {
                    value = false;
                }
                var update_record = false;
                _.each(self.all_display_data, function(data, index) {
                    _.each(data.records, function(record, index_row) {
                        if(parseInt(record.id) == wirte_id) {
                            self.all_display_data[index]['records'][index_row][self.group_by_field] = value;
                            update_record = self.all_display_data[index]['records'].splice(index_row,1)
                            return false;
                        }
                    });
                    if(update_record) {return false;}
                });
                _.each(self.all_display_data, function(data, index) {
                    if (data.value == value || (data.value == 'false' && value == false)) {
                        self.all_display_data[index]['records'].push(update_record[0]);
                    }
                });
                data_val[self.group_by_field] = value;
                self.dataset.write(wirte_id, data_val);
                search_action = true;
            }
        }
        if(search_action) {
            self.on_reload_kanban();
        }
        this.source_index = {};
    },

    on_reload_kanban: function(){
        var self = this;
        var new_qweb = new QWeb2.Engine();
        new_qweb.add_template('<templates><t t-name="custom_template">' + this.template_xml + '</t></templates>')
        _.each(self.all_display_data, function(data, index) {
            if(data.records.length > 0){
                _.each(data.records, function(record) {
                    self.$element.find("#data_" + record.id).children().remove()
                    self.$element.find("#data_" + record.id).append(new_qweb.render('custom_template', record));
                });
            }
            else{
                self.$element.find("#column_" + data.value).remove();
                self.all_display_data.splice(index, 1);
            }
        });
        this.$element.find( ".oe_table_column " ).css("width", 99 / self.all_display_data.length +"%");
        this.$element.find('button').click(function(){
            var record_id = $(this).closest(".record").attr("id");
            if(record_id) {
                record_id = parseInt(record_id.split("_")[1])
                if(record_id) {
                    if($(this).data("type") == "delete") {
                        self.do_delete(record_id);
                    }
                    else{
                        var button_attrs = $(this).data()
                        self.on_button_click(button_attrs, record_id);
                    }
                }
            }
        });
    },

    do_search: function (domains, contexts, group_by) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: group_by
        }, function (results) {
            self.group_by_field = false;
            self.datagroup = new openerp.base.DataGroup(self, self.model, results.domain, results.context, results.group_by || []);
            self.dataset.context = results.context;
            self.dataset.domain = results.domain;
            self.datagroup.list([],
                function (groups) {
                    self.groups = groups;
                    if (group_by.length >= 1) {
                        self.group_by_field = group_by[0].group_by;
                        self.do_render_group(groups);
                    }
                },
                function (dataset) {
                    self.domain = dataset.domain;
                    self.context = dataset.context;
                    self.groups = [];
                    self.dataset.read_slice({}, function(records) {
                        self.all_display_data = [{'records': records, 'value':false, 'header' : false, 'ids': self.dataset.ids}];
                        self.$element.find("#kanbanview").remove();
                        self.on_show_data(self.all_display_data);
                    });
                }
            );

        });
    },

    do_render_group : function(datagroups){
        this.all_display_data = [];
        var self = this;
        _.each(datagroups, function (group) {
            self.dataset.context = group.context;
            self.dataset.domain = group.domain;
            var group_name = group.value;
            var group_value = group.value;
            if(!group.value) {
                group_name = "Undefined";
                group_value = 'false';
            }
            else if(group.value instanceof Array) {
                group_name = group.value[1]
                group_value = group.value[0]
            }
            self.dataset.read_slice({}, function(records) {
                self.all_display_data.push({"value" : group_value, "records": records, 'header':group_name, 'ids': self.dataset.ids});
                if (datagroups.length == self.all_display_data.length) {
                    self.$element.find("#kanbanview").remove();
                    self.on_show_data(self.all_display_data);
                }
            });
        });
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<commit_msg>[FIX] Fix problem on dropd records.<commit_after>openerp.base_kanban = function (openerp) {
QWeb.add_template('/base_kanban/static/src/xml/base_kanban.xml');
openerp.base.views.add('kanban', 'openerp.base_kanban.KanbanView');
openerp.base_kanban.KanbanView = openerp.base.View.extend({

    init: function(parent, element_id, dataset, view_id) {
        this._super(parent, element_id);
        this.view_manager = parent;
        this.dataset = dataset;
        this.domain = dataset.domain;
        this.context = dataset.context;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.group_by_field = false;
        this.source_index = {};
        this.all_display_data = false;
        this.groups = [];
    },

    start: function() {
        this.rpc("/base_kanban/kanbanview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function(data) {
        var self = this;
        this.template_xml = '';
        this.columns = data.all_fields;
        _.each(data.fields_view.arch.children, function(child) {
            if (child.tag == "template"){
                self.template_xml = openerp.base.json_node_to_xml(child, true)
            }
        });
        if(this.template_xml){
            self.dataset.read_slice({
                context: self.dataset.get_context(),
                domain: self.dataset.get_domain()}, function (records) {
                self.all_display_data = [{'records': records, 'value':false, 'header': false, 'ids': self.dataset.ids}];
                self.on_show_data(self.all_display_data);
            });
        }
    },

    on_show_data: function(datas) {
        var self = this;
        var new_qweb = new QWeb2.Engine();
        self.$element.html(QWeb.render("KanbanBiew", {"datas" :datas}));

        this.on_reload_kanban();
        this.$element.find(".oe_column").sortable({
            connectWith: ".oe_column",
            start: function(event, ui) {
                self.source_index['index'] = ui.item.index();
                self.source_index['column'] = ui.item.parent().attr('id');
            },
            stop: self.on_recieve_record,
        });
        this.$element.find(".record").addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
            .find(".record-header")
                .addClass("ui-widget-header ui-corner-all")
                .prepend( "")
                .end()
            .find( ".record-content" );

        this.$element.find(".record-header .ui-icon").click(function() {
            $(this).toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
            $(this).parents(".record:first").find(".record-content").toggle();
        });
        this.$element.find('.record .ui-icon-closethick').click(this.on_close_action);
        this.$element.find(".oe_column").disableSelection();
    },

    on_button_click: function(button_attrs, record_id){
        var self = this;
        if(this.groups.length){
            _.each(this.groups, function (group) {
                group.list([],
                    function (groups) {},
                    function (dataset) {
                        dataset.read_slice({}, function(records) {
                            var index = parseInt(_.indexOf(dataset.ids, record_id));
                            if(index >= 0) {
                                self.on_confirm_click(dataset, button_attrs, index, record_id);
                            }
                        });
                    }
                );
            });
        } else{
            var index = parseInt(_.indexOf(self.dataset.ids, record_id));
            if(index >= 0) {
                _.extend(self.dataset, {domain: self.domain, context: self.context})
                self.on_confirm_click(self.dataset, button_attrs, index, record_id)
            }
        }
    },

    on_confirm_click: function(dataset, button_attrs, index, record_id){
        if(button_attrs.type == 'edit') {
            this.do_edit_record(dataset, index);
        } else{
            this.on_execute_button_click(dataset, button_attrs, record_id)
        }
    },

    do_edit_record: function (dataset, index) {
        var self = this;
        _.extend(this.dataset, {
            domain: dataset.domain,
            context: dataset.get_context()
        }).read_slice({}, function () {
            self.dataset.index = index;
            self.do_switch_view('form');
        });
    },

    do_delete: function (id) {
        var self = this;
        return $.when(this.dataset.unlink([id])).then(function () {
            self.drop_records(id);
        });
    },

    drop_records: function (id) {
        var self = this;
        _.each(self.all_display_data, function(data, index) {
            _.each(data.records, function(record, index_row) {
                if(parseInt(record.id) == id) {
                    self.all_display_data[index]['records'].splice(index_row, 1)
                    self.all_display_data[index]['ids'].splice(index_row, 1)
                    return false;
                }
            });
        });
        self.$element.find("#main_" + id).remove()
    },

    on_execute_button_click: function(dataset, button_attrs, record_id) {
        var self = this;
        this.execute_action(
            button_attrs, dataset,
            record_id, function () {
                var count = 1;
                _.each(self.all_display_data, function(data, index) {
                    self.dataset.read_ids( data.ids, [], function(records){
                        self.all_display_data[index].records = records;
                        if(self.all_display_data.length == count) {
                            self.on_reload_kanban();
                        }
                        count++;
                    });
                });
            }
        );
    },

    on_close_action: function(e) {
        var record_id = $(e.currentTarget).parents('.record:first').attr("id")
        if(record_id) {
            record_id = parseInt(record_id.split("_")[1])
            if(record_id) {
                this.do_delete(record_id);
            }
        }
    },

    on_recieve_record: function(event, ui) {
        var self = this;
        var from = ui.item.index();
        var search_action = false;
        var to = ui.item.prev().index() || 0;
        if(!ui.item.attr("id")){
            return false;
        }
        if(self.columns.sequence && (self.source_index.index >= 0 && self.source_index.index != from) ||
                (self.source_index.column && self.source_index.column != ui.item.parent().attr('id'))) {
            var child_record = ui.item.parent().children();
            var data, sequence = 1, index = to;
            child_record.splice(0, to);
            if(to >= 0 && child_record) {
                var record_id = parseInt($(child_record).attr("id").split("_")[1]);
                if(record_id) {
                    var flag = false;
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
	                        if(record_id == record.id && record.sequence) {
	                            sequence = record.sequence;
	                            flag = true;
	                            return false;
	                        }
                        });
                        if(flag) {return false;}
                    });
                }
            }
            _.each(child_record, function (child) {
                var child_id = parseInt($(child).attr("id").split("_")[1]);
                if(child_id) {
                    var flag = false;
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
                            if(parseInt(record.id) == child_id) {
                                self.all_display_data[index]['records'][index_row]['sequence'] = sequence;
                                flag = true;
                                return false;
                            }
                        });
                        if(flag) {return false;}
                    });
                    self.dataset.write(child_id, {sequence: sequence});
                    sequence++;
                    search_action = true;
                }
            });
        }
        if(self.group_by_field && self.source_index.column && self.source_index.column != ui.item.parent().attr('id')) {
            var value = ui.item.closest("td").attr("id")
            if(value) {
                var data_val = {};
                var wirte_id = parseInt(ui.item.attr("id").split("_")[1]);
                value = value.split("_")[1];
                if(value == 'false') {
                    value = false;
                }
                var update_record = false;
                _.each(self.all_display_data, function(data, index) {
                    _.each(data.records, function(record, index_row) {
                        if(parseInt(record.id) == wirte_id) {
                            self.all_display_data[index]['records'][index_row][self.group_by_field] = value;
                            update_record = self.all_display_data[index]['records'].splice(index_row,1)
                            return false;
                        }
                    });
                    if(update_record) {return false;}
                });
                _.each(self.all_display_data, function(data, index) {
                    if (data.value == value || (data.value == 'false' && value == false)) {
                        self.all_display_data[index]['records'].push(update_record[0]);
                    }
                });
                data_val[self.group_by_field] = value;
                self.dataset.write(wirte_id, data_val);
                search_action = true;
            }
        }
        if(search_action) {
            self.on_reload_kanban();
        }
        this.source_index = {};
    },

    on_reload_kanban: function(){
        var self = this;
        var new_qweb = new QWeb2.Engine();
        new_qweb.add_template('<templates><t t-name="custom_template">' + this.template_xml + '</t></templates>')
        _.each(self.all_display_data, function(data, index) {
            if(data.records.length > 0){
                _.each(data.records, function(record) {
                    self.$element.find("#data_" + record.id).children().remove()
                    self.$element.find("#data_" + record.id).append(new_qweb.render('custom_template', record));
                });
            }
            else{
                self.$element.find("#column_" + data.value).remove();
                self.all_display_data.splice(index, 1);
            }
        });
        this.$element.find( ".oe_table_column " ).css("width", 99 / self.all_display_data.length +"%");
        this.$element.find('button').click(function(){
            var record_id = $(this).closest(".record").attr("id");
            if(record_id) {
                record_id = parseInt(record_id.split("_")[1])
                if(record_id) {
                    if($(this).data("type") == "delete") {
                        self.do_delete(record_id);
                    }
                    else{
                        var button_attrs = $(this).data()
                        self.on_button_click(button_attrs, record_id);
                    }
                }
            }
        });
    },

    do_search: function (domains, contexts, group_by) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: group_by
        }, function (results) {
            self.group_by_field = false;
            self.datagroup = new openerp.base.DataGroup(self, self.model, results.domain, results.context, results.group_by || []);
            self.dataset.context = results.context;
            self.dataset.domain = results.domain;
            self.datagroup.list([],
                function (groups) {
                    self.groups = groups;
                    if (group_by.length >= 1) {
                        self.group_by_field = group_by[0].group_by;
                        self.do_render_group(groups);
                    }
                },
                function (dataset) {
                    self.domain = dataset.domain;
                    self.context = dataset.context;
                    self.groups = [];
                    self.dataset.read_slice({}, function(records) {
                        self.all_display_data = [{'records': records, 'value':false, 'header' : false, 'ids': self.dataset.ids}];
                        self.$element.find("#kanbanview").remove();
                        self.on_show_data(self.all_display_data);
                    });
                }
            );

        });
    },

    do_render_group : function(datagroups){
        this.all_display_data = [];
        var self = this;
        _.each(datagroups, function (group) {
            self.dataset.context = group.context;
            self.dataset.domain = group.domain;
            var group_name = group.value;
            var group_value = group.value;
            if(!group.value) {
                group_name = "Undefined";
                group_value = 'false';
            }
            else if(group.value instanceof Array) {
                group_name = group.value[1]
                group_value = group.value[0]
            }
            self.dataset.read_slice({}, function(records) {
                self.all_display_data.push({"value" : group_value, "records": records, 'header':group_name, 'ids': self.dataset.ids});
                if (datagroups.length == self.all_display_data.length) {
                    self.$element.find("#kanbanview").remove();
                    self.on_show_data(self.all_display_data);
                }
            });
        });
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<|endoftext|>


<commit_before>openerp.base_kanban = function (openerp) {
QWeb.add_template('/base_kanban/static/src/xml/base_kanban.xml');
openerp.base.views.add('kanban', 'openerp.base_kanban.KanbanView');
openerp.base_kanban.KanbanView = openerp.base.View.extend({

    init: function(parent, element_id, dataset, view_id) {
        this._super(parent, element_id);
        this.view_manager = parent;
        this.dataset = dataset;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.element_id = element_id;
        this.group_by_field = false;
        this.domains = this.dataset.domain;
        this.contexts = this.dataset.context;
        this.group_by = false;
    },

    start: function() {
        this.rpc("/base_kanban/kanbanview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function(data) {
        var self = this;
        this.template_xml = '';

        _.each(data.fields_view.arch.children, function(child) {
            if (child.tag == "template"){
                self.template_xml = openerp.base.json_node_to_xml(child, true)
            }
        });
        if(this.template_xml){
            self.dataset.read_slice([], 0, false, function (records) {
                self.on_reload_kanban([{'records': records, 'value':false, 'header': false}]);
	        });
	    }
    },

    on_show_data: function(datas) {
        var self = this;
        this.all_records = [];
        var new_qweb = new QWeb2.Engine();
        new_qweb.add_template('<templates><t t-name="custom_template">' + this.template_xml + '</t></templates>')
		self.$element.html(QWeb.render("KanbanBiew", {"datas" :datas}));
		_.each(datas, function(data) {
	        _.each(data.records, function(record) {
	            self.$element.find("#data_" + record.id).append(new_qweb.render('custom_template', record));
	            self.all_records.push(record);
	        });
        });
        this.$element.find( ".oe_table_column " ).css("width", 99 / datas.length +"%");
		this.$element.find(".oe_column").sortable({
		    connectWith: ".oe_column",
		    stop: self.on_recieve_record,
		});
		this.$element.find(".record").addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
		    .find(".record-header")
		        .addClass("ui-widget-header ui-corner-all")
		        .prepend( "")
		        .end()
		    .find( ".record-content" );

		this.$element.find(".record-header .ui-icon").click(function() {
		    $(this).toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
		    $(this).parents(".record:first").find(".record-content").toggle();
		});
		this.$element.find('.record .ui-icon-closethick').click(this.on_close_action);
		this.$element.find(".oe_column").disableSelection();
    },

    on_close_action: function(e) {
        $(e.currentTarget).parents('.record:first').remove();
    },

    on_recieve_record: function(event, ui) {
        var self = this;
        var from = ui.item.index(), to = ui.item.prev().index() || 0;
        var child_record = ui.item.parent().children();
        var data, sequence=1, index = to;
        this.flag = false;
        child_record.splice(0, to);
        if(to >= 0 && child_record) {
            var record_id = child_record.attr('id').split("_");
            if(record_id.length >= 2) {
	            _.each(this.all_records, function(record){
	                if(parseInt(record_id[1]) == record.id && record.sequence) {
	                    sequence = record.sequence;
	                }
	            });
            }
        }
        _.each(child_record, function (child) {
            var child_id = parseInt($(child).attr("id").split("_")[1]);
            if(child_id) {
                self.dataset.write(child_id, {sequence: sequence});
                sequence++;
                self.flag = true;
            }
        });
        console.log(":this.group_by_field:::",this.group_by_field);
        if(ui.item.attr("id") && this.group_by_field) {
            var value = ui.item.closest("td").attr("id")
            console.log("value:::",value);
            if(value) {
                var data_val = {};
                value = value.split("_")[1];
                if(value == 'false') {
                    value = false;
                }
                data_val[this.group_by_field] = value;
                console.log("D:D:::::",data_val, parseInt(ui.item.attr("id").split("_")[1]));
                this.dataset.write(parseInt(ui.item.attr("id").split("_")[1]), data_val);
                this.flag = true;
            }
        }
        if(this.flag) {
            this.do_actual_search(this.domains, this.contexts, this.group_by);
        }
    },

    on_reload_kanban: function(datas){
        this.$element.find("#kanbanview").remove();
        this.on_show_data(datas);
    },

    do_search: function (domains, contexts, group_by) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: group_by
        }, function (results) {
            self.contexts = results.context;
            self.domains = results.domain;
            self.group_by = results.group_by;
            self.do_actual_search(results.domain, results.context, results.group_by);
        });
    },

    do_actual_search: function (domain, context, group_by) {
        var self = this;

        this.group_by_field = false;

        self.dataset.context = context;
        self.dataset.domain = domain;
        this.groups = new openerp.base.DataGroup(this, this.model, domain, context, group_by || []);
        this.groups.list([],
            function (groups) {
                if (group_by.length >= 1) {
                    self.group_by_field = group_by[0];
                    self.do_render_group(groups);
                }
            },
            function (dataset) {
                self.dataset.read_slice(false, false, false, function(records) {
                    self.on_reload_kanban([{'records': records, 'value':false, 'header' : false}]);
                });
            }
        );

    },
    do_render_group : function(datagroups){
        this.columns = [];
        var self = this;
        _.each(datagroups, function (group) {
            self.dataset.context = group.context;
            self.dataset.domain = group.domain;
            var group_name = group.value;
            var group_value = group.value;
            if(!group.value) {
                group_name = "Undefined";
                group_value = 'false';
            }
            else if(group.value instanceof Array) {
                group_name = group.value[1]
                group_value = group.value[0]
            }
	        self.dataset.read_slice(false, false, false, function(records) {
                self.columns.push({"value" : group_value, "records": records, 'header':group_name});
                if (datagroups.length == self.columns.length) {
                    self.on_reload_kanban(self.columns);
	            }
	        });
        });
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<commit_msg>[IMP] Improve code.<commit_after>openerp.base_kanban = function (openerp) {
QWeb.add_template('/base_kanban/static/src/xml/base_kanban.xml');
openerp.base.views.add('kanban', 'openerp.base_kanban.KanbanView');
openerp.base_kanban.KanbanView = openerp.base.View.extend({

    init: function(parent, element_id, dataset, view_id) {
        this._super(parent, element_id);
        this.view_manager = parent;
        this.dataset = dataset;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.element_id = element_id;
        this.group_by_field = false;
        this.domains = this.dataset.domain;
        this.contexts = this.dataset.context;
        this.group_by = false;
        this.destination_index = false;
    },

    start: function() {
        this.rpc("/base_kanban/kanbanview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function(data) {
        var self = this;
        this.template_xml = '';

        _.each(data.fields_view.arch.children, function(child) {
            if (child.tag == "template"){
                self.template_xml = openerp.base.json_node_to_xml(child, true)
            }
        });
        if(this.template_xml){
            self.dataset.read_slice([], 0, false, function (records) {
                self.on_reload_kanban([{'records': records, 'value':false, 'header': false}]);
	        });
	    }
    },

    on_show_data: function(datas) {
        var self = this;
        this.all_records = [];
        var new_qweb = new QWeb2.Engine();
        new_qweb.add_template('<templates><t t-name="custom_template">' + this.template_xml + '</t></templates>')
		self.$element.html(QWeb.render("KanbanBiew", {"datas" :datas}));
		_.each(datas, function(data) {
	        _.each(data.records, function(record) {
	            self.$element.find("#data_" + record.id).append(new_qweb.render('custom_template', record));
	            self.all_records.push(record);
	        });
        });
        this.$element.find( ".oe_table_column " ).css("width", 99 / datas.length +"%");
		this.$element.find(".oe_column").sortable({
		    connectWith: ".oe_column",
		    start: function(event, ui) {
                self.destination_index = ui.item.index();
            },
		    stop: self.on_recieve_record,
		});
		this.$element.find(".record").addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
		    .find(".record-header")
		        .addClass("ui-widget-header ui-corner-all")
		        .prepend( "")
		        .end()
		    .find( ".record-content" );

		this.$element.find(".record-header .ui-icon").click(function() {
		    $(this).toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
		    $(this).parents(".record:first").find(".record-content").toggle();
		});
		this.$element.find('.record .ui-icon-closethick').click(this.on_close_action);
		this.$element.find(".oe_column").disableSelection();
    },

    on_close_action: function(e) {
        $(e.currentTarget).parents('.record:first').remove();
    },

    on_recieve_record: function(event, ui) {
        var self = this;
        var from = ui.item.index(), to = ui.item.prev().index() || 0;
        this.flag = false;
        if(self.destination_index != from){
	        var child_record = ui.item.parent().children();
	        var data, sequence=1, index = to;
	        child_record.splice(0, to);
	        if(to >= 0 && child_record) {
	            var record_id = child_record.attr('id').split("_");
	            if(record_id.length >= 2) {
		            _.each(this.all_records, function(record){
		                if(parseInt(record_id[1]) == record.id && record.sequence) {
		                    sequence = record.sequence;
		                }
		            });
	            }
	        }
	        _.each(child_record, function (child) {
	            var child_id = parseInt($(child).attr("id").split("_")[1]);
	            if(child_id) {
	                self.dataset.write(child_id, {sequence: sequence});
	                sequence++;
	                self.flag = true;
	            }
	        });
        }
        if(ui.item.attr("id") && this.group_by_field) {
            var value = ui.item.closest("td").attr("id")
            if(value) {
                var data_val = {};
                value = value.split("_")[1];
                if(value == 'false') {
                    value = false;
                }
                data_val[this.group_by_field] = value;
                this.dataset.write(parseInt(ui.item.attr("id").split("_")[1]), data_val);
                this.flag = true;
            }
        }
        if(this.flag) {
            this.do_actual_search(this.domains, this.contexts, this.group_by);
        }
        this.destination_index = false;
    },

    on_reload_kanban: function(datas){
        this.$element.find("#kanbanview").remove();
        this.on_show_data(datas);
    },

    do_search: function (domains, contexts, group_by) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: group_by
        }, function (results) {
            self.contexts = results.context;
            self.domains = results.domain;
            self.group_by = results.group_by;
            self.do_actual_search(results.domain, results.context, results.group_by);
        });
    },

    do_actual_search: function (domain, context, group_by) {
        var self = this;

        this.group_by_field = false;

        self.dataset.context = context;
        self.dataset.domain = domain;
        this.groups = new openerp.base.DataGroup(this, this.model, domain, context, group_by || []);
        this.groups.list([],
            function (groups) {
                if (group_by.length >= 1) {
                    self.group_by_field = group_by[0];
                    self.do_render_group(groups);
                }
            },
            function (dataset) {
                self.dataset.read_slice(false, false, false, function(records) {
                    self.on_reload_kanban([{'records': records, 'value':false, 'header' : false}]);
                });
            }
        );

    },
    do_render_group : function(datagroups){
        this.columns = [];
        var self = this;
        _.each(datagroups, function (group) {
            self.dataset.context = group.context;
            self.dataset.domain = group.domain;
            var group_name = group.value;
            var group_value = group.value;
            if(!group.value) {
                group_name = "Undefined";
                group_value = 'false';
            }
            else if(group.value instanceof Array) {
                group_name = group.value[1]
                group_value = group.value[0]
            }
	        self.dataset.read_slice(false, false, false, function(records) {
                self.columns.push({"value" : group_value, "records": records, 'header':group_name});
                if (datagroups.length == self.columns.length) {
                    self.on_reload_kanban(self.columns);
	            }
	        });
        });
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<|endoftext|>