mirror of
https://github.com/nasa/openmct.git
synced 2024-12-30 09:58:52 +00:00
[Navigation] navigationService provides checking
Remove policy checking in navigation action and depend on navigation service to provide those checks. * Register checkFunctions with navigationService.checkBeforeNavigation which returns a function for unregistering them. * navigationService.setNavigation will run checks before allowing navigation, unless a `force` argument is supplied. https://github.com/nasa/openmct/issues/1360
This commit is contained in:
parent
f0b9292458
commit
f2d61604f7
@ -198,7 +198,10 @@ define([
|
|||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"key": "navigationService",
|
"key": "navigationService",
|
||||||
"implementation": NavigationService
|
"implementation": NavigationService,
|
||||||
|
"depends": [
|
||||||
|
"$window"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actions": [
|
"actions": [
|
||||||
@ -206,10 +209,7 @@ define([
|
|||||||
"key": "navigate",
|
"key": "navigate",
|
||||||
"implementation": NavigateAction,
|
"implementation": NavigateAction,
|
||||||
"depends": [
|
"depends": [
|
||||||
"navigationService",
|
"navigationService"
|
||||||
"$q",
|
|
||||||
"policyService",
|
|
||||||
"$window"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -33,12 +33,9 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @implements {Action}
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function NavigateAction(navigationService, $q, policyService, $window, context) {
|
function NavigateAction(navigationService, context) {
|
||||||
this.domainObject = context.domainObject;
|
this.domainObject = context.domainObject;
|
||||||
this.$q = $q;
|
|
||||||
this.navigationService = navigationService;
|
this.navigationService = navigationService;
|
||||||
this.policyService = policyService;
|
|
||||||
this.$window = $window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,32 +48,12 @@ define(
|
|||||||
navigateTo = this.domainObject,
|
navigateTo = this.domainObject,
|
||||||
currentObject = self.navigationService.getNavigation();
|
currentObject = self.navigationService.getNavigation();
|
||||||
|
|
||||||
function allow() {
|
if (this.navigationService.shouldNavigate()) {
|
||||||
var navigationAllowed = true;
|
this.navigationService.setNavigation(this.domainObject, true);
|
||||||
self.policyService.allow("navigation", currentObject, navigateTo, function (message) {
|
return Promise.resolve({});
|
||||||
navigationAllowed = self.$window.confirm(message + "\r\n\r\n" +
|
|
||||||
" Are you sure you want to continue?");
|
|
||||||
});
|
|
||||||
return navigationAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelIfEditing() {
|
|
||||||
var editing = currentObject.hasCapability('editor') &&
|
|
||||||
currentObject.getCapability('editor').isEditContextRoot();
|
|
||||||
|
|
||||||
return self.$q.when(editing && currentObject.getCapability("editor").finish());
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigate() {
|
|
||||||
return self.navigationService.setNavigation(navigateTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allow()) {
|
|
||||||
return cancelIfEditing().then(navigate);
|
|
||||||
} else {
|
|
||||||
return this.$q.when(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.reject('Navigation Prevented by User');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,16 +30,20 @@ define(
|
|||||||
/**
|
/**
|
||||||
* The navigation service maintains the application's current
|
* The navigation service maintains the application's current
|
||||||
* navigation state, and allows listening for changes thereto.
|
* navigation state, and allows listening for changes thereto.
|
||||||
|
*
|
||||||
* @memberof platform/commonUI/browse
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function NavigationService() {
|
function NavigationService($window) {
|
||||||
this.navigated = undefined;
|
this.navigated = undefined;
|
||||||
this.callbacks = [];
|
this.callbacks = [];
|
||||||
|
this.checks = [];
|
||||||
|
this.$window = $window;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current navigation state.
|
* Get the current navigation state.
|
||||||
|
*
|
||||||
* @returns {DomainObject} the object that is navigated-to
|
* @returns {DomainObject} the object that is navigated-to
|
||||||
*/
|
*/
|
||||||
NavigationService.prototype.getNavigation = function () {
|
NavigationService.prototype.getNavigation = function () {
|
||||||
@ -47,16 +51,33 @@ define(
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current navigation state. This will invoke listeners.
|
* Navigate to a specified object. If navigation checks exist and
|
||||||
|
* return reasons to prevent navigation, it will prompt the user before
|
||||||
|
* continuing. Trying to navigate to the currently navigated object will
|
||||||
|
* do nothing.
|
||||||
|
*
|
||||||
|
* If a truthy value is passed for `force`, it will skip navigation
|
||||||
|
* and will not prevent navigation to an already selected object.
|
||||||
|
*
|
||||||
* @param {DomainObject} domainObject the domain object to navigate to
|
* @param {DomainObject} domainObject the domain object to navigate to
|
||||||
|
* @param {Boolean} force if true, force navigation to occur.
|
||||||
|
* @returns {Boolean} true if navigation occured, otherwise false.
|
||||||
*/
|
*/
|
||||||
NavigationService.prototype.setNavigation = function (value) {
|
NavigationService.prototype.setNavigation = function (domainObject, force) {
|
||||||
if (this.navigated !== value) {
|
if (force) {
|
||||||
this.navigated = value;
|
this.doNavigation(domainObject);
|
||||||
this.callbacks.forEach(function (callback) {
|
return true;
|
||||||
callback(value);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (this.navigated === domainObject) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var doNotNavigate = this.shouldWarnBeforeNavigate();
|
||||||
|
if (doNotNavigate && !this.$window.confirm(doNotNavigate)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doNavigation(domainObject);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -64,6 +85,7 @@ define(
|
|||||||
* Listen for changes in navigation. The passed callback will
|
* Listen for changes in navigation. The passed callback will
|
||||||
* be invoked with the new domain object of navigation when
|
* be invoked with the new domain object of navigation when
|
||||||
* this changes.
|
* this changes.
|
||||||
|
*
|
||||||
* @param {function} callback the callback to invoke when
|
* @param {function} callback the callback to invoke when
|
||||||
* navigation state changes
|
* navigation state changes
|
||||||
*/
|
*/
|
||||||
@ -73,6 +95,7 @@ define(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop listening for changes in navigation state.
|
* Stop listening for changes in navigation state.
|
||||||
|
*
|
||||||
* @param {function} callback the callback which should
|
* @param {function} callback the callback which should
|
||||||
* no longer be invoked when navigation state
|
* no longer be invoked when navigation state
|
||||||
* changes
|
* changes
|
||||||
@ -83,6 +106,73 @@ define(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if navigation should proceed. May prompt a user for input
|
||||||
|
* if any checkFns return messages. Returns true if the user wishes to
|
||||||
|
* navigate, otherwise false. If using this prior to calling
|
||||||
|
* `setNavigation`, you should call `setNavigation` with `force=true`
|
||||||
|
* to prevent duplicate dialogs being displayed to the user.
|
||||||
|
*
|
||||||
|
* @returns {Boolean} true if the user wishes to navigate, otherwise false.
|
||||||
|
*/
|
||||||
|
NavigationService.prototype.shouldNavigate = function () {
|
||||||
|
var doNotNavigate = this.shouldWarnBeforeNavigate();
|
||||||
|
return !doNotNavigate || this.$window.confirm(doNotNavigate);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a check function to be called before any navigation occurs.
|
||||||
|
* Check functions should return a human readable "message" if
|
||||||
|
* there are any reasons to prevent navigation. Otherwise, they should
|
||||||
|
* return falsy. Returns a function which can be called to remove the
|
||||||
|
* check function.
|
||||||
|
*
|
||||||
|
* @param {Function} checkFn a function to call before navigation occurs.
|
||||||
|
* @returns {Function} removeCheck call to remove check
|
||||||
|
*/
|
||||||
|
NavigationService.prototype.checkBeforeNavigation = function (checkFn) {
|
||||||
|
this.checks.push(checkFn);
|
||||||
|
return function removeCheck() {
|
||||||
|
this.checks = this.checks.filter(function (fn) {
|
||||||
|
return checkFn !== fn;
|
||||||
|
});
|
||||||
|
}.bind(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private method to actually perform navigation.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
NavigationService.prototype.doNavigation = function (value) {
|
||||||
|
this.navigated = value;
|
||||||
|
this.callbacks.forEach(function (callback) {
|
||||||
|
callback(value);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns either a false value, or a string that should be displayed
|
||||||
|
* to the user before navigation is allowed.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
NavigationService.prototype.shouldWarnBeforeNavigate = function () {
|
||||||
|
var reasons = [];
|
||||||
|
|
||||||
|
this.checks.forEach(function (checkFn) {
|
||||||
|
var reason = checkFn();
|
||||||
|
if (reason) {
|
||||||
|
reasons.push(reason);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (reasons.length) {
|
||||||
|
return reasons.join('\n');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
return NavigationService;
|
return NavigationService;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user