diff src/DML/MainVisBundle/Resources/assets/marionette/modules/ContextModule/ContextModule.10-ConfigGrid.js @ 0:493bcb69166c

added public content
author Daniel Wolff
date Tue, 09 Feb 2016 20:54:02 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/DML/MainVisBundle/Resources/assets/marionette/modules/ContextModule/ContextModule.10-ConfigGrid.js	Tue Feb 09 20:54:02 2016 +0100
@@ -0,0 +1,525 @@
+"use strict";
+
+App.module("ContextModule", function(ContextModule, App, Backbone, Marionette, $, _, Logger) {
+
+    // Define private variables
+    var logger = null;
+
+    ContextModule.addInitializer(function(options){
+
+        logger = Logger.get("ContextModule.ConfigGrid");
+        logger.setLevel(Logger.WARN);
+
+        /**
+         * ConfigGrid stores the configuration of a grid that consists of entityConfigs and viewConfigs
+         * (both are Backbone.Collection of Config)
+         *
+         * In real situation entityConfigs are music collection configs and music recording configs
+         *
+         * two sub-collections can be interacted directly (without proxy methods)
+         *
+         * The grid can be given a read-only type on creation in order to easily to distinguish between collection and recording grid later
+         * getType() method is available for this purpose. The type of the grid is not being serialized or unserialized
+         *
+         * The following events are triggered:
+         *
+         *      change_layout
+         *          when both or any of the two collections of Config gets new objects, looses objects or shuffles
+         *          (but not when parameters in individual parameter bags change)
+         *
+         *      change_entity:c123
+         *      change_view:c123
+         *          when a particular parameter bag changes (c123 is replaced with a corresponding client id of an entity or a view)
+         *
+         *      change_entity_neighbours:c123
+         *      change_view_neighbours:c123
+         *          when a Config, which is right before or right after the given parameter bag, changes
+         *          This includes cases when neighbours are added or removed
+         *
+         *      change_selection
+         *          when selectedEntityConfigClientId or (and) selectedViewConfigClientId change
+         *
+         *      change
+         *          this event is triggered together with any of the above ones, but
+         *          maximum once during a complex operation such as unserialize
+         */
+        ContextModule.ConfigGrid = Backbone.Model.extend({
+            defaults: {
+                entityConfigs: null,
+                viewConfigs: null,
+                selectedEntityConfigClientId: null,
+                selectedViewConfigClientId: null
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            initialize: function(type) {
+
+                this.type = type;
+
+                this.attributes.entityConfigs = new ContextModule.ConfigCollection(null, {
+                    comparator: false,
+                    configGridType: type,
+                    dimension: "entity",
+                });
+                this.attributes.viewConfigs = new ContextModule.ConfigCollection(null, {
+                    comparator: false,
+                    configGridType: type,
+                    dimension: "view",
+                });
+
+                // Shortcuts for entity configs and view configs (for quicker access)
+                this.entityConfigs = this.attributes.entityConfigs;
+                this.viewConfigs = this.attributes.viewConfigs;
+
+                this._modificationPropagationEnabled = true;
+                this._configCollectionsWereModified = false;
+                this._configsWereModified = false;
+                this._modifiedEntityConfigClientIds = [];
+                this._modifiedViewConfigClientIds = [];
+                this._lastSavedOrderedEntityClientIds = _.pluck(this.attributes.entityConfigs.models, "cid");
+                this._lastSavedOrderedViewClientIds = _.pluck(this.attributes.viewConfigs.models, "cid");
+                this._lastSavedSelectedEntityConfigClientId = this.attributes.selectedEntityConfigClientId;
+                this._lastSavedSelectedViewConfigClientId = this.attributes.selectedViewConfigClientId;
+
+                this.entityConfigs.bind("add remove reset sort", this._registerModificationOfConfigCollectionForEntities, this);
+                this.viewConfigs.bind("add remove reset sort", this._registerModificationOfConfigCollectionForViews, this);
+
+                this.entityConfigs.bind("change", this._registerModificationOfConfig, this);
+                this.viewConfigs.bind("change", this._registerModificationOfConfig, this);
+
+                this.bind("change:selectedEntityConfigClientId", this._registerModificationOfAtomicProperty);
+                this.bind("change:selectedViewConfigClientId", this._registerModificationOfAtomicProperty);
+                this.bind("change:entityWidth", this._registerModificationOfStandardAtomicProperty);
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            getType: function() {
+                return this.type;
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            getPrevEntityNeighbour: function(entityConfig) {
+                return this._getNeighbour(this.attributes.entityConfigs, entityConfig, -1);
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            getNextEntityNeighbour: function(entityConfig) {
+                return this._getNeighbour(this.attributes.entityConfigs, entityConfig, 1);
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            getPrevViewNeighbour: function(viewConfig) {
+                return this._getNeighbour(this.attributes.viewConfigs, viewConfig, -1);
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            getNextViewNeighbour: function(viewConfig) {
+                return this._getNeighbour(this.attributes.viewConfigs, viewConfig, 1);
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            relocateEntityConfig: function(entityConfig, indexOrNextConfigOrNextConfigClientId) {
+                return this._relocate(this.attributes.entityConfigs, entityConfig, indexOrNextConfigOrNextConfigClientId);
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            relocateViewConfig: function(viewConfig, indexOrNextConfigOrNextConfigClientId) {
+                return this._relocate(this.attributes.viewConfigs, viewConfig, indexOrNextConfigOrNextConfigClientId);
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            serialize: function() {
+                logger.debug("method called: ConfigGrid::serialize");
+                var _this = this;
+
+                var result = {
+                        entityConfigs: this.attributes.entityConfigs.map(function(config){ return config.serialize(); }),
+                        viewConfigs: this.attributes.viewConfigs.map(function(config){ return config.serialize(); })
+                };
+
+                if (this.attributes.selectedEntityConfigClientId) {
+                    result.selectedEntityConfigClientId = this.attributes.selectedEntityConfigClientId;
+                }
+                if (this.attributes.selectedViewConfigClientId) {
+                    result.selectedViewConfigClientId = this.attributes.selectedViewConfigClientId;
+                }
+                if (this.attributes.entityWidth) {
+                    result.entityWidth = this.attributes.entityWidth;
+                }
+
+                return result;
+            },
+
+            getSelectedEntityConfig: function() {
+                return this.attributes.entityConfigs.get(this.attributes.selectedEntityConfigClientId);
+            },
+
+            getSelectedViewConfig: function() {
+                return this.attributes.viewConfigs.get(this.attributes.selectedViewConfigClientId);
+            },
+
+//            getSelectedConfigAtGivenDimension: function(dimension) {
+//                if (dimension == "entity") {
+//                    return this.getSelectedEntityConfig();
+//                } else if (dimension == "view") {
+//                    return this.getSelectedViewConfig();
+//                }
+//            },
+//
+            addEntityAndSelectIt: function(entityConfig, indexOrNextConfigOrNextConfigClientId) {
+                this._addAndSelect(this.attributes.entityConfigs, entityConfig, _.isUndefined(indexOrNextConfigOrNextConfigClientId) ? null : indexOrNextConfigOrNextConfigClientId);
+            },
+
+            addViewAndSelectIt: function(viewConfig, indexOrNextConfigOrNextConfigClientId) {
+                this._addAndSelect(this.attributes.viewConfigs, viewConfig, _.isUndefined(indexOrNextConfigOrNextConfigClientId) ? null : indexOrNextConfigOrNextConfigClientId);
+            },
+
+            removeEntityAndSelectNeighbour: function(entityConfig) {
+                this._removeAndSelectNeighbour(this.attributes.entityConfigs, entityConfig);
+            },
+
+            removeViewAndSelectNeighbour: function(viewConfig) {
+                this._removeAndSelectNeighbour(this.attributes.viewConfigs, viewConfig);
+            },
+
+            _addAndSelect: function(configCollection, config, indexOrNextConfigOrNextConfigClientId) {
+                this._modificationPropagationEnabled = false;
+
+                configCollection.add(config);
+                if (configCollection == this.attributes.entityConfigs) {
+                    this.attributes.selectedEntityConfigClientId = config.getClientId();
+                } else {
+                    this.attributes.selectedViewConfigClientId = config.getClientId();
+                }
+                this._relocate(configCollection, config, indexOrNextConfigOrNextConfigClientId);
+
+                this._triggerModificationEventsIfNeeded();
+                this._modificationPropagationEnabled = true;
+
+            },
+
+            _removeAndSelectNeighbour: function(configCollection, config) {
+                this._modificationPropagationEnabled = false;
+
+                var neighbourToSelect = this._getNeighbour(configCollection, config, 1);
+                if (!neighbourToSelect) {
+                    neighbourToSelect = this._getNeighbour(configCollection, config, -1);
+                }
+                configCollection.remove(config);
+                if (configCollection == this.attributes.entityConfigs) {
+                    this.attributes.selectedEntityConfigClientId = neighbourToSelect ? neighbourToSelect.getClientId() : null;
+                } else {
+                    this.attributes.selectedViewConfigClientId = neighbourToSelect ? neighbourToSelect.getClientId() : null;
+                }
+
+                this._triggerModificationEventsIfNeeded();
+                this._modificationPropagationEnabled = true;
+
+            },
+
+            /**
+             * @memberOf App.ContextModule.ConfigGrid
+             */
+            unserialize: function(serializedAttributes) {
+                logger.debug("method called: ConfigGrid::unserialize");
+
+                this._modificationPropagationEnabled = false;
+
+                var fixedSerializedAttributes = serializedAttributes;
+                if (!_.isSimpleObject(serializedAttributes)) {
+                    logger.warn("ConfigGrid::unserialize called for not an object: ", serializedAttributes);
+                    fixedSerializedAttributes = {};
+                }
+
+                // entityConfigs
+                var newConfigs = [];
+                var fixedSerializedConfigs = fixedSerializedAttributes.entityConfigs;
+                if (!_.isArray(fixedSerializedConfigs)) {
+                    if (_.isSimpleObject(serializedAttributes)) {
+                        logger.warn("ConfigGrid::unserialize called for an object with faulty entityConfigs: ", fixedSerializedConfigs);
+                    }
+                    fixedSerializedConfigs = [];
+                };
+                for (var i = 0; i < fixedSerializedConfigs.length; i++) {
+                    var serializedConfig = fixedSerializedConfigs[i];
+                    var config = this.attributes.entityConfigs.get(serializedConfig.clientId);
+                    if (!config) {
+                        config = new App.ContextModule.Config(serializedConfig);
+                    } else {
+                        config.unserialize(serializedConfig);
+                    }
+                    newConfigs.push(config);
+                }
+                this.attributes.entityConfigs.reset(newConfigs);
+
+                // viewConfigs
+                var newConfigs = [];
+                var fixedSerializedConfigs = fixedSerializedAttributes.viewConfigs;
+                if (!_.isArray(fixedSerializedConfigs)) {
+                    if (_.isSimpleObject(serializedAttributes)) {
+                        logger.warn("ConfigGrid::unserialize called for an object with faulty viewConfigs: ", fixedSerializedConfigs);
+                    }
+                    fixedSerializedConfigs = [];
+                };
+                for (var i = 0; i < fixedSerializedConfigs.length; i++) {
+                    var serializedConfig = fixedSerializedConfigs[i];
+                    var config = this.attributes.viewConfigs.get(serializedConfig.clientId);
+                    if (!config) {
+                        config = new App.ContextModule.Config(serializedConfig);
+                    } else {
+                        config.unserialize(serializedConfig);
+                    }
+                    newConfigs.push(config);
+                }
+                this.attributes.viewConfigs.reset(newConfigs);
+
+                // selectedEntityConfigClientId, selectedViewConfigClientId
+                this.attributes.selectedEntityConfigClientId = fixedSerializedAttributes.selectedEntityConfigClientId;
+                this.attributes.selectedViewConfigClientId = fixedSerializedAttributes.selectedViewConfigClientId;
+
+                this.attributes.entityWidth = fixedSerializedAttributes.entityWidth;
+
+                this._triggerModificationEventsIfNeeded();
+                this._modificationPropagationEnabled = true;
+            },
+
+            _getNeighbour: function(configCollection, config, offset) {
+                var index = configCollection.indexOf(config);
+                if (index === -1) {
+                    throw _.str.sprintf("Can't find config %s", JSON.stringify(config.serialize()));
+                }
+                return configCollection.at(index + offset);
+            },
+
+            _relocate: function(configCollection, config, indexOrNextConfigOrNextConfigClientId) {
+                var clientIds = _.pluck(configCollection.models, "cid");
+                var nextConfigClientId = null;
+
+                if (_.isNumber(indexOrNextConfigOrNextConfigClientId) && indexOrNextConfigOrNextConfigClientId != clientIds.length) {
+                    nextConfigClientId = clientIds[indexOrNextConfigOrNextConfigClientId];
+                }
+                if (_.isObject(indexOrNextConfigOrNextConfigClientId)) {
+                    nextConfigClientId = indexOrNextConfigOrNextConfigClientId.getClientId();
+                }
+                if (_.isString(indexOrNextConfigOrNextConfigClientId)) {
+                    if (clientIds.indexOf(indexOrNextConfigOrNextConfigClientId) !== -1) {
+                        nextConfigClientId = indexOrNextConfigOrNextConfigClientId;
+                    }
+                }
+                if (!nextConfigClientId && !_.isNull(indexOrNextConfigOrNextConfigClientId) && indexOrNextConfigOrNextConfigClientId != configCollection.size()) {
+                    throw _.str.sprintf("Wrong value for indexOrNextConfigOrNextConfigClientId %s", indexOrNextConfigOrNextConfigClientId);
+                }
+
+                var configClientId = config.getClientId();
+                if (!configClientId || clientIds.indexOf(configClientId) == -1) {
+                    var flattenedConfig = config;
+                    if (_.isObject(flattenedConfig)) {
+                        flattenedConfig = JSON.stringify(flattenedConfig);
+                    }
+                    throw _.str.sprintf("Config %s with cid %s is either not a Config or does not belong to a corresponding configCollection with cids [%s]", flattenedConfig, _.isObject(config ) ? config.getClientId() : undefined, clientIds.join(", "));
+                }
+                if (configCollection.get(configClientId) !== config) {
+                    throw _.str.sprintf("Config %s with cid %s is is a clone of what is stored in the grid. Relocation is not possible.", JSON.stringify(config), config.cid);
+                }
+                var newClientIds = _.without(clientIds, configClientId);
+                if (_.isNull(nextConfigClientId)) {
+                    newClientIds.push(configClientId);
+                } else {
+                    var nextConfigIndex = newClientIds.indexOf(nextConfigClientId);
+                    //if (nextConfigIndex)
+                    var tempClientIds = newClientIds.slice(0, nextConfigIndex);
+                    tempClientIds.push(configClientId);
+                    newClientIds = tempClientIds.concat(newClientIds.slice(nextConfigIndex));
+                }
+
+                var oldComparator = configCollection.comparator;
+                configCollection.comparator = function(model) {
+                    return newClientIds.indexOf(model.getClientId());
+                };
+                configCollection.sort();
+                configCollection.comparator = oldComparator;
+            },
+
+            _registerModificationOfConfigCollectionForEntities: function(modelOrModels, options) {
+                if (!_.isEqual(this._lastSavedOrderedEntityClientIds, _.pluck(this.attributes.entityConfigs.models, "cid"))) {
+                    this._configCollectionsWereModified = true;
+                    if (this._modificationPropagationEnabled) {
+                        this._triggerModificationEventsIfNeeded();
+                    };
+                }
+            },
+
+            _registerModificationOfConfigCollectionForViews: function(modelOrModels, options) {
+                if (!_.isEqual(this._lastSavedOrderedViewClientIds, _.pluck(this.attributes.viewConfigs.models, "cid"))) {
+                    this._configCollectionsWereModified = true;
+                    if (this._modificationPropagationEnabled) {
+                        this._triggerModificationEventsIfNeeded();
+                    };
+                }
+            },
+
+            _registerModificationOfConfig: function() {
+                for (var i = 0; i < this.attributes.entityConfigs.length; i++) {
+                    if(this.attributes.entityConfigs.at(i).hasChanged()) {
+                        this._configsWereModified = true;
+                        this._modifiedEntityConfigClientIds.push(this.attributes.entityConfigs.at(i).getClientId());
+                    }
+                }
+                for (var i = 0; i < this.attributes.viewConfigs.length; i++) {
+                    if(this.attributes.viewConfigs.at(i).hasChanged()) {
+                        this._configsWereModified = true;
+                        this._modifiedViewConfigClientIds.push(this.attributes.viewConfigs.at(i).getClientId());
+                    }
+                }
+                if (this._modificationPropagationEnabled) {
+                    this._triggerModificationEventsIfNeeded();
+                };
+            },
+
+            _registerModificationOfAtomicProperty: function() {
+                if (this._modificationPropagationEnabled) {
+                    this._triggerModificationEventsIfNeeded(true);
+                };
+            },
+
+            _registerModificationOfStandardAtomicProperty: function() {
+                if (this._modificationPropagationEnabled) {
+                    this._triggerModificationEventsIfNeeded();
+                };
+            },
+
+            _triggerModificationEventsIfNeeded: function(specialCaseForRegisterModificationOfSelection) {
+
+                var triggeredAtLeastSomething = false;
+                if (this._configCollectionsWereModified) {
+                    triggeredAtLeastSomething = true;
+                    this.trigger("change_layout");
+                }
+
+                var newOrderedEntityClientIds = null;
+                var newOrderedViewClientIds = null;
+                if (this._configCollectionsWereModified || this._modifiedEntityConfigClientIds.length || this._modifiedViewConfigClientIds.length) {
+                    newOrderedEntityClientIds = _.pluck(this.attributes.entityConfigs.models, "cid");
+                    newOrderedViewClientIds = _.pluck(this.attributes.viewConfigs.models, "cid");
+
+                    // change_entity:c123
+                    if (this._modifiedEntityConfigClientIds.length) {
+                        for (var i = 0; i < newOrderedEntityClientIds.length; i++) {
+                            if (_.indexOf(this._modifiedEntityConfigClientIds, newOrderedEntityClientIds[i]) !== -1) {
+                                triggeredAtLeastSomething = true;
+                                this.trigger("change_entity:" + newOrderedEntityClientIds[i]);
+                            }
+                        }
+                    }
+                    // change_view:c123
+                    if (this._modifiedViewConfigClientIds.length) {
+                        for (var i = 0; i < newOrderedViewClientIds.length; i++) {
+                            if (_.indexOf(this._modifiedViewConfigClientIds, newOrderedViewClientIds[i]) !== -1) {
+                                triggeredAtLeastSomething = true;
+                                this.trigger("change_view:" + newOrderedViewClientIds[i]);
+                            }
+                        }
+                    }
+
+                    // change_entity_neighbours:c123
+                    for (var i = 0; i < newOrderedEntityClientIds.length; i++) {
+                        var entityClientId = newOrderedEntityClientIds[i];
+                        var oldEntityIndex = this._lastSavedOrderedEntityClientIds.indexOf(entityClientId);
+                        if (oldEntityIndex == -1) {
+                            continue;
+                        }
+                        var newPrevEntityClientId = newOrderedEntityClientIds[i - 1];
+                        var newNextEntityClientId = newOrderedEntityClientIds[i + 1];
+                        var oldPrevEntityClientId = this._lastSavedOrderedEntityClientIds[oldEntityIndex - 1];
+                        var oldNextEntityClientId = this._lastSavedOrderedEntityClientIds[oldEntityIndex + 1];
+
+                        if (newPrevEntityClientId != oldPrevEntityClientId
+                         || newNextEntityClientId != oldNextEntityClientId
+                         || this._modifiedEntityConfigClientIds.indexOf(newPrevEntityClientId) !== -1
+                         || this._modifiedEntityConfigClientIds.indexOf(newNextEntityClientId) !== -1
+                         ) {
+                            triggeredAtLeastSomething = true;
+                            this.trigger("change_entity_neighbours:" + entityClientId);
+                        };
+                    }
+
+                    // change_view_neighbours:c123
+                    for (var i = 0; i < newOrderedViewClientIds.length; i++) {
+                        var viewClientId = newOrderedViewClientIds[i];
+                        var oldViewIndex = this._lastSavedOrderedViewClientIds.indexOf(viewClientId);
+                        if (oldViewIndex == -1) {
+                            continue;
+                        }
+                        var newPrevViewClientId = newOrderedViewClientIds[i - 1];
+                        var newNextViewClientId = newOrderedViewClientIds[i + 1];
+                        var oldPrevViewClientId = this._lastSavedOrderedViewClientIds[oldViewIndex - 1];
+                        var oldNextViewClientId = this._lastSavedOrderedViewClientIds[oldViewIndex + 1];
+
+                        if (newPrevViewClientId != oldPrevViewClientId
+                         || newNextViewClientId != oldNextViewClientId
+                         || this._modifiedViewConfigClientIds.indexOf(newPrevViewClientId) !== -1
+                         || this._modifiedViewConfigClientIds.indexOf(newNextViewClientId) !== -1
+                         ) {
+                            triggeredAtLeastSomething = true;
+                            this.trigger("change_view_neighbours:" + viewClientId);
+                        };
+                    };
+                }
+
+                this._lastSavedOrderedEntityClientIds = _.pluck(this.attributes.entityConfigs.models, "cid");
+                this._lastSavedOrderedViewClientIds = _.pluck(this.attributes.viewConfigs.models, "cid");
+
+                // Fix selection
+                if (!this.attributes.entityConfigs.get(this.attributes.selectedEntityConfigClientId)) {
+                    this.attributes.selectedEntityConfigClientId = null;
+                }
+                if (!this.attributes.viewConfigs.get(this.attributes.selectedViewConfigClientId)) {
+                    this.attributes.selectedViewConfigClientId = null;
+                }
+                if (this._lastSavedSelectedEntityConfigClientId  != this.attributes.selectedEntityConfigClientId
+                 || this._lastSavedSelectedViewConfigClientId  != this.attributes.selectedViewConfigClientId
+                    ) {
+                    if (!specialCaseForRegisterModificationOfSelection) {
+                        triggeredAtLeastSomething = true;
+                    }
+                    this.trigger("change_selection");
+                }
+
+                if (this._lastSavedEntityWidth  != this.attributes.entityWidth) {
+                    triggeredAtLeastSomething = true;
+                }
+
+                this._configCollectionsWereModified = false;
+                this._configsWereModified = false;
+                this._selectionWasModified = false;
+                this._modifiedEntityConfigClientIds = [];
+                this._modifiedViewConfigClientIds = [];
+                this._lastSavedSelectedEntityConfigClientId  = this.attributes.selectedEntityConfigClientId;
+                this._lastSavedSelectedViewConfigClientId    = this.attributes.selectedViewConfigClientId;
+                this._lastSavedEntityWidth    = this.attributes.entityWidth;
+
+                if (triggeredAtLeastSomething) {
+                    this.trigger("change");
+                }
+            },
+        });
+    });
+}, Logger);