Merge branch 'master' of https://github.com/nasa/openmct into fix-tutorial

PR is also addresses #1206
This commit is contained in:
Ilya Bolkhovsky 2016-10-05 10:48:28 +03:00
commit 1f6ca8bcc3
19 changed files with 83 additions and 87 deletions

View File

@ -19,7 +19,6 @@
"comma-separated-values": "^3.6.4", "comma-separated-values": "^3.6.4",
"FileSaver.js": "^0.0.2", "FileSaver.js": "^0.0.2",
"zepto": "^1.1.6", "zepto": "^1.1.6",
"html2canvas": "^0.4.1", "html2canvas": "^0.4.1"
"jspdf": "^1.2.61"
} }
} }

View File

@ -29,7 +29,6 @@ requirejs.config({
"csv": "bower_components/comma-separated-values/csv.min", "csv": "bower_components/comma-separated-values/csv.min",
"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",
@ -48,9 +47,6 @@ requirejs.config({
"html2canvas": { "html2canvas": {
"exports": "html2canvas" "exports": "html2canvas"
}, },
"jsPDF": {
"exports": "jsPDF"
},
"moment-duration-format": { "moment-duration-format": {
"deps": ["moment"] "deps": ["moment"]
}, },

View File

@ -245,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

@ -25,7 +25,7 @@
<mct-control key="'button'" <mct-control key="'button'"
structure="{ structure="{
text: saveActions[0].getMetadata().name, text: saveActions[0].getMetadata().name,
click: saveActions[0].perform, click: actionPerformer(saveActions[0]),
cssclass: 'major ' + saveActions[0].getMetadata().cssclass cssclass: 'major ' + saveActions[0].getMetadata().cssclass
}"> }">
</mct-control> </mct-control>
@ -42,11 +42,12 @@
</span> </span>
<span ng-repeat="currentAction in otherEditActions"> <span ng-repeat="currentAction in otherEditActions">
<a class='s-button {{currentAction.getMetadata().cssclass}}' <mct-control key="'button'"
title='{{currentAction.getMetadata().name}}' structure="{
ng-click="currentAction.perform()" text: currentAction.getMetadata().name,
ng-class="{ major: $index === 0 && saveActions.length === 0 }"> click: actionPerformer(currentAction),
<span class="title-label">{{currentAction.getMetadata().name}}</span> cssclass: currentAction.getMetadata().cssclass
</a> }">
</mct-control>
</span> </span>
</span> </span>

View File

@ -61,6 +61,12 @@ define(
$scope.otherEditActions = $scope.action ? $scope.otherEditActions = $scope.action ?
$scope.action.getActions(OTHERS_ACTION_CONTEXT) : $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

@ -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

@ -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

@ -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

@ -368,17 +368,6 @@ define(
return this.pending; return this.pending;
}; };
/**
* 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

@ -72,7 +72,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

@ -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

@ -55,7 +55,6 @@ requirejs.config({
"csv": "bower_components/comma-separated-values/csv.min", "csv": "bower_components/comma-separated-values/csv.min",
"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",