diff --git a/platform/commonUI/browse/bundle.js b/platform/commonUI/browse/bundle.js
index 1fcd810b96..cf4ee5b7a0 100644
--- a/platform/commonUI/browse/bundle.js
+++ b/platform/commonUI/browse/bundle.js
@@ -111,7 +111,6 @@ define([
"$scope",
"$route",
"$location",
- "$q",
"objectService",
"navigationService",
"urlService",
diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html
index 08a5cd4d5e..75fcaaeb0a 100644
--- a/platform/commonUI/browse/res/templates/browse.html
+++ b/platform/commonUI/browse/res/templates/browse.html
@@ -72,7 +72,7 @@
diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js
index f65333870d..6013772965 100644
--- a/platform/commonUI/browse/src/BrowseController.js
+++ b/platform/commonUI/browse/src/BrowseController.js
@@ -49,7 +49,6 @@ define(
$scope,
$route,
$location,
- $q,
objectService,
navigationService,
urlService,
diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js
index 1d43971166..858a5d80eb 100644
--- a/platform/commonUI/browse/src/navigation/NavigationService.js
+++ b/platform/commonUI/browse/src/navigation/NavigationService.js
@@ -57,7 +57,7 @@ define(
NavigationService.prototype.setNavigation = function (value) {
var canNavigate = true;
if (this.navigated !== value) {
- canNavigate = (this.callbacks['before'] || [])
+ canNavigate = (this.callbacks.before || [])
.reduce(function (previous, callback) {
//Check whether the callback returned a value of
// 'false' indicating that navigation should not
@@ -67,7 +67,7 @@ define(
}, true);
if (canNavigate) {
this.navigated = value;
- this.callbacks['after'].forEach(function (callback) {
+ (this.callbacks.after || []).forEach(function (callback) {
callback(value);
});
}
diff --git a/platform/commonUI/browse/test/BrowseControllerSpec.js b/platform/commonUI/browse/test/BrowseControllerSpec.js
index e4fad10544..caab0ed7d8 100644
--- a/platform/commonUI/browse/test/BrowseControllerSpec.js
+++ b/platform/commonUI/browse/test/BrowseControllerSpec.js
@@ -29,8 +29,7 @@ define(
function (BrowseController) {
"use strict";
- //TODO: Disabled for NEM Beta
- xdescribe("The browse controller", function () {
+ describe("The browse controller", function () {
var mockScope,
mockRoute,
mockLocation,
@@ -214,7 +213,10 @@ define(
// prior to setting $route.current
mockLocation.path.andReturn("/browse/");
+ mockNavigationService.setNavigation.andReturn(true);
+
// Exercise the Angular workaround
+ mockNavigationService.addListener.mostRecentCall.args[0]();
mockScope.$on.mostRecentCall.args[1]();
expect(mockUnlisten).toHaveBeenCalled();
@@ -225,6 +227,32 @@ define(
);
});
+ it("after successful navigation event sets the selected tree " +
+ "object", function () {
+ mockScope.navigatedObject = mockDomainObject;
+ mockNavigationService.setNavigation.andReturn(true);
+
+ //Simulate a change in selected tree object
+ mockScope.treeModel = {selectedObject: mockDomainObject};
+ mockScope.$watch.mostRecentCall.args[1](mockNextObject);
+
+ expect(mockScope.treeModel.selectedObject).toBe(mockNextObject);
+ expect(mockScope.treeModel.selectedObject).not.toBe(mockDomainObject);
+ });
+
+ it("after failed navigation event resets the selected tree" +
+ " object", function () {
+ mockScope.navigatedObject = mockDomainObject;
+ mockNavigationService.setNavigation.andReturn(false);
+
+ //Simulate a change in selected tree object
+ mockScope.treeModel = {selectedObject: mockDomainObject};
+ mockScope.$watch.mostRecentCall.args[1](mockNextObject);
+
+ expect(mockScope.treeModel.selectedObject).not.toBe(mockNextObject);
+ expect(mockScope.treeModel.selectedObject).toBe(mockDomainObject);
+ });
+
});
}
);
diff --git a/platform/commonUI/browse/test/navigation/NavigationServiceSpec.js b/platform/commonUI/browse/test/navigation/NavigationServiceSpec.js
index 6d7f3fd20d..3a354dee78 100644
--- a/platform/commonUI/browse/test/navigation/NavigationServiceSpec.js
+++ b/platform/commonUI/browse/test/navigation/NavigationServiceSpec.js
@@ -84,6 +84,24 @@ define(
expect(callback).not.toHaveBeenCalled();
});
+ it("adds listeners to the 'after' state by default", function(){
+ expect(navigationService.callbacks.after).toBeUndefined();
+ navigationService.addListener(function(){});
+ expect(navigationService.callbacks.after).toBeDefined();
+ expect(navigationService.callbacks.after.length).toBe(1);
+ });
+
+ it("allows navigationService events to be prevented", function(){
+ var callback = jasmine.createSpy("callback"),
+ navigationResult;
+ callback.andReturn(false);
+ navigationService.addListener(callback, "before");
+ navigationResult = navigationService.setNavigation({});
+ expect(callback).toHaveBeenCalled();
+ expect(navigationResult).toBe(false);
+
+ });
+
});
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/src/representers/EditRepresenter.js b/platform/commonUI/edit/src/representers/EditRepresenter.js
index c062e6387f..5d96aeaf78 100644
--- a/platform/commonUI/edit/src/representers/EditRepresenter.js
+++ b/platform/commonUI/edit/src/representers/EditRepresenter.js
@@ -102,6 +102,11 @@ define(
scope.commit = commit;
scope.setEditable = setEditable;
+ // Clean up when the scope is destroyed
+ scope.$on("$destroy", function () {
+ self.destroy();
+ });
+
}
// Handle a specific representation of a specific domain object
@@ -119,8 +124,7 @@ define(
this.destroy();
function setEditing(){
- scope.viewRegionTemplate = 'edit-object';
- scope.inspectorRegionTemplate = 'inspector-edit'
+ scope.viewObjectTemplate = 'edit-object';
}
/**
@@ -132,7 +136,7 @@ define(
if (statuses.indexOf('editing')!=-1){
setEditing();
} else {
- delete scope.viewRegionTemplate;
+ delete scope.viewObjectTemplate;
}
});
@@ -144,7 +148,7 @@ define(
// Respond to the destruction of the current representation.
EditRepresenter.prototype.destroy = function destroy() {
// Nothing to clean up
- this.listenHandle && this.listenHandle();
+ return this.listenHandle && this.listenHandle();
};
return EditRepresenter;
diff --git a/platform/commonUI/edit/test/controllers/EditControllerSpec.js b/platform/commonUI/edit/test/controllers/EditControllerSpec.js
index 4e66cebd08..0a39874eb8 100644
--- a/platform/commonUI/edit/test/controllers/EditControllerSpec.js
+++ b/platform/commonUI/edit/test/controllers/EditControllerSpec.js
@@ -22,89 +22,72 @@
/*global define,describe,it,expect,beforeEach,jasmine*/
define(
- ["../../src/controllers/EditController"],
- function (EditController) {
+ ["../../src/controllers/EditObjectController"],
+ function (EditObjectController) {
"use strict";
describe("The Edit mode controller", function () {
var mockScope,
- mockQ,
- mockNavigationService,
mockObject,
mockType,
+ mockLocation,
+ mockStatusCapability,
+ mockCapabilities,
controller;
+ // Utility function; look for a $watch on scope and fire it
+ function fireWatch(expr, value) {
+ mockScope.$watch.calls.forEach(function (call) {
+ if (call.args[0] === expr) {
+ call.args[1](value);
+ }
+ });
+ }
+
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
- [ "$on" ]
- );
- mockQ = jasmine.createSpyObj('$q', ['when', 'all']);
- mockNavigationService = jasmine.createSpyObj(
- "navigationService",
- [ "getNavigation", "addListener", "removeListener" ]
+ [ "$on", "$watch" ]
);
mockObject = jasmine.createSpyObj(
"domainObject",
- [ "getId", "getModel", "getCapability", "hasCapability" ]
+ [ "getId", "getModel", "getCapability", "hasCapability", "useCapability" ]
);
mockType = jasmine.createSpyObj(
"type",
[ "hasFeature" ]
);
+ mockStatusCapability = jasmine.createSpyObj('statusCapability',
+ ["get"]
+ );
+
+ mockCapabilities = {
+ "type" : mockType,
+ "status": mockStatusCapability
+ };
+
+ mockLocation = jasmine.createSpyObj('$location',
+ ["search"]
+ );
+ mockLocation.search.andReturn({"view": "fixed"});
- mockNavigationService.getNavigation.andReturn(mockObject);
mockObject.getId.andReturn("test");
mockObject.getModel.andReturn({ name: "Test object" });
mockObject.getCapability.andCallFake(function (key) {
- return key === 'type' && mockType;
+ return mockCapabilities[key];
});
mockType.hasFeature.andReturn(true);
- controller = new EditController(
+ mockScope.domainObject = mockObject;
+
+ controller = new EditObjectController(
mockScope,
- mockQ,
- mockNavigationService
+ mockLocation
);
});
- it("exposes the currently-navigated object", function () {
- expect(controller.navigatedObject()).toBeDefined();
- expect(controller.navigatedObject().getId()).toEqual("test");
- });
-
- it("adds an editor capability to the navigated object", function () {
- // Should provide an editor capability...
- expect(controller.navigatedObject().getCapability("editor"))
- .toBeDefined();
- // Shouldn't have been the mock capability we provided
- expect(controller.navigatedObject().getCapability("editor"))
- .not.toEqual(mockType);
- });
-
- it("detaches its navigation listener when destroyed", function () {
- var navCallback = mockNavigationService
- .addListener.mostRecentCall.args[0];
-
- expect(mockScope.$on).toHaveBeenCalledWith(
- "$destroy",
- jasmine.any(Function)
- );
-
- // Verify precondition
- expect(mockNavigationService.removeListener)
- .not.toHaveBeenCalled();
-
- // Trigger destroy
- mockScope.$on.mostRecentCall.args[1]();
-
- // Listener should have been removed
- expect(mockNavigationService.removeListener)
- .toHaveBeenCalledWith(navCallback);
- });
-
it("exposes a warning message for unload", function () {
- var obj = controller.navigatedObject(),
+ var obj = mockObject,
mockEditor = jasmine.createSpyObj('editor', ['dirty']);
// Normally, should be undefined
@@ -112,14 +95,32 @@ define(
// Override the object's editor capability, make it look
// like there are unsaved changes.
- obj.getCapability = jasmine.createSpy();
- obj.getCapability.andReturn(mockEditor);
+ mockCapabilities.editor = mockEditor;
mockEditor.dirty.andReturn(true);
+ mockStatusCapability.get.andReturn(true);
// Should have some warning message here now
expect(controller.getUnloadWarning()).toEqual(jasmine.any(String));
});
+
+ it("sets the active view from query parameters", function () {
+ var testViews = [
+ { key: 'abc' },
+ { key: 'def', someKey: 'some value' },
+ { key: 'xyz' }
+ ];
+
+ mockObject.useCapability.andCallFake(function (c) {
+ return (c === 'view') && testViews;
+ });
+ mockLocation.search.andReturn({ view: 'def' });
+
+ fireWatch('domainObject', mockObject);
+ expect(mockScope.representation.selected)
+ .toEqual(testViews[1]);
+ });
+
});
}
);
diff --git a/platform/commonUI/edit/test/directives/MCTBeforeUnloadSpec.js b/platform/commonUI/edit/test/directives/MCTBeforeUnloadSpec.js
index 41070d76f5..fd94e3e90d 100644
--- a/platform/commonUI/edit/test/directives/MCTBeforeUnloadSpec.js
+++ b/platform/commonUI/edit/test/directives/MCTBeforeUnloadSpec.js
@@ -31,6 +31,7 @@ define(
mockScope,
testAttrs,
mockEvent,
+ mockNavigationService,
directive;
function fireListener(eventType, value) {
@@ -46,7 +47,8 @@ define(
mockScope = jasmine.createSpyObj("$scope", ['$eval', '$on']);
testAttrs = { mctBeforeUnload: "someExpression" };
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
- directive = new MCTBeforeUnload(mockWindow);
+ mockNavigationService = jasmine.createSpyObj("navigationService", ["addListener", "removeListener"]);
+ directive = new MCTBeforeUnload(mockWindow, mockNavigationService);
directive.link(mockScope, {}, testAttrs);
});
@@ -65,6 +67,10 @@ define(
);
});
+ it("listens for navigation changes", function () {
+ expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function), "before");
+ });
+
it("listens for its scope's destroy event", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
"$destroy",
@@ -108,9 +114,10 @@ define(
it("cleans up listeners when destroyed", function () {
fireListener("$destroy", mockEvent);
expect(mockWindow.onbeforeunload).toBeUndefined();
+ expect(mockNavigationService.removeListener).toHaveBeenCalled();
});
});
}
-);
\ No newline at end of file
+);
diff --git a/platform/commonUI/edit/test/representers/EditRepresenterSpec.js b/platform/commonUI/edit/test/representers/EditRepresenterSpec.js
index 79b336202a..3dcaa34627 100644
--- a/platform/commonUI/edit/test/representers/EditRepresenterSpec.js
+++ b/platform/commonUI/edit/test/representers/EditRepresenterSpec.js
@@ -33,8 +33,8 @@ define(
testRepresentation,
mockDomainObject,
mockPersistence,
- mockCapabilities,
mockStatusCapability,
+ mockCapabilities,
representer;
function mockPromise(value) {
@@ -48,7 +48,7 @@ define(
beforeEach(function () {
mockQ = { when: mockPromise };
mockLog = jasmine.createSpyObj("$log", ["info", "debug"]);
- mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
+ mockScope = jasmine.createSpyObj("$scope", ["$watch", "$on"]);
testRepresentation = { key: "test" };
mockDomainObject = jasmine.createSpyObj("domainObject", [
"getId",
@@ -60,7 +60,7 @@ define(
mockPersistence =
jasmine.createSpyObj("persistence", ["persist"]);
mockStatusCapability =
- jasmine.createSpyObj("status", ["get"]);
+ jasmine.createSpyObj("statusCapability", ["get", "listen"]);
mockStatusCapability.get.andReturn(false);
mockCapabilities = {
'persistence': mockPersistence,
@@ -82,6 +82,17 @@ define(
expect(mockScope.commit).toEqual(jasmine.any(Function));
});
+ it("Sets edit view template on edit mode", function () {
+ mockStatusCapability.listen.mostRecentCall.args[0](['editing']);
+ expect(mockScope.viewObjectTemplate).toEqual('edit-object');
+ });
+
+ it("Cleans up listeners on scope destroy", function () {
+ representer.listenHandle = jasmine.createSpy('listen');
+ mockScope.$on.mostRecentCall.args[1]();
+ expect(representer.listenHandle).toHaveBeenCalled();
+ });
+
it("mutates and persists upon observed changes", function () {
mockScope.model = { someKey: "some value" };
mockScope.configuration = { someConfiguration: "something" };
@@ -112,4 +123,4 @@ define(
});
}
-);
\ No newline at end of file
+);