Merge branch 'master' into open401

Resolve conflicts for #416

Conflicts:
	platform/commonUI/browse/bundle.json
	platform/commonUI/browse/src/BrowseController.js
This commit is contained in:
Victor Woeltjen
2016-02-22 14:27:21 -08:00
387 changed files with 14238 additions and 55416 deletions

View File

@@ -19,18 +19,23 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/*global define,Promise, confirm*/
/**
* This bundle implements Browse mode.
* @namespace platform/commonUI/browse
*/
define(
[],
function () {
[
'../../../representation/src/gestures/GestureConstants',
'../../edit/src/objects/EditableDomainObject'
],
function (GestureConstants, EditableDomainObject) {
"use strict";
var ROOT_ID = "ROOT";
var ROOT_ID = "ROOT",
DEFAULT_PATH = "mine",
CONFIRM_MSG = "Unsaved changes will be lost if you leave this page.";
/**
* The BrowseController is used to populate the initial scope in Browse
@@ -46,6 +51,7 @@ define(
$scope,
$route,
$location,
$q,
objectService,
navigationService,
urlService,
@@ -55,6 +61,13 @@ define(
($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) {
var priorRoute = $route.current,
// Act as if params HADN'T changed to avoid page reload
@@ -71,20 +84,36 @@ define(
// urlService.urlForLocation used to adjust current
// path to new, addressed, path based on
// domainObject
$location.path(urlService.urlForLocation("browse", domainObject));
$location.path(urlService.urlForLocation("browse",
domainObject.hasCapability('editor') ?
domainObject.getOriginalObject() : domainObject));
}
// Callback for updating the in-scope reference to the object
// that is currently navigated-to.
function setNavigation(domainObject) {
$scope.navigatedObject = domainObject;
$scope.treeModel.selectedObject = domainObject;
navigationService.setNavigation(domainObject);
updateRoute(domainObject);
if (domainObject === $scope.navigatedObject){
//do nothing;
return;
}
if (isDirty() && !confirm(CONFIRM_MSG)) {
$scope.treeModel.selectedObject = $scope.navigatedObject;
navigationService.setNavigation($scope.navigatedObject);
} else {
if ($scope.navigatedObject && $scope.navigatedObject.hasCapability("editor")){
$scope.navigatedObject.getCapability("editor").cancel();
}
$scope.navigatedObject = domainObject;
$scope.treeModel.selectedObject = domainObject;
navigationService.setNavigation(domainObject);
updateRoute(domainObject);
}
}
function navigateTo(domainObject) {
// Check if an object has been navigated-to already...
// If not, or if an ID path has been explicitly set in the URL,
// navigate to the URL-specified object.
@@ -156,12 +185,18 @@ define(
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.
navigationService.addListener(setNavigation);
// Also listen for changes which come from the tree
$scope.$watch("treeModel.selectedObject", setNavigation);
// Clean up when the scope is destroyed
$scope.$on("$destroy", function () {
navigationService.removeListener(setNavigation);

View File

@@ -22,8 +22,11 @@
/*global define,Promise*/
define(
[],
function () {
[
'../../../representation/src/gestures/GestureConstants',
'../../edit/src/objects/EditableDomainObject'
],
function (GestureConstants, EditableDomainObject) {
"use strict";
/**
@@ -32,8 +35,10 @@ define(
* @memberof platform/commonUI/browse
* @constructor
*/
function BrowseObjectController($scope, $location, $route) {
function BrowseObjectController($scope, $location, $route, $q, navigationService) {
var navigatedObject;
function setViewForDomainObject(domainObject) {
var locationViewKey = $location.search().view;
function selectViewIfMatching(view) {
@@ -47,12 +52,15 @@ define(
((domainObject && domainObject.useCapability('view')) || [])
.forEach(selectViewIfMatching);
}
navigatedObject = domainObject;
}
function updateQueryParam(viewKey) {
var unlisten, priorRoute = $route.current;
var unlisten,
priorRoute = $route.current,
isEditMode = $scope.domainObject && $scope.domainObject.hasCapability('editor');
if (viewKey) {
if (viewKey && !isEditMode) {
$location.search('view', viewKey);
unlisten = $scope.$on('$locationChangeSuccess', function () {
// Checks path to make sure /browse/ is at front
@@ -67,6 +75,15 @@ define(
$scope.$watch('domainObject', setViewForDomainObject);
$scope.$watch('representation.selected.key', updateQueryParam);
$scope.cancelEditing = function() {
navigationService.setNavigation($scope.domainObject.getDomainObject());
};
$scope.doAction = function (action){
return $scope[action] && $scope[action]();
};
}
return BrowseObjectController;

View File

@@ -0,0 +1,139 @@
/*****************************************************************************
* 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,Promise*/
/**
* Module defining AddAction. Created by ahenry on 01/21/16.
*/
define(
[
'./CreateWizard'
],
function (CreateWizard) {
"use strict";
/**
* The Add Action is performed to create new instances of
* domain objects of a specific type that are subobjects of an
* object being edited. This is the action that is performed when a
* user uses the Add menu option.
*
* @memberof platform/commonUI/browse
* @implements {Action}
* @constructor
*
* @param {Type} type the type of domain object to create
* @param {DomainObject} parent the domain object that should
* act as a container for the newly-created object
* (note that the user will have an opportunity to
* override this)
* @param {ActionContext} context the context in which the
* action is being performed
* @param {DialogService} dialogService
*/
function AddAction(type, parent, context, $q, dialogService, policyService) {
this.metadata = {
key: 'add',
glyph: type.getGlyph(),
name: type.getName(),
type: type.getKey(),
description: type.getDescription(),
context: context
};
this.type = type;
this.parent = parent;
this.$q = $q;
this.dialogService = dialogService;
this.policyService = policyService;
}
/**
*
* Create a new object of the given type.
* This will prompt for user input first.
*
* @returns {Promise} that will be resolved with the object that the
* action was originally invoked on (ie. the 'parent')
*/
AddAction.prototype.perform = function () {
var newModel = this.type.getInitialModel(),
newObject,
parentObject = this.parent,
wizard;
newModel.type = this.type.getKey();
newObject = parentObject.getCapability('instantiation').instantiate(newModel);
newObject.useCapability('mutation', function(model){
model.location = parentObject.getId();
});
wizard = new CreateWizard(newObject, this.parent, this.policyService);
function populateObjectFromInput (formValue) {
return wizard.populateObjectFromInput(formValue, newObject);
}
function addToParent (populatedObject) {
parentObject.getCapability('composition').add(populatedObject);
return parentObject.getCapability('persistence').persist().then(function(){
return parentObject;
});
}
function save(object) {
/*
It's necessary to persist the new sub-object in order
that it can be retrieved for composition in the parent.
Future refactoring that allows temporary objects to be
retrieved from object services will make this unnecessary.
*/
return object.getCapability('editor').save(true);
}
return this.dialogService
.getUserInput(wizard.getFormStructure(false), wizard.getInitialFormValue())
.then(populateObjectFromInput)
.then(save)
.then(addToParent);
};
/**
* Metadata associated with a Add action.
* @typedef {ActionMetadata} AddActionMetadata
* @property {string} type the key for the type of domain object
* to be created
*/
/**
* Get metadata about this action.
* @returns {AddActionMetadata} metadata about this action
*/
AddAction.prototype.getMetadata = function () {
return this.metadata;
};
return AddAction;
}
);

View File

@@ -0,0 +1,87 @@
/*****************************************************************************
* 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,Promise*/
/**
* Module defining AddActionProvider.js. Created by ahenry on 01/21/16.
*/
define(
["./AddAction"],
function (AddAction) {
"use strict";
/**
* The AddActionProvider is an ActionProvider which introduces
* an Add action for creating sub objects.
*
* @memberof platform/commonUI/browse
* @constructor
* @implements {ActionService}
*
* @param {TypeService} typeService the type service, used to discover
* available types
* @param {DialogService} dialogService the dialog service, used by
* specific Create actions to get user input to populate the
* model of the newly-created domain object.
* @param {CreationService} creationService the creation service (also
* introduced in this bundle), responsible for handling actual
* object creation.
*/
function AddActionProvider($q, typeService, dialogService, policyService) {
this.typeService = typeService;
this.dialogService = dialogService;
this.$q = $q;
this.policyService = policyService;
}
AddActionProvider.prototype.getActions = function (actionContext) {
var context = actionContext || {},
key = context.key,
destination = context.domainObject,
self = this;
// We only provide Add actions, and we need a
// domain object to serve as the container for the
// newly-created object (although the user may later
// make a different selection)
if (key !== 'add' || !destination) {
return [];
}
// Introduce one create action per type
return this.typeService.listTypes().filter(function (type) {
return self.policyService.allow("creation", type) && self.policyService.allow("composition", destination.getCapability('type'), type);
}).map(function (type) {
return new AddAction(
type,
destination,
context,
self.$q,
self.dialogService,
self.policyService
);
});
};
return AddActionProvider;
}
);

View File

@@ -25,8 +25,11 @@
* Module defining CreateAction. Created by vwoeltje on 11/10/14.
*/
define(
['./CreateWizard'],
function (CreateWizard) {
[
'./CreateWizard',
'../../../edit/src/objects/EditableDomainObject'
],
function (CreateWizard, EditableDomainObject) {
"use strict";
/**
@@ -45,13 +48,11 @@ define(
* override this)
* @param {ActionContext} context the context in which the
* action is being performed
* @param {DialogService} dialogService the dialog service
* to use when requesting user input
* @param {CreationService} creationService the creation service,
* which handles the actual instantiation and persistence
* of the newly-created domain object
* @param {NavigationService} navigationService the navigation service,
* which handles changes in navigation. It allows the object
* being browsed/edited to be set.
*/
function CreateAction(type, parent, context, dialogService, creationService, policyService) {
function CreateAction(type, parent, context, $q, navigationService) {
this.metadata = {
key: 'create',
glyph: type.getGlyph(),
@@ -63,9 +64,21 @@ define(
this.type = type;
this.parent = parent;
this.policyService = policyService;
this.dialogService = dialogService;
this.creationService = creationService;
this.navigationService = navigationService;
this.$q = $q;
}
// Get a count of views which are not flagged as non-editable.
function countEditableViews(domainObject) {
var views = domainObject && domainObject.useCapability('view'),
count = 0;
// A view is editable unless explicitly flagged as not
(views || []).forEach(function (view) {
count += (view.editable !== false) ? 1 : 0;
});
return count;
}
/**
@@ -73,45 +86,25 @@ define(
* This will prompt for user input first.
*/
CreateAction.prototype.perform = function () {
/*
Overview of steps in object creation:
var newModel = this.type.getInitialModel(),
parentObject = this.navigationService.getNavigation(),
newObject,
editableObject;
1. Show dialog
a. Prepare dialog contents
b. Invoke dialogService
2. Create new object in persistence service
a. Generate UUID
b. Store model
3. Mutate destination container
a. Get mutation capability
b. Add new id to composition
4. Persist destination container
a. ...use persistence capability.
*/
newModel.type = this.type.getKey();
newObject = parentObject.useCapability('instantiation', newModel);
editableObject = new EditableDomainObject(newObject, this.$q);
editableObject.setOriginalObject(parentObject);
editableObject.getCapability('status').set('editing', true);
editableObject.useCapability('mutation', function(model){
model.location = parentObject.getId();
});
// The wizard will handle creating the form model based
// on the type...
var wizard =
new CreateWizard(this.type, this.parent, this.policyService),
self = this;
// Create and persist the new object, based on user
// input.
function persistResult(formValue) {
var parent = wizard.getLocation(formValue),
newModel = wizard.createModel(formValue);
return self.creationService.createObject(newModel, parent);
if (countEditableViews(editableObject) > 0 && editableObject.hasCapability('composition')) {
this.navigationService.setNavigation(editableObject);
} else {
return editableObject.getCapability('action').perform('save');
}
function doNothing() {
// Create cancelled, do nothing
return false;
}
return this.dialogService.getUserInput(
wizard.getFormStructure(),
wizard.getInitialFormValue()
).then(persistResult, doNothing);
};

View File

@@ -46,10 +46,10 @@ define(
* introduced in this bundle), responsible for handling actual
* object creation.
*/
function CreateActionProvider(typeService, dialogService, creationService, policyService) {
function CreateActionProvider($q, typeService, navigationService, policyService) {
this.typeService = typeService;
this.dialogService = dialogService;
this.creationService = creationService;
this.navigationService = navigationService;
this.$q = $q;
this.policyService = policyService;
}
@@ -75,9 +75,8 @@ define(
type,
destination,
context,
self.dialogService,
self.creationService,
self.policyService
self.$q,
self.navigationService
);
});
};

View File

@@ -26,18 +26,21 @@ define(
'use strict';
/**
* Construct a new CreateWizard.
* A class for capturing user input data from an object creation
* dialog, and populating a domain object with that data.
*
* @param {TypeImpl} type the type of domain object to be created
* @param {DomainObject} domainObject the newly created object to
* populate with user input
* @param {DomainObject} parent the domain object to serve as
* the initial parent for the created object, in the dialog
* @memberof platform/commonUI/browse
* @constructor
*/
function CreateWizard(type, parent, policyService) {
this.type = type;
this.model = type.getInitialModel();
this.properties = type.getProperties();
function CreateWizard(domainObject, parent, policyService) {
this.type = domainObject.getCapability('type');
this.model = domainObject.getModel();
this.domainObject = domainObject;
this.properties = this.type.getProperties();
this.parent = parent;
this.policyService = policyService;
}
@@ -46,11 +49,14 @@ define(
* Get the form model for this wizard; this is a description
* that will be rendered to an HTML form. See the
* platform/forms bundle
*
* @param {boolean} includeLocation if true, a 'location' section
* will be included that will allow the user to select the location
* of the newly created object, otherwise the .location property of
* the model will be used.
* @return {FormModel} formModel the form model to
* show in the create dialog
*/
CreateWizard.prototype.getFormStructure = function () {
CreateWizard.prototype.getFormStructure = function (includeLocation) {
var sections = [],
type = this.type,
policyService = this.policyService;
@@ -84,12 +90,16 @@ define(
});
// Ensure there is always a "save in" section
sections.push({ name: 'Location', rows: [{
name: "Save In",
control: "locator",
validate: validateLocation,
key: "createParent"
}]});
if (includeLocation) {
sections.push({
name: 'Location', rows: [{
name: "Save In",
control: "locator",
validate: validateLocation,
key: "createParent"
}]
});
}
return {
sections: sections,
@@ -97,6 +107,23 @@ define(
};
};
/**
* Given some form input values and a domain object, populate the
* domain object used to create this wizard from the given form values.
* @param formValue
* @returns {DomainObject}
*/
CreateWizard.prototype.populateObjectFromInput = function(formValue) {
var parent = this.getLocation(formValue),
formModel = this.createModel(formValue);
formModel.location = parent.getId();
this.domainObject.useCapability("mutation", function(){
return formModel;
});
return this.domainObject;
};
/**
* Get the initial value for the form being described.
* This will include the values for all properties described
@@ -120,6 +147,7 @@ define(
/**
* Based on a populated form, get the domain object which
* should be used as a parent for the newly-created object.
* @private
* @return {DomainObject}
*/
CreateWizard.prototype.getLocation = function (formValue) {
@@ -129,6 +157,7 @@ define(
/**
* Create the domain object model for a newly-created object,
* based on user input read from a formModel.
* @private
* @return {object} the domain object model
*/
CreateWizard.prototype.createModel = function (formValue) {

View File

@@ -33,7 +33,7 @@ define(
* @memberof platform/commonUI/browse
* @constructor
*/
function LocatorController($scope, $timeout) {
function LocatorController($scope, $timeout, objectService) {
// Populate values needed by the locator control. These are:
// * rootObject: The top-level object, since we want to show
// the full tree
@@ -52,6 +52,18 @@ define(
$scope.rootObject =
(context && context.getRoot()) || $scope.rootObject;
}, 0);
} else if (!contextRoot){
//If no context root is available, default to the root
// object
$scope.rootObject = undefined;
// Update the displayed tree on a timeout to avoid
// an infinite digest exception.
objectService.getObjects(['ROOT'])
.then(function(objects){
$timeout(function () {
$scope.rootObject = objects.ROOT;
}, 0);
});
}
$scope.treeModel.selectedObject = domainObject;

View File

@@ -25,7 +25,7 @@
* Module defining FullscreenAction. Created by vwoeltje on 11/18/14.
*/
define(
["../../lib/screenfull.min"],
["screenfull"],
function () {
"use strict";