comparison src/DML/MainVisBundle/Resources/assets/marionette/modules/MainRegionModule/MainRegionModule.20-ConfigGridCellsView.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("MainRegionModule", function (MainRegionModule, App, Backbone, Marionette, $, _, Logger) {
4
5 MainRegionModule.ConfigGridCellsView = MainRegionModule.ConfigGridChildView.extend({
6
7 options: {
8 state: null,
9 configGrid: null,
10 parentConfigGridView: null,
11 scrollAnimationMinSpeed: 100,
12 scrollAnimationBaseSpeed: 400,
13 scrollAnimationBaseDistance: 500,
14 desiredPaddingAroundVisInstanceOnScroll: {
15 left: 35,
16 top: 20,
17 right: 35,
18 bottom: 33,
19 },
20 enableFixedHeaders: true, // headers become fixed when scrolling
21 },
22
23 _logger: null,
24
25 _$entityHeadersContainer: null,
26 _$entityHeadersBlind: null,
27 _$viewHeadersContainer: null,
28 _$viewHeadersBlind: null,
29 _$visInstancesContainer: null,
30 _$cornerBlind: null,
31 _$fixedContainer: null,
32
33 _$entityAdder: null,
34 _$viewAdder: null,
35
36 _distanceBetweenEntities: 10,
37 _distanceBetweenViews: 10,
38 _viewHeaderHeight: 0,
39 _entityAdderWidth: 0,
40 _viewAdderHeight: 0,
41 _cachedMinSpaceWidth: 0,
42 _cachedMinSpaceHeight: 0,
43 _spacePadding: null, // top, right, bottom, left, h = l + r, v = t + b
44 _scrollLeftBeforeLatestSelectionUpdate: 0,
45 _scrollTopBeforeLatestSelectionUpdate: 0,
46
47 _ignoreXOnNextScroll: false,
48 _ignoreYOnNextScroll: false,
49 _latestChangeWasAReset: false,
50
51 _cachedScrollPosGridHash: null,
52 _cachedScrollPosSelection: null,
53 _cachedScrollPosX: null,
54 _cachedScrollPosY: null,
55
56 _cachedSelectedEntityConfigClientId: null, // string
57 _cachedSelectedViewConfigClientId: null, // string
58
59 _cachedEntityHeaderViewsByClientId: {}, // string: Backbone view
60 _cachedViewHeaderViewsByClientId: {}, // string: Backbone view
61 _cachedVisInstanceViewsByClientIdPair: {}, // string: Backbone view
62
63 _cachedEntityConfigClientIds: null, // [string] (keys of _cachedEntityHeaderViewsByClientId)
64 _cachedViewConfigClientIds: null, // [string] (keys of _cachedViewHeaderViewsByClientId)
65
66 _cachedEntityWidth: null,
67 _cachedViewContentHeights: null,
68
69 initialize: function(options) {
70 var _this = this;
71
72 _this._logger = Logger.get("ConfigGridCellsView");
73 //_this._logger.setLevel(Logger.DEBUG);
74
75 _this.options = _.defaults(options || {}, this.options);
76 if (_this.options.enableFixedHeaders === null) {
77 _this.options.enableFixedHeaders = (navigator.userAgent.indexOf("afari") >= 0 && navigator.userAgent.indexOf("Chrom") == -1) || navigator.userAgent.indexOf("MSIE") >= 0 || navigator.userAgent.indexOf("MATM") >= 0 || navigator.userAgent.indexOf("Trident") >= 0;
78 }
79
80 var configGridType = _this.options.configGrid.getType();
81
82 _this.$el.empty();
83
84 _this._$entityHeadersContainer = $.bem.generateElement("config-grid-cells", "entity-headers-container");
85 _this._$entityHeadersBlind = $.bem.generateElement("config-grid-cells", "entity-headers-blind");
86 _this._$entityHeadersContainer.append(_this._$entityHeadersBlind);
87
88 _this._$viewHeadersContainer = $.bem.generateElement("config-grid-cells", "view-headers-container");
89 _this._$viewHeadersBlind = $.bem.generateElement("config-grid-cells", "view-headers-blind");
90 _this._$viewAdder = $.bem.generateElement("config-grid-cells", "view-header", ["kind_adder"]);
91 _this._$viewHeadersContainer.append(_this._$viewHeadersBlind, _this._$viewAdder);
92
93 _this._$visInstancesContainer = $.bem.generateElement("config-grid-cells", "vis-instances-container");
94
95 _this._$cornerBlind = $.bem.generateElement("config-grid-cells", "corner-blind");
96
97 _this._$space = $.bem.generateElement("config-grid-cells", "space");
98
99 _this._$containerOfScrollable = $.bem.generateElement("config-grid-cells", "container", ["position_scrollable"]);
100 _this._$containerOfFixed = $.bem.generateElement("config-grid-cells", "container", ["position_fixed"]);
101
102 // Entity and collection adders
103 if (configGridType == "collection") {
104 _this._$entityAdder = $.bem.generateElement("config-grid-cells", "entity-header", ["kind_adder"]);
105 var $entityAdderBackground = $.bem.generateElement("config-grid-cells", "entity-header-background");
106 var $entityAdderLabel = $.bem.generateElement("config-grid-cells", "entity-header-label");
107 $entityAdderLabel.html(Backbone.Marionette.TemplateCache.get("#config-grid_collection__entity-adder-label"));
108 _this._$entityAdder.append($entityAdderBackground, $entityAdderLabel);
109 _this._$entityHeadersContainer.append(_this._$entityAdder);
110 _this._$entityAdder.click(function() {
111 _this.options.configGrid.addEntityAndSelectIt(new App.ContextModule.Config());
112 });
113 } else {
114 _this._$entityAdder = $();
115 }
116 _this._$viewAdder = $.bem.generateElement("config-grid-cells", "view-header", ["kind_adder"]);
117 var $viewAdderBackground = $.bem.generateElement("config-grid-cells", "view-header-background");
118 var $viewAdderLabel = $.bem.generateElement("config-grid-cells", "view-header-label");
119 $viewAdderLabel.html(Backbone.Marionette.TemplateCache.get("#config-grid__view-adder-label"));
120 _this._$viewAdder.append($viewAdderBackground, $viewAdderLabel);
121 _this._$viewHeadersContainer.append(_this._$viewAdder);
122 _this._$viewAdder.click(function() {
123 _this.options.configGrid.addViewAndSelectIt(new App.ContextModule.Config());
124 });
125
126 _this._$entityHeadersContainer.append();
127 _this._$viewHeadersContainer.append();
128 _this._$space.append(
129 _this._$visInstancesContainer,
130 _this._$entityHeadersContainer,
131 _this._$viewHeadersContainer,
132 _this._$cornerBlind
133 );
134
135 _this._$containerOfScrollable.append(_this._$space);
136 _this.$el.append(_this._$containerOfScrollable, _this._$containerOfFixed);
137
138 // extract some size- and position-related constants
139 _this._viewHeaderHeight = _this._$viewAdder.height();
140 _this._entityAdderWidth = _this._$entityAdder.width();
141 _this._viewAdderHeight = _this._viewHeaderHeight;
142 if (!_this._entityAdderWidth) {
143 _this._entityAdderWidth = -_this._distanceBetweenEntities;
144 }
145
146 // When defining space padding, it is sometimes necessary to wait a bit
147 // A grid that is on the "back side of the card" may sometimes become blank when scrolling otherwise
148 _this._spacePadding = {};
149 var interval;
150 var setSpaceInterval = function() {
151 if (_this._$space.css("padding-top")) {
152 _this._spacePadding.top = parseInt(_this._$space.css("padding-top"), 10);
153 _this._spacePadding.right = parseInt(_this._$space.css("padding-right"), 10);
154 _this._spacePadding.bottom = parseInt(_this._$space.css("padding-bottom"), 10);
155 _this._spacePadding.left = parseInt(_this._$space.css("padding-left"), 10);
156 _this._spacePadding.h = _this._spacePadding.left + _this._spacePadding.right;
157 _this._spacePadding.v = _this._spacePadding.top + _this._spacePadding.bottom;
158 //_this._toggleFixedHeadersIfNeeded(false);
159 _this._updateDemensionsForContainerOfFixed();
160 clearInterval(interval);
161 }
162 };
163 if (_this._$space.css("padding-top")) {
164 setSpaceInterval();
165 } else {
166 interval = setInterval(setSpaceInterval, 50);
167 }
168
169 // subscribe to events
170 _this.listenTo(_this.options.configGrid, "change", _this.renderIfParentConfigGridIsVisible);
171
172 var isSafari = navigator.userAgent.indexOf("afari") >= 0;
173 var isChrome = navigator.userAgent.indexOf("rome") >= 0;
174 var isScrolling = false;
175 if (_this.options.enableFixedHeaders) {
176 _this._$containerOfScrollable.mousewheel(_.debounce(function(event) {
177 _this._toggleFixedHeadersIfNeeded(true);
178
179 var visInstanceViews = _.values(_this._cachedVisInstanceViewsByClientIdPair);
180 for (var i = visInstanceViews.length - 1; i >= 0; --i) {
181 visInstanceViews[i].cancelPointerHighlights();
182 }
183
184 App.TooltipModule.update();
185 if (isSafari || isChrome) {
186 _this._$containerOfScrollable.scrollLeft(_this._$containerOfScrollable.scrollLeft() + event.deltaX);
187 _this._$containerOfScrollable.scrollTop (_this._$containerOfScrollable.scrollTop() - event.deltaY);
188 event.preventDefault();
189 }
190 }, 50, true));
191 _this._$containerOfScrollable.mousewheel(_.debounce(function(event) {
192 if (!isScrolling) {
193 _this._toggleFixedHeadersIfNeeded(false);
194 }
195 }, 200));
196 }
197
198 _this._$containerOfScrollable.scroll(function(event) {
199 if (!isScrolling) {
200 isScrolling = true;
201 }
202 _this._toggleFixedHeadersIfNeeded(true);
203 });
204
205 _this._$containerOfScrollable.scroll(_.debounce(function(event) {
206 _this._toggleFixedHeadersIfNeeded(false);
207 _this._reviseSpaceSize();
208 isScrolling = false;
209 _this._updateCachedScroll();
210 }, 200));
211
212 $(window).resize(_.throttle(function() {
213 _this._reviseSpaceSize();
214 _this._updateDemensionsForContainerOfFixed();
215 }, 100));
216 _this._toggleFixedHeadersIfNeeded(false);
217 _this._updateDemensionsForContainerOfFixed();
218
219 // Restore and save precise scroll position of the currently selected entity and view
220 _this._cachedScrollPosGridHash = App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-grid-hash_%s", configGridType));
221 _this._cachedScrollPosSelection = App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-selection_%s", configGridType));
222 _this._cachedScrollPosX = 1 * App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-x_%s", configGridType));
223 _this._cachedScrollPosY = 1 * App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-y_%s", configGridType));
224
225 $(window).unload(function() {
226 App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-grid-hash_%s", configGridType), _this._cachedScrollPosGridHash);
227 App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-selection_%s", configGridType), _this._cachedScrollPosSelection);
228 App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-x_%s", configGridType), "" + _this._cachedScrollPosX);
229 App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-y_%s", configGridType), "" + _this._cachedScrollPosY);
230 });
231
232 },
233
234 render: function (deep, instant) {
235 var _this = this;
236
237 _this._updateLayout(deep, instant);
238 _this._updateSelection(deep, instant);
239 if (deep) {
240 _this._reviseSpaceSize();
241 _this._updateDemensionsForContainerOfFixed();
242 }
243 _this._adjustToScrollPos(deep, instant);
244 _this.scrollAccordingToSelection(deep, instant);
245
246 if (deep) {
247 var entityHeaderViews = _.values(_this._cachedEntityHeaderViewsByClientId);
248 for (var i = entityHeaderViews.length - 1; i >= 0; --i) {
249 entityHeaderViews[i].render(deep, instant);
250 }
251
252 var viewHeaderViews = _.values(_this._cachedViewHeaderViewsByClientId);
253 for (var i = viewHeaderViews.length - 1; i >= 0; --i) {
254 viewHeaderViews[i].render(deep, instant);
255 }
256
257 var visInstanceViews = _.values(_this._cachedVisInstanceViewsByClientIdPair);
258 for (var i = visInstanceViews.length - 1; i >= 0; --i) {
259 visInstanceViews[i].render(deep, instant);
260 }
261 };
262 },
263
264 getEntityWidth: function() {
265 var _this = this;
266 return (_this.options.configGrid.get("entityWidth") || App.options.defaultEntityWidth) * 1;
267 },
268
269 _updateLayout: function(deep, instant) {
270 var _this = this;
271
272 // Check if entities of views have changed
273 var entityListHasChanged = false;
274 var viewListHasChanged = false;
275 var newEntityConfigs = _this.options.configGrid.get("entityConfigs");
276 var newViewConfigs = _this.options.configGrid.get("viewConfigs");
277 var newEntityConfigClientIds = _.pluck(newEntityConfigs.models, "cid");
278 var newViewConfigClientIds = _.pluck(newViewConfigs.models, "cid");
279
280 _this._scrollLeftBeforeLatestLayoutUpdate = _this.$el.scrollLeft();
281 _this._scrollTopBeforeLatestLayoutUpdate = _this.$el.scrollTop();
282
283 if (_this._cachedEntityConfigClientIds === null) {
284 entityListHasChanged = true;
285 viewListHasChanged = true;
286 _this._cachedEntityConfigClientIds = [];
287 _this._cachedViewConfigClientIds = [];
288 }
289
290 var createdEntityConfigClientIds = _.difference(newEntityConfigClientIds, _this._cachedEntityConfigClientIds);
291 var createdViewConfigClientIds = _.difference(newViewConfigClientIds, _this._cachedViewConfigClientIds);
292 var removedEntityConfigClientIds = _.difference(_this._cachedEntityConfigClientIds, newEntityConfigClientIds);
293 var removedViewConfigClientIds = _.difference(_this._cachedViewConfigClientIds, newViewConfigClientIds);
294
295 _this._latestChangeWasAReset = false;
296
297 if (createdEntityConfigClientIds.length + removedEntityConfigClientIds.length == 1) {
298 _this._ignoreYOnNextScroll = true;
299 }
300 if (createdViewConfigClientIds.length + removedViewConfigClientIds.length == 1) {
301 _this._ignoreXOnNextScroll = true;
302 }
303
304 if (!_.isEqual(newEntityConfigClientIds, _this._cachedEntityConfigClientIds)) {
305 entityListHasChanged = true;
306 }
307 if (!_.isEqual(newViewConfigClientIds, _this._cachedViewConfigClientIds)) {
308 viewListHasChanged = true;
309 }
310
311 if ((entityListHasChanged && createdEntityConfigClientIds.length + removedEntityConfigClientIds.length > 1)
312 || (viewListHasChanged && createdViewConfigClientIds.length + removedViewConfigClientIds.length > 1)) {
313 _this._latestChangeWasAReset = true;
314 _this._ignoreXOnNextScroll = false;
315 _this._ignoreYOnNextScroll = false;
316 }
317
318
319 var newEntityHeaderViewsByClientId = _this._cachedEntityHeaderViewsByClientId;
320 var newViewHeaderViewsByClientId = _this._cachedViewHeaderViewsByClientId;
321 var newVisInstanceViewsByClientIdPair = _this._cachedVisInstanceViewsByClientIdPair;
322 var viewHeaderViewsToRender = [];
323 var entityHeaderViewsToRender = [];
324 var visInstanceViewsToRender = [];
325
326 // Replacement of entity headers if needed
327 if (entityListHasChanged) {
328 newEntityHeaderViewsByClientId = {};
329 for (var i = 0; i < newEntityConfigClientIds.length; i++) {
330 var currentEntityClientId = newEntityConfigClientIds[i];
331
332 // Look for an existing entity header view
333 var entityHeaderView = _this._cachedEntityHeaderViewsByClientId[currentEntityClientId];
334
335 // Create a new entity header if it does not exist
336 if (!entityHeaderView) {
337 _this._logger.debug("generate entity header ", currentEntityClientId);
338 entityHeaderView = _this._generateEntityHeaderView(newEntityConfigs.get(currentEntityClientId));
339 entityHeaderViewsToRender.push(entityHeaderView);
340 _this._$entityHeadersContainer.append(entityHeaderView.el);
341 }
342 newEntityHeaderViewsByClientId[currentEntityClientId] = entityHeaderView;
343 }
344
345 // Remove entity header views that are no longer needed
346 // The order of the views does not matter as the right layout is achieved with absolute positioning
347 for (var i = removedEntityConfigClientIds.length - 1; i >= 0; --i) {
348 _this._cachedEntityHeaderViewsByClientId[removedEntityConfigClientIds[i]].remove();
349 App.dynamicDerivedConfigDataProvider.retire(removedEntityConfigClientIds[i]);
350 }
351 } else {
352 newEntityHeaderViewsByClientId = _this._cachedEntityHeaderViewsByClientId;
353 }
354
355 // Replacement of view headers if needed
356 if (viewListHasChanged) {
357 newViewHeaderViewsByClientId = {};
358 for (var i = 0; i < newViewConfigClientIds.length; i++) {
359 var currentViewClientId = newViewConfigClientIds[i];
360
361 // Look for an existing entity header
362 var viewHeaderView = _this._cachedViewHeaderViewsByClientId[currentViewClientId];
363
364 // Create a new view header if it does not exist
365 if (!viewHeaderView) {
366 _this._logger.debug("generate view header ", currentViewClientId);
367 viewHeaderView = _this._generateViewHeaderView(newViewConfigs.get(currentViewClientId));
368 viewHeaderViewsToRender.push(viewHeaderView);
369 _this._$viewHeadersContainer.append(viewHeaderView.el);
370 }
371 newViewHeaderViewsByClientId[currentViewClientId] = viewHeaderView;
372 }
373
374 // Remove entity header views that are no longer needed
375 // The order of the views does not matter as the right layout is achieved with absolute positioning
376 for (var i = removedViewConfigClientIds.length - 1; i >= 0; --i) {
377 _this._cachedViewHeaderViewsByClientId[removedViewConfigClientIds[i]].remove();
378 App.dynamicDerivedConfigDataProvider.retire(removedViewConfigClientIds[i]);
379 }
380 } else {
381 newViewHeaderViewsByClientId = _this._cachedViewHeaderViewsByClientId;
382 }
383
384 // Replacement of vis instances
385 if (viewListHasChanged || entityListHasChanged) {
386 newVisInstanceViewsByClientIdPair = {};
387 for (var i = 0; i < newEntityConfigClientIds.length; i++) {
388 var currentEntityClientId = newEntityConfigClientIds[i];
389
390 for (var j = 0; j < newViewConfigClientIds.length; j++) {
391 var currentViewClientId = newViewConfigClientIds[j];
392 var currentClientIdPair = currentEntityClientId + currentViewClientId;
393
394 // Look for an existing vis instance view
395 var visInstanceView = _this._cachedVisInstanceViewsByClientIdPair[currentClientIdPair];
396
397 // Create a new vis instance view if it does not exist
398 if (!visInstanceView) {
399 _this._logger.debug("generate vis instance", currentEntityClientId, currentViewClientId);
400 visInstanceView = _this._generateVisInstanceView(newEntityConfigs.get(currentEntityClientId), newViewConfigs.get(currentViewClientId));
401 visInstanceViewsToRender.push(visInstanceView);
402 _this._$visInstancesContainer.append(visInstanceView.el);
403 }
404 newVisInstanceViewsByClientIdPair[currentClientIdPair] = visInstanceView;
405 }
406 }
407
408 // Add new vis instances and remove those that are no longer needed
409 // The order does not matter as the right layout is achieved with absolute positioning
410 for (var i = this._cachedEntityConfigClientIds.length - 1; i >= 0; --i) {
411 for (var j = removedViewConfigClientIds.length - 1; j >= 0; --j) {
412 var visInstanceToRemove = _this._cachedVisInstanceViewsByClientIdPair[this._cachedEntityConfigClientIds[i] + removedViewConfigClientIds[j]];
413 visInstanceToRemove.remove();
414 }
415 }
416 for (var i = removedEntityConfigClientIds.length - 1; i >= 0; --i) {
417 for (var j = this._cachedViewConfigClientIds.length - 1; j >= 0; --j) {
418 var visInstanceToRemove = _this._cachedVisInstanceViewsByClientIdPair[removedEntityConfigClientIds[i] + this._cachedViewConfigClientIds[j]];
419 if (visInstanceToRemove) {
420 visInstanceToRemove.remove();
421 }
422 }
423 }
424 }
425
426 // view heights
427 var viewHeightsHaveChanged = false;
428 var entityWidthHasChanged = false;
429
430 var entityWidth = _this.getEntityWidth();
431 var viewContentHeights = [];
432 for (var row = 0; row < newViewConfigClientIds.length; row++) {
433 var currentViewConfigClientId = newViewConfigClientIds[row];
434 var viewConfig = newViewConfigs.get(currentViewConfigClientId);
435 var viewContentHeight = App.RepresentationModule.getMasterForConfig(viewConfig).calculateVisInstanceContentHeight(viewConfig, entityWidth);
436 viewContentHeights.push(viewContentHeight);
437 }
438
439 if (entityWidth !== _this._cachedEntityWidth) {
440 entityWidthHasChanged = true;
441 _this._cachedEntityWidth = entityWidth;
442 }
443 if (!_.isEqual(viewContentHeights, _this._cachedViewContentHeights)) {
444 viewHeightsHaveChanged = true;
445 _this._cachedViewContentHeights = viewContentHeights;
446 }
447
448 // Set up positions and sizes for entities and views
449 if (viewListHasChanged || entityListHasChanged || entityWidthHasChanged || viewHeightsHaveChanged) {
450 var newEntityDimensions = []; //entityId, x, width
451 var newViewDimensions = []; //viewId, y, height
452 var x = 0;
453 var configGridType = _this.options.configGrid.getType();
454 for (var col = 0; col < newEntityConfigClientIds.length; col++) {
455 var currentEntityConfigClientId = newEntityConfigClientIds[col];
456 newEntityDimensions.push([currentEntityConfigClientId, x, entityWidth]);
457 x += entityWidth + _this._distanceBetweenEntities;
458 }
459 var y = 0;
460 var viewHeaderHeight = _this._viewHeaderHeight;
461 for (var row = 0; row < newViewConfigClientIds.length; row++) {
462 var currentViewConfigClientId = newViewConfigClientIds[row];
463 newViewDimensions.push([currentViewConfigClientId, y, _this._cachedViewContentHeights[row]]);
464 y += viewHeaderHeight + _this._cachedViewContentHeights[row] + _this._distanceBetweenViews;
465 }
466
467 // Reposition and resize view headers
468 for (var row = newViewDimensions.length - 1; row >= 0; --row) {
469 var currentViewDimensions = newViewDimensions[row];
470 var viewHeaderView = newViewHeaderViewsByClientId[currentViewDimensions[0]];
471 viewHeaderView.$el.css("top", currentViewDimensions[1])
472 .attr("data-top", currentViewDimensions[1])
473 .attr("data-total-height", currentViewDimensions[2] + _this._viewHeaderHeight);
474 viewHeaderView.setSize(currentViewDimensions[2]);
475 }
476 for (var col = newEntityDimensions.length - 1; col >= 0; --col) {
477 var currentEntityDimensions = newEntityDimensions[col];
478
479 // Reposition and resize entity headers
480 var entityHeaderView = newEntityHeaderViewsByClientId[currentEntityDimensions[0]];
481 entityHeaderView.$el.css("left", currentEntityDimensions[1])
482 .attr("data-left", currentEntityDimensions[1])
483 .attr("data-width", currentEntityDimensions[2]);
484 entityHeaderView.setSize(currentEntityDimensions[2]);
485
486 for (var row = newViewDimensions.length - 1; row >= 0; --row) {
487 var currentViewDimensions = newViewDimensions[row];
488
489 // Reposition and resize vis instances
490 var visInstanceView = newVisInstanceViewsByClientIdPair[currentEntityDimensions[0] + currentViewDimensions[0]];
491 visInstanceView.$el.css({
492 "left": currentEntityDimensions[1],
493 "top": currentViewDimensions[1] + viewHeaderHeight
494 });
495 visInstanceView.setSize(currentEntityDimensions[2], currentViewDimensions[2]);
496 }
497 }
498
499 // Reposition entity and view adders
500 var needToResizeSpace = false;
501 if (x != _this._$entityAdder.css("left")) {
502 _this._$entityAdder.css("left", x);
503 needToResizeSpace = true;
504 }
505 if (y != _this._$viewAdder.css("top")) {
506 _this._$viewAdder.css("top", y);
507 needToResizeSpace = true;
508 }
509
510 // Resize the space
511 if (needToResizeSpace) {
512 _this._cachedMinSpaceWidth = x + _this._entityAdderWidth;
513 _this._cachedMinSpaceHeight = y + _this._viewAdderHeight;
514 _this._reviseSpaceSize(!_this._latestChangeWasAReset);
515 }
516 }
517
518 // Update cached view data
519 if (entityListHasChanged) {
520 _this._cachedEntityHeaderViewsByClientId = newEntityHeaderViewsByClientId;
521 _this._cachedEntityConfigClientIds = newEntityConfigClientIds;
522 }
523 if (viewListHasChanged) {
524 _this._cachedViewHeaderViewsByClientId = newViewHeaderViewsByClientId;
525 _this._cachedViewConfigClientIds = newViewConfigClientIds;
526 }
527 if (viewListHasChanged || entityListHasChanged) {
528 _this._cachedVisInstanceViewsByClientIdPair = newVisInstanceViewsByClientIdPair;
529 }
530
531 // Render new vis instances and those that have changed their dimensions
532 // If deep rendering takes place, all view instances will be rendered later
533
534 if (!deep && entityHeaderViewsToRender) {
535 for (var i = entityHeaderViewsToRender.length - 1; i >= 0; --i) {
536 entityHeaderViewsToRender[i].render();
537 }
538 }
539 if (!deep && viewHeaderViewsToRender) {
540 for (var i = viewHeaderViewsToRender.length - 1; i >= 0; --i) {
541 viewHeaderViewsToRender[i].render();
542 }
543 }
544 if (!deep && visInstanceViewsToRender) {
545 for (var i = visInstanceViewsToRender.length - 1; i >= 0; --i) {
546 visInstanceViewsToRender[i].render();
547 }
548 }
549
550 // Destroy detached vis instances
551 if (viewListHasChanged || entityListHasChanged) {
552 var destroyedVisInstanceViews = _.difference(_.values(this._cachedVisInstanceViewsByClientIdPair), _.values(newVisInstanceViewsByClientIdPair));
553 for (var i = destroyedVisInstanceViews.length - 1; i >= 0; --i) {
554 destroyedVisInstanceViews[i].remove();
555 }
556 }
557 },
558
559 _updateSelection: function(deep, instant) {
560 var _this = this;
561
562 var selectedEntityConfig = _this.options.configGrid.getSelectedEntityConfig();
563 var selectedViewConfig = _this.options.configGrid.getSelectedViewConfig();
564 var selectedEntityConfigClientId = selectedEntityConfig ? selectedEntityConfig.getClientId() : null;
565 var selectedViewConfigClientId = selectedViewConfig ? selectedViewConfig.getClientId() : null;
566
567 if (_this._cachedSelectedEntityConfigClientId !== selectedEntityConfigClientId) {
568 _this._cachedSelectedEntityConfigClientId = selectedEntityConfigClientId;
569 }
570 if (_this._cachedSelectedViewConfigClientId !== selectedViewConfigClientId) {
571 _this._cachedSelectedViewConfigClientId = selectedViewConfigClientId;
572 }
573 //
574 // // entity headers
575 // var selectionChanged = false;
576 // selectionChanged = true;
577 // if (_this._cachedSelectedEntityConfigClientId) {
578 // $(_this._cachedEntityHeaderViewsByClientId[_this._cachedSelectedEntityConfigClientId])
579 // .toggleSelected(false);
580 // }
581 // if (newSelectedEntityConfigClientId) {
582 // $(_this._cachedEntityHeaderViewsByClientId[newSelectedEntityConfigClientId])
583 // .toggleSelected(true);
584 // }
585 // _this._cachedSelectedEntityConfigClientId = newSelectedEntityConfigClientId;
586 // };
587 //
588 // // view headers
589 // if (_this._cachedSelectedViewConfigClientId !== newSelectedViewConfigClientId) {
590 // selectionChanged = true;
591 // if (_this._cachedSelectedViewConfigClientId) {
592 // $(_this._cachedViewHeaderViewsByClientId[_this._cachedSelectedViewConfigClientId])
593 // .toggleSelected(false);
594 // }
595 // if (newSelectedViewConfigClientId) {
596 // $(_this._cachedViewHeaderViewsByClientId[newSelectedViewConfigClientId])
597 // .toggleSelected(true);
598 // }
599 // _this._cachedSelectedViewConfigClientId = newSelectedViewConfigClientId;
600 // };
601 },
602
603 scrollAccordingToSelection: function(deep, instant) {
604 var _this = this;
605
606 return;
607 var entityConfigClientId = _this._cachedSelectedEntityConfigClientId;
608 var viewConfigClientId = _this._cachedSelectedViewConfigClientId;
609
610 var dimensions = {
611 left: 0,
612 top: 0,
613 width: 0,
614 height: 0
615 };
616
617 if (entityConfigClientId) {
618 dimensions.left = parseInt(_this._cachedEntityHeaderViewsByClientId[entityConfigClientId].el.getAttribute("data-left"), 10);
619 dimensions.width = parseInt(_this._cachedEntityHeaderViewsByClientId[entityConfigClientId].el.getAttribute("data-width"), 10);
620 }
621 if (viewConfigClientId) {
622 dimensions.top = parseInt(_this._cachedViewHeaderViewsByClientId[viewConfigClientId].el.getAttribute("data-top"), 10);
623 dimensions.height = parseInt(_this._cachedViewHeaderViewsByClientId[viewConfigClientId].el.getAttribute("data-total-height"), 10);
624 }
625 var desiredPaddingAroundVisInstanceOnScroll = _this.options.desiredPaddingAroundVisInstanceOnScroll;
626 var spacePadding = _this._spacePadding;
627
628 var targetScrollRange = {
629 leftMax: dimensions.left - desiredPaddingAroundVisInstanceOnScroll.left,
630 topMax: dimensions.top - desiredPaddingAroundVisInstanceOnScroll.top - _this._viewHeaderHeight,
631 leftMin: dimensions.left + desiredPaddingAroundVisInstanceOnScroll.right + dimensions.width - _this._$containerOfScrollable[0].clientWidth + spacePadding.left,
632 topMin: dimensions.top + desiredPaddingAroundVisInstanceOnScroll.bottom + dimensions.height - _this._$containerOfScrollable[0].clientHeight + spacePadding.top
633 };
634
635 var currentScroll = {
636 left: (_this._scrollLeftBeforeLatestLayoutUpdate == null ? _this._$containerOfScrollable.scrollLeft() : _this._scrollLeftBeforeLatestLayoutUpdate),
637 top: (_this._scrollTopBeforeLatestLayoutUpdate == null ? _this._$containerOfScrollable.scrollTop() : _this._scrollTopBeforeLatestLayoutUpdate)
638 };
639
640 var targetScrollLeft = currentScroll.left;
641 var targetScrollTop = currentScroll.top;
642
643 if (_this._latestChangeWasAReset) {
644 _this._cachedScrollPosSelection = null;
645 targetScrollLeft = 0;
646 targetScrollTop = 0;
647 }
648
649 var currentGridHash = _this.getEntityWidth() + "~" + _this._cachedEntityConfigClientIds.join("|") + "~" + _this._cachedViewConfigClientIds.join("|");
650 //_this._logger.debug("scrollAccordingToSelection[1]:", _this._cachedScrollPosGridHash === currentGridHash, _this._cachedScrollPosGridHash, currentGridHash);
651 //_this._logger.debug("scrollAccordingToSelection[2]:", _this._cachedScrollPosSelection === "" + entityConfigClientId + viewConfigClientId, _this._cachedScrollPosSelection, "" + entityConfigClientId + viewConfigClientId);
652 if (_this._cachedScrollPosGridHash === currentGridHash
653 && _this._cachedScrollPosSelection === "" + entityConfigClientId + viewConfigClientId) {
654 targetScrollLeft = _this._cachedScrollPosX;
655 targetScrollTop = _this._cachedScrollPosY;
656 _this._cachedScrollPosSelection = "";
657 } else {
658 if (!_this._ignoreXOnNextScroll) {
659 if (targetScrollLeft < targetScrollRange.leftMin) {
660 targetScrollLeft = targetScrollRange.leftMin;
661 }
662 if (targetScrollLeft > targetScrollRange.leftMax) {
663 targetScrollLeft = targetScrollRange.leftMax;
664 }
665 }
666 if (!_this._ignoreYOnNextScroll) {
667 if (targetScrollTop < targetScrollRange.topMin) {
668 targetScrollTop = targetScrollRange.topMin;
669 }
670 if (targetScrollTop > targetScrollRange.topMax) {
671 targetScrollTop = targetScrollRange.topMax;
672 }
673 }
674 if (targetScrollLeft < 0) {
675 targetScrollLeft = 0;
676 }
677 if (targetScrollTop < 0) {
678 targetScrollTop = 0;
679 }
680 }
681
682 var scrollDiffX = targetScrollLeft - currentScroll.left;
683 var scrollDiffY = targetScrollTop - currentScroll.top;
684
685 if (!entityConfigClientId && !viewConfigClientId && !_this._latestChangeWasAReset) {
686 _this._updateCachedScroll();
687 } else if (instant || _this._latestChangeWasAReset) {
688 _this._$containerOfScrollable.stop(true, true);
689 _this._$containerOfScrollable.scrollLeft(targetScrollLeft);
690 _this._$containerOfScrollable.scrollTop (targetScrollTop);
691 _this._updateCachedScroll();
692 _this._reviseSpaceSize();
693 } else {
694 _this._$containerOfScrollable.stop(true, false);
695 if (_this._scrollLeftBeforeLatestLayoutUpdate !== null) {
696 _this._$containerOfScrollable.scrollLeft(_this._scrollLeftBeforeLatestLayoutUpdate);
697 _this._$containerOfScrollable.scrollTop (_this. _scrollTopBeforeLatestLayoutUpdate);
698 }
699 _this._$containerOfScrollable.animate(
700 {"scrollLeft": targetScrollLeft, "scrollTop": targetScrollTop},
701 _this.options.scrollAnimationMinSpeed + Math.min(Math.max(Math.abs(scrollDiffX), Math.abs(scrollDiffY)), _this.options.scrollAnimationBaseDistance) / _this.options.scrollAnimationBaseDistance * _this.options.scrollAnimationBaseSpeed,
702 function() {
703 _this._reviseSpaceSize();
704 });
705 }
706 _this._ignoreXOnNextScroll = false;
707 _this._ignoreYOnNextScroll = false;
708 },
709
710 /**
711 * Returns the positions of the currently selected items
712 * relative to the top-left corner of the top-left view
713 */
714 getPositionsOfSelectedHeaders: function() {
715 var _this = this;
716
717 var result = [];
718
719 var selectedEntityHeaderView = _this._cachedEntityHeaderViewsByClientId[_this._cachedSelectedEntityConfigClientId];
720 var selectedViewHeaderView = _this._cachedViewHeaderViewsByClientId [_this._cachedSelectedViewConfigClientId];
721
722 if (selectedEntityHeaderView) {
723 var $selectedEntityHeader = selectedEntityHeaderView.$el;
724 result.push(parseInt($selectedEntityHeader.css("left"), 10) - _this._$containerOfScrollable.scrollLeft(), parseInt($selectedEntityHeader[0].style.width, 10));
725 } else {
726 result.push(null, null);
727 }
728
729 if (selectedViewHeaderView) {
730 var $selectedViewHeader = selectedViewHeaderView.$el;
731 result.push(parseInt($selectedViewHeader.css("top"), 10) - _this._$containerOfScrollable.scrollTop(), _this._viewHeaderHeight);
732 } else {
733 result.push(null, null);
734 }
735
736 return result;
737 },
738
739 _updateCachedScroll: function() {
740 var _this = this;
741
742 _this._cachedScrollPosGridHash = _this.getEntityWidth() + "~" + _this._cachedEntityConfigClientIds.join("|") + "~" + _this._cachedViewConfigClientIds.join("|");
743 _this._cachedScrollPosSelection = "" + _this._cachedSelectedEntityConfigClientId + _this._cachedSelectedViewConfigClientId;
744 _this._cachedScrollPosX = _this._$containerOfScrollable.scrollLeft();
745 _this._cachedScrollPosY = _this._$containerOfScrollable.scrollTop();
746
747 //_this._logger.debug(_.str.sprintf("ConfigGridCellsView[%s]._updateCachedScroll()", _this.options.configGrid.getType()), _this._cachedScrollPosGridHash, _this._cachedScrollPosSelection, _this._cachedScrollPosX, _this._cachedScrollPosY);
748 },
749
750 _toggleFixedHeadersIfNeeded: function(trueOrFalse) {
751 //trueOrFalse = true;
752 var _this = this;
753 if (_this.options.enableFixedHeaders && trueOrFalse == true) {
754 //_this._logger.debug("_toggleFixedHeadersIfNeeded(true)");
755 if (!_this._$containerOfFixed[0].childNodes.length) {
756 _this._$containerOfFixed.append(_this._$visInstancesContainer, _this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind);
757 //_this._$containerOfFixed.append(_this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind);
758 _this._$cornerBlind.css({"transform": "translate(0px, 0px)"});
759 _this._$containerOfFixed.show();
760 }
761 } else {
762 //_this._logger.debug("_toggleFixedHeadersIfNeeded(false)");
763 _this._$containerOfFixed.hide();
764 _this._$space.append(_this._$visInstancesContainer, _this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind);
765 //_this._$space.append(_this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind);
766 _this._$entityHeadersBlind.css({"transform": "translate(0px, 0px)"});
767 _this._$visInstancesContainer.css({"transform": "translate(0px, 0px)"});
768
769 }
770 _this._adjustToScrollPos();
771 },
772
773 _adjustToScrollPos: function() {
774 var _this = this;
775 if (_this._scrollLeftBeforeLatestLayoutUpdate !== null) {
776 _this._scrollLeftBeforeLatestLayoutUpdate = null;
777 _this._scrollTopBeforeLatestLayoutUpdate = null;
778 }
779
780 var scrollLeft = _this._$containerOfScrollable.scrollLeft();
781 var scrollTop = _this._$containerOfScrollable.scrollTop();
782 if (_this._$containerOfFixed[0].childNodes.length) {
783 _this._$entityHeadersContainer.css({"transform": "translate(" + (-scrollLeft) + "px, 0px)"});
784 _this._$entityHeadersBlind.css({"transform": "translate(" + scrollLeft + "px, 0px)"});
785 _this._$visInstancesContainer.css({"transform": "translate(" + (-scrollLeft) + "px, " + (-scrollTop) + "px)"});
786 _this._$viewHeadersContainer.css({"transform": "translate(0px, " + (-scrollTop) + "px)"});
787 } else {
788 _this._$entityHeadersContainer.css({"transform": "translate(0, " + scrollTop + "px)"});
789 _this._$viewHeadersContainer.css({"transform": "translate(" + scrollLeft + "px, 0)"});
790 _this._$cornerBlind.css({"transform": "translate(" + scrollLeft + "px, " + scrollTop + "px)"});
791 }
792
793 _this._reportPositionsOfSelectedHeaders();
794 },
795
796 _reportPositionsOfSelectedHeaders: function() {
797 var _this = this;
798
799 var positionsOfSelectedHeaders = _this.getPositionsOfSelectedHeaders();
800 _this.trigger("change-positions-of-selected-headers", positionsOfSelectedHeaders[0], positionsOfSelectedHeaders[1], positionsOfSelectedHeaders[2], positionsOfSelectedHeaders[3]);
801 },
802
803
804 _reviseSpaceSize: function(increaseOnly) {
805 var _this = this;
806
807 var elInnerWidth = _this._$containerOfScrollable[0].clientWidth;
808 var elInnerHeight = _this._$containerOfScrollable[0].clientHeight;
809 var elScrollLeft = _this._$containerOfScrollable.scrollLeft();
810 var elScrollTop = _this._$containerOfScrollable.scrollTop();
811 var spaceWidth = _this._cachedMinSpaceWidth;
812 var spaceHeight = _this._cachedMinSpaceHeight;
813
814 var missingWidth = elScrollLeft + elInnerWidth - _this._spacePadding.h - spaceWidth;
815 var missingHeight = elScrollTop + elInnerHeight - _this._spacePadding.v - spaceHeight;
816
817 spaceWidth += Math.max(0, missingWidth);
818 spaceHeight += Math.max(0, missingHeight);
819
820 if (!increaseOnly || (spaceWidth >= _this._$space.width() && spaceHeight >= _this._$space.height())) {
821 _this._$space.css({
822 "width": spaceWidth,
823 "height": spaceHeight
824 });
825 _this._$viewHeadersBlind.height(spaceHeight);
826 }
827 },
828
829 _updateDemensionsForContainerOfFixed: function() {
830 var _this = this;
831 _this._$containerOfFixed.width(_this._$containerOfScrollable[0].clientWidth);
832 _this._$containerOfFixed.height(_this._$containerOfScrollable[0].clientHeight);
833 },
834
835 _generateEntityHeaderView: function(entityConfig) {
836 var _this = this;
837
838 var $el = $.bem.generateElement("config-grid-cells", "entity-header");
839
840 var result = new App.MainRegionModule.ConfigHeaderView({
841 dimension: "entity",
842 el: $el,
843 state: _this.options.state,
844 configGrid: _this.options.configGrid,
845 config: entityConfig,
846 parentConfigGridView: _this.options.parentConfigGridView
847 });
848
849 result.$el.dblclick(function() {
850 if (entityConfig.getParameterValue("kind")) {
851 return;
852 }
853 if (_this.options.configGrid.getSelectedEntityConfig() == entityConfig) {
854 _this.options.configGrid.addEntityAndSelectIt(new App.ContextModule.Config({
855 parameters: {
856 "kind": "pair",
857 "comparisonMode": "superposition"
858 }
859 }), _this.options.configGrid.getNextEntityNeighbour(entityConfig)) ;
860 }
861 });
862
863 return result;
864 },
865
866 _generateViewHeaderView: function(viewConfig) {
867 var _this = this;
868
869 var $el = $.bem.generateElement("config-grid-cells", "view-header");
870
871 var result = new App.MainRegionModule.ConfigHeaderView({
872 dimension: "view",
873 el: $el,
874 state: _this.options.state,
875 configGrid: _this.options.configGrid,
876 config: viewConfig,
877 parentConfigGridView: _this.options.parentConfigGridView
878 });
879
880 return result;
881 },
882
883 _generateVisInstanceView: function(entityConfig, viewConfig) {
884 var _this = this;
885
886 var $el = $.bem.generateElement("config-grid-cells", "vis-instance").addClass("vis-instance");
887
888 var result = new App.MainRegionModule.VisInstanceView({
889 el: $el,
890 state: _this.options.state,
891 configGrid: _this.options.configGrid,
892 entityConfig: entityConfig,
893 viewConfig: viewConfig,
894 parentConfigGridView: _this.options.parentConfigGridView
895 });
896
897 return result;
898 }
899 });
900 }, Logger);