mirror of
https://github.com/nasa/openmct.git
synced 2025-03-11 23:14:16 +00:00
Merge pull request #712 from nasa/open627_no_regions_master
[Edit Mode] #627 Remove edit-related concerns from Browse controllers
This commit is contained in:
commit
75178576dd
@ -111,10 +111,11 @@ define([
|
|||||||
"$scope",
|
"$scope",
|
||||||
"$route",
|
"$route",
|
||||||
"$location",
|
"$location",
|
||||||
"$q",
|
"$window",
|
||||||
"objectService",
|
"objectService",
|
||||||
"navigationService",
|
"navigationService",
|
||||||
"urlService",
|
"urlService",
|
||||||
|
"policyService",
|
||||||
"DEFAULT_PATH"
|
"DEFAULT_PATH"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -134,9 +135,7 @@ define([
|
|||||||
"depends": [
|
"depends": [
|
||||||
"$scope",
|
"$scope",
|
||||||
"$location",
|
"$location",
|
||||||
"$route",
|
"$route"
|
||||||
"$q",
|
|
||||||
"navigationService"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -170,6 +169,10 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"representations": [
|
"representations": [
|
||||||
|
{
|
||||||
|
"key": "view-object",
|
||||||
|
"templateUrl": "templates/view-object.html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "browse-object",
|
"key": "browse-object",
|
||||||
"template": browseObjectTemplate,
|
"template": browseObjectTemplate,
|
||||||
|
@ -47,11 +47,6 @@
|
|||||||
<div ng-if="isEditable" class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
|
<div ng-if="isEditable" class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
|
||||||
<!-- Toolbar and Save/Cancel buttons -->
|
<!-- Toolbar and Save/Cancel buttons -->
|
||||||
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
|
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
|
||||||
<mct-toolbar name="mctToolbar"
|
|
||||||
structure="toolbar.structure"
|
|
||||||
ng-model="toolbar.state"
|
|
||||||
class="flex-elem grows">
|
|
||||||
</mct-toolbar>
|
|
||||||
<mct-representation key="'edit-action-buttons'"
|
<mct-representation key="'edit-action-buttons'"
|
||||||
mct-object="domainObject"
|
mct-object="domainObject"
|
||||||
class='flex-elem conclude-editing'>
|
class='flex-elem conclude-editing'>
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
<mct-split-pane class='l-object-and-inspector contents abs' anchor='right'>
|
<mct-split-pane class='l-object-and-inspector contents abs' anchor='right'>
|
||||||
<div class='split-pane-component t-object pane primary-pane left'>
|
<div class='split-pane-component t-object pane primary-pane left'>
|
||||||
<mct-representation mct-object="navigatedObject"
|
<mct-representation mct-object="navigatedObject"
|
||||||
key="'browse-object'"
|
key="'view-object'"
|
||||||
class="abs holder holder-object">
|
class="abs holder holder-object">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,14 +19,15 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<div content="jquery-wrapper"
|
<!--
|
||||||
class="abs holder-all edit-mode"
|
A representation that allows the 'View' region of an object view to change
|
||||||
ng-controller="EditController as editMode"
|
dynamically (eg. between browse and edit modes). Values correspond to a
|
||||||
mct-before-unload="editMode.getUnloadWarning()">
|
representation key, and currently defaults to 'browse-object'.
|
||||||
|
|
||||||
<mct-representation key="'edit-object'" mct-object="editMode.navigatedObject()">
|
In the case of edit, the EditRepresenter will change this to editable
|
||||||
|
representation of the object as needed.
|
||||||
|
-->
|
||||||
|
<mct-representation mct-object="domainObject"
|
||||||
|
key="viewObjectTemplate || 'browse-object'"
|
||||||
|
class="abs holder holder-object">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
|
|
||||||
<mct-include key="'bottombar'"></mct-include>
|
|
||||||
|
|
||||||
</div>
|
|
@ -27,14 +27,12 @@
|
|||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'../../../representation/src/gestures/GestureConstants',
|
'../../../representation/src/gestures/GestureConstants'
|
||||||
'../../edit/src/objects/EditableDomainObject'
|
|
||||||
],
|
],
|
||||||
function (GestureConstants, EditableDomainObject) {
|
function (GestureConstants) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var ROOT_ID = "ROOT",
|
var ROOT_ID = "ROOT";
|
||||||
CONFIRM_MSG = "Unsaved changes will be lost if you leave this page.";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The BrowseController is used to populate the initial scope in Browse
|
* The BrowseController is used to populate the initial scope in Browse
|
||||||
@ -50,23 +48,17 @@ define(
|
|||||||
$scope,
|
$scope,
|
||||||
$route,
|
$route,
|
||||||
$location,
|
$location,
|
||||||
$q,
|
$window,
|
||||||
objectService,
|
objectService,
|
||||||
navigationService,
|
navigationService,
|
||||||
urlService,
|
urlService,
|
||||||
|
policyService,
|
||||||
defaultPath
|
defaultPath
|
||||||
) {
|
) {
|
||||||
var path = [ROOT_ID].concat(
|
var path = [ROOT_ID].concat(
|
||||||
($route.current.params.ids || defaultPath).split("/")
|
($route.current.params.ids || defaultPath).split("/")
|
||||||
);
|
);
|
||||||
|
|
||||||
function isDirty(){
|
|
||||||
var editorCapability = $scope.navigatedObject &&
|
|
||||||
$scope.navigatedObject.getCapability("editor"),
|
|
||||||
hasChanges = editorCapability && editorCapability.dirty();
|
|
||||||
return hasChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateRoute(domainObject) {
|
function updateRoute(domainObject) {
|
||||||
var priorRoute = $route.current,
|
var priorRoute = $route.current,
|
||||||
// Act as if params HADN'T changed to avoid page reload
|
// Act as if params HADN'T changed to avoid page reload
|
||||||
@ -83,31 +75,35 @@ define(
|
|||||||
// urlService.urlForLocation used to adjust current
|
// urlService.urlForLocation used to adjust current
|
||||||
// path to new, addressed, path based on
|
// path to new, addressed, path based on
|
||||||
// domainObject
|
// domainObject
|
||||||
$location.path(urlService.urlForLocation("browse",
|
$location.path(urlService.urlForLocation("browse", domainObject));
|
||||||
domainObject.hasCapability('editor') ?
|
|
||||||
domainObject.getOriginalObject() : domainObject));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback for updating the in-scope reference to the object
|
// Callback for updating the in-scope reference to the object
|
||||||
// that is currently navigated-to.
|
// that is currently navigated-to.
|
||||||
function setNavigation(domainObject) {
|
function setNavigation(domainObject) {
|
||||||
|
var navigationAllowed = true;
|
||||||
|
|
||||||
if (domainObject === $scope.navigatedObject){
|
if (domainObject === $scope.navigatedObject){
|
||||||
//do nothing;
|
//do nothing;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDirty() && !confirm(CONFIRM_MSG)) {
|
policyService.allow("navigation", $scope.navigatedObject, domainObject, function(message){
|
||||||
$scope.treeModel.selectedObject = $scope.navigatedObject;
|
navigationAllowed = $window.confirm(message + "\r\n\r\n" +
|
||||||
navigationService.setNavigation($scope.navigatedObject);
|
" Are you sure you want to continue?");
|
||||||
} else {
|
});
|
||||||
if ($scope.navigatedObject && $scope.navigatedObject.hasCapability("editor")){
|
|
||||||
$scope.navigatedObject.getCapability("editor").cancel();
|
if (navigationAllowed) {
|
||||||
}
|
|
||||||
$scope.navigatedObject = domainObject;
|
$scope.navigatedObject = domainObject;
|
||||||
$scope.treeModel.selectedObject = domainObject;
|
$scope.treeModel.selectedObject = domainObject;
|
||||||
navigationService.setNavigation(domainObject);
|
navigationService.setNavigation(domainObject);
|
||||||
updateRoute(domainObject);
|
updateRoute(domainObject);
|
||||||
|
} else {
|
||||||
|
//If navigation was unsuccessful (ie. blocked), reset
|
||||||
|
// the selected object in the tree to the currently
|
||||||
|
// navigated object
|
||||||
|
$scope.treeModel.selectedObject = $scope.navigatedObject ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,16 +180,11 @@ define(
|
|||||||
selectedObject: navigationService.getNavigation()
|
selectedObject: navigationService.getNavigation()
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.beforeUnloadWarning = function() {
|
|
||||||
return isDirty() ?
|
|
||||||
"Unsaved changes will be lost if you leave this page." :
|
|
||||||
undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Listen for changes in navigation state.
|
// Listen for changes in navigation state.
|
||||||
navigationService.addListener(setNavigation);
|
navigationService.addListener(setNavigation);
|
||||||
|
|
||||||
// Also listen for changes which come from the tree
|
// Also listen for changes which come from the tree. Changes in
|
||||||
|
// the tree will trigger a change in browse navigation state.
|
||||||
$scope.$watch("treeModel.selectedObject", setNavigation);
|
$scope.$watch("treeModel.selectedObject", setNavigation);
|
||||||
|
|
||||||
// Clean up when the scope is destroyed
|
// Clean up when the scope is destroyed
|
||||||
|
@ -22,11 +22,8 @@
|
|||||||
/*global define,Promise*/
|
/*global define,Promise*/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
[
|
[],
|
||||||
'../../../representation/src/gestures/GestureConstants',
|
function () {
|
||||||
'../../edit/src/objects/EditableDomainObject'
|
|
||||||
],
|
|
||||||
function (GestureConstants, EditableDomainObject) {
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,7 +32,7 @@ define(
|
|||||||
* @memberof platform/commonUI/browse
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function BrowseObjectController($scope, $location, $route, $q, navigationService) {
|
function BrowseObjectController($scope, $location, $route) {
|
||||||
var navigatedObject;
|
var navigatedObject;
|
||||||
function setViewForDomainObject(domainObject) {
|
function setViewForDomainObject(domainObject) {
|
||||||
|
|
||||||
@ -57,10 +54,9 @@ define(
|
|||||||
|
|
||||||
function updateQueryParam(viewKey) {
|
function updateQueryParam(viewKey) {
|
||||||
var unlisten,
|
var unlisten,
|
||||||
priorRoute = $route.current,
|
priorRoute = $route.current;
|
||||||
isEditMode = $scope.domainObject && $scope.domainObject.hasCapability('editor');
|
|
||||||
|
|
||||||
if (viewKey && !isEditMode) {
|
if (viewKey) {
|
||||||
$location.search('view', viewKey);
|
$location.search('view', viewKey);
|
||||||
unlisten = $scope.$on('$locationChangeSuccess', function () {
|
unlisten = $scope.$on('$locationChangeSuccess', function () {
|
||||||
// Checks path to make sure /browse/ is at front
|
// Checks path to make sure /browse/ is at front
|
||||||
@ -76,10 +72,6 @@ define(
|
|||||||
$scope.$watch('domainObject', setViewForDomainObject);
|
$scope.$watch('domainObject', setViewForDomainObject);
|
||||||
$scope.$watch('representation.selected.key', updateQueryParam);
|
$scope.$watch('representation.selected.key', updateQueryParam);
|
||||||
|
|
||||||
$scope.cancelEditing = function() {
|
|
||||||
navigationService.setNavigation($scope.domainObject.getDomainObject());
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.doAction = function (action){
|
$scope.doAction = function (action){
|
||||||
return $scope[action] && $scope[action]();
|
return $scope[action] && $scope[action]();
|
||||||
};
|
};
|
||||||
|
@ -59,6 +59,7 @@ define(
|
|||||||
callback(value);
|
callback(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,8 +29,7 @@ define(
|
|||||||
function (BrowseController) {
|
function (BrowseController) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
//TODO: Disabled for NEM Beta
|
describe("The browse controller", function () {
|
||||||
xdescribe("The browse controller", function () {
|
|
||||||
var mockScope,
|
var mockScope,
|
||||||
mockRoute,
|
mockRoute,
|
||||||
mockLocation,
|
mockLocation,
|
||||||
@ -40,6 +39,8 @@ define(
|
|||||||
mockUrlService,
|
mockUrlService,
|
||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockNextObject,
|
mockNextObject,
|
||||||
|
mockWindow,
|
||||||
|
mockPolicyService,
|
||||||
testDefaultRoot,
|
testDefaultRoot,
|
||||||
controller;
|
controller;
|
||||||
|
|
||||||
@ -56,14 +57,25 @@ define(
|
|||||||
mockScope,
|
mockScope,
|
||||||
mockRoute,
|
mockRoute,
|
||||||
mockLocation,
|
mockLocation,
|
||||||
|
mockWindow,
|
||||||
mockObjectService,
|
mockObjectService,
|
||||||
mockNavigationService,
|
mockNavigationService,
|
||||||
mockUrlService,
|
mockUrlService,
|
||||||
|
mockPolicyService,
|
||||||
testDefaultRoot
|
testDefaultRoot
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
mockWindow = jasmine.createSpyObj('$window', [
|
||||||
|
"confirm"
|
||||||
|
]);
|
||||||
|
mockWindow.confirm.andReturn(true);
|
||||||
|
|
||||||
|
mockPolicyService = jasmine.createSpyObj('policyService', [
|
||||||
|
'allow'
|
||||||
|
]);
|
||||||
|
|
||||||
testDefaultRoot = "some-root-level-domain-object";
|
testDefaultRoot = "some-root-level-domain-object";
|
||||||
|
|
||||||
mockScope = jasmine.createSpyObj(
|
mockScope = jasmine.createSpyObj(
|
||||||
@ -214,7 +226,10 @@ define(
|
|||||||
// prior to setting $route.current
|
// prior to setting $route.current
|
||||||
mockLocation.path.andReturn("/browse/");
|
mockLocation.path.andReturn("/browse/");
|
||||||
|
|
||||||
|
mockNavigationService.setNavigation.andReturn(true);
|
||||||
|
|
||||||
// Exercise the Angular workaround
|
// Exercise the Angular workaround
|
||||||
|
mockNavigationService.addListener.mostRecentCall.args[0]();
|
||||||
mockScope.$on.mostRecentCall.args[1]();
|
mockScope.$on.mostRecentCall.args[1]();
|
||||||
expect(mockUnlisten).toHaveBeenCalled();
|
expect(mockUnlisten).toHaveBeenCalled();
|
||||||
|
|
||||||
@ -225,6 +240,36 @@ 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;
|
||||||
|
mockWindow.confirm.andReturn(false);
|
||||||
|
mockPolicyService.allow.andCallFake(function(category, object, context, callback){
|
||||||
|
callback("unsaved changes");
|
||||||
|
return 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);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -22,10 +22,10 @@
|
|||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
"./src/controllers/EditController",
|
|
||||||
"./src/controllers/EditActionController",
|
"./src/controllers/EditActionController",
|
||||||
"./src/controllers/EditPanesController",
|
"./src/controllers/EditPanesController",
|
||||||
"./src/controllers/ElementsController",
|
"./src/controllers/ElementsController",
|
||||||
|
"./src/controllers/EditObjectController",
|
||||||
"./src/directives/MCTBeforeUnload",
|
"./src/directives/MCTBeforeUnload",
|
||||||
"./src/actions/LinkAction",
|
"./src/actions/LinkAction",
|
||||||
"./src/actions/EditAction",
|
"./src/actions/EditAction",
|
||||||
@ -34,9 +34,9 @@ define([
|
|||||||
"./src/actions/SaveAction",
|
"./src/actions/SaveAction",
|
||||||
"./src/actions/CancelAction",
|
"./src/actions/CancelAction",
|
||||||
"./src/policies/EditActionPolicy",
|
"./src/policies/EditActionPolicy",
|
||||||
|
"./src/policies/EditNavigationPolicy",
|
||||||
"./src/representers/EditRepresenter",
|
"./src/representers/EditRepresenter",
|
||||||
"./src/representers/EditToolbarRepresenter",
|
"./src/representers/EditToolbarRepresenter",
|
||||||
"text!./res/templates/edit.html",
|
|
||||||
"text!./res/templates/library.html",
|
"text!./res/templates/library.html",
|
||||||
"text!./res/templates/edit-object.html",
|
"text!./res/templates/edit-object.html",
|
||||||
"text!./res/templates/edit-action-buttons.html",
|
"text!./res/templates/edit-action-buttons.html",
|
||||||
@ -44,10 +44,10 @@ define([
|
|||||||
"text!./res/templates/topbar-edit.html",
|
"text!./res/templates/topbar-edit.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
EditController,
|
|
||||||
EditActionController,
|
EditActionController,
|
||||||
EditPanesController,
|
EditPanesController,
|
||||||
ElementsController,
|
ElementsController,
|
||||||
|
EditObjectController,
|
||||||
MCTBeforeUnload,
|
MCTBeforeUnload,
|
||||||
LinkAction,
|
LinkAction,
|
||||||
EditAction,
|
EditAction,
|
||||||
@ -56,9 +56,9 @@ define([
|
|||||||
SaveAction,
|
SaveAction,
|
||||||
CancelAction,
|
CancelAction,
|
||||||
EditActionPolicy,
|
EditActionPolicy,
|
||||||
|
EditNavigationPolicy,
|
||||||
EditRepresenter,
|
EditRepresenter,
|
||||||
EditToolbarRepresenter,
|
EditToolbarRepresenter,
|
||||||
editTemplate,
|
|
||||||
libraryTemplate,
|
libraryTemplate,
|
||||||
editObjectTemplate,
|
editObjectTemplate,
|
||||||
editActionButtonsTemplate,
|
editActionButtonsTemplate,
|
||||||
@ -70,22 +70,7 @@ define([
|
|||||||
|
|
||||||
legacyRegistry.register("platform/commonUI/edit", {
|
legacyRegistry.register("platform/commonUI/edit", {
|
||||||
"extensions": {
|
"extensions": {
|
||||||
"routes": [
|
|
||||||
{
|
|
||||||
"when": "/edit",
|
|
||||||
"template": editTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controllers": [
|
"controllers": [
|
||||||
{
|
|
||||||
"key": "EditController",
|
|
||||||
"implementation": EditController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"$q",
|
|
||||||
"navigationService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "EditActionController",
|
"key": "EditActionController",
|
||||||
"implementation": EditActionController,
|
"implementation": EditActionController,
|
||||||
@ -106,6 +91,15 @@ define([
|
|||||||
"depends": [
|
"depends": [
|
||||||
"$scope"
|
"$scope"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "EditObjectController",
|
||||||
|
"implementation": EditObjectController,
|
||||||
|
"depends": [
|
||||||
|
"$scope",
|
||||||
|
"$location",
|
||||||
|
"policyService"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"directives": [
|
"directives": [
|
||||||
@ -192,7 +186,13 @@ define([
|
|||||||
{
|
{
|
||||||
"category": "action",
|
"category": "action",
|
||||||
"implementation": EditActionPolicy
|
"implementation": EditActionPolicy
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "navigation",
|
||||||
|
"message": "There are unsaved changes.",
|
||||||
|
"implementation": EditNavigationPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
"templates": [
|
"templates": [
|
||||||
{
|
{
|
||||||
@ -206,6 +206,9 @@ define([
|
|||||||
"template": editObjectTemplate,
|
"template": editObjectTemplate,
|
||||||
"uses": [
|
"uses": [
|
||||||
"view"
|
"view"
|
||||||
|
],
|
||||||
|
"gestures": [
|
||||||
|
"drop"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -19,50 +19,51 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<mct-representation key="'topbar-edit'"
|
<div class="abs l-flex-col" ng-controller="EditObjectController as EditObjectController">
|
||||||
|
<div mct-before-unload="EditObjectController.getUnloadWarning()"
|
||||||
|
class="holder flex-elem l-flex-row object-browse-bar ">
|
||||||
|
<div class="items-select left flex-elem l-flex-row grows">
|
||||||
|
<mct-representation key="'back-arrow'"
|
||||||
|
mct-object="domainObject"
|
||||||
|
class="flex-elem l-back"></mct-representation>
|
||||||
|
<mct-representation key="'object-header'"
|
||||||
|
mct-object="domainObject"
|
||||||
|
class="l-flex-row flex-elem grows object-header">
|
||||||
|
</mct-representation>
|
||||||
|
</div>
|
||||||
|
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
|
||||||
|
<mct-representation key="'switcher'"
|
||||||
mct-object="domainObject"
|
mct-object="domainObject"
|
||||||
ng-model="representation">
|
ng-model="representation">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
<div class="holder edit-area abs">
|
<!-- Temporarily, on mobile, the action buttons are hidden-->
|
||||||
<mct-split-pane class='contents abs' anchor='right'>
|
<mct-representation key="'action-group'"
|
||||||
<div class='split-pane-component pane left edit-main'>
|
mct-object="domainObject"
|
||||||
|
parameters="{ category: 'view-control' }"
|
||||||
|
class="mobile-hide">
|
||||||
|
</mct-representation>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="holder l-flex-col flex-elem grows l-object-wrapper">
|
||||||
|
<div class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
|
||||||
|
<!-- Toolbar and Save/Cancel buttons -->
|
||||||
|
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
|
||||||
<mct-toolbar name="mctToolbar"
|
<mct-toolbar name="mctToolbar"
|
||||||
structure="toolbar.structure"
|
structure="toolbar.structure"
|
||||||
ng-model="toolbar.state">
|
ng-model="toolbar.state"
|
||||||
|
class="flex-elem grows">
|
||||||
</mct-toolbar>
|
</mct-toolbar>
|
||||||
|
<mct-representation key="'edit-action-buttons'"
|
||||||
|
mct-object="domainObject"
|
||||||
|
class='flex-elem conclude-editing'>
|
||||||
|
</mct-representation>
|
||||||
|
|
||||||
|
</div>
|
||||||
<mct-representation key="representation.selected.key"
|
<mct-representation key="representation.selected.key"
|
||||||
toolbar="toolbar"
|
|
||||||
mct-object="representation.selected.key && domainObject"
|
mct-object="representation.selected.key && domainObject"
|
||||||
class="holder abs object-holder work-area">
|
class="abs flex-elem grows object-holder-main scroll"
|
||||||
|
toolbar="toolbar">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
|
</div><!--/ l-object-wrapper-inner -->
|
||||||
</div>
|
</div>
|
||||||
<mct-splitter></mct-splitter>
|
|
||||||
<div
|
|
||||||
class='split-pane-component pane right edit-objects menus-to-left'
|
|
||||||
ng-controller='EditPanesController as editPanes'
|
|
||||||
>
|
|
||||||
<mct-split-pane class='contents abs' anchor='bottom'>
|
|
||||||
<div
|
|
||||||
class="abs pane top accordion"
|
|
||||||
ng-controller="ToggleController as toggle"
|
|
||||||
>
|
|
||||||
<mct-container key="accordion" label="Library">
|
|
||||||
<mct-representation key="'tree'"
|
|
||||||
mct-object="editPanes.getRoot()">
|
|
||||||
</mct-representation>
|
|
||||||
</mct-container>
|
|
||||||
</div>
|
|
||||||
<mct-splitter></mct-splitter>
|
|
||||||
<div
|
|
||||||
class="abs pane bottom accordion"
|
|
||||||
ng-controller="ToggleController as toggle"
|
|
||||||
>
|
|
||||||
<mct-container key="accordion" label="Elements">
|
|
||||||
<mct-representation key="'edit-elements'" mct-object="domainObject">
|
|
||||||
</mct-representation>
|
|
||||||
</mct-container>
|
|
||||||
</div>
|
|
||||||
</mct-split-pane>
|
|
||||||
</div>
|
|
||||||
</mct-split-pane>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -72,13 +72,26 @@ define(
|
|||||||
* Enter edit mode.
|
* Enter edit mode.
|
||||||
*/
|
*/
|
||||||
EditAction.prototype.perform = function () {
|
EditAction.prototype.perform = function () {
|
||||||
var editableObject;
|
var self = this;
|
||||||
if (!this.domainObject.hasCapability("editor")) {
|
if (!this.domainObject.hasCapability("editor")) {
|
||||||
editableObject = new EditableDomainObject(this.domainObject, this.$q);
|
//TODO: This is only necessary because the drop gesture is
|
||||||
editableObject.getCapability('status').set('editing', true);
|
// wrapping the object itself, need to refactor this later.
|
||||||
this.navigationService.setNavigation(editableObject);
|
// All responsibility for switching into edit mode should be
|
||||||
|
// in the edit action, and not duplicated in the gesture
|
||||||
|
this.domainObject = new EditableDomainObject(this.domainObject, this.$q);
|
||||||
}
|
}
|
||||||
//this.$location.path("/edit");
|
this.navigationService.setNavigation(this.domainObject);
|
||||||
|
this.domainObject.getCapability('status').set('editing', true);
|
||||||
|
|
||||||
|
//Register a listener to automatically cancel this edit action
|
||||||
|
//if the user navigates away from this object.
|
||||||
|
function cancelEditing(navigatedTo){
|
||||||
|
if (!navigatedTo || navigatedTo.getId() !== self.domainObject.getId()) {
|
||||||
|
self.domainObject.getCapability('editor').cancel();
|
||||||
|
self.navigationService.removeListener(cancelEditing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.navigationService.addListener(cancelEditing);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,7 +124,6 @@ define(
|
|||||||
*/
|
*/
|
||||||
EditorCapability.prototype.cancel = function () {
|
EditorCapability.prototype.cancel = function () {
|
||||||
this.editableObject.getCapability("status").set("editing", false);
|
this.editableObject.getCapability("status").set("editing", false);
|
||||||
//TODO: Reset the cache as well here.
|
|
||||||
this.cache.markClean();
|
this.cache.markClean();
|
||||||
return resolvePromise(undefined);
|
return resolvePromise(undefined);
|
||||||
};
|
};
|
||||||
|
@ -26,41 +26,45 @@
|
|||||||
* @namespace platform/commonUI/edit
|
* @namespace platform/commonUI/edit
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
["../objects/EditableDomainObject"],
|
[],
|
||||||
function (EditableDomainObject) {
|
function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller which is responsible for populating the scope for
|
* Controller which is responsible for populating the scope for
|
||||||
* Edit mode; introduces an editable version of the currently
|
* Edit mode
|
||||||
* navigated domain object into the scope.
|
|
||||||
* @memberof platform/commonUI/edit
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditController($scope, $q, navigationService) {
|
function EditObjectController($scope, $location, policyService) {
|
||||||
var self = this;
|
this.scope = $scope;
|
||||||
|
this.policyService = policyService;
|
||||||
|
|
||||||
function setNavigation(domainObject) {
|
var navigatedObject;
|
||||||
// Wrap the domain object such that all mutation is
|
function setViewForDomainObject(domainObject) {
|
||||||
// confined to edit mode (until Save)
|
|
||||||
self.navigatedDomainObject =
|
var locationViewKey = $location.search().view;
|
||||||
domainObject && new EditableDomainObject(domainObject, $q);
|
|
||||||
|
function selectViewIfMatching(view) {
|
||||||
|
if (view.key === locationViewKey) {
|
||||||
|
$scope.representation = $scope.representation || {};
|
||||||
|
$scope.representation.selected = view;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setNavigation(navigationService.getNavigation());
|
if (locationViewKey) {
|
||||||
navigationService.addListener(setNavigation);
|
((domainObject && domainObject.useCapability('view')) || [])
|
||||||
$scope.$on("$destroy", function () {
|
.forEach(selectViewIfMatching);
|
||||||
navigationService.removeListener(setNavigation);
|
}
|
||||||
});
|
navigatedObject = domainObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$scope.$watch('domainObject', setViewForDomainObject);
|
||||||
* Get the domain object which is navigated-to.
|
|
||||||
* @returns {DomainObject} the domain object that is navigated-to
|
$scope.doAction = function (action){
|
||||||
*/
|
return $scope[action] && $scope[action]();
|
||||||
EditController.prototype.navigatedObject = function () {
|
|
||||||
return this.navigatedDomainObject;
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the warning to show if the user attempts to navigate
|
* Get the warning to show if the user attempts to navigate
|
||||||
@ -68,17 +72,18 @@ define(
|
|||||||
* @returns {string} the warning to show, or undefined if
|
* @returns {string} the warning to show, or undefined if
|
||||||
* there are no unsaved changes
|
* there are no unsaved changes
|
||||||
*/
|
*/
|
||||||
EditController.prototype.getUnloadWarning = function () {
|
EditObjectController.prototype.getUnloadWarning = function () {
|
||||||
var navigatedObject = this.navigatedDomainObject,
|
var navigatedObject = this.scope.domainObject,
|
||||||
editorCapability = navigatedObject &&
|
policyMessage;
|
||||||
navigatedObject.getCapability("editor"),
|
|
||||||
hasChanges = editorCapability && editorCapability.dirty();
|
this.policyService.allow("navigation", navigatedObject, undefined, function(message) {
|
||||||
|
policyMessage = message;
|
||||||
|
});
|
||||||
|
|
||||||
|
return policyMessage;
|
||||||
|
|
||||||
return hasChanges ?
|
|
||||||
"Unsaved changes will be lost if you leave this page." :
|
|
||||||
undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return EditController;
|
return EditObjectController;
|
||||||
}
|
}
|
||||||
);
|
);
|
67
platform/commonUI/edit/src/policies/EditNavigationPolicy.js
Normal file
67
platform/commonUI/edit/src/policies/EditNavigationPolicy.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Policy controlling whether navigation events should proceed
|
||||||
|
* when object is being edited.
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @constructor
|
||||||
|
* @implements {Policy.<Action, ActionContext>}
|
||||||
|
*/
|
||||||
|
function EditNavigationPolicy(policyService) {
|
||||||
|
this.policyService = policyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
EditNavigationPolicy.prototype.isDirty = function(domainObject) {
|
||||||
|
var navigatedObject = domainObject,
|
||||||
|
editorCapability = navigatedObject &&
|
||||||
|
navigatedObject.getCapability("editor"),
|
||||||
|
statusCapability = navigatedObject &&
|
||||||
|
navigatedObject.getCapability("status");
|
||||||
|
|
||||||
|
return statusCapability && statusCapability.get('editing')
|
||||||
|
&& editorCapability && editorCapability.dirty();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow navigation if an object is not dirty, or if the user elects
|
||||||
|
* to proceed anyway.
|
||||||
|
* @param currentNavigation
|
||||||
|
* @returns {boolean|*} true if the object model is clean; or if
|
||||||
|
* it's dirty and the user wishes to proceed anyway.
|
||||||
|
*/
|
||||||
|
EditNavigationPolicy.prototype.allow = function (currentNavigation) {
|
||||||
|
return !this.isDirty(currentNavigation);
|
||||||
|
};
|
||||||
|
|
||||||
|
return EditNavigationPolicy;
|
||||||
|
}
|
||||||
|
);
|
@ -49,6 +49,7 @@ define(
|
|||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
|
this.listenHandle = undefined;
|
||||||
|
|
||||||
// Mutate and persist a new version of a domain object's model.
|
// Mutate and persist a new version of a domain object's model.
|
||||||
function doPersist(model) {
|
function doPersist(model) {
|
||||||
@ -100,10 +101,18 @@ define(
|
|||||||
// Place the "commit" method in the scope
|
// Place the "commit" method in the scope
|
||||||
scope.commit = commit;
|
scope.commit = commit;
|
||||||
scope.setEditable = setEditable;
|
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
|
// Handle a specific representation of a specific domain object
|
||||||
EditRepresenter.prototype.represent = function represent(representation, representedObject) {
|
EditRepresenter.prototype.represent = function represent(representation, representedObject) {
|
||||||
|
var scope = this.scope,
|
||||||
|
self = this;
|
||||||
// Track the key, to know which view configuration to save to.
|
// Track the key, to know which view configuration to save to.
|
||||||
this.key = (representation || {}).key;
|
this.key = (representation || {}).key;
|
||||||
// Track the represented object
|
// Track the represented object
|
||||||
@ -113,11 +122,32 @@ define(
|
|||||||
|
|
||||||
// Ensure existing watches are released
|
// Ensure existing watches are released
|
||||||
this.destroy();
|
this.destroy();
|
||||||
|
|
||||||
|
function setEditing(){
|
||||||
|
scope.viewObjectTemplate = 'edit-object';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for changes in object state. If the object becomes
|
||||||
|
* editable then change the view and inspector regions
|
||||||
|
* object representation accordingly
|
||||||
|
*/
|
||||||
|
this.listenHandle = this.domainObject.getCapability('status').listen(function(statuses){
|
||||||
|
if (statuses.indexOf('editing')!=-1){
|
||||||
|
setEditing();
|
||||||
|
} else {
|
||||||
|
delete scope.viewObjectTemplate;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (representedObject.getCapability('status').get('editing')){
|
||||||
|
setEditing();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Respond to the destruction of the current representation.
|
// Respond to the destruction of the current representation.
|
||||||
EditRepresenter.prototype.destroy = function destroy() {
|
EditRepresenter.prototype.destroy = function destroy() {
|
||||||
// Nothing to clean up
|
return this.listenHandle && this.listenHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
return EditRepresenter;
|
return EditRepresenter;
|
||||||
|
@ -22,102 +22,110 @@
|
|||||||
/*global define,describe,it,expect,beforeEach,jasmine*/
|
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
["../../src/controllers/EditController"],
|
["../../src/controllers/EditObjectController"],
|
||||||
function (EditController) {
|
function (EditObjectController) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("The Edit mode controller", function () {
|
describe("The Edit mode controller", function () {
|
||||||
var mockScope,
|
var mockScope,
|
||||||
mockQ,
|
|
||||||
mockNavigationService,
|
|
||||||
mockObject,
|
mockObject,
|
||||||
mockType,
|
mockType,
|
||||||
|
mockLocation,
|
||||||
|
mockStatusCapability,
|
||||||
|
mockCapabilities,
|
||||||
|
mockPolicyService,
|
||||||
controller;
|
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 () {
|
beforeEach(function () {
|
||||||
|
mockPolicyService = jasmine.createSpyObj(
|
||||||
|
"policyService",
|
||||||
|
[
|
||||||
|
"allow"
|
||||||
|
]
|
||||||
|
);
|
||||||
mockScope = jasmine.createSpyObj(
|
mockScope = jasmine.createSpyObj(
|
||||||
"$scope",
|
"$scope",
|
||||||
[ "$on" ]
|
[ "$on", "$watch" ]
|
||||||
);
|
|
||||||
mockQ = jasmine.createSpyObj('$q', ['when', 'all']);
|
|
||||||
mockNavigationService = jasmine.createSpyObj(
|
|
||||||
"navigationService",
|
|
||||||
[ "getNavigation", "addListener", "removeListener" ]
|
|
||||||
);
|
);
|
||||||
mockObject = jasmine.createSpyObj(
|
mockObject = jasmine.createSpyObj(
|
||||||
"domainObject",
|
"domainObject",
|
||||||
[ "getId", "getModel", "getCapability", "hasCapability" ]
|
[ "getId", "getModel", "getCapability", "hasCapability", "useCapability" ]
|
||||||
);
|
);
|
||||||
mockType = jasmine.createSpyObj(
|
mockType = jasmine.createSpyObj(
|
||||||
"type",
|
"type",
|
||||||
[ "hasFeature" ]
|
[ "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.getId.andReturn("test");
|
||||||
mockObject.getModel.andReturn({ name: "Test object" });
|
mockObject.getModel.andReturn({ name: "Test object" });
|
||||||
mockObject.getCapability.andCallFake(function (key) {
|
mockObject.getCapability.andCallFake(function (key) {
|
||||||
return key === 'type' && mockType;
|
return mockCapabilities[key];
|
||||||
});
|
});
|
||||||
mockType.hasFeature.andReturn(true);
|
mockType.hasFeature.andReturn(true);
|
||||||
|
|
||||||
controller = new EditController(
|
mockScope.domainObject = mockObject;
|
||||||
|
|
||||||
|
controller = new EditObjectController(
|
||||||
mockScope,
|
mockScope,
|
||||||
mockQ,
|
mockLocation,
|
||||||
mockNavigationService
|
mockPolicyService
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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 () {
|
it("exposes a warning message for unload", function () {
|
||||||
var obj = controller.navigatedObject(),
|
var obj = mockObject,
|
||||||
mockEditor = jasmine.createSpyObj('editor', ['dirty']);
|
errorMessage = "Unsaved changes";
|
||||||
|
|
||||||
// Normally, should be undefined
|
// Normally, should be undefined
|
||||||
expect(controller.getUnloadWarning()).toBeUndefined();
|
expect(controller.getUnloadWarning()).toBeUndefined();
|
||||||
|
|
||||||
// Override the object's editor capability, make it look
|
// Override the policy service to prevent navigation
|
||||||
// like there are unsaved changes.
|
mockPolicyService.allow.andCallFake(function(category, object, context, callback){
|
||||||
obj.getCapability = jasmine.createSpy();
|
callback(errorMessage);
|
||||||
obj.getCapability.andReturn(mockEditor);
|
});
|
||||||
mockEditor.dirty.andReturn(true);
|
|
||||||
|
|
||||||
// Should have some warning message here now
|
// Should have some warning message here now
|
||||||
expect(controller.getUnloadWarning()).toEqual(jasmine.any(String));
|
expect(controller.getUnloadWarning()).toEqual(errorMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
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]);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -33,8 +33,8 @@ define(
|
|||||||
testRepresentation,
|
testRepresentation,
|
||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockPersistence,
|
mockPersistence,
|
||||||
mockCapabilities,
|
|
||||||
mockStatusCapability,
|
mockStatusCapability,
|
||||||
|
mockCapabilities,
|
||||||
representer;
|
representer;
|
||||||
|
|
||||||
function mockPromise(value) {
|
function mockPromise(value) {
|
||||||
@ -48,7 +48,7 @@ define(
|
|||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockQ = { when: mockPromise };
|
mockQ = { when: mockPromise };
|
||||||
mockLog = jasmine.createSpyObj("$log", ["info", "debug"]);
|
mockLog = jasmine.createSpyObj("$log", ["info", "debug"]);
|
||||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
mockScope = jasmine.createSpyObj("$scope", ["$watch", "$on"]);
|
||||||
testRepresentation = { key: "test" };
|
testRepresentation = { key: "test" };
|
||||||
mockDomainObject = jasmine.createSpyObj("domainObject", [
|
mockDomainObject = jasmine.createSpyObj("domainObject", [
|
||||||
"getId",
|
"getId",
|
||||||
@ -60,7 +60,7 @@ define(
|
|||||||
mockPersistence =
|
mockPersistence =
|
||||||
jasmine.createSpyObj("persistence", ["persist"]);
|
jasmine.createSpyObj("persistence", ["persist"]);
|
||||||
mockStatusCapability =
|
mockStatusCapability =
|
||||||
jasmine.createSpyObj("status", ["get"]);
|
jasmine.createSpyObj("statusCapability", ["get", "listen"]);
|
||||||
mockStatusCapability.get.andReturn(false);
|
mockStatusCapability.get.andReturn(false);
|
||||||
mockCapabilities = {
|
mockCapabilities = {
|
||||||
'persistence': mockPersistence,
|
'persistence': mockPersistence,
|
||||||
@ -82,6 +82,17 @@ define(
|
|||||||
expect(mockScope.commit).toEqual(jasmine.any(Function));
|
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 () {
|
it("mutates and persists upon observed changes", function () {
|
||||||
mockScope.model = { someKey: "some value" };
|
mockScope.model = { someKey: "some value" };
|
||||||
mockScope.configuration = { someConfiguration: "something" };
|
mockScope.configuration = { someConfiguration: "something" };
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<span class="l-inspect">
|
<span class="l-inspect">
|
||||||
<div ng-controller="PaneController as modelPaneEdit">
|
<div ng-controller="PaneController">
|
||||||
<mct-split-pane class='abs contents split-layout' anchor='bottom'>
|
<mct-split-pane class='abs contents split-layout' anchor='bottom'>
|
||||||
<div class="split-pane-component pane top">
|
<div class="split-pane-component pane top">
|
||||||
<div class="abs holder holder-inspector l-flex-col">
|
<div class="abs holder holder-inspector l-flex-col">
|
||||||
@ -31,8 +31,8 @@
|
|||||||
ng-model="ngModel"
|
ng-model="ngModel"
|
||||||
class="flex-elem grows vscroll l-flex-col">
|
class="flex-elem grows vscroll l-flex-col">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div><!--/ holder-inspector -->
|
</div>
|
||||||
</div><!--/ split-pane-component -->
|
</div>
|
||||||
<mct-splitter class="splitter-inspect-panel mobile-hide"></mct-splitter>
|
<mct-splitter class="splitter-inspect-panel mobile-hide"></mct-splitter>
|
||||||
<div class="split-pane-component pane bottom">
|
<div class="split-pane-component pane bottom">
|
||||||
<div class="abs holder holder-elements l-flex-col">
|
<div class="abs holder holder-elements l-flex-col">
|
||||||
@ -45,5 +45,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mct-split-pane>
|
</mct-split-pane>
|
||||||
</div><!--/ PaneController -->
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
@ -80,13 +80,6 @@ define(
|
|||||||
}).length > 0;
|
}).length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldCreateVirtualPanel(domainObject){
|
|
||||||
return domainObject.useCapability('view').filter(function (view){
|
|
||||||
return (view.key === 'plot' || view.key === 'scrolling')
|
|
||||||
&& domainObject.getModel().type !== 'telemetry.panel';
|
|
||||||
}).length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragOver(e) {
|
function dragOver(e) {
|
||||||
//Refresh domain object on each dragOver to catch external
|
//Refresh domain object on each dragOver to catch external
|
||||||
// updates to the model
|
// updates to the model
|
||||||
@ -111,9 +104,7 @@ define(
|
|||||||
key: 'compose',
|
key: 'compose',
|
||||||
selectedObject: selectedObject
|
selectedObject: selectedObject
|
||||||
})[0];
|
})[0];
|
||||||
//TODO: Fix this. Define an action for creating new
|
if (action) {
|
||||||
// virtual panel
|
|
||||||
if (action || shouldCreateVirtualPanel(domainObject, selectedObject)) {
|
|
||||||
event.dataTransfer.dropEffect = 'move';
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
|
||||||
// Indicate that we will accept the drag
|
// Indicate that we will accept the drag
|
||||||
@ -123,65 +114,24 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createVirtualPanel(base, selectedObject){
|
|
||||||
|
|
||||||
var typeKey = 'telemetry.panel',
|
|
||||||
type = typeService.getType(typeKey),
|
|
||||||
model = type.getInitialModel(),
|
|
||||||
newPanel,
|
|
||||||
composeAction;
|
|
||||||
|
|
||||||
model.type = typeKey;
|
|
||||||
newPanel = new EditableDomainObject(instantiate(model), $q);
|
|
||||||
if (!canCompose(newPanel, selectedObject)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
[base.getId(), selectedObject.getId()].forEach(function(id){
|
|
||||||
newPanel.getCapability('composition').add(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
newPanel.getCapability('location')
|
|
||||||
.setPrimaryLocation(base.getCapability('location')
|
|
||||||
.getContextualLocation());
|
|
||||||
|
|
||||||
newPanel.setOriginalObject(base);
|
|
||||||
return newPanel;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function drop(e) {
|
function drop(e) {
|
||||||
var event = (e || {}).originalEvent || e,
|
var event = (e || {}).originalEvent || e,
|
||||||
id = event.dataTransfer.getData(GestureConstants.MCT_DRAG_TYPE),
|
id = event.dataTransfer.getData(GestureConstants.MCT_DRAG_TYPE),
|
||||||
domainObjectType = editableDomainObject.getModel().type,
|
domainObjectType = editableDomainObject.getModel().type;
|
||||||
selectedObject = dndService.getData(
|
|
||||||
GestureConstants.MCT_EXTENDED_DRAG_TYPE
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle the drop; add the dropped identifier to the
|
// Handle the drop; add the dropped identifier to the
|
||||||
// destination domain object's composition, and persist
|
// destination domain object's composition, and persist
|
||||||
// the change.
|
// the change.
|
||||||
if (id) {
|
if (id) {
|
||||||
if (shouldCreateVirtualPanel(domainObject, selectedObject)){
|
|
||||||
editableDomainObject = createVirtualPanel(domainObject, selectedObject);
|
|
||||||
if (editableDomainObject) {
|
|
||||||
navigationService.setNavigation(editableDomainObject);
|
|
||||||
broadcastDrop(id, event);
|
|
||||||
editableDomainObject.getCapability('status').set('editing', true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$q.when(action && action.perform()).then(function (result) {
|
$q.when(action && action.perform()).then(function (result) {
|
||||||
//Don't go into edit mode for folders
|
//Don't go into edit mode for folders
|
||||||
if (domainObjectType!=='folder') {
|
if (domainObjectType!=='folder') {
|
||||||
navigationService.setNavigation(editableDomainObject);
|
editableDomainObject.getCapability('action').perform('edit');
|
||||||
editableDomainObject.getCapability('status').set('editing', true);
|
|
||||||
}
|
}
|
||||||
broadcastDrop(id, event);
|
broadcastDrop(id, event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Alert user if drag and drop is not allowed
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can only handle drops if we have access to actions...
|
// We can only handle drops if we have access to actions...
|
||||||
if (actionCapability) {
|
if (actionCapability) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user