mirror of
https://github.com/nasa/openmct.git
synced 2025-05-14 06:23:19 +00:00
[Layout] Layout rebuilds after resize/reposition #32
Refactored layoutPanels method Fixed JSLint errors fixed failing tests
This commit is contained in:
parent
d6e2895666
commit
6d0f3c7faa
@ -9,7 +9,7 @@
|
|||||||
"glyph": "L",
|
"glyph": "L",
|
||||||
"type": "layout",
|
"type": "layout",
|
||||||
"templateUrl": "templates/layout.html",
|
"templateUrl": "templates/layout.html",
|
||||||
"uses": [ "composition" ],
|
"uses": [],
|
||||||
"gestures": [ "drop" ]
|
"gestures": [ "drop" ]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -47,42 +47,6 @@ define(
|
|||||||
function LayoutController($scope) {
|
function LayoutController($scope) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Utility function to copy raw positions from configuration,
|
|
||||||
// without writing directly to configuration (to avoid triggering
|
|
||||||
// persistence from watchers during drags).
|
|
||||||
function shallowCopy(obj, keys) {
|
|
||||||
var copy = {};
|
|
||||||
keys.forEach(function (k) {
|
|
||||||
copy[k] = obj[k];
|
|
||||||
});
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute panel positions based on the layout's object model
|
|
||||||
function lookupPanels(ids) {
|
|
||||||
var configuration = $scope.configuration || {};
|
|
||||||
|
|
||||||
// ids is read from model.composition and may be undefined;
|
|
||||||
// fall back to an array if that occurs
|
|
||||||
ids = ids || [];
|
|
||||||
|
|
||||||
// Pull panel positions from configuration
|
|
||||||
self.rawPositions =
|
|
||||||
shallowCopy(configuration.panels || {}, ids);
|
|
||||||
|
|
||||||
// Clear prior computed positions
|
|
||||||
self.positions = {};
|
|
||||||
|
|
||||||
// Update width/height that we are tracking
|
|
||||||
self.gridSize =
|
|
||||||
($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
|
|
||||||
|
|
||||||
// Compute positions and add defaults where needed
|
|
||||||
ids.forEach(function (id, index) {
|
|
||||||
self.populatePosition(id, index);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update grid size when it changed
|
// Update grid size when it changed
|
||||||
function updateGridSize(layoutGrid) {
|
function updateGridSize(layoutGrid) {
|
||||||
var oldSize = self.gridSize;
|
var oldSize = self.gridSize;
|
||||||
@ -92,7 +56,7 @@ define(
|
|||||||
// Only update panel positions if this actually changed things
|
// Only update panel positions if this actually changed things
|
||||||
if (self.gridSize[0] !== oldSize[0] ||
|
if (self.gridSize[0] !== oldSize[0] ||
|
||||||
self.gridSize[1] !== oldSize[1]) {
|
self.gridSize[1] !== oldSize[1]) {
|
||||||
lookupPanels(Object.keys(self.positions));
|
self.layoutPanels(Object.keys(self.positions));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +91,25 @@ define(
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getComposition(domainObject){
|
||||||
|
return domainObject.useCapability('composition');
|
||||||
|
}
|
||||||
|
|
||||||
|
function composeView (composition){
|
||||||
|
$scope.composition = composition;
|
||||||
|
return composition.map(function (object) {
|
||||||
|
return object.getId();
|
||||||
|
}) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Will fetch fully contextualized composed objects, and populate
|
||||||
|
// scope with them.
|
||||||
|
function refreshComposition(ids) {
|
||||||
|
return getComposition($scope.domainObject)
|
||||||
|
.then(composeView)
|
||||||
|
.then(function(ids){self.layoutPanels(ids);});
|
||||||
|
}
|
||||||
|
|
||||||
// End drag; we don't want to put $scope into this
|
// End drag; we don't want to put $scope into this
|
||||||
// because it triggers "cpws" (copy window or scope)
|
// because it triggers "cpws" (copy window or scope)
|
||||||
// errors in Angular.
|
// errors in Angular.
|
||||||
@ -156,8 +139,8 @@ define(
|
|||||||
// Watch for changes to the grid size in the model
|
// Watch for changes to the grid size in the model
|
||||||
$scope.$watch("model.layoutGrid", updateGridSize);
|
$scope.$watch("model.layoutGrid", updateGridSize);
|
||||||
|
|
||||||
// Position panes when the model field changes
|
// Update composed objects on screen, and position panes
|
||||||
$scope.$watch("model.composition", lookupPanels);
|
$scope.$watchCollection("model.composition", refreshComposition);
|
||||||
|
|
||||||
// Position panes where they are dropped
|
// Position panes where they are dropped
|
||||||
$scope.$on("mctDrop", handleDrop);
|
$scope.$on("mctDrop", handleDrop);
|
||||||
@ -263,6 +246,43 @@ define(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Utility function to copy raw positions from configuration,
|
||||||
|
// without writing directly to configuration (to avoid triggering
|
||||||
|
// persistence from watchers during drags).
|
||||||
|
function shallowCopy(obj, keys) {
|
||||||
|
var copy = {};
|
||||||
|
keys.forEach(function (k) {
|
||||||
|
copy[k] = obj[k];
|
||||||
|
});
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute panel positions based on the layout's object model.
|
||||||
|
* Defined as member function to facilitate testing.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
LayoutController.prototype.layoutPanels = function (ids) {
|
||||||
|
var configuration = this.$scope.configuration || {},
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
// Pull panel positions from configuration
|
||||||
|
this.rawPositions =
|
||||||
|
shallowCopy(configuration.panels || {}, ids);
|
||||||
|
|
||||||
|
// Clear prior computed positions
|
||||||
|
this.positions = {};
|
||||||
|
|
||||||
|
// Update width/height that we are tracking
|
||||||
|
this.gridSize =
|
||||||
|
(this.$scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
|
||||||
|
|
||||||
|
// Compute positions and add defaults where needed
|
||||||
|
ids.forEach(function (id, index) {
|
||||||
|
self.populatePosition(id, index);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End the active drag gesture. This will update the
|
* End the active drag gesture. This will update the
|
||||||
* view configuration.
|
* view configuration.
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
/*global define,describe,it,expect,beforeEach,jasmine*/
|
/*global define,describe,it,expect,beforeEach,jasmine,spyOn*/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
["../src/LayoutController"],
|
["../src/LayoutController"],
|
||||||
@ -31,21 +31,42 @@ define(
|
|||||||
mockEvent,
|
mockEvent,
|
||||||
testModel,
|
testModel,
|
||||||
testConfiguration,
|
testConfiguration,
|
||||||
controller;
|
controller,
|
||||||
|
mockCompositionCapability,
|
||||||
|
mockComposition;
|
||||||
|
|
||||||
|
function mockPromise(value){
|
||||||
|
return {
|
||||||
|
then: function (thenFunc) {
|
||||||
|
return mockPromise(thenFunc(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockDomainObject(id){
|
||||||
|
return {
|
||||||
|
getId: function() {
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
useCapability: function() {
|
||||||
|
return mockCompositionCapability;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockScope = jasmine.createSpyObj(
|
mockScope = jasmine.createSpyObj(
|
||||||
"$scope",
|
"$scope",
|
||||||
[ "$watch", "$on", "commit" ]
|
[ "$watch", "$watchCollection", "$on", "commit" ]
|
||||||
);
|
);
|
||||||
mockEvent = jasmine.createSpyObj(
|
mockEvent = jasmine.createSpyObj(
|
||||||
'event',
|
'event',
|
||||||
[ 'preventDefault' ]
|
[ 'preventDefault' ]
|
||||||
);
|
);
|
||||||
|
|
||||||
testModel = {
|
testModel = {};
|
||||||
composition: [ "a", "b", "c" ]
|
|
||||||
};
|
mockComposition = ["a", "b", "c"];
|
||||||
|
|
||||||
testConfiguration = {
|
testConfiguration = {
|
||||||
panels: {
|
panels: {
|
||||||
@ -56,23 +77,38 @@ define(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mockCompositionCapability = mockPromise(mockComposition.map(mockDomainObject));
|
||||||
|
|
||||||
|
mockScope.domainObject = mockDomainObject("mockDomainObject");
|
||||||
mockScope.model = testModel;
|
mockScope.model = testModel;
|
||||||
mockScope.configuration = testConfiguration;
|
mockScope.configuration = testConfiguration;
|
||||||
|
spyOn(mockScope.domainObject, "useCapability").andCallThrough();
|
||||||
|
|
||||||
controller = new LayoutController(mockScope);
|
controller = new LayoutController(mockScope);
|
||||||
|
spyOn(controller, "layoutPanels").andCallThrough();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Model changes will indicate that panel positions
|
// Model changes will indicate that panel positions
|
||||||
// may have changed, for instance.
|
// may have changed, for instance.
|
||||||
it("watches for changes to composition", function () {
|
it("watches for changes to composition", function () {
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
expect(mockScope.$watchCollection).toHaveBeenCalledWith(
|
||||||
"model.composition",
|
"model.composition",
|
||||||
jasmine.any(Function)
|
jasmine.any(Function)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Retrieves updated composition from composition capability", function () {
|
||||||
|
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||||
|
expect(mockScope.domainObject.useCapability).toHaveBeenCalledWith(
|
||||||
|
"composition"
|
||||||
|
);
|
||||||
|
expect(controller.layoutPanels).toHaveBeenCalledWith(
|
||||||
|
mockComposition
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("provides styles for frames, from configuration", function () {
|
it("provides styles for frames, from configuration", function () {
|
||||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||||
expect(controller.getFrameStyle("a")).toEqual({
|
expect(controller.getFrameStyle("a")).toEqual({
|
||||||
top: "320px",
|
top: "320px",
|
||||||
left: "640px",
|
left: "640px",
|
||||||
@ -85,7 +121,7 @@ define(
|
|||||||
var styleB, styleC;
|
var styleB, styleC;
|
||||||
|
|
||||||
// b and c do not have configured positions
|
// b and c do not have configured positions
|
||||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||||
|
|
||||||
styleB = controller.getFrameStyle("b");
|
styleB = controller.getFrameStyle("b");
|
||||||
styleC = controller.getFrameStyle("c");
|
styleC = controller.getFrameStyle("c");
|
||||||
@ -102,7 +138,7 @@ define(
|
|||||||
|
|
||||||
it("allows panels to be dragged", function () {
|
it("allows panels to be dragged", function () {
|
||||||
// Populate scope
|
// Populate scope
|
||||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||||
|
|
||||||
// Verify precondtion
|
// Verify precondtion
|
||||||
expect(testConfiguration.panels.b).not.toBeDefined();
|
expect(testConfiguration.panels.b).not.toBeDefined();
|
||||||
@ -121,7 +157,7 @@ define(
|
|||||||
|
|
||||||
it("invokes commit after drag", function () {
|
it("invokes commit after drag", function () {
|
||||||
// Populate scope
|
// Populate scope
|
||||||
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
|
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||||
|
|
||||||
// Do a drag
|
// Do a drag
|
||||||
controller.startDrag("b", [1, 1], [0, 0]);
|
controller.startDrag("b", [1, 1], [0, 0]);
|
||||||
@ -147,7 +183,6 @@ define(
|
|||||||
expect(testConfiguration.panels.d).not.toBeDefined();
|
expect(testConfiguration.panels.d).not.toBeDefined();
|
||||||
|
|
||||||
// Notify that a drop occurred
|
// Notify that a drop occurred
|
||||||
testModel.composition.push('d');
|
|
||||||
mockScope.$on.mostRecentCall.args[1](
|
mockScope.$on.mostRecentCall.args[1](
|
||||||
mockEvent,
|
mockEvent,
|
||||||
'd',
|
'd',
|
||||||
@ -167,7 +202,6 @@ define(
|
|||||||
mockEvent.defaultPrevented = true;
|
mockEvent.defaultPrevented = true;
|
||||||
|
|
||||||
// Notify that a drop occurred
|
// Notify that a drop occurred
|
||||||
testModel.composition.push('d');
|
|
||||||
mockScope.$on.mostRecentCall.args[1](
|
mockScope.$on.mostRecentCall.args[1](
|
||||||
mockEvent,
|
mockEvent,
|
||||||
'd',
|
'd',
|
||||||
@ -184,7 +218,7 @@ define(
|
|||||||
|
|
||||||
// White-boxy; we know which watch is which
|
// White-boxy; we know which watch is which
|
||||||
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
|
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
|
||||||
mockScope.$watch.calls[1].args[1](testModel.composition);
|
mockScope.$watchCollection.calls[0].args[1](testModel.composition);
|
||||||
|
|
||||||
styleB = controller.getFrameStyle("b");
|
styleB = controller.getFrameStyle("b");
|
||||||
|
|
||||||
@ -201,7 +235,6 @@ define(
|
|||||||
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
|
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
|
||||||
|
|
||||||
// Notify that a drop occurred
|
// Notify that a drop occurred
|
||||||
testModel.composition.push('d');
|
|
||||||
mockScope.$on.mostRecentCall.args[1](
|
mockScope.$on.mostRecentCall.args[1](
|
||||||
mockEvent,
|
mockEvent,
|
||||||
'd',
|
'd',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user