Merged from master to resolve build issues

This commit is contained in:
Henry 2016-10-05 12:25:04 -07:00
commit 3e9c0eb7a5
92 changed files with 623 additions and 290 deletions

View File

@ -17,6 +17,7 @@ Differences between the two APIs include a move away from a declarative system o
## Building and Running Open MCT Locally ## Building and Running Open MCT Locally
Building and running Open MCT in your local dev environment is very easy. Be sure you have [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/) installed, then follow the directions below. Need additional information? Check out the [Getting Started](https://nasa.github.io/openmct/getting-started/) page on our website. Building and running Open MCT in your local dev environment is very easy. Be sure you have [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/) installed, then follow the directions below. Need additional information? Check out the [Getting Started](https://nasa.github.io/openmct/getting-started/) page on our website.
(These instructions assume you are installing as a non-root user; developers have [reported issues](https://github.com/nasa/openmct/issues/1151) running these steps with root privileges.)
1. Clone the source code 1. Clone the source code

10
app.js
View File

@ -67,14 +67,10 @@
}); });
app.use('/proxyUrl', function proxyRequest(req, res, next) { app.use('/proxyUrl', function proxyRequest(req, res, next) {
var targetUrl = req.query.url; console.log('Proxying request to: ', req.query.url);
var queryParameters = req.query;
console.log('Proxying request to: ', targetUrl);
delete queryParameters['url'];
req.pipe(request({ req.pipe(request({
url: targetUrl, url: req.query.url,
strictSSL: false, strictSSL: false
qs: queryParameters
}).on('error', next)).pipe(res); }).on('error', next)).pipe(res);
}); });

View File

@ -21,7 +21,6 @@
"zepto": "^1.1.6", "zepto": "^1.1.6",
"eventemitter3": "^1.2.0", "eventemitter3": "^1.2.0",
"d3": "~4.1.0", "d3": "~4.1.0",
"html2canvas": "^0.4.1", "html2canvas": "^0.4.1"
"jspdf": "^1.2.61"
} }
} }

View File

@ -32,7 +32,7 @@ WEBSITE_DIRECTORY="website"
BUILD_SHA=`git rev-parse HEAD` BUILD_SHA=`git rev-parse HEAD`
# A remote will be created for the git repository we are pushing to. # A remote will be created for the git repository we are pushing to.
# Don't worry, as this entire directory will get trashed inbetween builds. # Don't worry, as this entire directory will get trashed in between builds.
REMOTE_NAME="documentation" REMOTE_NAME="documentation"
WEBSITE_BRANCH="master" WEBSITE_BRANCH="master"

View File

@ -616,7 +616,7 @@ follows:
part of an action's extension definition. part of an action's extension definition.
* `CreateActionProvider` provides the various Create actions which * `CreateActionProvider` provides the various Create actions which
populate the Create menu. These are driven by the available types, populate the Create menu. These are driven by the available types,
so do not map easily ot extension category `actions`; instead, these so do not map easily to extension category `actions`; instead, these
are generated after looking up which actions are available from the are generated after looking up which actions are available from the
[`TypeService`](#type-service). [`TypeService`](#type-service).
* `ActionAggregator` merges together actions from multiple providers. * `ActionAggregator` merges together actions from multiple providers.

View File

@ -98,7 +98,7 @@ Worked on bug fixes in the platform and a plugin for search.
It is hard to figure out what the difference between the various ways of It is hard to figure out what the difference between the various ways of
dealing with telemetry are. e.g., what is the difference between just dealing with telemetry are. e.g., what is the difference between just
"Telemetry" and the "Telemetry Service"? There are many "Telemetry" and the "Telemetry Service"? There are many
"Telemetry Thing"s which seem related, but in an unclear way. "Telemetry Things" which seem related, but in an unclear way.
### Developer Intern 2 ### Developer Intern 2
@ -456,7 +456,7 @@ Instead, propose that:
For parity with actions, a `View` would be a constructor which For parity with actions, a `View` would be a constructor which
takes an `ActionContext` as a parameter (with similarly-defined takes an `ActionContext` as a parameter (with similarly-defined
properties) and exposes a method to retrieve the HTML elements properties) and exposes a method to retrieve the HTML elements
associateed with it. associated with it.
The platform would then additionally expose an `AngularView` The platform would then additionally expose an `AngularView`
implementation to improve compatibility with existing implementation to improve compatibility with existing

View File

@ -99,7 +99,7 @@ To reduce interface depth, we can replace our own provider and registry patterns
## More angular: for all services ## More angular: for all services
Increasing our commitment to angular would mean using more of the angular factorys, services, etc, and less of our home grown tools. We'd implement our services and extension points as angular providers, and make them configurable via app.config. Increasing our commitment to angular would mean using more of the angular factories, services, etc, and less of our home grown tools. We'd implement our services and extension points as angular providers, and make them configurable via app.config.
As an example, registering a specific type of model provider in angular would look like: As an example, registering a specific type of model provider in angular would look like:

View File

@ -3238,7 +3238,7 @@ define(
__tutorials/telemetry/src/ExampleTelemetryServerAdapter.js__ __tutorials/telemetry/src/ExampleTelemetryServerAdapter.js__
Here, we have added `subscribe` and `unsubscribe` methods which issue the Here, we have added `subscribe` and `unsubscribe` methods which issue the
corresponding requests to the server. Seperately, we introduce the ability to corresponding requests to the server. Separately, we introduce the ability to
listen for `data` messages as they come in: These will contain the data associated listen for `data` messages as they come in: These will contain the data associated
with these subscriptions. with these subscriptions.

View File

@ -10,7 +10,7 @@
"LMP: 47 degrees.", "LMP: 47 degrees.",
"CC: Eagle, looking great. You're GO.", "CC: Eagle, looking great. You're GO.",
"CC: Roger. 1202. We copy it.", "CC: Roger. 1202. We copy it.",
"O1: LMP 35 degrees. 35 degrees. 750. Coming aown to 23.fl", "O1: LMP 35 degrees. 35 degrees. 750. Coming down to 23.fl",
"LMP: 700 feet, 21 down, 33 degrees.", "LMP: 700 feet, 21 down, 33 degrees.",
"LMP: 600 feet, down at 19.", "LMP: 600 feet, down at 19.",
"LMP: 540 feet, down at - 30. Down at 15.", "LMP: 540 feet, down at - 30. Down at 15.",

View File

@ -103,11 +103,6 @@ gulp.task('stylesheets', function () {
.pipe(gulp.dest(__dirname)); .pipe(gulp.dest(__dirname));
}); });
gulp.task('nsp', function (done) {
var nsp = require('gulp-nsp');
nsp({package: __dirname + '/package.json'}, done);
});
gulp.task('lint', function () { gulp.task('lint', function () {
var nonspecs = paths.specs.map(function (glob) { var nonspecs = paths.specs.map(function (glob) {
return "!" + glob; return "!" + glob;
@ -157,6 +152,6 @@ gulp.task('develop', ['serve', 'stylesheets', 'watch']);
gulp.task('install', [ 'static', 'scripts' ]); gulp.task('install', [ 'static', 'scripts' ]);
gulp.task('verify', [ 'lint', 'test', 'checkstyle', 'nsp' ]); gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
gulp.task('build', [ 'verify', 'install' ]); gulp.task('build', [ 'verify', 'install' ]);

View File

@ -30,7 +30,6 @@ requirejs.config({
"EventEmitter": "bower_components/eventemitter3/index", "EventEmitter": "bower_components/eventemitter3/index",
"es6-promise": "bower_components/es6-promise/es6-promise.min", "es6-promise": "bower_components/es6-promise/es6-promise.min",
"html2canvas": "bower_components/html2canvas/build/html2canvas.min", "html2canvas": "bower_components/html2canvas/build/html2canvas.min",
"jsPDF": "bower_components/jspdf/dist/jspdf.min",
"moment": "bower_components/moment/moment", "moment": "bower_components/moment/moment",
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format", "moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
"saveAs": "bower_components/FileSaver.js/FileSaver.min", "saveAs": "bower_components/FileSaver.js/FileSaver.min",
@ -50,9 +49,6 @@ requirejs.config({
"html2canvas": { "html2canvas": {
"exports": "html2canvas" "exports": "html2canvas"
}, },
"jsPDF": {
"exports": "jsPDF"
},
"EventEmitter": { "EventEmitter": {
"exports": "EventEmitter" "exports": "EventEmitter"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "openmct", "name": "openmct",
"version": "0.11.3-SNAPSHOT", "version": "0.12.0-SNAPSHOT",
"description": "The Open MCT core platform", "description": "The Open MCT core platform",
"dependencies": { "dependencies": {
"express": "^4.13.1", "express": "^4.13.1",
@ -15,7 +15,6 @@
"gulp-jscs": "^3.0.2", "gulp-jscs": "^3.0.2",
"gulp-jshint": "^2.0.0", "gulp-jshint": "^2.0.0",
"gulp-jshint-html-reporter": "^0.1.3", "gulp-jshint-html-reporter": "^0.1.3",
"gulp-nsp": "^2.4.2",
"gulp-rename": "^1.2.2", "gulp-rename": "^1.2.2",
"gulp-replace-task": "^0.11.0", "gulp-replace-task": "^0.11.0",
"gulp-requirejs-optimize": "^0.3.1", "gulp-requirejs-optimize": "^0.3.1",

View File

@ -48,20 +48,35 @@ define(
*/ */
NavigateAction.prototype.perform = function () { NavigateAction.prototype.perform = function () {
var self = this, var self = this,
navigationAllowed = true; navigateTo = this.domainObject,
currentObject = self.navigationService.getNavigation();
function allow() { function allow() {
self.policyService.allow("navigation", self.navigationService.getNavigation(), self.domainObject, function (message) { var navigationAllowed = true;
self.policyService.allow("navigation", currentObject, navigateTo, function (message) {
navigationAllowed = self.$window.confirm(message + "\r\n\r\n" + navigationAllowed = self.$window.confirm(message + "\r\n\r\n" +
" Are you sure you want to continue?"); " Are you sure you want to continue?");
}); });
return navigationAllowed; return navigationAllowed;
} }
// Set navigation, and wrap like a promise function cancelIfEditing() {
return this.$q.when( var editing = currentObject.hasCapability('editor') &&
allow() && this.navigationService.setNavigation(this.domainObject) 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);
}
}; };
/** /**

View File

@ -32,7 +32,9 @@ define(
mockQ, mockQ,
mockDomainObject, mockDomainObject,
mockPolicyService, mockPolicyService,
mockNavigatedObject,
mockWindow, mockWindow,
capabilities,
action; action;
function mockPromise(value) { function mockPromise(value) {
@ -44,6 +46,29 @@ define(
} }
beforeEach(function () { beforeEach(function () {
capabilities = {};
mockQ = { when: mockPromise };
mockNavigatedObject = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"hasCapability",
"getCapability"
]
);
capabilities.editor = jasmine.createSpyObj("editorCapability", [
"isEditContextRoot",
"finish"
]);
mockNavigatedObject.getCapability.andCallFake(function (capability) {
return capabilities[capability];
});
mockNavigatedObject.hasCapability.andReturn(false);
mockNavigationService = jasmine.createSpyObj( mockNavigationService = jasmine.createSpyObj(
"navigationService", "navigationService",
[ [
@ -51,11 +76,14 @@ define(
"getNavigation" "getNavigation"
] ]
); );
mockNavigationService.getNavigation.andReturn({}); mockNavigationService.getNavigation.andReturn(mockNavigatedObject);
mockQ = { when: mockPromise };
mockDomainObject = jasmine.createSpyObj( mockDomainObject = jasmine.createSpyObj(
"domainObject", "domainObject",
["getId", "getModel", "getCapability"] [
"getId",
"getModel"
]
); );
mockPolicyService = jasmine.createSpyObj("policyService", mockPolicyService = jasmine.createSpyObj("policyService",
@ -112,6 +140,21 @@ define(
}); });
}); });
describe("in edit mode", function () {
beforeEach(function () {
mockNavigatedObject.hasCapability.andCallFake(function (capability) {
return capability === "editor";
});
capabilities.editor.isEditContextRoot.andReturn(true);
});
it("finishes editing if in edit mode", function () {
action.perform();
expect(capabilities.editor.finish)
.toHaveBeenCalled();
});
});
it("is only applicable when a domain object is in context", function () { it("is only applicable when a domain object is in context", function () {
expect(NavigateAction.appliesTo({})).toBeFalsy(); expect(NavigateAction.appliesTo({})).toBeFalsy();
expect(NavigateAction.appliesTo({ expect(NavigateAction.appliesTo({

View File

@ -19,7 +19,7 @@
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 class="abs overlay"> <div class="abs overlay" ng-class="{'delayEntry100ms' : ngModel.delay}">
<div class="abs blocker"></div> <div class="abs blocker"></div>
<div class="abs holder"> <div class="abs holder">
<a ng-click="ngModel.cancel()" <a ng-click="ngModel.cancel()"

View File

@ -187,7 +187,7 @@ define(
/** /**
* A description of the model options that may be passed to the * A description of the model options that may be passed to the
* showBlockingMessage method. Note that the DialogModel desribed * showBlockingMessage method. Note that the DialogModel described
* here is shared with the Notifications framework. * here is shared with the Notifications framework.
* @see NotificationService * @see NotificationService
* *
@ -200,6 +200,9 @@ define(
* shown above a progress bar to indicate what's happening. * shown above a progress bar to indicate what's happening.
* @property {number} progress a percentage value (1-100) * @property {number} progress a percentage value (1-100)
* indicating the completion of the blocking task * indicating the completion of the blocking task
* @property {boolean} delay adds a brief delay before loading
* the dialog. Useful for removing the dialog flicker when the
* conditions for displaying the dialog change rapidly.
* @property {string} progressText the message to show below a * @property {string} progressText the message to show below a
* progress bar to indicate progress. For example, this might be * progress bar to indicate progress. For example, this might be
* used to indicate time remaining, or items still to process. * used to indicate time remaining, or items still to process.

View File

@ -31,6 +31,7 @@ define([
"./src/actions/PropertiesAction", "./src/actions/PropertiesAction",
"./src/actions/RemoveAction", "./src/actions/RemoveAction",
"./src/actions/SaveAction", "./src/actions/SaveAction",
"./src/actions/SaveAndStopEditingAction",
"./src/actions/SaveAsAction", "./src/actions/SaveAsAction",
"./src/actions/CancelAction", "./src/actions/CancelAction",
"./src/policies/EditActionPolicy", "./src/policies/EditActionPolicy",
@ -70,6 +71,7 @@ define([
PropertiesAction, PropertiesAction,
RemoveAction, RemoveAction,
SaveAction, SaveAction,
SaveAndStopEditingAction,
SaveAsAction, SaveAsAction,
CancelAction, CancelAction,
EditActionPolicy, EditActionPolicy,
@ -203,20 +205,30 @@ define([
] ]
}, },
{ {
"key": "save", "key": "save-and-stop-editing",
"category": "conclude-editing", "category": "save",
"implementation": SaveAction, "implementation": SaveAndStopEditingAction,
"name": "Save", "name": "Save and Finish Editing",
"cssclass": "icon-save labeled", "cssclass": "icon-save labeled",
"description": "Save changes made to these objects.", "description": "Save changes made to these objects.",
"depends": [ "depends": [
"dialogService" "dialogService"
], ]
"priority": "mandatory"
}, },
{ {
"key": "save", "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, "implementation": SaveAsAction,
"name": "Save As...", "name": "Save As...",
"cssclass": "icon-save labeled", "cssclass": "icon-save labeled",
@ -225,7 +237,6 @@ define([
"$injector", "$injector",
"policyService", "policyService",
"dialogService", "dialogService",
"creationService",
"copyService" "copyService"
], ],
"priority": "mandatory" "priority": "mandatory"
@ -234,7 +245,9 @@ define([
"key": "cancel", "key": "cancel",
"category": "conclude-editing", "category": "conclude-editing",
"implementation": CancelAction, "implementation": CancelAction,
"name": "Cancel", // Because we use the name as label for edit buttons and mct-control buttons need
// the label to be set to undefined in order to not apply the labeled CSS rule.
"name": undefined,
"cssclass": "icon-x no-label", "cssclass": "icon-x no-label",
"description": "Discard changes made to these objects.", "description": "Discard changes made to these objects.",
"depends": [] "depends": []

View File

@ -20,12 +20,34 @@
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<span ng-controller="EditActionController"> <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. -->
<a class='s-button {{currentAction.getMetadata().cssclass}}' <span ng-if="saveActions.length === 1">
title='{{currentAction.getMetadata().name}}' <mct-control key="'button'"
ng-click="currentAction.perform()" structure="{
ng-class="{ major: $index === 0 }"> text: saveActions[0].getMetadata().name,
<span class="title-label">{{currentAction.getMetadata().name}}</span> click: actionPerformer(saveActions[0]),
</a> cssclass: 'major ' + saveActions[0].getMetadata().cssclass
}">
</mct-control>
</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">
<mct-control key="'button'"
structure="{
text: currentAction.getMetadata().name,
click: actionPerformer(currentAction),
cssclass: currentAction.getMetadata().cssclass
}">
</mct-control>
</span> </span>
</span> </span>

View File

@ -62,7 +62,7 @@ define(
} }
function cancel(allowed) { function cancel(allowed) {
return allowed && domainObject.getCapability("editor").cancel(); return allowed && domainObject.getCapability("editor").finish();
} }
//Do navigation first in order to trigger unsaved changes dialog //Do navigation first in order to trigger unsaved changes dialog

View File

@ -69,18 +69,13 @@ define(
* Enter edit mode. * Enter edit mode.
*/ */
EditAction.prototype.perform = function () { EditAction.prototype.perform = function () {
var self = this;
function cancelEditing() {
self.domainObject.getCapability('editor').cancel();
self.navigationService.removeListener(cancelEditing);
}
//If this is not the currently navigated object, then navigate //If this is not the currently navigated object, then navigate
// to it. // to it.
if (this.navigationService.getNavigation() !== this.domainObject) { if (this.navigationService.getNavigation() !== this.domainObject) {
this.navigationService.setNavigation(this.domainObject); this.navigationService.setNavigation(this.domainObject);
} }
this.navigationService.addListener(cancelEditing);
this.domainObject.useCapability("editor"); this.domainObject.useCapability("editor");
}; };

View File

@ -25,9 +25,8 @@ define(
function (SaveInProgressDialog) { function (SaveInProgressDialog) {
/** /**
* The "Save" action; the action triggered by clicking Save from * The "Save" action; it invokes object capabilities to persist
* Edit Mode. Exits the editing user interface and invokes object * the changes that have been made.
* capabilities to persist the changes that have been made.
* @constructor * @constructor
* @implements {Action} * @implements {Action}
* @memberof platform/commonUI/edit * @memberof platform/commonUI/edit
@ -41,7 +40,7 @@ define(
} }
/** /**
* Save changes and conclude editing. * Save changes.
* *
* @returns {Promise} a promise that will be fulfilled when * @returns {Promise} a promise that will be fulfilled when
* cancellation has completed * cancellation has completed
@ -51,40 +50,22 @@ define(
var domainObject = this.domainObject, var domainObject = this.domainObject,
dialog = new SaveInProgressDialog(this.dialogService); dialog = new SaveInProgressDialog(this.dialogService);
function resolveWith(object) {
return function () {
return object;
};
}
// Invoke any save behavior introduced by the editor capability; // Invoke any save behavior introduced by the editor capability;
// this is introduced by EditableDomainObject which is // this is introduced by EditableDomainObject which is
// used to insulate underlying objects from changes made // used to insulate underlying objects from changes made
// during editing. // during editing.
function doSave() { function doSave() {
return domainObject.getCapability("editor").save() return domainObject.getCapability("editor").save();
.then(resolveWith(domainObject));
} }
// Discard the current root view (which will be the editing function hideBlockingDialog() {
// UI, which will have been pushed atop the Browse UI.)
function returnToBrowse(object) {
if (object) {
object.getCapability("action").perform("navigate");
}
return object;
}
function hideBlockingDialog(object) {
dialog.hide(); dialog.hide();
return object;
} }
dialog.show(); dialog.show();
return doSave() return doSave()
.then(hideBlockingDialog) .then(hideBlockingDialog)
.then(returnToBrowse)
.catch(hideBlockingDialog); .catch(hideBlockingDialog);
}; };

View File

@ -0,0 +1,73 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
["./SaveAction"],
function (SaveAction) {
/**
* The "Save and Stop Editing" action performs a [Save action]{@link SaveAction}
* on the object under edit followed by exiting the edit user interface.
* @constructor
* @implements {Action}
* @memberof platform/commonUI/edit
*/
function SaveAndStopEditingAction(
dialogService,
context
) {
this.context = context;
this.domainObject = (context || {}).domainObject;
this.dialogService = dialogService;
}
/**
* Trigger a save operation and exit edit mode.
*
* @returns {Promise} a promise that will be fulfilled when
* cancellation has completed
* @memberof platform/commonUI/edit.SaveAndStopEditingAction#
*/
SaveAndStopEditingAction.prototype.perform = function () {
var domainObject = this.domainObject,
saveAction = new SaveAction(this.dialogService, this.context);
function closeEditor() {
return domainObject.getCapability("editor").finish();
}
return saveAction.perform()
.then(closeEditor)
.catch(closeEditor);
};
/**
* Check if this action is applicable in a given context.
* This will ensure that a domain object is present in the context,
* and that this domain object is in Edit mode.
* @returns true if applicable
*/
SaveAndStopEditingAction.appliesTo = SaveAction.appliesTo;
return SaveAndStopEditingAction;
}
);

View File

@ -42,7 +42,6 @@ define([
$injector, $injector,
policyService, policyService,
dialogService, dialogService,
creationService,
copyService, copyService,
context context
) { ) {
@ -52,7 +51,6 @@ define([
}; };
this.policyService = policyService; this.policyService = policyService;
this.dialogService = dialogService; this.dialogService = dialogService;
this.creationService = creationService;
this.copyService = copyService; this.copyService = copyService;
} }
@ -166,11 +164,16 @@ define([
.then(resolveWith(object)); .then(resolveWith(object));
} }
function commitEditingAfterClone(clonedObject) { function saveAfterClone(clonedObject) {
return domainObject.getCapability("editor").save() return domainObject.getCapability("editor").save()
.then(resolveWith(clonedObject)); .then(resolveWith(clonedObject));
} }
function finishEditing(clonedObject) {
return domainObject.getCapability("editor").finish()
.then(resolveWith(clonedObject));
}
function onFailure() { function onFailure() {
hideBlockingDialog(); hideBlockingDialog();
return false; return false;
@ -182,7 +185,8 @@ define([
.then(getParent) .then(getParent)
.then(cloneIntoParent) .then(cloneIntoParent)
.then(undirtyOriginals) .then(undirtyOriginals)
.then(commitEditingAfterClone) .then(saveAfterClone)
.then(finishEditing)
.then(hideBlockingDialog) .then(hideBlockingDialog)
.catch(onFailure); .catch(onFailure);
}; };

View File

@ -9,7 +9,8 @@ define([], function () {
title: "Saving...", title: "Saving...",
hint: "Do not navigate away from this page or close this browser tab while this message is displayed.", hint: "Do not navigate away from this page or close this browser tab while this message is displayed.",
unknownProgress: true, unknownProgress: true,
severity: "info" severity: "info",
delay: true
}); });
}; };

View File

@ -28,8 +28,8 @@ define(
* A capability that implements an editing 'session' for a domain * A capability that implements an editing 'session' for a domain
* object. An editing session is initiated via a call to .edit(). * object. An editing session is initiated via a call to .edit().
* Once initiated, any persist operations will be queued pending a * Once initiated, any persist operations will be queued pending a
* subsequent call to [.save()](@link #save) or [.cancel()](@link * subsequent call to [.save()](@link #save) or [.finish()](@link
* #cancel). * #finish).
* @param transactionService * @param transactionService
* @param domainObject * @param domainObject
* @constructor * @constructor
@ -45,7 +45,7 @@ define(
/** /**
* Initiate an editing session. This will start a transaction during * Initiate an editing session. This will start a transaction during
* which any persist operations will be deferred until either save() * which any persist operations will be deferred until either save()
* or cancel() are called. * or finish() are called.
*/ */
EditorCapability.prototype.edit = function () { EditorCapability.prototype.edit = function () {
this.transactionService.startTransaction(); this.transactionService.startTransaction();
@ -81,25 +81,25 @@ define(
}; };
/** /**
* Save any changes from this editing session. This will flush all * Save any unsaved changes from this editing session. This will
* pending persists and end the current transaction * end the current transaction and continue with a new one.
* @returns {*} * @returns {*}
*/ */
EditorCapability.prototype.save = function () { EditorCapability.prototype.save = function () {
var domainObject = this.domainObject; var transactionService = this.transactionService;
return this.transactionService.commit().then(function () { return transactionService.commit().then(function () {
domainObject.getCapability('status').set('editing', false); transactionService.startTransaction();
}); });
}; };
EditorCapability.prototype.invoke = EditorCapability.prototype.edit; EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
/** /**
* Cancel the current editing session. This will discard any pending * Finish the current editing session. This will discard any pending
* persist operations * persist operations
* @returns {*} * @returns {*}
*/ */
EditorCapability.prototype.cancel = function () { EditorCapability.prototype.finish = function () {
var domainObject = this.domainObject; var domainObject = this.domainObject;
return this.transactionService.cancel().then(function () { return this.transactionService.cancel().then(function () {
domainObject.getCapability("status").set("editing", false); domainObject.getCapability("status").set("editing", false);

View File

@ -27,7 +27,8 @@ define(
[], [],
function () { 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. * Controller which supplies action instances for Save/Cancel.
@ -35,12 +36,37 @@ define(
* @constructor * @constructor
*/ */
function EditActionController($scope) { 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() { function updateActions() {
$scope.editActions = $scope.action ? $scope.saveActions = $scope.action ?
$scope.action.getActions(ACTION_CONTEXT) : $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) :
[];
// Required because Angular does not allow 'bind'
// in expressions.
$scope.actionPerformer = function (action) {
return action.perform.bind(action);
};
} }
// Update set of actions whenever the action capability // Update set of actions whenever the action capability

View File

@ -67,12 +67,17 @@ define(
editAction, editAction,
editorCapability; editorCapability;
function closeEditor() {
return editorCapability.finish();
}
function onSave() { function onSave() {
return editorCapability.save(); return editorCapability.save()
.then(closeEditor);
} }
function onCancel() { function onCancel() {
return editorCapability.cancel(); return closeEditor();
} }
newModel.type = this.type.getKey(); newModel.type = this.type.getKey();
@ -85,9 +90,9 @@ define(
if (editAction) { if (editAction) {
return editAction.perform(); return editAction.perform();
} else if (editorCapability) { } else if (editorCapability) {
//otherwise, use the save action //otherwise, use the save as action
editorCapability.edit(); editorCapability.edit();
return newObject.getCapability("action").perform("save").then(onSave, onCancel); return newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
} }
}; };

View File

@ -138,7 +138,7 @@ define(
try { try {
results.push(onCancel()); results.push(onCancel());
} catch (error) { } catch (error) {
this.$log.error("Error committing transaction."); this.$log.error("Error cancelling transaction.");
} }
} }
return this.$q.all(results).then(function () { return this.$q.all(results).then(function () {

View File

@ -63,7 +63,7 @@ define(
capabilities.editor = jasmine.createSpyObj( capabilities.editor = jasmine.createSpyObj(
"editor", "editor",
["save", "cancel", "isEditContextRoot"] ["save", "finish", "isEditContextRoot"]
); );
capabilities.action = jasmine.createSpyObj( capabilities.action = jasmine.createSpyObj(
"actionCapability", "actionCapability",
@ -105,7 +105,7 @@ define(
return !!capabilities[name]; return !!capabilities[name];
}); });
capabilities.editor.cancel.andReturn(mockPromise(true)); capabilities.editor.finish.andReturn(mockPromise(true));
action = new CancelAction(actionContext); action = new CancelAction(actionContext);
@ -130,8 +130,8 @@ define(
capabilities.action.perform.andReturn(mockPromise(true)); capabilities.action.perform.andReturn(mockPromise(true));
action.perform(); action.perform();
// Should have called cancel // Should have called finish
expect(capabilities.editor.cancel).toHaveBeenCalled(); expect(capabilities.editor.finish).toHaveBeenCalled();
// Definitely shouldn't call save! // Definitely shouldn't call save!
expect(capabilities.editor.save).not.toHaveBeenCalled(); expect(capabilities.editor.save).not.toHaveBeenCalled();

View File

@ -58,7 +58,7 @@ define(
); );
mockEditor = jasmine.createSpyObj( mockEditor = jasmine.createSpyObj(
"editorCapability", "editorCapability",
["edit", "isEditContextRoot", "cancel"] ["edit", "isEditContextRoot"]
); );
capabilities = { capabilities = {
@ -98,13 +98,6 @@ define(
expect(EditAction.appliesTo(actionContext)).toBe(false); expect(EditAction.appliesTo(actionContext)).toBe(false);
}); });
it ("cancels editing when user navigates away", function () {
action.perform();
expect(mockNavigationService.addListener).toHaveBeenCalled();
mockNavigationService.addListener.mostRecentCall.args[0]();
expect(mockEditor.cancel).toHaveBeenCalled();
});
it ("invokes the Edit capability on the object", function () { it ("invokes the Edit capability on the object", function () {
action.perform(); action.perform();
expect(mockDomainObject.useCapability).toHaveBeenCalledWith("editor"); expect(mockDomainObject.useCapability).toHaveBeenCalledWith("editor");

View File

@ -56,7 +56,7 @@ define(
); );
mockEditorCapability = jasmine.createSpyObj( mockEditorCapability = jasmine.createSpyObj(
"editor", "editor",
["save", "cancel", "isEditContextRoot"] ["save", "isEditContextRoot"]
); );
mockActionCapability = jasmine.createSpyObj( mockActionCapability = jasmine.createSpyObj(
"actionCapability", "actionCapability",
@ -105,12 +105,6 @@ define(
expect(mockEditorCapability.save).toHaveBeenCalled(); expect(mockEditorCapability.save).toHaveBeenCalled();
}); });
it("navigates to the object after saving",
function () {
action.perform();
expect(mockActionCapability.perform).toHaveBeenCalledWith("navigate");
});
describe("a blocking dialog", function () { describe("a blocking dialog", function () {
var mockDialogHandle; var mockDialogHandle;

View File

@ -0,0 +1,123 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
["../../src/actions/SaveAndStopEditingAction"],
function (SaveAndStopEditingAction) {
describe("The Save and Stop Editing action", function () {
// Some mocks appear unused because the
// underlying SaveAction that this action
// depends on is not mocked, so we mock some
// of SaveAction's own dependencies to make
// it run.
var mockDomainObject,
mockEditorCapability,
actionContext,
dialogService,
mockActionCapability,
capabilities = {},
action;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
},
catch: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[
"getCapability",
"hasCapability",
"getModel",
"getOriginalObject"
]
);
mockEditorCapability = jasmine.createSpyObj(
"editor",
["save", "finish", "isEditContextRoot"]
);
mockActionCapability = jasmine.createSpyObj(
"actionCapability",
["perform"]
);
capabilities.editor = mockEditorCapability;
capabilities.action = mockActionCapability;
actionContext = {
domainObject: mockDomainObject
};
dialogService = jasmine.createSpyObj(
"dialogService",
["showBlockingMessage"]
);
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andCallFake(function (capability) {
return capabilities[capability];
});
mockDomainObject.getModel.andReturn({ persisted: 0 });
mockEditorCapability.save.andReturn(mockPromise(true));
mockEditorCapability.isEditContextRoot.andReturn(true);
action = new SaveAndStopEditingAction(dialogService, actionContext);
});
it("only applies to domain object with an editor capability", function () {
expect(SaveAndStopEditingAction.appliesTo(actionContext)).toBe(true);
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
mockDomainObject.hasCapability.andReturn(false);
mockDomainObject.getCapability.andReturn(undefined);
expect(SaveAndStopEditingAction.appliesTo(actionContext)).toBe(false);
});
it("only applies to domain object that has already been persisted", function () {
mockDomainObject.getModel.andReturn({ persisted: undefined });
expect(SaveAndStopEditingAction.appliesTo(actionContext)).toBe(false);
});
it("does not close the editor before completing the save", function () {
mockEditorCapability.save.andReturn(new Promise(function () {
}));
action.perform();
expect(mockEditorCapability.save).toHaveBeenCalled();
expect(mockEditorCapability.finish).not.toHaveBeenCalled();
});
it("closes the editor after saving", function () {
action.perform();
expect(mockEditorCapability.save).toHaveBeenCalled();
expect(mockEditorCapability.finish).toHaveBeenCalled();
});
});
}
);

View File

@ -19,7 +19,7 @@
* 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.
*****************************************************************************/ *****************************************************************************/
/*global describe,it,expect,beforeEach,jasmine*/ /*global describe,it,expect,beforeEach,jasmine,runs,waitsFor,spyOn*/
define( define(
["../../src/actions/SaveAsAction"], ["../../src/actions/SaveAsAction"],
@ -33,7 +33,6 @@ define(
mockDialogService, mockDialogService,
mockCopyService, mockCopyService,
mockParent, mockParent,
mockUrlService,
actionContext, actionContext,
capabilities = {}, capabilities = {},
action; action;
@ -78,10 +77,10 @@ define(
mockEditorCapability = jasmine.createSpyObj( mockEditorCapability = jasmine.createSpyObj(
"editor", "editor",
["save", "cancel", "isEditContextRoot"] ["save", "finish", "isEditContextRoot"]
); );
mockEditorCapability.cancel.andReturn(mockPromise(undefined));
mockEditorCapability.save.andReturn(mockPromise(true)); mockEditorCapability.save.andReturn(mockPromise(true));
mockEditorCapability.finish.andReturn(mockPromise(true));
mockEditorCapability.isEditContextRoot.andReturn(true); mockEditorCapability.isEditContextRoot.andReturn(true);
capabilities.editor = mockEditorCapability; capabilities.editor = mockEditorCapability;
@ -113,16 +112,11 @@ define(
] ]
); );
mockUrlService = jasmine.createSpyObj(
"urlService",
["urlForLocation"]
);
actionContext = { actionContext = {
domainObject: mockDomainObject domainObject: mockDomainObject
}; };
action = new SaveAsAction(undefined, undefined, mockDialogService, undefined, mockCopyService, actionContext); action = new SaveAsAction(undefined, undefined, mockDialogService, mockCopyService, actionContext);
spyOn(action, "getObjectService"); spyOn(action, "getObjectService");
action.getObjectService.andReturn(mockObjectService); action.getObjectService.andReturn(mockObjectService);
@ -156,6 +150,28 @@ define(
expect(SaveAsAction.appliesTo(actionContext)).toBe(false); expect(SaveAsAction.appliesTo(actionContext)).toBe(false);
}); });
it("uses the editor capability to save the object", function () {
mockEditorCapability.save.andReturn(new Promise(function () {}));
runs(function () {
action.perform();
});
waitsFor(function () {
return mockEditorCapability.save.calls.length > 0;
}, "perform() should call EditorCapability.save");
runs(function () {
expect(mockEditorCapability.finish).not.toHaveBeenCalled();
});
});
it("uses the editor capability to finish editing the object", function () {
runs(function () {
action.perform();
});
waitsFor(function () {
return mockEditorCapability.finish.calls.length > 0;
}, "perform() should call EditorCapability.finish");
});
it("returns to browse after save", function () { it("returns to browse after save", function () {
spyOn(action, "save"); spyOn(action, "save");
action.save.andReturn(mockPromise(mockDomainObject)); action.save.andReturn(mockPromise(mockDomainObject));

View File

@ -134,15 +134,15 @@ define(
it("commits the transaction", function () { it("commits the transaction", function () {
expect(mockTransactionService.commit).toHaveBeenCalled(); expect(mockTransactionService.commit).toHaveBeenCalled();
}); });
it("resets the edit state", function () { it("begins a new transaction", function () {
expect(mockStatusCapability.set).toHaveBeenCalledWith('editing', false); expect(mockTransactionService.startTransaction).toHaveBeenCalled();
}); });
}); });
describe("cancel", function () { describe("finish", function () {
beforeEach(function () { beforeEach(function () {
capability.edit(); capability.edit();
capability.cancel(); capability.finish();
}); });
it("cancels the transaction", function () { it("cancels the transaction", function () {
expect(mockTransactionService.cancel).toHaveBeenCalled(); expect(mockTransactionService.cancel).toHaveBeenCalled();
@ -158,7 +158,7 @@ define(
beforeEach(function () { beforeEach(function () {
mockDomainObject.getModel.andReturn(model); mockDomainObject.getModel.andReturn(model);
capability.edit(); capability.edit();
capability.cancel(); capability.finish();
}); });
it("returns true if the object has been modified since it" + it("returns true if the object has been modified since it" +
" was last persisted", function () { " was last persisted", function () {

View File

@ -19,22 +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.
*****************************************************************************/ *****************************************************************************/
/*global describe,it,expect,beforeEach,jasmine*/
define( define(
["../../src/controllers/EditActionController"], ["../../src/controllers/EditActionController"],
function (EditActionController) { function (EditActionController) {
describe("The Edit Action controller", function () { describe("The Edit Action controller", function () {
var mockSaveActionMetadata = {
name: "mocked-save-action",
cssclass: "mocked-save-action-css"
};
function fakeGetActions(actionContext) {
if (actionContext.category === "save") {
var mockedSaveActions = [
jasmine.createSpyObj("mockSaveAction", ["getMetadata", "perform"]),
jasmine.createSpyObj("mockSaveAction", ["getMetadata", "perform"])
];
mockedSaveActions.forEach(function (action) {
action.getMetadata.andReturn(mockSaveActionMetadata);
});
return mockedSaveActions;
} else if (actionContext.category === "conclude-editing") {
return ["a", "b", "c"];
} else {
throw "EditActionController uses a context that's not covered by tests.";
}
}
var mockScope, var mockScope,
mockActions, mockActions,
controller; controller;
beforeEach(function () { beforeEach(function () {
mockActions = jasmine.createSpyObj("action", ["getActions"]); mockActions = jasmine.createSpyObj("action", ["getActions"]);
mockActions.getActions.andCallFake(fakeGetActions);
mockScope = jasmine.createSpyObj("$scope", ["$watch"]); mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
mockScope.action = mockActions;
controller = new EditActionController(mockScope); controller = new EditActionController(mockScope);
}); });
function makeControllerUpdateActions() {
mockScope.$watch.mostRecentCall.args[1]();
}
it("watches scope that may change applicable actions", function () { it("watches scope that may change applicable actions", function () {
// The action capability // The action capability
expect(mockScope.$watch).toHaveBeenCalledWith( expect(mockScope.$watch).toHaveBeenCalledWith(
@ -43,16 +72,34 @@ define(
); );
}); });
it("populates the scope with grouped and ungrouped actions", function () { it("populates the scope with 'save' actions", function () {
mockScope.action = mockActions; 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 expect(menuOptions.length).toEqual(2);
mockScope.$watch.mostRecentCall.args[1](); expect(menuOptions[0].key).toEqual(mockScope.saveActions[0]);
expect(menuOptions[1].key).toEqual(mockScope.saveActions[1]);
menuOptions.forEach(function (option) {
expect(option.name).toEqual(mockSaveActionMetadata.name);
expect(option.cssclass).toEqual(mockSaveActionMetadata.cssclass);
});
});
// Should have grouped and ungrouped actions in scope now it("uses a click handler to perform the clicked action", function () {
expect(mockScope.editActions.length).toEqual(3); makeControllerUpdateActions();
var sampleSaveAction = mockScope.saveActions[0];
mockScope.saveActionMenuClickHandler(sampleSaveAction);
expect(sampleSaveAction.perform).toHaveBeenCalled();
});
it("populates the scope with other editing actions", function () {
makeControllerUpdateActions();
expect(mockScope.otherEditActions).toEqual(["a", "b", "c"]);
}); });
}); });
} }

View File

@ -103,7 +103,7 @@ define(
[ [
"edit", "edit",
"save", "save",
"cancel" "finish"
] ]
); );
@ -142,6 +142,7 @@ define(
}); });
describe("the perform function", function () { describe("the perform function", function () {
var promise = jasmine.createSpyObj("promise", ["then"]);
beforeEach(function () { beforeEach(function () {
capabilities.action.getActions.andReturn([mockEditAction]); capabilities.action.getActions.andReturn([mockEditAction]);
}); });
@ -156,19 +157,20 @@ define(
expect(mockEditAction.perform).toHaveBeenCalled(); expect(mockEditAction.perform).toHaveBeenCalled();
}); });
it("uses the save action if object does not have an edit action" + it("uses the save-as action if object does not have an edit action" +
" available", function () { " available", function () {
capabilities.action.getActions.andReturn([]); capabilities.action.getActions.andReturn([]);
capabilities.action.perform.andReturn(mockPromise(undefined)); capabilities.action.perform.andReturn(mockPromise(undefined));
capabilities.editor.save.andReturn(promise);
action.perform(); action.perform();
expect(capabilities.action.perform).toHaveBeenCalledWith("save"); expect(capabilities.action.perform).toHaveBeenCalledWith("save-as");
}); });
describe("uses to editor capability", function () { describe("uses to editor capability", function () {
var promise = jasmine.createSpyObj("promise", ["then"]);
beforeEach(function () { beforeEach(function () {
capabilities.action.getActions.andReturn([]); capabilities.action.getActions.andReturn([]);
capabilities.action.perform.andReturn(promise); capabilities.action.perform.andReturn(promise);
capabilities.editor.save.andReturn(promise);
}); });
it("to save the edit if user saves dialog", function () { it("to save the edit if user saves dialog", function () {
@ -178,10 +180,10 @@ define(
expect(capabilities.editor.save).toHaveBeenCalled(); expect(capabilities.editor.save).toHaveBeenCalled();
}); });
it("to cancel the edit if user cancels dialog", function () { it("to finish the edit if user cancels dialog", function () {
action.perform(); action.perform();
promise.then.mostRecentCall.args[1](); promise.then.mostRecentCall.args[1]();
expect(capabilities.editor.cancel).toHaveBeenCalled(); expect(capabilities.editor.finish).toHaveBeenCalled();
}); });
}); });
}); });

View File

@ -195,7 +195,7 @@ define(
expect(failure).toHaveBeenCalled(); expect(failure).toHaveBeenCalled();
}); });
it("logs an error when mutaton fails", function () { it("logs an error when mutation fails", function () {
// If mutation of the parent fails, we've lost the // If mutation of the parent fails, we've lost the
// created object - this is an error. // created object - this is an error.
var model = { someKey: "some value" }; var model = { someKey: "some value" };

View File

@ -112,7 +112,7 @@ define(
expect(mockPersistence.persist).toHaveBeenCalled(); expect(mockPersistence.persist).toHaveBeenCalled();
// Finally, check that the provided mutation function // Finally, check that the provided mutation function
// includes both model and configuratioon // includes both model and configuration
expect( expect(
mockDomainObject.useCapability.mostRecentCall.args[1]() mockDomainObject.useCapability.mostRecentCall.args[1]()
).toEqual({ ).toEqual({

View File

@ -79,7 +79,7 @@ define(
it("removes state from parent scope on destroy", function () { it("removes state from parent scope on destroy", function () {
// Verify precondition // Verify precondition
expect(mockScope.$parent.testToolbar).toBeDefined(); expect(mockScope.$parent.testToolbar).toBeDefined();
// Destroy the represeter // Destroy the representer
representer.destroy(); representer.destroy();
// Should have removed toolbar state from view // Should have removed toolbar state from view
expect(mockScope.$parent.testToolbar).toBeUndefined(); expect(mockScope.$parent.testToolbar).toBeUndefined();

View File

@ -61,6 +61,9 @@ $ueDesktopMinW: 600px;
$ovrTopBarH: 45px; $ovrTopBarH: 45px;
$ovrFooterH: 24px; $ovrFooterH: 24px;
$overlayMargin: 25px; $overlayMargin: 25px;
/*************** Progress Overlay */
$durEntryMs: 50ms;
$delayEntryMs: 100ms;
/*************** Items */ /*************** Items */
$ueBrowseGridItemLg: 200px; $ueBrowseGridItemLg: 200px;
$ueBrowseGridItemTopBarH: 20px; $ueBrowseGridItemTopBarH: 20px;

View File

@ -31,23 +31,10 @@
.has-control-bar { .has-control-bar {
$btnExportH: $btnFrameH; $btnExportH: $btnFrameH;
.l-control-bar { .l-control-bar {
@include trans-prop-nice(opacity, $dur: 50ms); display: none;
opacity: 0;
} }
.l-view-section { .l-view-section {
@include trans-prop-nice(top, $dur: 150ms, $delay: 50ms);
top: 0; top: 0;
} }
&:hover {
.l-control-bar {
@include trans-prop-nice(opacity, 150ms, 100ms);
opacity: 1;
} }
.l-view-section {
@include trans-prop-nice(top, $dur: 150ms);
top: $btnExportH + $interiorMargin;
}
}
}
} }

View File

@ -216,6 +216,7 @@ input[type="search"] {
.l-input-lg input[type="text"] { width: 100% !important; } .l-input-lg input[type="text"] { width: 100% !important; }
.l-input-med input[type="text"] { width: 200px !important; } .l-input-med input[type="text"] { width: 200px !important; }
.l-input-sm input[type="text"] { width: 50px !important; } .l-input-sm input[type="text"] { width: 50px !important; }
.l-textarea-sm textarea { position: relative; height: 50px; }
.l-numeric input[type="text"] { text-align: right; } .l-numeric input[type="text"] { text-align: right; }
.input-labeled { .input-labeled {

View File

@ -19,8 +19,17 @@
* 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.
*****************************************************************************/ *****************************************************************************/
.overlay { .overlay {
font-size: 90%; font-size: 90%;
&.delayEntry100ms {
@include keyframes(fadeInFromNone) {
0% { display: none; opacity: 0; }
100% { display: block; opacity: 1; }
}
@include animation-delay($delayEntryMs);
@include animation(fadeInFromNone $durEntryMs ease-in);
}
.blocker { .blocker {
background: $colorOvrBlocker; background: $colorOvrBlocker;
z-index: 100; z-index: 100;

View File

@ -38,7 +38,7 @@ define(
$scope.contextutalParents = []; $scope.contextutalParents = [];
//$scope.isLink = false; //$scope.isLink = false;
// Gets an array of the contextual parents/anscestors of the selected object // Gets an array of the contextual parents/ancestors of the selected object
function getContextualPath() { function getContextualPath() {
var currentObj = $scope.ngModel.selectedObject, var currentObj = $scope.ngModel.selectedObject,
currentParent, currentParent,
@ -61,7 +61,7 @@ define(
$scope.contextutalParents = parents; $scope.contextutalParents = parents;
} }
// Gets an array of the parents/anscestors of the selected object's // Gets an array of the parents/ancestors of the selected object's
// primary location (locational of original non-link) // primary location (locational of original non-link)
function getPrimaryPath(current) { function getPrimaryPath(current) {
var location; var location;

View File

@ -25,7 +25,7 @@ define(function () {
/** /**
* Implements the `reverse` filter, which reverses text strings. * Implements the `reverse` filter, which reverses text strings.
* Useful in cases where text should be reversed for presentational * Useful in cases where text should be reversed for presentational
* reasons (e.g. in conjunction with CSS tricks involing text direction), * reasons (e.g. in conjunction with CSS tricks involving text direction),
* allowing such behavior to be handled independently from the controller * allowing such behavior to be handled independently from the controller
* layer. * layer.
* *

View File

@ -35,7 +35,7 @@ define(
} }
/** /**
* Options controlling how the popup is displaed. * Options controlling how the popup is displayed.
* *
* @typedef PopupOptions * @typedef PopupOptions
* @memberof platform/commonUI/general * @memberof platform/commonUI/general

View File

@ -60,7 +60,7 @@ define(
expect(controller.isActive()).toBe(false); expect(controller.isActive()).toBe(false);
}); });
it("allows active state to be explictly specified", function () { it("allows active state to be explicitly specified", function () {
controller.setState(true); controller.setState(true);
expect(controller.isActive()).toBe(true); expect(controller.isActive()).toBe(true);
controller.setState(true); controller.setState(true);

View File

@ -46,7 +46,7 @@ define(
expect(controller.isActive()).toBe(false); expect(controller.isActive()).toBe(false);
}); });
it("allows active state to be explictly specified", function () { it("allows active state to be explicitly specified", function () {
controller.setState(true); controller.setState(true);
expect(controller.isActive()).toBe(true); expect(controller.isActive()).toBe(true);
controller.setState(true); controller.setState(true);

View File

@ -72,7 +72,7 @@ define(
expect(directive.restrict).toEqual("A"); expect(directive.restrict).toEqual("A");
}); });
it("transcludes at the elmeent level", function () { it("transcludes at the element level", function () {
expect(directive.transclude).toEqual('element'); expect(directive.transclude).toEqual('element');
}); });

View File

@ -361,7 +361,7 @@ define(
autodismiss specified), leave it to run. Otherwise force a autodismiss specified), leave it to run. Otherwise force a
timeout. timeout.
This notifcation has been added to queue and will be This notification has been added to queue and will be
serviced as soon as possible. serviced as soon as possible.
*/ */
this.active.timeout = this.$timeout(function () { this.active.timeout = this.$timeout(function () {

View File

@ -45,7 +45,7 @@ define(
['getKey', 'getDefinition', 'getInitialModel'] ['getKey', 'getDefinition', 'getInitialModel']
); );
mockType.getKey.andReturn(type); mockType.getKey.andReturn(type);
// Return a model to drive apparant capabilities // Return a model to drive apparent capabilities
mockType.getInitialModel.andReturn({ id: type }); mockType.getInitialModel.andReturn({ id: type });
return mockType; return mockType;
}); });

View File

@ -50,7 +50,7 @@ define(
// third one defines no containership rules // third one defines no containership rules
contains: (index < 2) ? [{ has: 'b' }] : undefined contains: (index < 2) ? [{ has: 'b' }] : undefined
}); });
// Return a model to drive apparant capabilities // Return a model to drive apparent capabilities
mockType.getInitialModel.andReturn({ id: type }); mockType.getInitialModel.andReturn({ id: type });
return mockType; return mockType;
}); });

View File

@ -252,6 +252,14 @@ define([
"pattern": "\\S+", "pattern": "\\S+",
"required": true, "required": true,
"cssclass": "l-input-lg" "cssclass": "l-input-lg"
},
{
"name": "Notes",
"key": "notes",
"property": "notes",
"control": "textarea",
"required": false,
"cssclass": "l-textarea-sm"
} }
] ]
}, },

View File

@ -24,7 +24,7 @@ define([], function () {
/** /**
* Provides a cache for domain object models which exist in memory, * Provides a cache for domain object models which exist in memory,
* but may or may not exist in backing persistene stores. * but may or may not exist in backing persistence stores.
* @constructor * @constructor
* @memberof platform/core * @memberof platform/core
*/ */

View File

@ -42,7 +42,7 @@ define(
* @implements {ModelService} * @implements {ModelService}
* @param {Array} roots all `roots[]` extensions * @param {Array} roots all `roots[]` extensions
* @param $q Angular's $q, for promises * @param $q Angular's $q, for promises
* @param $log Anuglar's $log, for logging * @param $log Angular's $log, for logging
*/ */
function RootModelProvider(roots, $q, $log) { function RootModelProvider(roots, $q, $log) {
// Pull out identifiers to used as ROOT's // Pull out identifiers to used as ROOT's

View File

@ -49,7 +49,7 @@ define(
} }
} }
// Prepoulate maps with models to make subsequent lookup faster. // Prepopulate maps with models to make subsequent lookup faster.
models.forEach(addModelToMap); models.forEach(addModelToMap);
this.modelMap = modelMap; this.modelMap = modelMap;

View File

@ -43,7 +43,7 @@ define(
}, },
ARRAY_SUFFIX = '[]'; ARRAY_SUFFIX = '[]';
// Utility function to handle arrays of conversiions // Utility function to handle arrays of conversions
function ArrayConversion(conversion) { function ArrayConversion(conversion) {
return { return {
toModelValue: function (formValue) { toModelValue: function (formValue) {

View File

@ -68,7 +68,7 @@ define(
}) : array; }) : array;
} }
// Reduce an array of type definitions to a single type definiton, // Reduce an array of type definitions to a single type definition,
// which has merged all properties in order. // which has merged all properties in order.
function collapse(typeDefs) { function collapse(typeDefs) {
var collapsed = typeDefs.reduce(function (a, b) { var collapsed = typeDefs.reduce(function (a, b) {

View File

@ -3,7 +3,7 @@
Entanglement is the process of moving, copying, and linking domain objects Entanglement is the process of moving, copying, and linking domain objects
in such a way that their relationships are impossible to discern. in such a way that their relationships are impossible to discern.
This bundle provides move, copy, and link functionality. Acheiving a state of This bundle provides move, copy, and link functionality. Achieving a state of
entanglement is left up to the end user. entanglement is left up to the end user.

View File

@ -94,7 +94,7 @@ define(
}; };
/** /**
* End a drag gesture. This should be callled when a drag * End a drag gesture. This should be called when a drag
* concludes to trigger commit of changes. * concludes to trigger commit of changes.
*/ */
FixedDragHandle.prototype.endDrag = function () { FixedDragHandle.prototype.endDrag = function () {

View File

@ -152,7 +152,7 @@ define(
} }
// Convert from { positions: ..., dimensions: ... } to an // Convert from { positions: ..., dimensions: ... } to an
// apropriate ng-style argument, to position frames. // appropriate ng-style argument, to position frames.
LayoutController.prototype.convertPosition = function (raw) { LayoutController.prototype.convertPosition = function (raw) {
var gridSize = this.gridSize; var gridSize = this.gridSize;
// Multiply position/dimensions by grid size // Multiply position/dimensions by grid size

View File

@ -164,7 +164,7 @@ define(
// Populate scope // Populate scope
mockScope.$watchCollection.mostRecentCall.args[1](); mockScope.$watchCollection.mostRecentCall.args[1]();
// Verify precondtion // Verify precondition
expect(testConfiguration.panels.b).not.toBeDefined(); expect(testConfiguration.panels.b).not.toBeDefined();
// Do a drag // Do a drag

View File

@ -146,16 +146,6 @@ define([
"copyright": "Copyright © 2012 Niklas von Hertzen.", "copyright": "Copyright © 2012 Niklas von Hertzen.",
"license": "license-mit", "license": "license-mit",
"link": "https://github.com/niklasvh/html2canvas/blob/master/LICENSE" "link": "https://github.com/niklasvh/html2canvas/blob/master/LICENSE"
},
{
"name": "jsPDF",
"version": "1.2.61",
"author": "James Hall",
"description": "JavaScript HTML renderer",
"website": "https://github.com/MrRio/jsPDF",
"copyright": "Copyright © 2010-2016 James Hall",
"license": "license-mit",
"link": "https://github.com/MrRio/jsPDF/blob/master/MIT-LICENSE.txt"
} }
] ]
} }

View File

@ -23,11 +23,6 @@
class="abs holder holder-plot has-control-bar"> class="abs holder holder-plot has-control-bar">
<div class="l-control-bar" ng-show="!plot.hideExportButtons"> <div class="l-control-bar" ng-show="!plot.hideExportButtons">
<span class="l-btn-set"> <span class="l-btn-set">
<a class="s-button t-export icon-download labeled first"
ng-click="plot.exportPDF()"
title="Export This View's Data as PDF">
PDF
</a>
<a class="s-button t-export labeled" <a class="s-button t-export labeled"
ng-click="plot.exportPNG()" ng-click="plot.exportPNG()"
title="Export This View's Data as PNG"> title="Export This View's Data as PNG">

View File

@ -380,17 +380,6 @@ define(
} }
}; };
/**
* Export the plot to PDF
*/
PlotController.prototype.exportPDF = function () {
var self = this;
self.hideExportButtons = true;
self.exportImageService.exportPDF(self.$element[0], "plot.pdf").finally(function () {
self.hideExportButtons = false;
});
};
/** /**
* Export the plot to PNG * Export the plot to PNG
*/ */

View File

@ -26,32 +26,29 @@
define( define(
[ [
"html2canvas", "html2canvas",
"jsPDF",
"saveAs" "saveAs"
], ],
function ( function (
html2canvas, html2canvas,
jsPDF,
saveAs saveAs
) { ) {
var self = this; var self = this;
/** /**
* The export image service will export any HTML node to * The export image service will export any HTML node to
* PDF, JPG, or PNG. * JPG, or PNG.
* @param {object} $q * @param {object} $q
* @param {object} $timeout * @param {object} $timeout
* @param {object} $log * @param {object} $log
* @param {constant} EXPORT_IMAGE_TIMEOUT time in milliseconds before a timeout error is returned * @param {constant} EXPORT_IMAGE_TIMEOUT time in milliseconds before a timeout error is returned
* @constructor * @constructor
*/ */
function ExportImageService($q, $timeout, $log, EXPORT_IMAGE_TIMEOUT, injHtml2Canvas, injJsPDF, injSaveAs, injFileReader) { function ExportImageService($q, $timeout, $log, EXPORT_IMAGE_TIMEOUT, injHtml2Canvas, injSaveAs, injFileReader) {
self.$q = $q; self.$q = $q;
self.$timeout = $timeout; self.$timeout = $timeout;
self.$log = $log; self.$log = $log;
self.EXPORT_IMAGE_TIMEOUT = EXPORT_IMAGE_TIMEOUT; self.EXPORT_IMAGE_TIMEOUT = EXPORT_IMAGE_TIMEOUT;
self.html2canvas = injHtml2Canvas || html2canvas; self.html2canvas = injHtml2Canvas || html2canvas;
self.jsPDF = injJsPDF || jsPDF;
self.saveAs = injSaveAs || saveAs; self.saveAs = injSaveAs || saveAs;
self.reader = injFileReader || new FileReader(); self.reader = injFileReader || new FileReader();
} }
@ -128,23 +125,6 @@ define(
} }
} }
/**
* Takes a screenshot of a DOM node and exports to PDF.
* @param {node} element to be exported
* @param {string} filename the exported image
* @returns {promise}
*/
ExportImageService.prototype.exportPDF = function (element, filename) {
return renderElement(element, "jpeg").then(function (img) {
self.reader.readAsDataURL(img);
self.reader.onloadend = function () {
var pdf = new self.jsPDF("l", "px", [element.offsetHeight, element.offsetWidth]);
pdf.addImage(self.reader.result, "JPEG", 0, 0, element.offsetWidth, element.offsetHeight);
pdf.save(filename);
};
});
};
/** /**
* Takes a screenshot of a DOM node and exports to JPG. * Takes a screenshot of a DOM node and exports to JPG.
* @param {node} element to be exported * @param {node} element to be exported

View File

@ -59,7 +59,7 @@ define(
expect(mock2d.clearRect).toHaveBeenCalled(); expect(mock2d.clearRect).toHaveBeenCalled();
}); });
it("doees not construct if 2D is unavailable", function () { it("does not construct if 2D is unavailable", function () {
mockCanvas.getContext.andReturn(undefined); mockCanvas.getContext.andReturn(undefined);
expect(function () { expect(function () {
return new Canvas2DChart(mockCanvas); return new Canvas2DChart(mockCanvas);

View File

@ -82,7 +82,7 @@ define(
expect(mockGL.clear).toHaveBeenCalled(); expect(mockGL.clear).toHaveBeenCalled();
}); });
it("doees not construct if WebGL is unavailable", function () { it("does not construct if WebGL is unavailable", function () {
mockCanvas.getContext.andReturn(undefined); mockCanvas.getContext.andReturn(undefined);
expect(function () { expect(function () {
return new GLChart(mockCanvas); return new GLChart(mockCanvas);

View File

@ -73,7 +73,7 @@ define(
mockElement = angular.element('<div />'); mockElement = angular.element('<div />');
mockExportImageService = jasmine.createSpyObj( mockExportImageService = jasmine.createSpyObj(
"ExportImageService", "ExportImageService",
["exportJPG", "exportPNG", "exportPDF"] ["exportJPG", "exportPNG"]
); );
mockFormatter = jasmine.createSpyObj( mockFormatter = jasmine.createSpyObj(
"formatter", "formatter",

View File

@ -33,8 +33,6 @@ define(
mockLog, mockLog,
mockHtml2Canvas, mockHtml2Canvas,
mockCanvas, mockCanvas,
mockJsPDF,
mockJsPDFSave,
mockSaveAs, mockSaveAs,
mockFileReader, mockFileReader,
mockExportTimeoutConstant, mockExportTimeoutConstant,
@ -79,13 +77,6 @@ define(
"canvas", "canvas",
["toBlob"] ["toBlob"]
); );
mockJsPDFSave = jasmine.createSpy("jsPDFSave");
mockJsPDF = function () {
return {
"addImage": function () {},
"save": mockJsPDFSave
};
};
mockSaveAs = jasmine.createSpy("saveAs"); mockSaveAs = jasmine.createSpy("saveAs");
mockFileReader = jasmine.createSpyObj( mockFileReader = jasmine.createSpyObj(
"FileReader", "FileReader",
@ -100,23 +91,11 @@ define(
mockLog, mockLog,
mockExportTimeoutConstant, mockExportTimeoutConstant,
mockHtml2Canvas, mockHtml2Canvas,
mockJsPDF,
mockSaveAs, mockSaveAs,
mockFileReader mockFileReader
); );
}); });
it("runs html2canvas and tries to save a pdf", function () {
exportImageService.exportPDF(testElement, "plot.pdf");
mockFileReader.onloadend();
expect(mockHtml2Canvas).toHaveBeenCalledWith(testElement, { onrendered: jasmine.any(Function) });
expect(mockCanvas.toBlob).toHaveBeenCalledWith(mockDeferred.resolve, "image/jpeg");
expect(mockDeferred.reject).not.toHaveBeenCalled();
expect(mockJsPDFSave).toHaveBeenCalled();
expect(mockPromise.finally).toHaveBeenCalled();
});
it("runs html2canvas and tries to save a png", function () { it("runs html2canvas and tries to save a png", function () {
exportImageService.exportPNG(testElement, "plot.png"); exportImageService.exportPNG(testElement, "plot.png");

View File

@ -182,6 +182,16 @@ define([
"capacity" "capacity"
], ],
"pattern": "^-?\\d+(\\.\\d*)?$" "pattern": "^-?\\d+(\\.\\d*)?$"
},
{
"name": "Battery starting SOC (%)",
"control": "textfield",
"required": false,
"conversion": "number",
"property": [
"startingSOC"
],
"pattern": "^([0-9](\\.\\d*)?|[1-9][0-9](\\.\\d*)?|100)%?$"
} }
], ],
"model": { "model": {

View File

@ -37,7 +37,8 @@ define(
// Build graphs for this group of utilizations // Build graphs for this group of utilizations
function buildGraphs(utilizations) { function buildGraphs(utilizations) {
var utilizationMap = {}, var utilizationMap = {},
result = {}; result = {},
startingSOC;
// Bucket utilizations by type // Bucket utilizations by type
utilizations.forEach(function (u) { utilizations.forEach(function (u) {
@ -55,12 +56,14 @@ define(
if (domainObject.getModel().type === 'timeline' && if (domainObject.getModel().type === 'timeline' &&
result.power && result.power &&
domainObject.getModel().capacity > 0) { domainObject.getModel().capacity > 0) {
startingSOC = isNaN(parseFloat(domainObject.getModel().startingSOC)) ?
100 : parseFloat(domainObject.getModel().startingSOC);
result.battery = new CumulativeGraph( result.battery = new CumulativeGraph(
result.power, result.power,
0, 0,
domainObject.getModel().capacity, // Watts domainObject.getModel().capacity, // Watts
domainObject.getModel().capacity, (startingSOC / 100) * domainObject.getModel().capacity,
1 / 3600000 // millis-to-hour (since units are watt-hours) 1 / 3600000 // millis-to-hour (since units are watt-hours)
); );
} }

View File

@ -26,7 +26,7 @@ define(
/** /**
* Control for Gantt bars in a timeline view. * Control for Gantt bars in a timeline view.
* Primarily reesponsible for supporting the positioning of Gantt * Primarily responsible for supporting the positioning of Gantt
* bars; particularly, this ensures that the left and right edges * bars; particularly, this ensures that the left and right edges
* never go to far off screen, because in some environments this * never go to far off screen, because in some environments this
* will effect rendering performance without visible results. * will effect rendering performance without visible results.

View File

@ -28,7 +28,7 @@ define(
/** /**
* Provides labels for the tick mark area of a timeline view. * Provides labels for the tick mark area of a timeline view.
* Since the tick mark regin is potentially extremeley large, * Since the tick mark region is potentially extremely large,
* only the subset of ticks which will actually be shown in * only the subset of ticks which will actually be shown in
* view are provided. * view are provided.
* @constructor * @constructor

View File

@ -148,7 +148,7 @@ define(
var timespan = timespans[toId(id)]; var timespan = timespans[toId(id)];
// Use as setter if argument is present // Use as setter if argument is present
if ((typeof value === 'number') && timespan) { if ((typeof value === 'number') && timespan) {
// Set the end (ensuring it doesn't preceed start) // Set the end (ensuring it doesn't precede start)
timespan.setEnd( timespan.setEnd(
Math.max(value, timespan.getStart()) Math.max(value, timespan.getStart())
); );

View File

@ -41,7 +41,7 @@ define(
ids, ids,
candidates; candidates;
// Filter an id for inclustion // Filter an id for inclusion
function include(id) { function include(id) {
return id !== exclude; return id !== exclude;
} }

View File

@ -101,6 +101,7 @@ define(
it("provides a battery graph for timelines with capacity", function () { it("provides a battery graph for timelines with capacity", function () {
var mockCallback = jasmine.createSpy('callback'); var mockCallback = jasmine.createSpy('callback');
testModel.capacity = 1000; testModel.capacity = 1000;
testModel.startingSOC = 100;
testModel.type = "timeline"; testModel.type = "timeline";
mockDomainObject.useCapability.andReturn(asPromise([ mockDomainObject.useCapability.andReturn(asPromise([
{ key: "power", start: 0, end: 15 } { key: "power", start: 0, end: 15 }

View File

@ -32,6 +32,7 @@ define([
"text!./res/templates/controls/datetime.html", "text!./res/templates/controls/datetime.html",
"text!./res/templates/controls/select.html", "text!./res/templates/controls/select.html",
"text!./res/templates/controls/textfield.html", "text!./res/templates/controls/textfield.html",
"text!./res/templates/controls/textarea.html",
"text!./res/templates/controls/button.html", "text!./res/templates/controls/button.html",
"text!./res/templates/controls/color.html", "text!./res/templates/controls/color.html",
"text!./res/templates/controls/composite.html", "text!./res/templates/controls/composite.html",
@ -51,6 +52,7 @@ define([
datetimeTemplate, datetimeTemplate,
selectTemplate, selectTemplate,
textfieldTemplate, textfieldTemplate,
textareaTemplate,
buttonTemplate, buttonTemplate,
colorTemplate, colorTemplate,
compositeTemplate, compositeTemplate,
@ -103,6 +105,10 @@ define([
"key": "textfield", "key": "textfield",
"template": textfieldTemplate "template": textfieldTemplate
}, },
{
"key": "textarea",
"template": textareaTemplate
},
{ {
"key": "button", "key": "button",
"template": buttonTemplate "template": buttonTemplate

View File

@ -0,0 +1,31 @@
<!--
Open MCT, Copyright (c) 2014-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT 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 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.
-->
<span class='form-control shell'>
<span class='field control {{structure.cssclass}}'>
<textarea ng-required="ngRequired"
ng-model="ngModel[field]"
ng-pattern="ngPattern"
size="{{structure.size}}"
name="mctControl">
</textarea>
</span>
</span>

View File

@ -174,7 +174,7 @@ define(
* category. * category.
* *
* @param {string} category name of the extension category * @param {string} category name of the extension category
* @returns {Array} extension definitions of that cataegory * @returns {Array} extension definitions of that category
*/ */
Bundle.prototype.getExtensions = function (category) { Bundle.prototype.getExtensions = function (category) {
var extensions = this.definition.extensions[category] || [], var extensions = this.definition.extensions[category] || [],

View File

@ -27,7 +27,7 @@ define(
/** /**
* A CouchDocument describes domain object model in a format * A CouchDocument describes domain object model in a format
* which is easily read-written to CouchDB. This includes * which is easily read-written to CouchDB. This includes
* Couch's _id and _rev fields, as well as a sseparate * Couch's _id and _rev fields, as well as a separate
* metadata field which contains a subset of information found * metadata field which contains a subset of information found
* in the model itself (to support search optimization with * in the model itself (to support search optimization with
* CouchDB views.) * CouchDB views.)
@ -37,7 +37,7 @@ define(
* @param {object} model the model to store * @param {object} model the model to store
* @param {string} rev the revision to include (or undefined, * @param {string} rev the revision to include (or undefined,
* if no revision should be noted for couch) * if no revision should be noted for couch)
* @param {boolean} whether or not to mark this documnet as * @param {boolean} whether or not to mark this document as
* deleted (see CouchDB docs for _deleted) * deleted (see CouchDB docs for _deleted)
*/ */
function CouchDocument(id, model, rev, markDeleted) { function CouchDocument(id, model, rev, markDeleted) {

View File

@ -69,7 +69,7 @@ define(
initialDescrption = indicator.getDescription(), initialDescrption = indicator.getDescription(),
initialGlyphClass = indicator.getGlyphClass(); initialGlyphClass = indicator.getGlyphClass();
// Nominal just means getting back an objeect, without // Nominal just means getting back an object, without
// an error field. // an error field.
mockPromise.then.mostRecentCall.args[0]({ data: {} }); mockPromise.then.mostRecentCall.args[0]({ data: {} });
@ -88,7 +88,7 @@ define(
initialDescrption = indicator.getDescription(), initialDescrption = indicator.getDescription(),
initialGlyphClass = indicator.getGlyphClass(); initialGlyphClass = indicator.getGlyphClass();
// Nominal just means getting back an objeect, with // Nominal just means getting back an object, with
// an error field. // an error field.
mockPromise.then.mostRecentCall.args[0]( mockPromise.then.mostRecentCall.args[0](
{ data: { error: "Uh oh." } } { data: { error: "Uh oh." } }
@ -110,7 +110,7 @@ define(
initialDescrption = indicator.getDescription(), initialDescrption = indicator.getDescription(),
initialGlyphClass = indicator.getGlyphClass(); initialGlyphClass = indicator.getGlyphClass();
// Nominal just means getting back an objeect, without // Nominal just means getting back an object, without
// an error field. // an error field.
mockPromise.then.mostRecentCall.args[1]({ data: {} }); mockPromise.then.mostRecentCall.args[1]({ data: {} });

View File

@ -51,7 +51,7 @@ define([
* Search for domain objects using elasticsearch as a search provider. * Search for domain objects using elasticsearch as a search provider.
* *
* @param {String} searchTerm the term to search by. * @param {String} searchTerm the term to search by.
* @param {Number} [maxResults] the max numer of results to return. * @param {Number} [maxResults] the max number of results to return.
* @returns {Promise} promise for a modelResults object. * @returns {Promise} promise for a modelResults object.
*/ */
ElasticSearchProvider.prototype.query = function (searchTerm, maxResults) { ElasticSearchProvider.prototype.query = function (searchTerm, maxResults) {

View File

@ -71,7 +71,7 @@ define(
initialDescrption = indicator.getDescription(), initialDescrption = indicator.getDescription(),
initialGlyphClass = indicator.getGlyphClass(); initialGlyphClass = indicator.getGlyphClass();
// Nominal just means getting back an objeect, without // Nominal just means getting back an object, without
// an error field. // an error field.
mockPromise.then.mostRecentCall.args[0]({ data: {} }); mockPromise.then.mostRecentCall.args[0]({ data: {} });
@ -90,7 +90,7 @@ define(
initialDescrption = indicator.getDescription(), initialDescrption = indicator.getDescription(),
initialGlyphClass = indicator.getGlyphClass(); initialGlyphClass = indicator.getGlyphClass();
// Nominal just means getting back an objeect, without // Nominal just means getting back an object, without
// an error field. // an error field.
mockPromise.then.mostRecentCall.args[1]({ data: {} }); mockPromise.then.mostRecentCall.args[1]({ data: {} });

View File

@ -35,7 +35,7 @@ define(
/** /**
* The PersistenceQueue is used by the QueuingPersistenceCapability * The PersistenceQueue is used by the QueuingPersistenceCapability
* to aggregrate calls for object persistence. These are then issued * to aggregate calls for object persistence. These are then issued
* in a group, such that if some or all are rejected, this result can * in a group, such that if some or all are rejected, this result can
* be shown to the user (again, in a group.) * be shown to the user (again, in a group.)
* *

View File

@ -25,7 +25,7 @@ define(
function () { function () {
/** /**
* Handles actual persistence invocations for queeud persistence * Handles actual persistence invocations for queued persistence
* attempts, in a group. Handling in a group in this manner * attempts, in a group. Handling in a group in this manner
* also allows failure to be handled in a group (e.g. in a single * also allows failure to be handled in a group (e.g. in a single
* summary dialog.) * summary dialog.)

View File

@ -246,7 +246,7 @@ define([
/** /**
* @private * @private
* @returns {Number} a unique, unusued query Id. * @returns {Number} a unique, unused query Id.
*/ */
GenericSearchProvider.prototype.makeQueryId = function () { GenericSearchProvider.prototype.makeQueryId = function () {
var queryId = Math.ceil(Math.random() * 100000); var queryId = Math.ceil(Math.random() * 100000);

View File

@ -123,7 +123,7 @@ define([
expect(mockScope.results).toContain('a'); expect(mockScope.results).toContain('a');
}); });
it('is loading until the service\'s promise fufills', function () { it('is loading until the service\'s promise fulfills', function () {
expect(mockScope.loading).toBeTruthy(); expect(mockScope.loading).toBeTruthy();
// Then resolve the promises // Then resolve the promises
@ -163,7 +163,7 @@ define([
// Flag should be true with nonempty input // Flag should be true with nonempty input
expect(mockScope.ngModel.search).toEqual(true); expect(mockScope.ngModel.search).toEqual(true);
// Flag should be flase with empty input // Flag should be false with empty input
mockScope.ngModel.input = ''; mockScope.ngModel.input = '';
controller.search(); controller.search();
mockPromise.then.mostRecentCall.args[0]({hits: [], total: 0}); mockPromise.then.mostRecentCall.args[0]({hits: [], total: 0});

View File

@ -54,7 +54,7 @@ define(
controller = new SearchMenuController(mockScope, mockTypes); controller = new SearchMenuController(mockScope, mockTypes);
}); });
it("gets types on initiliztion", function () { it("gets types on initialization", function () {
expect(mockScope.ngModel.types).toBeDefined(); expect(mockScope.ngModel.types).toBeDefined();
}); });

View File

@ -31,7 +31,7 @@ define(
* `telemetrySubscriber`. * `telemetrySubscriber`.
* *
* Subscriptions may also be made directly using the * Subscriptions may also be made directly using the
* `telemetry` capability of a domain objcet; the subscriber * `telemetry` capability of a domain object; the subscriber
* uses this as well, but additionally handles delegation * uses this as well, but additionally handles delegation
* (e.g. for telemetry panels) as well as latest-value * (e.g. for telemetry panels) as well as latest-value
* extraction. * extraction.

View File

@ -57,7 +57,7 @@ define(
* `telemetrySubscriber` service. * `telemetrySubscriber` service.
* *
* Subscriptions may also be made directly using the * Subscriptions may also be made directly using the
* `telemetry` capability of a domain objcet; the subscriber * `telemetry` capability of a domain object; the subscriber
* uses this as well, but additionally handles delegation * uses this as well, but additionally handles delegation
* (e.g. for telemetry panels) as well as latest-value * (e.g. for telemetry panels) as well as latest-value
* extraction. * extraction.

View File

@ -56,7 +56,6 @@ requirejs.config({
"EventEmitter": "bower_components/eventemitter3/index", "EventEmitter": "bower_components/eventemitter3/index",
"es6-promise": "bower_components/es6-promise/es6-promise.min", "es6-promise": "bower_components/es6-promise/es6-promise.min",
"html2canvas": "bower_components/html2canvas/build/html2canvas.min", "html2canvas": "bower_components/html2canvas/build/html2canvas.min",
"jsPDF": "bower_components/jspdf/dist/jspdf.min",
"moment": "bower_components/moment/moment", "moment": "bower_components/moment/moment",
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format", "moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
"saveAs": "bower_components/FileSaver.js/FileSaver.min", "saveAs": "bower_components/FileSaver.js/FileSaver.min",