Mercurial > hg > dml-open-vis
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DML/MainVisBundle/Resources/assets/marionette/modules/MainRegionModule/MainRegionModule.20-ConfigGridCellsView.js Tue Feb 09 20:54:02 2016 +0100 @@ -0,0 +1,900 @@ +"use strict"; + +App.module("MainRegionModule", function (MainRegionModule, App, Backbone, Marionette, $, _, Logger) { + + MainRegionModule.ConfigGridCellsView = MainRegionModule.ConfigGridChildView.extend({ + + options: { + state: null, + configGrid: null, + parentConfigGridView: null, + scrollAnimationMinSpeed: 100, + scrollAnimationBaseSpeed: 400, + scrollAnimationBaseDistance: 500, + desiredPaddingAroundVisInstanceOnScroll: { + left: 35, + top: 20, + right: 35, + bottom: 33, + }, + enableFixedHeaders: true, // headers become fixed when scrolling + }, + + _logger: null, + + _$entityHeadersContainer: null, + _$entityHeadersBlind: null, + _$viewHeadersContainer: null, + _$viewHeadersBlind: null, + _$visInstancesContainer: null, + _$cornerBlind: null, + _$fixedContainer: null, + + _$entityAdder: null, + _$viewAdder: null, + + _distanceBetweenEntities: 10, + _distanceBetweenViews: 10, + _viewHeaderHeight: 0, + _entityAdderWidth: 0, + _viewAdderHeight: 0, + _cachedMinSpaceWidth: 0, + _cachedMinSpaceHeight: 0, + _spacePadding: null, // top, right, bottom, left, h = l + r, v = t + b + _scrollLeftBeforeLatestSelectionUpdate: 0, + _scrollTopBeforeLatestSelectionUpdate: 0, + + _ignoreXOnNextScroll: false, + _ignoreYOnNextScroll: false, + _latestChangeWasAReset: false, + + _cachedScrollPosGridHash: null, + _cachedScrollPosSelection: null, + _cachedScrollPosX: null, + _cachedScrollPosY: null, + + _cachedSelectedEntityConfigClientId: null, // string + _cachedSelectedViewConfigClientId: null, // string + + _cachedEntityHeaderViewsByClientId: {}, // string: Backbone view + _cachedViewHeaderViewsByClientId: {}, // string: Backbone view + _cachedVisInstanceViewsByClientIdPair: {}, // string: Backbone view + + _cachedEntityConfigClientIds: null, // [string] (keys of _cachedEntityHeaderViewsByClientId) + _cachedViewConfigClientIds: null, // [string] (keys of _cachedViewHeaderViewsByClientId) + + _cachedEntityWidth: null, + _cachedViewContentHeights: null, + + initialize: function(options) { + var _this = this; + + _this._logger = Logger.get("ConfigGridCellsView"); + //_this._logger.setLevel(Logger.DEBUG); + + _this.options = _.defaults(options || {}, this.options); + if (_this.options.enableFixedHeaders === null) { + _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; + } + + var configGridType = _this.options.configGrid.getType(); + + _this.$el.empty(); + + _this._$entityHeadersContainer = $.bem.generateElement("config-grid-cells", "entity-headers-container"); + _this._$entityHeadersBlind = $.bem.generateElement("config-grid-cells", "entity-headers-blind"); + _this._$entityHeadersContainer.append(_this._$entityHeadersBlind); + + _this._$viewHeadersContainer = $.bem.generateElement("config-grid-cells", "view-headers-container"); + _this._$viewHeadersBlind = $.bem.generateElement("config-grid-cells", "view-headers-blind"); + _this._$viewAdder = $.bem.generateElement("config-grid-cells", "view-header", ["kind_adder"]); + _this._$viewHeadersContainer.append(_this._$viewHeadersBlind, _this._$viewAdder); + + _this._$visInstancesContainer = $.bem.generateElement("config-grid-cells", "vis-instances-container"); + + _this._$cornerBlind = $.bem.generateElement("config-grid-cells", "corner-blind"); + + _this._$space = $.bem.generateElement("config-grid-cells", "space"); + + _this._$containerOfScrollable = $.bem.generateElement("config-grid-cells", "container", ["position_scrollable"]); + _this._$containerOfFixed = $.bem.generateElement("config-grid-cells", "container", ["position_fixed"]); + + // Entity and collection adders + if (configGridType == "collection") { + _this._$entityAdder = $.bem.generateElement("config-grid-cells", "entity-header", ["kind_adder"]); + var $entityAdderBackground = $.bem.generateElement("config-grid-cells", "entity-header-background"); + var $entityAdderLabel = $.bem.generateElement("config-grid-cells", "entity-header-label"); + $entityAdderLabel.html(Backbone.Marionette.TemplateCache.get("#config-grid_collection__entity-adder-label")); + _this._$entityAdder.append($entityAdderBackground, $entityAdderLabel); + _this._$entityHeadersContainer.append(_this._$entityAdder); + _this._$entityAdder.click(function() { + _this.options.configGrid.addEntityAndSelectIt(new App.ContextModule.Config()); + }); + } else { + _this._$entityAdder = $(); + } + _this._$viewAdder = $.bem.generateElement("config-grid-cells", "view-header", ["kind_adder"]); + var $viewAdderBackground = $.bem.generateElement("config-grid-cells", "view-header-background"); + var $viewAdderLabel = $.bem.generateElement("config-grid-cells", "view-header-label"); + $viewAdderLabel.html(Backbone.Marionette.TemplateCache.get("#config-grid__view-adder-label")); + _this._$viewAdder.append($viewAdderBackground, $viewAdderLabel); + _this._$viewHeadersContainer.append(_this._$viewAdder); + _this._$viewAdder.click(function() { + _this.options.configGrid.addViewAndSelectIt(new App.ContextModule.Config()); + }); + + _this._$entityHeadersContainer.append(); + _this._$viewHeadersContainer.append(); + _this._$space.append( + _this._$visInstancesContainer, + _this._$entityHeadersContainer, + _this._$viewHeadersContainer, + _this._$cornerBlind + ); + + _this._$containerOfScrollable.append(_this._$space); + _this.$el.append(_this._$containerOfScrollable, _this._$containerOfFixed); + + // extract some size- and position-related constants + _this._viewHeaderHeight = _this._$viewAdder.height(); + _this._entityAdderWidth = _this._$entityAdder.width(); + _this._viewAdderHeight = _this._viewHeaderHeight; + if (!_this._entityAdderWidth) { + _this._entityAdderWidth = -_this._distanceBetweenEntities; + } + + // When defining space padding, it is sometimes necessary to wait a bit + // A grid that is on the "back side of the card" may sometimes become blank when scrolling otherwise + _this._spacePadding = {}; + var interval; + var setSpaceInterval = function() { + if (_this._$space.css("padding-top")) { + _this._spacePadding.top = parseInt(_this._$space.css("padding-top"), 10); + _this._spacePadding.right = parseInt(_this._$space.css("padding-right"), 10); + _this._spacePadding.bottom = parseInt(_this._$space.css("padding-bottom"), 10); + _this._spacePadding.left = parseInt(_this._$space.css("padding-left"), 10); + _this._spacePadding.h = _this._spacePadding.left + _this._spacePadding.right; + _this._spacePadding.v = _this._spacePadding.top + _this._spacePadding.bottom; + //_this._toggleFixedHeadersIfNeeded(false); + _this._updateDemensionsForContainerOfFixed(); + clearInterval(interval); + } + }; + if (_this._$space.css("padding-top")) { + setSpaceInterval(); + } else { + interval = setInterval(setSpaceInterval, 50); + } + + // subscribe to events + _this.listenTo(_this.options.configGrid, "change", _this.renderIfParentConfigGridIsVisible); + + var isSafari = navigator.userAgent.indexOf("afari") >= 0; + var isChrome = navigator.userAgent.indexOf("rome") >= 0; + var isScrolling = false; + if (_this.options.enableFixedHeaders) { + _this._$containerOfScrollable.mousewheel(_.debounce(function(event) { + _this._toggleFixedHeadersIfNeeded(true); + + var visInstanceViews = _.values(_this._cachedVisInstanceViewsByClientIdPair); + for (var i = visInstanceViews.length - 1; i >= 0; --i) { + visInstanceViews[i].cancelPointerHighlights(); + } + + App.TooltipModule.update(); + if (isSafari || isChrome) { + _this._$containerOfScrollable.scrollLeft(_this._$containerOfScrollable.scrollLeft() + event.deltaX); + _this._$containerOfScrollable.scrollTop (_this._$containerOfScrollable.scrollTop() - event.deltaY); + event.preventDefault(); + } + }, 50, true)); + _this._$containerOfScrollable.mousewheel(_.debounce(function(event) { + if (!isScrolling) { + _this._toggleFixedHeadersIfNeeded(false); + } + }, 200)); + } + + _this._$containerOfScrollable.scroll(function(event) { + if (!isScrolling) { + isScrolling = true; + } + _this._toggleFixedHeadersIfNeeded(true); + }); + + _this._$containerOfScrollable.scroll(_.debounce(function(event) { + _this._toggleFixedHeadersIfNeeded(false); + _this._reviseSpaceSize(); + isScrolling = false; + _this._updateCachedScroll(); + }, 200)); + + $(window).resize(_.throttle(function() { + _this._reviseSpaceSize(); + _this._updateDemensionsForContainerOfFixed(); + }, 100)); + _this._toggleFixedHeadersIfNeeded(false); + _this._updateDemensionsForContainerOfFixed(); + + // Restore and save precise scroll position of the currently selected entity and view + _this._cachedScrollPosGridHash = App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-grid-hash_%s", configGridType)); + _this._cachedScrollPosSelection = App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-selection_%s", configGridType)); + _this._cachedScrollPosX = 1 * App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-x_%s", configGridType)); + _this._cachedScrollPosY = 1 * App.DataModule.Storage.getStrCache(MainRegionModule, _.str.sprintf("scroll-pos-y_%s", configGridType)); + + $(window).unload(function() { + App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-grid-hash_%s", configGridType), _this._cachedScrollPosGridHash); + App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-selection_%s", configGridType), _this._cachedScrollPosSelection); + App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-x_%s", configGridType), "" + _this._cachedScrollPosX); + App.DataModule.Storage.setStrCache(MainRegionModule, _.str.sprintf("scroll-pos-y_%s", configGridType), "" + _this._cachedScrollPosY); + }); + + }, + + render: function (deep, instant) { + var _this = this; + + _this._updateLayout(deep, instant); + _this._updateSelection(deep, instant); + if (deep) { + _this._reviseSpaceSize(); + _this._updateDemensionsForContainerOfFixed(); + } + _this._adjustToScrollPos(deep, instant); + _this.scrollAccordingToSelection(deep, instant); + + if (deep) { + var entityHeaderViews = _.values(_this._cachedEntityHeaderViewsByClientId); + for (var i = entityHeaderViews.length - 1; i >= 0; --i) { + entityHeaderViews[i].render(deep, instant); + } + + var viewHeaderViews = _.values(_this._cachedViewHeaderViewsByClientId); + for (var i = viewHeaderViews.length - 1; i >= 0; --i) { + viewHeaderViews[i].render(deep, instant); + } + + var visInstanceViews = _.values(_this._cachedVisInstanceViewsByClientIdPair); + for (var i = visInstanceViews.length - 1; i >= 0; --i) { + visInstanceViews[i].render(deep, instant); + } + }; + }, + + getEntityWidth: function() { + var _this = this; + return (_this.options.configGrid.get("entityWidth") || App.options.defaultEntityWidth) * 1; + }, + + _updateLayout: function(deep, instant) { + var _this = this; + + // Check if entities of views have changed + var entityListHasChanged = false; + var viewListHasChanged = false; + var newEntityConfigs = _this.options.configGrid.get("entityConfigs"); + var newViewConfigs = _this.options.configGrid.get("viewConfigs"); + var newEntityConfigClientIds = _.pluck(newEntityConfigs.models, "cid"); + var newViewConfigClientIds = _.pluck(newViewConfigs.models, "cid"); + + _this._scrollLeftBeforeLatestLayoutUpdate = _this.$el.scrollLeft(); + _this._scrollTopBeforeLatestLayoutUpdate = _this.$el.scrollTop(); + + if (_this._cachedEntityConfigClientIds === null) { + entityListHasChanged = true; + viewListHasChanged = true; + _this._cachedEntityConfigClientIds = []; + _this._cachedViewConfigClientIds = []; + } + + var createdEntityConfigClientIds = _.difference(newEntityConfigClientIds, _this._cachedEntityConfigClientIds); + var createdViewConfigClientIds = _.difference(newViewConfigClientIds, _this._cachedViewConfigClientIds); + var removedEntityConfigClientIds = _.difference(_this._cachedEntityConfigClientIds, newEntityConfigClientIds); + var removedViewConfigClientIds = _.difference(_this._cachedViewConfigClientIds, newViewConfigClientIds); + + _this._latestChangeWasAReset = false; + + if (createdEntityConfigClientIds.length + removedEntityConfigClientIds.length == 1) { + _this._ignoreYOnNextScroll = true; + } + if (createdViewConfigClientIds.length + removedViewConfigClientIds.length == 1) { + _this._ignoreXOnNextScroll = true; + } + + if (!_.isEqual(newEntityConfigClientIds, _this._cachedEntityConfigClientIds)) { + entityListHasChanged = true; + } + if (!_.isEqual(newViewConfigClientIds, _this._cachedViewConfigClientIds)) { + viewListHasChanged = true; + } + + if ((entityListHasChanged && createdEntityConfigClientIds.length + removedEntityConfigClientIds.length > 1) + || (viewListHasChanged && createdViewConfigClientIds.length + removedViewConfigClientIds.length > 1)) { + _this._latestChangeWasAReset = true; + _this._ignoreXOnNextScroll = false; + _this._ignoreYOnNextScroll = false; + } + + + var newEntityHeaderViewsByClientId = _this._cachedEntityHeaderViewsByClientId; + var newViewHeaderViewsByClientId = _this._cachedViewHeaderViewsByClientId; + var newVisInstanceViewsByClientIdPair = _this._cachedVisInstanceViewsByClientIdPair; + var viewHeaderViewsToRender = []; + var entityHeaderViewsToRender = []; + var visInstanceViewsToRender = []; + + // Replacement of entity headers if needed + if (entityListHasChanged) { + newEntityHeaderViewsByClientId = {}; + for (var i = 0; i < newEntityConfigClientIds.length; i++) { + var currentEntityClientId = newEntityConfigClientIds[i]; + + // Look for an existing entity header view + var entityHeaderView = _this._cachedEntityHeaderViewsByClientId[currentEntityClientId]; + + // Create a new entity header if it does not exist + if (!entityHeaderView) { + _this._logger.debug("generate entity header ", currentEntityClientId); + entityHeaderView = _this._generateEntityHeaderView(newEntityConfigs.get(currentEntityClientId)); + entityHeaderViewsToRender.push(entityHeaderView); + _this._$entityHeadersContainer.append(entityHeaderView.el); + } + newEntityHeaderViewsByClientId[currentEntityClientId] = entityHeaderView; + } + + // Remove entity header views that are no longer needed + // The order of the views does not matter as the right layout is achieved with absolute positioning + for (var i = removedEntityConfigClientIds.length - 1; i >= 0; --i) { + _this._cachedEntityHeaderViewsByClientId[removedEntityConfigClientIds[i]].remove(); + App.dynamicDerivedConfigDataProvider.retire(removedEntityConfigClientIds[i]); + } + } else { + newEntityHeaderViewsByClientId = _this._cachedEntityHeaderViewsByClientId; + } + + // Replacement of view headers if needed + if (viewListHasChanged) { + newViewHeaderViewsByClientId = {}; + for (var i = 0; i < newViewConfigClientIds.length; i++) { + var currentViewClientId = newViewConfigClientIds[i]; + + // Look for an existing entity header + var viewHeaderView = _this._cachedViewHeaderViewsByClientId[currentViewClientId]; + + // Create a new view header if it does not exist + if (!viewHeaderView) { + _this._logger.debug("generate view header ", currentViewClientId); + viewHeaderView = _this._generateViewHeaderView(newViewConfigs.get(currentViewClientId)); + viewHeaderViewsToRender.push(viewHeaderView); + _this._$viewHeadersContainer.append(viewHeaderView.el); + } + newViewHeaderViewsByClientId[currentViewClientId] = viewHeaderView; + } + + // Remove entity header views that are no longer needed + // The order of the views does not matter as the right layout is achieved with absolute positioning + for (var i = removedViewConfigClientIds.length - 1; i >= 0; --i) { + _this._cachedViewHeaderViewsByClientId[removedViewConfigClientIds[i]].remove(); + App.dynamicDerivedConfigDataProvider.retire(removedViewConfigClientIds[i]); + } + } else { + newViewHeaderViewsByClientId = _this._cachedViewHeaderViewsByClientId; + } + + // Replacement of vis instances + if (viewListHasChanged || entityListHasChanged) { + newVisInstanceViewsByClientIdPair = {}; + for (var i = 0; i < newEntityConfigClientIds.length; i++) { + var currentEntityClientId = newEntityConfigClientIds[i]; + + for (var j = 0; j < newViewConfigClientIds.length; j++) { + var currentViewClientId = newViewConfigClientIds[j]; + var currentClientIdPair = currentEntityClientId + currentViewClientId; + + // Look for an existing vis instance view + var visInstanceView = _this._cachedVisInstanceViewsByClientIdPair[currentClientIdPair]; + + // Create a new vis instance view if it does not exist + if (!visInstanceView) { + _this._logger.debug("generate vis instance", currentEntityClientId, currentViewClientId); + visInstanceView = _this._generateVisInstanceView(newEntityConfigs.get(currentEntityClientId), newViewConfigs.get(currentViewClientId)); + visInstanceViewsToRender.push(visInstanceView); + _this._$visInstancesContainer.append(visInstanceView.el); + } + newVisInstanceViewsByClientIdPair[currentClientIdPair] = visInstanceView; + } + } + + // Add new vis instances and remove those that are no longer needed + // The order does not matter as the right layout is achieved with absolute positioning + for (var i = this._cachedEntityConfigClientIds.length - 1; i >= 0; --i) { + for (var j = removedViewConfigClientIds.length - 1; j >= 0; --j) { + var visInstanceToRemove = _this._cachedVisInstanceViewsByClientIdPair[this._cachedEntityConfigClientIds[i] + removedViewConfigClientIds[j]]; + visInstanceToRemove.remove(); + } + } + for (var i = removedEntityConfigClientIds.length - 1; i >= 0; --i) { + for (var j = this._cachedViewConfigClientIds.length - 1; j >= 0; --j) { + var visInstanceToRemove = _this._cachedVisInstanceViewsByClientIdPair[removedEntityConfigClientIds[i] + this._cachedViewConfigClientIds[j]]; + if (visInstanceToRemove) { + visInstanceToRemove.remove(); + } + } + } + } + + // view heights + var viewHeightsHaveChanged = false; + var entityWidthHasChanged = false; + + var entityWidth = _this.getEntityWidth(); + var viewContentHeights = []; + for (var row = 0; row < newViewConfigClientIds.length; row++) { + var currentViewConfigClientId = newViewConfigClientIds[row]; + var viewConfig = newViewConfigs.get(currentViewConfigClientId); + var viewContentHeight = App.RepresentationModule.getMasterForConfig(viewConfig).calculateVisInstanceContentHeight(viewConfig, entityWidth); + viewContentHeights.push(viewContentHeight); + } + + if (entityWidth !== _this._cachedEntityWidth) { + entityWidthHasChanged = true; + _this._cachedEntityWidth = entityWidth; + } + if (!_.isEqual(viewContentHeights, _this._cachedViewContentHeights)) { + viewHeightsHaveChanged = true; + _this._cachedViewContentHeights = viewContentHeights; + } + + // Set up positions and sizes for entities and views + if (viewListHasChanged || entityListHasChanged || entityWidthHasChanged || viewHeightsHaveChanged) { + var newEntityDimensions = []; //entityId, x, width + var newViewDimensions = []; //viewId, y, height + var x = 0; + var configGridType = _this.options.configGrid.getType(); + for (var col = 0; col < newEntityConfigClientIds.length; col++) { + var currentEntityConfigClientId = newEntityConfigClientIds[col]; + newEntityDimensions.push([currentEntityConfigClientId, x, entityWidth]); + x += entityWidth + _this._distanceBetweenEntities; + } + var y = 0; + var viewHeaderHeight = _this._viewHeaderHeight; + for (var row = 0; row < newViewConfigClientIds.length; row++) { + var currentViewConfigClientId = newViewConfigClientIds[row]; + newViewDimensions.push([currentViewConfigClientId, y, _this._cachedViewContentHeights[row]]); + y += viewHeaderHeight + _this._cachedViewContentHeights[row] + _this._distanceBetweenViews; + } + + // Reposition and resize view headers + for (var row = newViewDimensions.length - 1; row >= 0; --row) { + var currentViewDimensions = newViewDimensions[row]; + var viewHeaderView = newViewHeaderViewsByClientId[currentViewDimensions[0]]; + viewHeaderView.$el.css("top", currentViewDimensions[1]) + .attr("data-top", currentViewDimensions[1]) + .attr("data-total-height", currentViewDimensions[2] + _this._viewHeaderHeight); + viewHeaderView.setSize(currentViewDimensions[2]); + } + for (var col = newEntityDimensions.length - 1; col >= 0; --col) { + var currentEntityDimensions = newEntityDimensions[col]; + + // Reposition and resize entity headers + var entityHeaderView = newEntityHeaderViewsByClientId[currentEntityDimensions[0]]; + entityHeaderView.$el.css("left", currentEntityDimensions[1]) + .attr("data-left", currentEntityDimensions[1]) + .attr("data-width", currentEntityDimensions[2]); + entityHeaderView.setSize(currentEntityDimensions[2]); + + for (var row = newViewDimensions.length - 1; row >= 0; --row) { + var currentViewDimensions = newViewDimensions[row]; + + // Reposition and resize vis instances + var visInstanceView = newVisInstanceViewsByClientIdPair[currentEntityDimensions[0] + currentViewDimensions[0]]; + visInstanceView.$el.css({ + "left": currentEntityDimensions[1], + "top": currentViewDimensions[1] + viewHeaderHeight + }); + visInstanceView.setSize(currentEntityDimensions[2], currentViewDimensions[2]); + } + } + + // Reposition entity and view adders + var needToResizeSpace = false; + if (x != _this._$entityAdder.css("left")) { + _this._$entityAdder.css("left", x); + needToResizeSpace = true; + } + if (y != _this._$viewAdder.css("top")) { + _this._$viewAdder.css("top", y); + needToResizeSpace = true; + } + + // Resize the space + if (needToResizeSpace) { + _this._cachedMinSpaceWidth = x + _this._entityAdderWidth; + _this._cachedMinSpaceHeight = y + _this._viewAdderHeight; + _this._reviseSpaceSize(!_this._latestChangeWasAReset); + } + } + + // Update cached view data + if (entityListHasChanged) { + _this._cachedEntityHeaderViewsByClientId = newEntityHeaderViewsByClientId; + _this._cachedEntityConfigClientIds = newEntityConfigClientIds; + } + if (viewListHasChanged) { + _this._cachedViewHeaderViewsByClientId = newViewHeaderViewsByClientId; + _this._cachedViewConfigClientIds = newViewConfigClientIds; + } + if (viewListHasChanged || entityListHasChanged) { + _this._cachedVisInstanceViewsByClientIdPair = newVisInstanceViewsByClientIdPair; + } + + // Render new vis instances and those that have changed their dimensions + // If deep rendering takes place, all view instances will be rendered later + + if (!deep && entityHeaderViewsToRender) { + for (var i = entityHeaderViewsToRender.length - 1; i >= 0; --i) { + entityHeaderViewsToRender[i].render(); + } + } + if (!deep && viewHeaderViewsToRender) { + for (var i = viewHeaderViewsToRender.length - 1; i >= 0; --i) { + viewHeaderViewsToRender[i].render(); + } + } + if (!deep && visInstanceViewsToRender) { + for (var i = visInstanceViewsToRender.length - 1; i >= 0; --i) { + visInstanceViewsToRender[i].render(); + } + } + + // Destroy detached vis instances + if (viewListHasChanged || entityListHasChanged) { + var destroyedVisInstanceViews = _.difference(_.values(this._cachedVisInstanceViewsByClientIdPair), _.values(newVisInstanceViewsByClientIdPair)); + for (var i = destroyedVisInstanceViews.length - 1; i >= 0; --i) { + destroyedVisInstanceViews[i].remove(); + } + } + }, + + _updateSelection: function(deep, instant) { + var _this = this; + + var selectedEntityConfig = _this.options.configGrid.getSelectedEntityConfig(); + var selectedViewConfig = _this.options.configGrid.getSelectedViewConfig(); + var selectedEntityConfigClientId = selectedEntityConfig ? selectedEntityConfig.getClientId() : null; + var selectedViewConfigClientId = selectedViewConfig ? selectedViewConfig.getClientId() : null; + + if (_this._cachedSelectedEntityConfigClientId !== selectedEntityConfigClientId) { + _this._cachedSelectedEntityConfigClientId = selectedEntityConfigClientId; + } + if (_this._cachedSelectedViewConfigClientId !== selectedViewConfigClientId) { + _this._cachedSelectedViewConfigClientId = selectedViewConfigClientId; + } +// +// // entity headers +// var selectionChanged = false; +// selectionChanged = true; +// if (_this._cachedSelectedEntityConfigClientId) { +// $(_this._cachedEntityHeaderViewsByClientId[_this._cachedSelectedEntityConfigClientId]) +// .toggleSelected(false); +// } +// if (newSelectedEntityConfigClientId) { +// $(_this._cachedEntityHeaderViewsByClientId[newSelectedEntityConfigClientId]) +// .toggleSelected(true); +// } +// _this._cachedSelectedEntityConfigClientId = newSelectedEntityConfigClientId; +// }; +// +// // view headers +// if (_this._cachedSelectedViewConfigClientId !== newSelectedViewConfigClientId) { +// selectionChanged = true; +// if (_this._cachedSelectedViewConfigClientId) { +// $(_this._cachedViewHeaderViewsByClientId[_this._cachedSelectedViewConfigClientId]) +// .toggleSelected(false); +// } +// if (newSelectedViewConfigClientId) { +// $(_this._cachedViewHeaderViewsByClientId[newSelectedViewConfigClientId]) +// .toggleSelected(true); +// } +// _this._cachedSelectedViewConfigClientId = newSelectedViewConfigClientId; +// }; + }, + + scrollAccordingToSelection: function(deep, instant) { + var _this = this; + + return; + var entityConfigClientId = _this._cachedSelectedEntityConfigClientId; + var viewConfigClientId = _this._cachedSelectedViewConfigClientId; + + var dimensions = { + left: 0, + top: 0, + width: 0, + height: 0 + }; + + if (entityConfigClientId) { + dimensions.left = parseInt(_this._cachedEntityHeaderViewsByClientId[entityConfigClientId].el.getAttribute("data-left"), 10); + dimensions.width = parseInt(_this._cachedEntityHeaderViewsByClientId[entityConfigClientId].el.getAttribute("data-width"), 10); + } + if (viewConfigClientId) { + dimensions.top = parseInt(_this._cachedViewHeaderViewsByClientId[viewConfigClientId].el.getAttribute("data-top"), 10); + dimensions.height = parseInt(_this._cachedViewHeaderViewsByClientId[viewConfigClientId].el.getAttribute("data-total-height"), 10); + } + var desiredPaddingAroundVisInstanceOnScroll = _this.options.desiredPaddingAroundVisInstanceOnScroll; + var spacePadding = _this._spacePadding; + + var targetScrollRange = { + leftMax: dimensions.left - desiredPaddingAroundVisInstanceOnScroll.left, + topMax: dimensions.top - desiredPaddingAroundVisInstanceOnScroll.top - _this._viewHeaderHeight, + leftMin: dimensions.left + desiredPaddingAroundVisInstanceOnScroll.right + dimensions.width - _this._$containerOfScrollable[0].clientWidth + spacePadding.left, + topMin: dimensions.top + desiredPaddingAroundVisInstanceOnScroll.bottom + dimensions.height - _this._$containerOfScrollable[0].clientHeight + spacePadding.top + }; + + var currentScroll = { + left: (_this._scrollLeftBeforeLatestLayoutUpdate == null ? _this._$containerOfScrollable.scrollLeft() : _this._scrollLeftBeforeLatestLayoutUpdate), + top: (_this._scrollTopBeforeLatestLayoutUpdate == null ? _this._$containerOfScrollable.scrollTop() : _this._scrollTopBeforeLatestLayoutUpdate) + }; + + var targetScrollLeft = currentScroll.left; + var targetScrollTop = currentScroll.top; + + if (_this._latestChangeWasAReset) { + _this._cachedScrollPosSelection = null; + targetScrollLeft = 0; + targetScrollTop = 0; + } + + var currentGridHash = _this.getEntityWidth() + "~" + _this._cachedEntityConfigClientIds.join("|") + "~" + _this._cachedViewConfigClientIds.join("|"); + //_this._logger.debug("scrollAccordingToSelection[1]:", _this._cachedScrollPosGridHash === currentGridHash, _this._cachedScrollPosGridHash, currentGridHash); + //_this._logger.debug("scrollAccordingToSelection[2]:", _this._cachedScrollPosSelection === "" + entityConfigClientId + viewConfigClientId, _this._cachedScrollPosSelection, "" + entityConfigClientId + viewConfigClientId); + if (_this._cachedScrollPosGridHash === currentGridHash + && _this._cachedScrollPosSelection === "" + entityConfigClientId + viewConfigClientId) { + targetScrollLeft = _this._cachedScrollPosX; + targetScrollTop = _this._cachedScrollPosY; + _this._cachedScrollPosSelection = ""; + } else { + if (!_this._ignoreXOnNextScroll) { + if (targetScrollLeft < targetScrollRange.leftMin) { + targetScrollLeft = targetScrollRange.leftMin; + } + if (targetScrollLeft > targetScrollRange.leftMax) { + targetScrollLeft = targetScrollRange.leftMax; + } + } + if (!_this._ignoreYOnNextScroll) { + if (targetScrollTop < targetScrollRange.topMin) { + targetScrollTop = targetScrollRange.topMin; + } + if (targetScrollTop > targetScrollRange.topMax) { + targetScrollTop = targetScrollRange.topMax; + } + } + if (targetScrollLeft < 0) { + targetScrollLeft = 0; + } + if (targetScrollTop < 0) { + targetScrollTop = 0; + } + } + + var scrollDiffX = targetScrollLeft - currentScroll.left; + var scrollDiffY = targetScrollTop - currentScroll.top; + + if (!entityConfigClientId && !viewConfigClientId && !_this._latestChangeWasAReset) { + _this._updateCachedScroll(); + } else if (instant || _this._latestChangeWasAReset) { + _this._$containerOfScrollable.stop(true, true); + _this._$containerOfScrollable.scrollLeft(targetScrollLeft); + _this._$containerOfScrollable.scrollTop (targetScrollTop); + _this._updateCachedScroll(); + _this._reviseSpaceSize(); + } else { + _this._$containerOfScrollable.stop(true, false); + if (_this._scrollLeftBeforeLatestLayoutUpdate !== null) { + _this._$containerOfScrollable.scrollLeft(_this._scrollLeftBeforeLatestLayoutUpdate); + _this._$containerOfScrollable.scrollTop (_this. _scrollTopBeforeLatestLayoutUpdate); + } + _this._$containerOfScrollable.animate( + {"scrollLeft": targetScrollLeft, "scrollTop": targetScrollTop}, + _this.options.scrollAnimationMinSpeed + Math.min(Math.max(Math.abs(scrollDiffX), Math.abs(scrollDiffY)), _this.options.scrollAnimationBaseDistance) / _this.options.scrollAnimationBaseDistance * _this.options.scrollAnimationBaseSpeed, + function() { + _this._reviseSpaceSize(); + }); + } + _this._ignoreXOnNextScroll = false; + _this._ignoreYOnNextScroll = false; + }, + + /** + * Returns the positions of the currently selected items + * relative to the top-left corner of the top-left view + */ + getPositionsOfSelectedHeaders: function() { + var _this = this; + + var result = []; + + var selectedEntityHeaderView = _this._cachedEntityHeaderViewsByClientId[_this._cachedSelectedEntityConfigClientId]; + var selectedViewHeaderView = _this._cachedViewHeaderViewsByClientId [_this._cachedSelectedViewConfigClientId]; + + if (selectedEntityHeaderView) { + var $selectedEntityHeader = selectedEntityHeaderView.$el; + result.push(parseInt($selectedEntityHeader.css("left"), 10) - _this._$containerOfScrollable.scrollLeft(), parseInt($selectedEntityHeader[0].style.width, 10)); + } else { + result.push(null, null); + } + + if (selectedViewHeaderView) { + var $selectedViewHeader = selectedViewHeaderView.$el; + result.push(parseInt($selectedViewHeader.css("top"), 10) - _this._$containerOfScrollable.scrollTop(), _this._viewHeaderHeight); + } else { + result.push(null, null); + } + + return result; + }, + + _updateCachedScroll: function() { + var _this = this; + + _this._cachedScrollPosGridHash = _this.getEntityWidth() + "~" + _this._cachedEntityConfigClientIds.join("|") + "~" + _this._cachedViewConfigClientIds.join("|"); + _this._cachedScrollPosSelection = "" + _this._cachedSelectedEntityConfigClientId + _this._cachedSelectedViewConfigClientId; + _this._cachedScrollPosX = _this._$containerOfScrollable.scrollLeft(); + _this._cachedScrollPosY = _this._$containerOfScrollable.scrollTop(); + + //_this._logger.debug(_.str.sprintf("ConfigGridCellsView[%s]._updateCachedScroll()", _this.options.configGrid.getType()), _this._cachedScrollPosGridHash, _this._cachedScrollPosSelection, _this._cachedScrollPosX, _this._cachedScrollPosY); + }, + + _toggleFixedHeadersIfNeeded: function(trueOrFalse) { + //trueOrFalse = true; + var _this = this; + if (_this.options.enableFixedHeaders && trueOrFalse == true) { + //_this._logger.debug("_toggleFixedHeadersIfNeeded(true)"); + if (!_this._$containerOfFixed[0].childNodes.length) { + _this._$containerOfFixed.append(_this._$visInstancesContainer, _this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind); + //_this._$containerOfFixed.append(_this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind); + _this._$cornerBlind.css({"transform": "translate(0px, 0px)"}); + _this._$containerOfFixed.show(); + } + } else { + //_this._logger.debug("_toggleFixedHeadersIfNeeded(false)"); + _this._$containerOfFixed.hide(); + _this._$space.append(_this._$visInstancesContainer, _this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind); + //_this._$space.append(_this._$entityHeadersContainer, _this._$viewHeadersContainer, _this._$cornerBlind); + _this._$entityHeadersBlind.css({"transform": "translate(0px, 0px)"}); + _this._$visInstancesContainer.css({"transform": "translate(0px, 0px)"}); + + } + _this._adjustToScrollPos(); + }, + + _adjustToScrollPos: function() { + var _this = this; + if (_this._scrollLeftBeforeLatestLayoutUpdate !== null) { + _this._scrollLeftBeforeLatestLayoutUpdate = null; + _this._scrollTopBeforeLatestLayoutUpdate = null; + } + + var scrollLeft = _this._$containerOfScrollable.scrollLeft(); + var scrollTop = _this._$containerOfScrollable.scrollTop(); + if (_this._$containerOfFixed[0].childNodes.length) { + _this._$entityHeadersContainer.css({"transform": "translate(" + (-scrollLeft) + "px, 0px)"}); + _this._$entityHeadersBlind.css({"transform": "translate(" + scrollLeft + "px, 0px)"}); + _this._$visInstancesContainer.css({"transform": "translate(" + (-scrollLeft) + "px, " + (-scrollTop) + "px)"}); + _this._$viewHeadersContainer.css({"transform": "translate(0px, " + (-scrollTop) + "px)"}); + } else { + _this._$entityHeadersContainer.css({"transform": "translate(0, " + scrollTop + "px)"}); + _this._$viewHeadersContainer.css({"transform": "translate(" + scrollLeft + "px, 0)"}); + _this._$cornerBlind.css({"transform": "translate(" + scrollLeft + "px, " + scrollTop + "px)"}); + } + + _this._reportPositionsOfSelectedHeaders(); + }, + + _reportPositionsOfSelectedHeaders: function() { + var _this = this; + + var positionsOfSelectedHeaders = _this.getPositionsOfSelectedHeaders(); + _this.trigger("change-positions-of-selected-headers", positionsOfSelectedHeaders[0], positionsOfSelectedHeaders[1], positionsOfSelectedHeaders[2], positionsOfSelectedHeaders[3]); + }, + + + _reviseSpaceSize: function(increaseOnly) { + var _this = this; + + var elInnerWidth = _this._$containerOfScrollable[0].clientWidth; + var elInnerHeight = _this._$containerOfScrollable[0].clientHeight; + var elScrollLeft = _this._$containerOfScrollable.scrollLeft(); + var elScrollTop = _this._$containerOfScrollable.scrollTop(); + var spaceWidth = _this._cachedMinSpaceWidth; + var spaceHeight = _this._cachedMinSpaceHeight; + + var missingWidth = elScrollLeft + elInnerWidth - _this._spacePadding.h - spaceWidth; + var missingHeight = elScrollTop + elInnerHeight - _this._spacePadding.v - spaceHeight; + + spaceWidth += Math.max(0, missingWidth); + spaceHeight += Math.max(0, missingHeight); + + if (!increaseOnly || (spaceWidth >= _this._$space.width() && spaceHeight >= _this._$space.height())) { + _this._$space.css({ + "width": spaceWidth, + "height": spaceHeight + }); + _this._$viewHeadersBlind.height(spaceHeight); + } + }, + + _updateDemensionsForContainerOfFixed: function() { + var _this = this; + _this._$containerOfFixed.width(_this._$containerOfScrollable[0].clientWidth); + _this._$containerOfFixed.height(_this._$containerOfScrollable[0].clientHeight); + }, + + _generateEntityHeaderView: function(entityConfig) { + var _this = this; + + var $el = $.bem.generateElement("config-grid-cells", "entity-header"); + + var result = new App.MainRegionModule.ConfigHeaderView({ + dimension: "entity", + el: $el, + state: _this.options.state, + configGrid: _this.options.configGrid, + config: entityConfig, + parentConfigGridView: _this.options.parentConfigGridView + }); + + result.$el.dblclick(function() { + if (entityConfig.getParameterValue("kind")) { + return; + } + if (_this.options.configGrid.getSelectedEntityConfig() == entityConfig) { + _this.options.configGrid.addEntityAndSelectIt(new App.ContextModule.Config({ + parameters: { + "kind": "pair", + "comparisonMode": "superposition" + } + }), _this.options.configGrid.getNextEntityNeighbour(entityConfig)) ; + } + }); + + return result; + }, + + _generateViewHeaderView: function(viewConfig) { + var _this = this; + + var $el = $.bem.generateElement("config-grid-cells", "view-header"); + + var result = new App.MainRegionModule.ConfigHeaderView({ + dimension: "view", + el: $el, + state: _this.options.state, + configGrid: _this.options.configGrid, + config: viewConfig, + parentConfigGridView: _this.options.parentConfigGridView + }); + + return result; + }, + + _generateVisInstanceView: function(entityConfig, viewConfig) { + var _this = this; + + var $el = $.bem.generateElement("config-grid-cells", "vis-instance").addClass("vis-instance"); + + var result = new App.MainRegionModule.VisInstanceView({ + el: $el, + state: _this.options.state, + configGrid: _this.options.configGrid, + entityConfig: entityConfig, + viewConfig: viewConfig, + parentConfigGridView: _this.options.parentConfigGridView + }); + + return result; + } + }); +}, Logger); \ No newline at end of file