Addressing issues from code review

This commit is contained in:
Henry
2016-02-29 17:22:13 -08:00
parent 2cc2c6a9d3
commit f192544be3
13 changed files with 147 additions and 98 deletions

View File

@@ -111,9 +111,11 @@ define([
"$scope",
"$route",
"$location",
"$window",
"objectService",
"navigationService",
"urlService",
"policyService",
"DEFAULT_PATH"
]
},

View File

@@ -33,6 +33,7 @@ define(
"use strict";
var ROOT_ID = "ROOT",
DEFAULT_PATH = "mine",
CONFIRM_MSG = "Unsaved changes will be lost if you leave this page.";
/**
@@ -46,12 +47,14 @@ define(
* @constructor
*/
function BrowseController(
$scope,
$route,
$location,
objectService,
navigationService,
urlService,
$scope,
$route,
$location,
$window,
objectService,
navigationService,
urlService,
policyService,
defaultPath
) {
var path = [ROOT_ID].concat(
@@ -81,14 +84,22 @@ define(
// Callback for updating the in-scope reference to the object
// that is currently navigated-to.
function setNavigation(domainObject) {
var navigationAllowed = true;
if (domainObject === $scope.navigatedObject){
//do nothing;
return;
}
if (navigationService.setNavigation(domainObject)) {
policyService.allow("navigation", $scope.navigatedObject, domainObject, function(message){
navigationAllowed = $window.confirm(message + "\r\n\r\n" +
" Are you sure you want to continue?");
});
if (navigationAllowed) {
$scope.navigatedObject = domainObject;
$scope.treeModel.selectedObject = domainObject;
navigationService.setNavigation(domainObject);
updateRoute(domainObject);
} else {
//If navigation was unsuccessful (ie. blocked), reset

View File

@@ -37,7 +37,7 @@ define(
*/
function NavigationService() {
this.navigated = undefined;
this.callbacks = {};
this.callbacks = [];
}
/**
@@ -50,48 +50,27 @@ define(
/**
* Set the current navigation state. This will invoke listeners.
* Changing the navigation state will be blocked if any of the
* 'before' navigation state change listeners return 'false'.
* @param {DomainObject} domainObject the domain object to navigate to
*/
NavigationService.prototype.setNavigation = function (value) {
var canNavigate = true;
if (this.navigated !== value) {
canNavigate = (this.callbacks.before || [])
.reduce(function (previous, callback) {
//Check whether the callback returned a value of
// 'false' indicating that navigation should not
// continue. All other return values will allow
// navigation to continue
return (callback(value)!==false) && previous;
}, true);
if (canNavigate) {
this.navigated = value;
(this.callbacks.after || []).forEach(function (callback) {
callback(value);
});
}
this.navigated = value;
this.callbacks.forEach(function (callback) {
callback(value);
});
}
return canNavigate;
return true;
};
/**
* Listen for changes in navigation. The passed callback will
* be invoked with the new domain object of navigation when
* this changes. Callbacks can be registered to listen to pre or
* post-navigation events. The event to listen to is specified using
* the event parameter. In the case of pre-navigation events
* returning a false value will prevent the navigation event from
* going ahead.
* this changes.
* @param {function} callback the callback to invoke when
* navigation state changes
* @param {string} [event=after] the navigation event to listen to.
* One of 'before' or 'after'.
*/
NavigationService.prototype.addListener = function (callback, event) {
event = event || 'after';
this.callbacks[event] = this.callbacks[event] || [];
this.callbacks[event].push(callback);
NavigationService.prototype.addListener = function (callback) {
this.callbacks.push(callback);
};
/**
@@ -99,12 +78,9 @@ define(
* @param {function} callback the callback which should
* no longer be invoked when navigation state
* changes
* @param {string} [event=after] the navigation event that the
* callback is registered to. One of 'before' or 'after'.
*/
NavigationService.prototype.removeListener = function (callback, event) {
event = event || 'after';
this.callbacks[event] = this.callbacks[event].filter(function (cb) {
NavigationService.prototype.removeListener = function (callback) {
this.callbacks = this.callbacks.filter(function (cb) {
return cb !== callback;
});
};

View File

@@ -39,6 +39,8 @@ define(
mockUrlService,
mockDomainObject,
mockNextObject,
mockWindow,
mockPolicyService,
testDefaultRoot,
controller;
@@ -55,14 +57,25 @@ define(
mockScope,
mockRoute,
mockLocation,
mockWindow,
mockObjectService,
mockNavigationService,
mockUrlService,
mockPolicyService,
testDefaultRoot
);
}
beforeEach(function () {
mockWindow = jasmine.createSpyObj('$window', [
"confirm"
]);
mockWindow.confirm.andReturn(true);
mockPolicyService = jasmine.createSpyObj('policyService', [
'allow'
]);
testDefaultRoot = "some-root-level-domain-object";
mockScope = jasmine.createSpyObj(

View File

@@ -84,24 +84,6 @@ 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);
});
});
}
);