Merged from Master
This commit is contained in:
@@ -45,43 +45,8 @@ define(
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function LayoutController($scope) {
|
||||
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.
|
||||
* Defined as member function to facilitate testing.
|
||||
* @private
|
||||
*/
|
||||
LayoutController.prototype.layoutPanels = function layoutPanels (ids) {
|
||||
var configuration = $scope.configuration || {};
|
||||
|
||||
// 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);
|
||||
});
|
||||
};
|
||||
var self = this,
|
||||
callbackCount = 0;
|
||||
|
||||
// Update grid size when it changed
|
||||
function updateGridSize(layoutGrid) {
|
||||
@@ -127,23 +92,26 @@ define(
|
||||
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() {
|
||||
return getComposition($scope.domainObject)
|
||||
.then(composeView)
|
||||
.then(self.layoutPanels);
|
||||
//Keep a track of how many composition callbacks have been made
|
||||
var thisCount = ++callbackCount;
|
||||
|
||||
$scope.domainObject.useCapability('composition').then(function(composition){
|
||||
var ids;
|
||||
|
||||
//Is this callback for the most recent composition
|
||||
// request? If not, discard it. Prevents race condition
|
||||
if (thisCount === callbackCount){
|
||||
ids = composition.map(function (object) {
|
||||
return object.getId();
|
||||
}) || [];
|
||||
|
||||
$scope.composition = composition;
|
||||
self.layoutPanels(ids);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// End drag; we don't want to put $scope into this
|
||||
@@ -176,7 +144,7 @@ define(
|
||||
$scope.$watch("model.layoutGrid", updateGridSize);
|
||||
|
||||
// Update composed objects on screen, and position panes
|
||||
$scope.$watch("model.composition", refreshComposition);
|
||||
$scope.$watchCollection("model.composition", refreshComposition);
|
||||
|
||||
// Position panes where they are dropped
|
||||
$scope.$on("mctDrop", handleDrop);
|
||||
@@ -282,6 +250,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
|
||||
* view configuration.
|
||||
|
||||
@@ -33,7 +33,8 @@ define(
|
||||
testConfiguration,
|
||||
controller,
|
||||
mockCompositionCapability,
|
||||
mockComposition;
|
||||
mockComposition,
|
||||
mockCompositionObjects;
|
||||
|
||||
function mockPromise(value){
|
||||
return {
|
||||
@@ -57,7 +58,7 @@ define(
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
[ "$watch", "$on", "commit" ]
|
||||
[ "$watch", "$watchCollection", "$on", "commit" ]
|
||||
);
|
||||
mockEvent = jasmine.createSpyObj(
|
||||
'event',
|
||||
@@ -67,6 +68,7 @@ define(
|
||||
testModel = {};
|
||||
|
||||
mockComposition = ["a", "b", "c"];
|
||||
mockCompositionObjects = mockComposition.map(mockDomainObject);
|
||||
|
||||
testConfiguration = {
|
||||
panels: {
|
||||
@@ -77,7 +79,7 @@ define(
|
||||
}
|
||||
};
|
||||
|
||||
mockCompositionCapability = mockPromise(mockComposition.map(mockDomainObject));
|
||||
mockCompositionCapability = mockPromise(mockCompositionObjects);
|
||||
|
||||
mockScope.domainObject = mockDomainObject("mockDomainObject");
|
||||
mockScope.model = testModel;
|
||||
@@ -91,14 +93,14 @@ define(
|
||||
// Model changes will indicate that panel positions
|
||||
// may have changed, for instance.
|
||||
it("watches for changes to composition", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
expect(mockScope.$watchCollection).toHaveBeenCalledWith(
|
||||
"model.composition",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("Retrieves updated composition from composition capability", function () {
|
||||
mockScope.$watch.mostRecentCall.args[1]();
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
expect(mockScope.domainObject.useCapability).toHaveBeenCalledWith(
|
||||
"composition"
|
||||
);
|
||||
@@ -107,8 +109,32 @@ define(
|
||||
);
|
||||
});
|
||||
|
||||
it("Is robust to concurrent changes to composition", function () {
|
||||
var secondMockComposition = ["a", "b", "c", "d"],
|
||||
secondMockCompositionObjects = secondMockComposition.map(mockDomainObject),
|
||||
firstCompositionCB,
|
||||
secondCompositionCB;
|
||||
|
||||
spyOn(mockCompositionCapability, "then");
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
firstCompositionCB = mockCompositionCapability.then.calls[0].args[0];
|
||||
secondCompositionCB = mockCompositionCapability.then.calls[1].args[0];
|
||||
|
||||
//Resolve promises in reverse order
|
||||
secondCompositionCB(secondMockCompositionObjects);
|
||||
firstCompositionCB(mockCompositionObjects);
|
||||
|
||||
//Expect the promise call that was initiated most recently to
|
||||
// be the one used to populate scope, irrespective of order that
|
||||
// it was eventually resolved
|
||||
expect(mockScope.composition).toBe(secondMockCompositionObjects);
|
||||
});
|
||||
|
||||
|
||||
it("provides styles for frames, from configuration", function () {
|
||||
mockScope.$watch.mostRecentCall.args[1]();
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
expect(controller.getFrameStyle("a")).toEqual({
|
||||
top: "320px",
|
||||
left: "640px",
|
||||
@@ -121,7 +147,7 @@ define(
|
||||
var styleB, styleC;
|
||||
|
||||
// b and c do not have configured positions
|
||||
mockScope.$watch.mostRecentCall.args[1]();
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
styleB = controller.getFrameStyle("b");
|
||||
styleC = controller.getFrameStyle("c");
|
||||
@@ -138,7 +164,7 @@ define(
|
||||
|
||||
it("allows panels to be dragged", function () {
|
||||
// Populate scope
|
||||
mockScope.$watch.mostRecentCall.args[1]();
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
// Verify precondtion
|
||||
expect(testConfiguration.panels.b).not.toBeDefined();
|
||||
@@ -157,7 +183,7 @@ define(
|
||||
|
||||
it("invokes commit after drag", function () {
|
||||
// Populate scope
|
||||
mockScope.$watch.mostRecentCall.args[1]();
|
||||
mockScope.$watchCollection.mostRecentCall.args[1]();
|
||||
|
||||
// Do a drag
|
||||
controller.startDrag("b", [1, 1], [0, 0]);
|
||||
@@ -218,7 +244,7 @@ define(
|
||||
|
||||
// White-boxy; we know which watch is which
|
||||
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");
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ define(
|
||||
if (canvas.width !== canvas.offsetWidth ||
|
||||
canvas.height !== canvas.offsetHeight) {
|
||||
doDraw(scope.draw);
|
||||
scope.$apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +182,7 @@ define(
|
||||
canvas.addEventListener("webglcontextlost", fallbackFromWebGL);
|
||||
|
||||
// Check for resize, on a timer
|
||||
activeInterval = $interval(drawIfResized, 1000);
|
||||
activeInterval = $interval(drawIfResized, 1000, 0, false);
|
||||
|
||||
// Watch "draw" for external changes to the set of
|
||||
// things to be drawn.
|
||||
|
||||
@@ -45,8 +45,10 @@ define(
|
||||
jasmine.createSpy("$interval");
|
||||
mockLog =
|
||||
jasmine.createSpyObj("$log", ["warn", "info", "debug"]);
|
||||
mockScope =
|
||||
jasmine.createSpyObj("$scope", ["$watchCollection", "$on"]);
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$watchCollection", "$on", "$apply"]
|
||||
);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", ["find", "html"]);
|
||||
mockInterval.cancel = jasmine.createSpy("cancelInterval");
|
||||
@@ -152,7 +154,9 @@ define(
|
||||
// Should track canvas size in an interval
|
||||
expect(mockInterval).toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
jasmine.any(Number)
|
||||
jasmine.any(Number),
|
||||
0,
|
||||
false
|
||||
);
|
||||
|
||||
// Verify pre-condition
|
||||
|
||||
Reference in New Issue
Block a user