diff --git a/platform/features/layout/src/FixedController.js b/platform/features/layout/src/FixedController.js index cec05fb800..f2f8a354ee 100644 --- a/platform/features/layout/src/FixedController.js +++ b/platform/features/layout/src/FixedController.js @@ -5,8 +5,7 @@ define( function (LayoutSelection, FixedProxy, ElementProxies, FixedDragHandle) { "use strict"; - var DEFAULT_DIMENSIONS = [ 2, 1 ], - DEFAULT_GRID_SIZE = [64, 16], + var DEFAULT_GRID_SIZE = [64, 16], DEFAULT_GRID_EXTENT = [4, 4]; /** @@ -29,6 +28,7 @@ define( elementProxiesById = {}, handles = [], moveHandle, + viewProxy, selection; // Refresh cell styles (e.g. because grid extent changed) @@ -198,14 +198,6 @@ define( telemetrySubscriber.subscribe(domainObject, updateValues); } - // Handle changes in the object's composition - function updateComposition(ids) { - // Populate panel positions - // TODO: Ensure defaults here - // Resubscribe - objects in view have changed - subscribe($scope.domainObject); - } - // Add an element to this view function addElement(element) { // Ensure that configuration field is populated @@ -226,29 +218,93 @@ define( } } + // Add a telemetry element to this view + function addTelemetryElement(id, x, y) { + viewProxy.add("fixed.telemetry", { id: id, x: x, y: y }); + } + + // Ensure that all telemetry elements have elements in view + function ensureElements(ids) { + var contained = {}, + found = {}; + + // Track that a telemetry element is in the view + function track(element) { + if (element.type === 'fixed.telemetry') { + found[element.id] = true; + } + } + + // Used to filter down to elements not yet present + function notFound(id) { + return !found[id]; + } + + // Add a telemetry element + function add(id, index) { + addTelemetryElement(id, 0, index); + } + + // Build list of all found elements + (($scope.configuration || {}).elements || []).forEach(track); + + // Add in telemetry elements where needed + (ids || []).filter(notFound).forEach(add); + } + + // Remove telemetry elements which don't match set of contained ids + function removeOtherElements(ids) { + // Set of ids, to simplify lookup + var contained = {}, + elements = ($scope.configuration || {}).elements; + + // Track that an id is present; used to build set + function track(id) { + contained[id] = true; + } + + // Check if an element is still valid + function valid(element) { + return (element.type !== "fixed.telemetry") || + contained[element.id]; + } + + // Only need to remove elements if any have been defined + if (Array.isArray(elements)) { + // Build set of contained ids + ids.forEach(track); + // Filter out removed telemetry elements + $scope.configuration.elements = elements.filter(valid); + // Refresh elements exposed to template + refreshElements(); + } + } + + // Handle changes in the object's composition + function updateComposition(ids) { + // Remove any obsolete telemetry elements + removeOtherElements(ids); + // Populate panel positions + ensureElements(ids); + // Resubscribe - objects in view have changed + subscribe($scope.domainObject); + } + // Position a panel after a drop event function handleDrop(e, id, position) { // Store the position of this element. - addElement({ - type: "fixed.telemetry", - x: Math.floor(position.x / gridSize[0]), - y: Math.floor(position.y / gridSize[1]), - id: id, - stroke: "transparent", - color: "#717171", - titled: true, - width: DEFAULT_DIMENSIONS[0], - height: DEFAULT_DIMENSIONS[1] - }); + addTelemetryElement( + id, + Math.floor(position.x / gridSize[0]), + Math.floor(position.y / gridSize[1]) + ); } // Track current selection state + viewProxy = new FixedProxy(addElement, $q, dialogService); if (Array.isArray($scope.selection)) { - selection = new LayoutSelection( - $scope.selection, - new FixedProxy(addElement, $q, dialogService) - ); + selection = new LayoutSelection($scope.selection, viewProxy); } // Refresh list of elements whenever model changes diff --git a/platform/features/layout/src/FixedProxy.js b/platform/features/layout/src/FixedProxy.js index 4b5b4312e0..846f16aa84 100644 --- a/platform/features/layout/src/FixedProxy.js +++ b/platform/features/layout/src/FixedProxy.js @@ -21,9 +21,14 @@ define( /** * Add a new visual element to this view. */ - add: function (type) { + add: function (type, state) { // Place a configured element into the view configuration function addElement(element) { + // Populate element with additional state + Object.keys(state || {}).forEach(function (k) { + element[k] = state[k]; + }); + // Configure common properties of the element element.x = element.x || 0; element.y = element.y || 0; diff --git a/platform/features/layout/src/elements/ElementFactory.js b/platform/features/layout/src/elements/ElementFactory.js index 3ae8cad80a..708d7c6d24 100644 --- a/platform/features/layout/src/elements/ElementFactory.js +++ b/platform/features/layout/src/elements/ElementFactory.js @@ -25,6 +25,13 @@ define( fill: "transparent", stroke: "transparent", color: "#717171" + }, + "fixed.telemetry": { + stroke: "transparent", + color: "#717171", + titled: true, + width: 2, + height: 1 } }, DIALOGS = { diff --git a/platform/features/layout/test/FixedControllerSpec.js b/platform/features/layout/test/FixedControllerSpec.js index 087028c44a..4d976acd7f 100644 --- a/platform/features/layout/test/FixedControllerSpec.js +++ b/platform/features/layout/test/FixedControllerSpec.js @@ -13,6 +13,7 @@ define( mockFormatter, mockDomainObject, mockSubscription, + mockPromise, testGrid, testModel, testValues, @@ -77,6 +78,10 @@ define( 'subscription', [ 'unsubscribe', 'getTelemetryObjects', 'getRangeValue' ] ); + mockPromise = jasmine.createSpyObj( + 'promise', + [ 'then' ] + ); testGrid = [ 123, 456 ]; testModel = { @@ -103,6 +108,8 @@ define( mockScope.model = testModel; mockScope.configuration = testConfiguration; mockScope.selection = []; // Act like edit mode + mockQ.when.andReturn(mockPromise); + mockPromise.then.andCallFake(function (cb) { cb({}); }); controller = new FixedController( mockScope, @@ -363,6 +370,19 @@ define( // Style should have been updated expect(controller.selected().style).not.toEqual(oldStyle); }); + + it("ensures elements in view match elements in composition", function () { + // View should ensure that at least one element is present + // for each id, and then unused ids do not have elements. + mockScope.model = testModel; + testModel.composition = [ 'b', 'd' ]; + findWatch("model.composition")(mockScope.model.composition); + + // Should have a new element for d; should not have elements for a, c + expect(testConfiguration.elements.length).toEqual(2); + expect(testConfiguration.elements[0].id).toEqual('b'); + expect(testConfiguration.elements[1].id).toEqual('d'); + }); }); } ); \ No newline at end of file