mirror of
https://github.com/nasa/openmct.git
synced 2025-01-21 03:55:31 +00:00
[Edit] Introduce dropdown Save menu
And fix style issues in SaveAsActionSpec
This commit is contained in:
parent
31ee92b711
commit
d1f67fd8b9
@ -30,6 +30,7 @@ define([
|
||||
"./src/actions/EditAction",
|
||||
"./src/actions/PropertiesAction",
|
||||
"./src/actions/RemoveAction",
|
||||
"./src/actions/SaveAction",
|
||||
"./src/actions/SaveAndStopEditingAction",
|
||||
"./src/actions/SaveAsAction",
|
||||
"./src/actions/CancelAction",
|
||||
@ -69,6 +70,7 @@ define([
|
||||
EditAction,
|
||||
PropertiesAction,
|
||||
RemoveAction,
|
||||
SaveAction,
|
||||
SaveAndStopEditingAction,
|
||||
SaveAsAction,
|
||||
CancelAction,
|
||||
@ -203,20 +205,30 @@ define([
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "save",
|
||||
"category": "conclude-editing",
|
||||
"key": "save-and-stop-editing",
|
||||
"category": "save",
|
||||
"implementation": SaveAndStopEditingAction,
|
||||
"name": "Save",
|
||||
"name": "Save and Done Editing",
|
||||
"cssclass": "icon-save labeled",
|
||||
"description": "Save changes made to these objects.",
|
||||
"depends": [
|
||||
"dialogService"
|
||||
],
|
||||
"priority": "mandatory"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "save",
|
||||
"category": "conclude-editing",
|
||||
"category": "save",
|
||||
"implementation": SaveAction,
|
||||
"name": "Save and Continue Editing",
|
||||
"cssclass": "icon-save labeled",
|
||||
"description": "Save changes made to these objects.",
|
||||
"depends": [
|
||||
"dialogService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "save-as",
|
||||
"category": "save",
|
||||
"implementation": SaveAsAction,
|
||||
"name": "Save As...",
|
||||
"cssclass": "icon-save labeled",
|
||||
|
@ -20,11 +20,30 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span ng-controller="EditActionController">
|
||||
<span ng-repeat="currentAction in editActions">
|
||||
<!-- If there's a single save action show a button, otherwise show a dropdown with all save actions. -->
|
||||
<span ng-if="saveActions.length === 1">
|
||||
<a class='s-button major {{saveActions[0].getMetadata().cssclass}}'
|
||||
title='{{saveActions[0].getMetadata().name}}'
|
||||
ng-click="saveActions[0].perform()">
|
||||
<span class="title-label">{{saveActions[0].getMetadata().name}}</span>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<span ng-if="saveActions.length > 1">
|
||||
<mct-control key="'menu-button'"
|
||||
structure="{
|
||||
options: saveActionsAsMenuOptions,
|
||||
click: saveActionMenuClickHandler,
|
||||
cssclass: 'btn-bar right icon-save no-label major'
|
||||
}">
|
||||
</mct-control>
|
||||
</span>
|
||||
|
||||
<span ng-repeat="currentAction in otherEditActions">
|
||||
<a class='s-button {{currentAction.getMetadata().cssclass}}'
|
||||
title='{{currentAction.getMetadata().name}}'
|
||||
ng-click="currentAction.perform()"
|
||||
ng-class="{ major: $index === 0 }">
|
||||
ng-class="{ major: $index === 0 && saveActions.length === 0 }">
|
||||
<span class="title-label">{{currentAction.getMetadata().name}}</span>
|
||||
</a>
|
||||
</span>
|
||||
|
@ -27,7 +27,8 @@ define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
var ACTION_CONTEXT = { category: 'conclude-editing' };
|
||||
var SAVE_ACTION_CONTEXT = { category: 'save' };
|
||||
var OTHERS_ACTION_CONTEXT = { category: 'conclude-editing' };
|
||||
|
||||
/**
|
||||
* Controller which supplies action instances for Save/Cancel.
|
||||
@ -35,11 +36,30 @@ define(
|
||||
* @constructor
|
||||
*/
|
||||
function EditActionController($scope) {
|
||||
// Maintain all "conclude-editing" actions in the present
|
||||
// context.
|
||||
|
||||
function actionToMenuOption(action) {
|
||||
return {
|
||||
key: action,
|
||||
name: action.getMetadata().name,
|
||||
cssclass: action.getMetadata().cssclass
|
||||
};
|
||||
}
|
||||
|
||||
// Maintain all "conclude-editing" and "save" actions in the
|
||||
// present context.
|
||||
function updateActions() {
|
||||
$scope.editActions = $scope.action ?
|
||||
$scope.action.getActions(ACTION_CONTEXT) :
|
||||
$scope.saveActions = $scope.action ?
|
||||
$scope.action.getActions(SAVE_ACTION_CONTEXT) :
|
||||
[];
|
||||
|
||||
$scope.saveActionsAsMenuOptions = $scope.saveActions.map(actionToMenuOption);
|
||||
|
||||
$scope.saveActionMenuClickHandler = function (clickedAction) {
|
||||
clickedAction.perform();
|
||||
};
|
||||
|
||||
$scope.otherEditActions = $scope.action ?
|
||||
$scope.action.getActions(OTHERS_ACTION_CONTEXT) :
|
||||
[];
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ define(
|
||||
mockDomainObject.getModel.andReturn({persisted: 0});
|
||||
expect(SaveAsAction.appliesTo(actionContext)).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
it("uses the editor capability to save the object", function () {
|
||||
mockEditorCapability.save.andReturn(new Promise(function () {}));
|
||||
runs(function () {
|
||||
|
@ -19,22 +19,54 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global describe,it,expect,beforeEach,jasmine,spyOn*/
|
||||
|
||||
define(
|
||||
["../../src/controllers/EditActionController"],
|
||||
function (EditActionController) {
|
||||
|
||||
describe("The Edit Action controller", function () {
|
||||
function FakeSaveAction() {
|
||||
}
|
||||
|
||||
var fakeSaveActionMetadata = {
|
||||
name: "mocked-save-action",
|
||||
cssclass: "mocked-save-action-css"
|
||||
};
|
||||
|
||||
FakeSaveAction.prototype.getMetadata = function () {
|
||||
return fakeSaveActionMetadata;
|
||||
};
|
||||
|
||||
FakeSaveAction.prototype.perform = function () {
|
||||
};
|
||||
|
||||
function fakeGetActions(actionContext) {
|
||||
if (actionContext.category === "save") {
|
||||
return [new FakeSaveAction(), new FakeSaveAction()];
|
||||
} else if (actionContext.category === "conclude-editing") {
|
||||
return ["a", "b", "c"];
|
||||
} else {
|
||||
throw "EditActionController uses a context that's not covered by tests.";
|
||||
}
|
||||
}
|
||||
|
||||
var mockScope,
|
||||
mockActions,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockActions = jasmine.createSpyObj("action", ["getActions"]);
|
||||
mockActions.getActions.andCallFake(fakeGetActions);
|
||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
||||
mockScope.action = mockActions;
|
||||
controller = new EditActionController(mockScope);
|
||||
});
|
||||
|
||||
function makeControllerUpdateActions() {
|
||||
mockScope.$watch.mostRecentCall.args[1]();
|
||||
}
|
||||
|
||||
it("watches scope that may change applicable actions", function () {
|
||||
// The action capability
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
@ -43,16 +75,36 @@ define(
|
||||
);
|
||||
});
|
||||
|
||||
it("populates the scope with grouped and ungrouped actions", function () {
|
||||
mockScope.action = mockActions;
|
||||
it("populates the scope with 'save' actions", function () {
|
||||
makeControllerUpdateActions();
|
||||
expect(mockScope.saveActions.length).toEqual(2);
|
||||
});
|
||||
|
||||
mockActions.getActions.andReturn(["a", "b", "c"]);
|
||||
it("converts 'save' actions to their menu counterparts", function () {
|
||||
makeControllerUpdateActions();
|
||||
var menuOptions = mockScope.saveActionsAsMenuOptions;
|
||||
|
||||
// Call the watch
|
||||
mockScope.$watch.mostRecentCall.args[1]();
|
||||
expect(menuOptions.length).toEqual(2);
|
||||
expect(menuOptions[0].key).toEqual(mockScope.saveActions[0]);
|
||||
expect(menuOptions[1].key).toEqual(mockScope.saveActions[1]);
|
||||
menuOptions.forEach(function (option) {
|
||||
expect(option.name).toEqual(fakeSaveActionMetadata.name);
|
||||
expect(option.cssclass).toEqual(fakeSaveActionMetadata.cssclass);
|
||||
});
|
||||
});
|
||||
|
||||
// Should have grouped and ungrouped actions in scope now
|
||||
expect(mockScope.editActions.length).toEqual(3);
|
||||
it("uses a click handler to perform the clicked action", function () {
|
||||
makeControllerUpdateActions();
|
||||
var sampleSaveAction = mockScope.saveActions[0];
|
||||
|
||||
spyOn(sampleSaveAction, "perform");
|
||||
mockScope.saveActionMenuClickHandler(sampleSaveAction);
|
||||
expect(sampleSaveAction.perform).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("populates the scope with other 'conclude-editing' actions", function () {
|
||||
makeControllerUpdateActions();
|
||||
expect(mockScope.otherEditActions).toEqual(["a", "b", "c"]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user