comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:493bcb69166c
1 "use strict";
2
3 App.module("ContextModule", function(ContextModule, App, Backbone, Marionette, $, _, Logger) {
4
5 // Define private variables
6 var logger = null;
7
8 ContextModule.addInitializer(function(options){
9
10 logger = Logger.get("ContextModule.ConfigGrid");
11 logger.setLevel(Logger.WARN);
12
13 /**
14 * ConfigGrid stores the configuration of a grid that consists of entityConfigs and viewConfigs
15 * (both are Backbone.Collection of Config)
16 *
17 * In real situation entityConfigs are music collection configs and music recording configs
18 *
19 * two sub-collections can be interacted directly (without proxy methods)
20 *
21 * The grid can be given a read-only type on creation in order to easily to distinguish between collection and recording grid later
22 * getType() method is available for this purpose. The type of the grid is not being serialized or unserialized
23 *
24 * The following events are triggered:
25 *
26 * change_layout
27 * when both or any of the two collections of Config gets new objects, looses objects or shuffles
28 * (but not when parameters in individual parameter bags change)
29 *
30 * change_entity:c123
31 * change_view:c123
32 * when a particular parameter bag changes (c123 is replaced with a corresponding client id of an entity or a view)
33 *
34 * change_entity_neighbours:c123
35 * change_view_neighbours:c123
36 * when a Config, which is right before or right after the given parameter bag, changes
37 * This includes cases when neighbours are added or removed
38 *
39 * change_selection
40 * when selectedEntityConfigClientId or (and) selectedViewConfigClientId change
41 *
42 * change
43 * this event is triggered together with any of the above ones, but
44 * maximum once during a complex operation such as unserialize
45 */
46 ContextModule.ConfigGrid = Backbone.Model.extend({
47 defaults: {
48 entityConfigs: null,
49 viewConfigs: null,
50 selectedEntityConfigClientId: null,
51 selectedViewConfigClientId: null
52 },
53
54 /**
55 * @memberOf App.ContextModule.ConfigGrid
56 */
57 initialize: function(type) {
58
59 this.type = type;
60
61 this.attributes.entityConfigs = new ContextModule.ConfigCollection(null, {
62 comparator: false,
63 configGridType: type,
64 dimension: "entity",
65 });
66 this.attributes.viewConfigs = new ContextModule.ConfigCollection(null, {
67 comparator: false,
68 configGridType: type,
69 dimension: "view",
70 });
71
72 // Shortcuts for entity configs and view configs (for quicker access)
73 this.entityConfigs = this.attributes.entityConfigs;
74 this.viewConfigs = this.attributes.viewConfigs;
75
76 this._modificationPropagationEnabled = true;
77 this._configCollectionsWereModified = false;
78 this._configsWereModified = false;
79 this._modifiedEntityConfigClientIds = [];
80 this._modifiedViewConfigClientIds = [];
81 this._lastSavedOrderedEntityClientIds = _.pluck(this.attributes.entityConfigs.models, "cid");
82 this._lastSavedOrderedViewClientIds = _.pluck(this.attributes.viewConfigs.models, "cid");
83 this._lastSavedSelectedEntityConfigClientId = this.attributes.selectedEntityConfigClientId;
84 this._lastSavedSelectedViewConfigClientId = this.attributes.selectedViewConfigClientId;
85
86 this.entityConfigs.bind("add remove reset sort", this._registerModificationOfConfigCollectionForEntities, this);
87 this.viewConfigs.bind("add remove reset sort", this._registerModificationOfConfigCollectionForViews, this);
88
89 this.entityConfigs.bind("change", this._registerModificationOfConfig, this);
90 this.viewConfigs.bind("change", this._registerModificationOfConfig, this);
91
92 this.bind("change:selectedEntityConfigClientId", this._registerModificationOfAtomicProperty);
93 this.bind("change:selectedViewConfigClientId", this._registerModificationOfAtomicProperty);
94 this.bind("change:entityWidth", this._registerModificationOfStandardAtomicProperty);
95 },
96
97 /**
98 * @memberOf App.ContextModule.ConfigGrid
99 */
100 getType: function() {
101 return this.type;
102 },
103
104 /**
105 * @memberOf App.ContextModule.ConfigGrid
106 */
107 getPrevEntityNeighbour: function(entityConfig) {
108 return this._getNeighbour(this.attributes.entityConfigs, entityConfig, -1);
109 },
110
111 /**
112 * @memberOf App.ContextModule.ConfigGrid
113 */
114 getNextEntityNeighbour: function(entityConfig) {
115 return this._getNeighbour(this.attributes.entityConfigs, entityConfig, 1);
116 },
117
118 /**
119 * @memberOf App.ContextModule.ConfigGrid
120 */
121 getPrevViewNeighbour: function(viewConfig) {
122 return this._getNeighbour(this.attributes.viewConfigs, viewConfig, -1);
123 },
124
125 /**
126 * @memberOf App.ContextModule.ConfigGrid
127 */
128 getNextViewNeighbour: function(viewConfig) {
129 return this._getNeighbour(this.attributes.viewConfigs, viewConfig, 1);
130 },
131
132 /**
133 * @memberOf App.ContextModule.ConfigGrid
134 */
135 relocateEntityConfig: function(entityConfig, indexOrNextConfigOrNextConfigClientId) {
136 return this._relocate(this.attributes.entityConfigs, entityConfig, indexOrNextConfigOrNextConfigClientId);
137 },
138
139 /**
140 * @memberOf App.ContextModule.ConfigGrid
141 */
142 relocateViewConfig: function(viewConfig, indexOrNextConfigOrNextConfigClientId) {
143 return this._relocate(this.attributes.viewConfigs, viewConfig, indexOrNextConfigOrNextConfigClientId);
144 },
145
146 /**
147 * @memberOf App.ContextModule.ConfigGrid
148 */
149 serialize: function() {
150 logger.debug("method called: ConfigGrid::serialize");
151 var _this = this;
152
153 var result = {
154 entityConfigs: this.attributes.entityConfigs.map(function(config){ return config.serialize(); }),
155 viewConfigs: this.attributes.viewConfigs.map(function(config){ return config.serialize(); })
156 };
157
158 if (this.attributes.selectedEntityConfigClientId) {
159 result.selectedEntityConfigClientId = this.attributes.selectedEntityConfigClientId;
160 }
161 if (this.attributes.selectedViewConfigClientId) {
162 result.selectedViewConfigClientId = this.attributes.selectedViewConfigClientId;
163 }
164 if (this.attributes.entityWidth) {
165 result.entityWidth = this.attributes.entityWidth;
166 }
167
168 return result;
169 },
170
171 getSelectedEntityConfig: function() {
172 return this.attributes.entityConfigs.get(this.attributes.selectedEntityConfigClientId);
173 },
174
175 getSelectedViewConfig: function() {
176 return this.attributes.viewConfigs.get(this.attributes.selectedViewConfigClientId);
177 },
178
179 // getSelectedConfigAtGivenDimension: function(dimension) {
180 // if (dimension == "entity") {
181 // return this.getSelectedEntityConfig();
182 // } else if (dimension == "view") {
183 // return this.getSelectedViewConfig();
184 // }
185 // },
186 //
187 addEntityAndSelectIt: function(entityConfig, indexOrNextConfigOrNextConfigClientId) {
188 this._addAndSelect(this.attributes.entityConfigs, entityConfig, _.isUndefined(indexOrNextConfigOrNextConfigClientId) ? null : indexOrNextConfigOrNextConfigClientId);
189 },
190
191 addViewAndSelectIt: function(viewConfig, indexOrNextConfigOrNextConfigClientId) {
192 this._addAndSelect(this.attributes.viewConfigs, viewConfig, _.isUndefined(indexOrNextConfigOrNextConfigClientId) ? null : indexOrNextConfigOrNextConfigClientId);
193 },
194
195 removeEntityAndSelectNeighbour: function(entityConfig) {
196 this._removeAndSelectNeighbour(this.attributes.entityConfigs, entityConfig);
197 },
198
199 removeViewAndSelectNeighbour: function(viewConfig) {
200 this._removeAndSelectNeighbour(this.attributes.viewConfigs, viewConfig);
201 },
202
203 _addAndSelect: function(configCollection, config, indexOrNextConfigOrNextConfigClientId) {
204 this._modificationPropagationEnabled = false;
205
206 configCollection.add(config);
207 if (configCollection == this.attributes.entityConfigs) {
208 this.attributes.selectedEntityConfigClientId = config.getClientId();
209 } else {
210 this.attributes.selectedViewConfigClientId = config.getClientId();
211 }
212 this._relocate(configCollection, config, indexOrNextConfigOrNextConfigClientId);
213
214 this._triggerModificationEventsIfNeeded();
215 this._modificationPropagationEnabled = true;
216
217 },
218
219 _removeAndSelectNeighbour: function(configCollection, config) {
220 this._modificationPropagationEnabled = false;
221
222 var neighbourToSelect = this._getNeighbour(configCollection, config, 1);
223 if (!neighbourToSelect) {
224 neighbourToSelect = this._getNeighbour(configCollection, config, -1);
225 }
226 configCollection.remove(config);
227 if (configCollection == this.attributes.entityConfigs) {
228 this.attributes.selectedEntityConfigClientId = neighbourToSelect ? neighbourToSelect.getClientId() : null;
229 } else {
230 this.attributes.selectedViewConfigClientId = neighbourToSelect ? neighbourToSelect.getClientId() : null;
231 }
232
233 this._triggerModificationEventsIfNeeded();
234 this._modificationPropagationEnabled = true;
235
236 },
237
238 /**
239 * @memberOf App.ContextModule.ConfigGrid
240 */
241 unserialize: function(serializedAttributes) {
242 logger.debug("method called: ConfigGrid::unserialize");
243
244 this._modificationPropagationEnabled = false;
245
246 var fixedSerializedAttributes = serializedAttributes;
247 if (!_.isSimpleObject(serializedAttributes)) {
248 logger.warn("ConfigGrid::unserialize called for not an object: ", serializedAttributes);
249 fixedSerializedAttributes = {};
250 }
251
252 // entityConfigs
253 var newConfigs = [];
254 var fixedSerializedConfigs = fixedSerializedAttributes.entityConfigs;
255 if (!_.isArray(fixedSerializedConfigs)) {
256 if (_.isSimpleObject(serializedAttributes)) {
257 logger.warn("ConfigGrid::unserialize called for an object with faulty entityConfigs: ", fixedSerializedConfigs);
258 }
259 fixedSerializedConfigs = [];
260 };
261 for (var i = 0; i < fixedSerializedConfigs.length; i++) {
262 var serializedConfig = fixedSerializedConfigs[i];
263 var config = this.attributes.entityConfigs.get(serializedConfig.clientId);
264 if (!config) {
265 config = new App.ContextModule.Config(serializedConfig);
266 } else {
267 config.unserialize(serializedConfig);
268 }
269 newConfigs.push(config);
270 }
271 this.attributes.entityConfigs.reset(newConfigs);
272
273 // viewConfigs
274 var newConfigs = [];
275 var fixedSerializedConfigs = fixedSerializedAttributes.viewConfigs;
276 if (!_.isArray(fixedSerializedConfigs)) {
277 if (_.isSimpleObject(serializedAttributes)) {
278 logger.warn("ConfigGrid::unserialize called for an object with faulty viewConfigs: ", fixedSerializedConfigs);
279 }
280 fixedSerializedConfigs = [];
281 };
282 for (var i = 0; i < fixedSerializedConfigs.length; i++) {
283 var serializedConfig = fixedSerializedConfigs[i];
284 var config = this.attributes.viewConfigs.get(serializedConfig.clientId);
285 if (!config) {
286 config = new App.ContextModule.Config(serializedConfig);
287 } else {
288 config.unserialize(serializedConfig);
289 }
290 newConfigs.push(config);
291 }
292 this.attributes.viewConfigs.reset(newConfigs);
293
294 // selectedEntityConfigClientId, selectedViewConfigClientId
295 this.attributes.selectedEntityConfigClientId = fixedSerializedAttributes.selectedEntityConfigClientId;
296 this.attributes.selectedViewConfigClientId = fixedSerializedAttributes.selectedViewConfigClientId;
297
298 this.attributes.entityWidth = fixedSerializedAttributes.entityWidth;
299
300 this._triggerModificationEventsIfNeeded();
301 this._modificationPropagationEnabled = true;
302 },
303
304 _getNeighbour: function(configCollection, config, offset) {
305 var index = configCollection.indexOf(config);
306 if (index === -1) {
307 throw _.str.sprintf("Can't find config %s", JSON.stringify(config.serialize()));
308 }
309 return configCollection.at(index + offset);
310 },
311
312 _relocate: function(configCollection, config, indexOrNextConfigOrNextConfigClientId) {
313 var clientIds = _.pluck(configCollection.models, "cid");
314 var nextConfigClientId = null;
315
316 if (_.isNumber(indexOrNextConfigOrNextConfigClientId) && indexOrNextConfigOrNextConfigClientId != clientIds.length) {
317 nextConfigClientId = clientIds[indexOrNextConfigOrNextConfigClientId];
318 }
319 if (_.isObject(indexOrNextConfigOrNextConfigClientId)) {
320 nextConfigClientId = indexOrNextConfigOrNextConfigClientId.getClientId();
321 }
322 if (_.isString(indexOrNextConfigOrNextConfigClientId)) {
323 if (clientIds.indexOf(indexOrNextConfigOrNextConfigClientId) !== -1) {
324 nextConfigClientId = indexOrNextConfigOrNextConfigClientId;
325 }
326 }
327 if (!nextConfigClientId && !_.isNull(indexOrNextConfigOrNextConfigClientId) && indexOrNextConfigOrNextConfigClientId != configCollection.size()) {
328 throw _.str.sprintf("Wrong value for indexOrNextConfigOrNextConfigClientId %s", indexOrNextConfigOrNextConfigClientId);
329 }
330
331 var configClientId = config.getClientId();
332 if (!configClientId || clientIds.indexOf(configClientId) == -1) {
333 var flattenedConfig = config;
334 if (_.isObject(flattenedConfig)) {
335 flattenedConfig = JSON.stringify(flattenedConfig);
336 }
337 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(", "));
338 }
339 if (configCollection.get(configClientId) !== config) {
340 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);
341 }
342 var newClientIds = _.without(clientIds, configClientId);
343 if (_.isNull(nextConfigClientId)) {
344 newClientIds.push(configClientId);
345 } else {
346 var nextConfigIndex = newClientIds.indexOf(nextConfigClientId);
347 //if (nextConfigIndex)
348 var tempClientIds = newClientIds.slice(0, nextConfigIndex);
349 tempClientIds.push(configClientId);
350 newClientIds = tempClientIds.concat(newClientIds.slice(nextConfigIndex));
351 }
352
353 var oldComparator = configCollection.comparator;
354 configCollection.comparator = function(model) {
355 return newClientIds.indexOf(model.getClientId());
356 };
357 configCollection.sort();
358 configCollection.comparator = oldComparator;
359 },
360
361 _registerModificationOfConfigCollectionForEntities: function(modelOrModels, options) {
362 if (!_.isEqual(this._lastSavedOrderedEntityClientIds, _.pluck(this.attributes.entityConfigs.models, "cid"))) {
363 this._configCollectionsWereModified = true;
364 if (this._modificationPropagationEnabled) {
365 this._triggerModificationEventsIfNeeded();
366 };
367 }
368 },
369
370 _registerModificationOfConfigCollectionForViews: function(modelOrModels, options) {
371 if (!_.isEqual(this._lastSavedOrderedViewClientIds, _.pluck(this.attributes.viewConfigs.models, "cid"))) {
372 this._configCollectionsWereModified = true;
373 if (this._modificationPropagationEnabled) {
374 this._triggerModificationEventsIfNeeded();
375 };
376 }
377 },
378
379 _registerModificationOfConfig: function() {
380 for (var i = 0; i < this.attributes.entityConfigs.length; i++) {
381 if(this.attributes.entityConfigs.at(i).hasChanged()) {
382 this._configsWereModified = true;
383 this._modifiedEntityConfigClientIds.push(this.attributes.entityConfigs.at(i).getClientId());
384 }
385 }
386 for (var i = 0; i < this.attributes.viewConfigs.length; i++) {
387 if(this.attributes.viewConfigs.at(i).hasChanged()) {
388 this._configsWereModified = true;
389 this._modifiedViewConfigClientIds.push(this.attributes.viewConfigs.at(i).getClientId());
390 }
391 }
392 if (this._modificationPropagationEnabled) {
393 this._triggerModificationEventsIfNeeded();
394 };
395 },
396
397 _registerModificationOfAtomicProperty: function() {
398 if (this._modificationPropagationEnabled) {
399 this._triggerModificationEventsIfNeeded(true);
400 };
401 },
402
403 _registerModificationOfStandardAtomicProperty: function() {
404 if (this._modificationPropagationEnabled) {
405 this._triggerModificationEventsIfNeeded();
406 };
407 },
408
409 _triggerModificationEventsIfNeeded: function(specialCaseForRegisterModificationOfSelection) {
410
411 var triggeredAtLeastSomething = false;
412 if (this._configCollectionsWereModified) {
413 triggeredAtLeastSomething = true;
414 this.trigger("change_layout");
415 }
416
417 var newOrderedEntityClientIds = null;
418 var newOrderedViewClientIds = null;
419 if (this._configCollectionsWereModified || this._modifiedEntityConfigClientIds.length || this._modifiedViewConfigClientIds.length) {
420 newOrderedEntityClientIds = _.pluck(this.attributes.entityConfigs.models, "cid");
421 newOrderedViewClientIds = _.pluck(this.attributes.viewConfigs.models, "cid");
422
423 // change_entity:c123
424 if (this._modifiedEntityConfigClientIds.length) {
425 for (var i = 0; i < newOrderedEntityClientIds.length; i++) {
426 if (_.indexOf(this._modifiedEntityConfigClientIds, newOrderedEntityClientIds[i]) !== -1) {
427 triggeredAtLeastSomething = true;
428 this.trigger("change_entity:" + newOrderedEntityClientIds[i]);
429 }
430 }
431 }
432 // change_view:c123
433 if (this._modifiedViewConfigClientIds.length) {
434 for (var i = 0; i < newOrderedViewClientIds.length; i++) {
435 if (_.indexOf(this._modifiedViewConfigClientIds, newOrderedViewClientIds[i]) !== -1) {
436 triggeredAtLeastSomething = true;
437 this.trigger("change_view:" + newOrderedViewClientIds[i]);
438 }
439 }
440 }
441
442 // change_entity_neighbours:c123
443 for (var i = 0; i < newOrderedEntityClientIds.length; i++) {
444 var entityClientId = newOrderedEntityClientIds[i];
445 var oldEntityIndex = this._lastSavedOrderedEntityClientIds.indexOf(entityClientId);
446 if (oldEntityIndex == -1) {
447 continue;
448 }
449 var newPrevEntityClientId = newOrderedEntityClientIds[i - 1];
450 var newNextEntityClientId = newOrderedEntityClientIds[i + 1];
451 var oldPrevEntityClientId = this._lastSavedOrderedEntityClientIds[oldEntityIndex - 1];
452 var oldNextEntityClientId = this._lastSavedOrderedEntityClientIds[oldEntityIndex + 1];
453
454 if (newPrevEntityClientId != oldPrevEntityClientId
455 || newNextEntityClientId != oldNextEntityClientId
456 || this._modifiedEntityConfigClientIds.indexOf(newPrevEntityClientId) !== -1
457 || this._modifiedEntityConfigClientIds.indexOf(newNextEntityClientId) !== -1
458 ) {
459 triggeredAtLeastSomething = true;
460 this.trigger("change_entity_neighbours:" + entityClientId);
461 };
462 }
463
464 // change_view_neighbours:c123
465 for (var i = 0; i < newOrderedViewClientIds.length; i++) {
466 var viewClientId = newOrderedViewClientIds[i];
467 var oldViewIndex = this._lastSavedOrderedViewClientIds.indexOf(viewClientId);
468 if (oldViewIndex == -1) {
469 continue;
470 }
471 var newPrevViewClientId = newOrderedViewClientIds[i - 1];
472 var newNextViewClientId = newOrderedViewClientIds[i + 1];
473 var oldPrevViewClientId = this._lastSavedOrderedViewClientIds[oldViewIndex - 1];
474 var oldNextViewClientId = this._lastSavedOrderedViewClientIds[oldViewIndex + 1];
475
476 if (newPrevViewClientId != oldPrevViewClientId
477 || newNextViewClientId != oldNextViewClientId
478 || this._modifiedViewConfigClientIds.indexOf(newPrevViewClientId) !== -1
479 || this._modifiedViewConfigClientIds.indexOf(newNextViewClientId) !== -1
480 ) {
481 triggeredAtLeastSomething = true;
482 this.trigger("change_view_neighbours:" + viewClientId);
483 };
484 };
485 }
486
487 this._lastSavedOrderedEntityClientIds = _.pluck(this.attributes.entityConfigs.models, "cid");
488 this._lastSavedOrderedViewClientIds = _.pluck(this.attributes.viewConfigs.models, "cid");
489
490 // Fix selection
491 if (!this.attributes.entityConfigs.get(this.attributes.selectedEntityConfigClientId)) {
492 this.attributes.selectedEntityConfigClientId = null;
493 }
494 if (!this.attributes.viewConfigs.get(this.attributes.selectedViewConfigClientId)) {
495 this.attributes.selectedViewConfigClientId = null;
496 }
497 if (this._lastSavedSelectedEntityConfigClientId != this.attributes.selectedEntityConfigClientId
498 || this._lastSavedSelectedViewConfigClientId != this.attributes.selectedViewConfigClientId
499 ) {
500 if (!specialCaseForRegisterModificationOfSelection) {
501 triggeredAtLeastSomething = true;
502 }
503 this.trigger("change_selection");
504 }
505
506 if (this._lastSavedEntityWidth != this.attributes.entityWidth) {
507 triggeredAtLeastSomething = true;
508 }
509
510 this._configCollectionsWereModified = false;
511 this._configsWereModified = false;
512 this._selectionWasModified = false;
513 this._modifiedEntityConfigClientIds = [];
514 this._modifiedViewConfigClientIds = [];
515 this._lastSavedSelectedEntityConfigClientId = this.attributes.selectedEntityConfigClientId;
516 this._lastSavedSelectedViewConfigClientId = this.attributes.selectedViewConfigClientId;
517 this._lastSavedEntityWidth = this.attributes.entityWidth;
518
519 if (triggeredAtLeastSomething) {
520 this.trigger("change");
521 }
522 },
523 });
524 });
525 }, Logger);