Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nasa/openmct.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry <akhenry@gmail.com>2018-04-09 22:40:17 +0300
committerHenry <akhenry@gmail.com>2018-04-09 22:40:17 +0300
commit4d279481a5cd98182f474bcc75a52a8de836cac8 (patch)
tree7baa73712c705bba4e3f7aca5f7a93992a7f0bcc
parent674f608188f1678781a0ffd4bda8a64ccc57fff5 (diff)
Merged notebook branch based on painterro fixsim-rev0
-rw-r--r--bower.json2
-rw-r--r--index.html1
-rw-r--r--karma.conf.js2
-rw-r--r--openmct.js10
-rw-r--r--package.json2
-rw-r--r--platform/commonUI/browse/res/templates/browse.html2
-rw-r--r--platform/commonUI/browse/src/BrowseController.js23
-rw-r--r--platform/commonUI/browse/src/navigation/NavigationService.js5
-rw-r--r--platform/commonUI/general/bundle.js42
-rw-r--r--platform/commonUI/general/res/sass/_global.scss3
-rw-r--r--platform/commonUI/general/res/sass/_glyphs.scss8
-rw-r--r--platform/commonUI/general/res/sass/_mixins.scss2
-rw-r--r--platform/commonUI/general/res/sass/_widgets.scss33
-rw-r--r--platform/commonUI/general/res/sass/controls/_buttons.scss9
-rw-r--r--platform/commonUI/general/res/sass/controls/_controls.scss21
-rw-r--r--platform/commonUI/general/res/sass/features/_imagery.scss2
-rw-r--r--platform/commonUI/general/res/sass/mobile/_layout.scss22
-rw-r--r--platform/commonUI/general/res/sass/search/_search.scss36
-rw-r--r--platform/commonUI/general/res/sass/user-environ/_frame.scss2
-rw-r--r--platform/commonUI/general/res/templates/preview.html45
-rw-r--r--platform/commonUI/general/src/actions/MCTPreviewAction.js66
-rw-r--r--platform/commonUI/general/src/directives/MCTPreview.js67
-rw-r--r--platform/commonUI/general/src/services/Overlay.js191
-rw-r--r--platform/features/layout/src/MCTTriggerModal.js101
-rw-r--r--platform/features/layout/test/MCTTriggerModalSpec.js6
-rw-r--r--platform/features/notebook/bundle.js314
-rw-r--r--platform/features/notebook/res/sass/_notebook-base.scss283
-rw-r--r--platform/features/notebook/res/sass/_notebook-thematic.scss92
-rw-r--r--platform/features/notebook/res/sass/notebook-espresso.scss30
-rw-r--r--platform/features/notebook/res/sass/notebook-snow.scss30
-rw-r--r--platform/features/notebook/res/sass/notebook.scss28
-rw-r--r--platform/features/notebook/res/templates/annotation.html2
-rw-r--r--platform/features/notebook/res/templates/controls/embedControl.html51
-rw-r--r--platform/features/notebook/res/templates/controls/snapSelect.html30
-rw-r--r--platform/features/notebook/res/templates/entry.html38
-rw-r--r--platform/features/notebook/res/templates/frameLayoutNotebook.html54
-rw-r--r--platform/features/notebook/res/templates/layoutNotebook.html84
-rw-r--r--platform/features/notebook/res/templates/notebook.html124
-rw-r--r--platform/features/notebook/res/templates/notifications.html8
-rw-r--r--platform/features/notebook/src/actions/AnnotateSnapshot.js131
-rw-r--r--platform/features/notebook/src/actions/CreateSnapshot.js65
-rw-r--r--platform/features/notebook/src/actions/NewEntryContextual.js193
-rw-r--r--platform/features/notebook/src/actions/RemoveEmbed.js72
-rw-r--r--platform/features/notebook/src/actions/RemoveSnapshot.js74
-rw-r--r--platform/features/notebook/src/actions/ViewSnapshot.js169
-rw-r--r--platform/features/notebook/src/capabilities/NotebookCapability.js50
-rw-r--r--platform/features/notebook/src/controllers/LayoutNotebookController.js54
-rw-r--r--platform/features/notebook/src/controllers/NewEntryController.js66
-rw-r--r--platform/features/notebook/src/controllers/NotebookController.js400
-rw-r--r--platform/features/notebook/src/controllers/SelectSnapshotController.js44
-rw-r--r--platform/features/notebook/src/directives/EntryDnd.js126
-rw-r--r--platform/features/notebook/src/directives/MCTModalNotebook.js166
-rw-r--r--platform/features/notebook/src/directives/MCTSnapshot.js104
-rw-r--r--platform/features/notebook/src/policies/CompositionPolicy.js44
-rw-r--r--platform/features/notebook/src/policies/ViewPolicy.js40
-rw-r--r--platform/features/notebook/src/shims/painterro-shim.js13
-rw-r--r--platform/representation/src/MCTInclude.js6
-rw-r--r--platform/search/res/templates/search.html2
-rw-r--r--src/plugins/plot/src/services/ExportImageService.js11
-rw-r--r--src/plugins/plugins.js3
-rw-r--r--src/plugins/summaryWidget/res/conditionTemplate.html4
-rw-r--r--src/plugins/summaryWidget/res/ruleTemplate.html6
-rw-r--r--src/plugins/summaryWidget/res/testDataItemTemplate.html4
-rw-r--r--test-main.js7
64 files changed, 3572 insertions, 153 deletions
diff --git a/bower.json b/bower.json
index 59ead276f..37bff6b71 100644
--- a/bower.json
+++ b/bower.json
@@ -25,4 +25,4 @@
"html2canvas": "^0.4.1",
"moment-timezone": "^0.5.13"
}
-}
+} \ No newline at end of file
diff --git a/index.html b/index.html
index 1405bcec2..de14ae36e 100644
--- a/index.html
+++ b/index.html
@@ -68,6 +68,7 @@
]
}));
openmct.install(openmct.plugins.SummaryWidget());
+ openmct.install(openmct.plugins.Notebook());
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.start();
diff --git a/karma.conf.js b/karma.conf.js
index 2c8c27f93..0784638df 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -38,6 +38,8 @@ module.exports = function(config) {
{pattern: 'node_modules/d3-*/**/*.js', included: false},
{pattern: 'node_modules/vue/**/*.js', included: false},
{pattern: 'src/**/*', included: false},
+ {pattern: 'node_modules/@cristian77/**/*.js', included: false},
+ {pattern: 'node_modules/dom-to-image/dist/*', included: false},
{pattern: 'example/**/*.html', included: false},
{pattern: 'example/**/*.js', included: false},
{pattern: 'example/**/*.json', included: false},
diff --git a/openmct.js b/openmct.js
index 645e00520..ad9a0b83a 100644
--- a/openmct.js
+++ b/openmct.js
@@ -49,7 +49,9 @@ requirejs.config({
"d3-format": "node_modules/d3-format/build/d3-format.min",
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
"d3-time": "node_modules/d3-time/build/d3-time.min",
- "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min"
+ "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
+ "dom-to-image": "node_modules/dom-to-image/dist/dom-to-image.min",
+ "painterro": "node_modules/@cristian77/painterro/build/painterro.min"
},
"shim": {
"angular": {
@@ -67,6 +69,9 @@ requirejs.config({
"moment-duration-format": {
"deps": ["moment"]
},
+ "painterro": {
+ "exports": "Painterro"
+ },
"saveAs": {
"exports": "saveAs"
},
@@ -88,6 +93,9 @@ requirejs.config({
},
"d3-axis": {
"exports": "d3-axis"
+ },
+ "dom-to-image": {
+ "exports": "domtoimage"
}
}
});
diff --git a/package.json b/package.json
index 9a280f324..6ac03cedf 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,8 @@
"d3-selection": "1.3.x",
"d3-time": "1.0.x",
"d3-time-format": "2.1.x",
+ "@cristian77/painterro": "^0.2.48",
+ "dom-to-image": "^2.6.0",
"express": "^4.13.1",
"minimist": "^1.1.1",
"request": "^2.69.0",
diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html
index de03573bd..3c7103b7f 100644
--- a/platform/commonUI/browse/res/templates/browse.html
+++ b/platform/commonUI/browse/res/templates/browse.html
@@ -65,7 +65,7 @@
<div class='split-pane-component t-object pane primary-pane left'>
<mct-representation mct-object="navigatedObject"
key="navigatedObject.getCapability('status').get('editing') ? 'edit-object' : 'browse-object'"
- class="abs holder holder-object">
+ class="abs holder holder-object t-main-view">
</mct-representation>
<a class="mini-tab-icon anchor-right mobile-hide toggle-pane toggle-inspect flush-right"
title="{{ modelPaneInspect.visible()? 'Hide' : 'Show' }} the Inspection pane"
diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js
index 4a8119726..6b5cc2def 100644
--- a/platform/commonUI/browse/src/BrowseController.js
+++ b/platform/commonUI/browse/src/BrowseController.js
@@ -47,8 +47,10 @@ define(
urlService,
defaultPath
) {
- var initialPath = ($route.current.params.ids || defaultPath).split("/");
- var currentIds;
+ var initialPath = ($route.current.params.ids || defaultPath).split("/"),
+ currentIds,
+ actions,
+ previewAction;
$scope.treeModel = {
selectedObject: undefined,
@@ -56,7 +58,22 @@ define(
navigationService.setNavigation(object, true);
},
allowSelection: function (object) {
- return navigationService.shouldNavigate();
+ // return navigationService.shouldNavigate();
+ if (navigationService.anyChecksBeforeNavigation()) {
+
+ actions = actions || $scope.domainObject.getCapability('action');
+ previewAction = previewAction || actions.getActions({key: 'mct-preview-action'})[0];
+
+ if (previewAction && previewAction.perform) {
+ previewAction.perform(object);
+ return false;
+ } else {
+ return navigationService.shouldNavigate();
+ }
+
+ } else {
+ return true;
+ }
}
};
diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js
index 351bddc37..5cc7e04e8 100644
--- a/platform/commonUI/browse/src/navigation/NavigationService.js
+++ b/platform/commonUI/browse/src/navigation/NavigationService.js
@@ -109,6 +109,10 @@ define(
});
};
+ NavigationService.prototype.anyChecksBeforeNavigation = function () {
+ return this.checks.length;
+ };
+
/**
* Check if navigation should proceed. May prompt a user for input
* if any checkFns return messages. Returns true if the user wishes to
@@ -162,7 +166,6 @@ define(
*/
NavigationService.prototype.shouldWarnBeforeNavigate = function () {
var reasons = [];
-
this.checks.forEach(function (checkFn) {
var reason = checkFn();
if (reason) {
diff --git a/platform/commonUI/general/bundle.js b/platform/commonUI/general/bundle.js
index 8d62185cc..370a140cd 100644
--- a/platform/commonUI/general/bundle.js
+++ b/platform/commonUI/general/bundle.js
@@ -49,6 +49,8 @@ define([
"./src/directives/MCTSplitPane",
"./src/directives/MCTSplitter",
"./src/directives/MCTTree",
+ "./src/directives/MCTPreview",
+ "./src/actions/MCTPreviewAction",
"./src/filters/ReverseFilter",
"text!./res/templates/bottombar.html",
"text!./res/templates/controls/action-button.html",
@@ -69,6 +71,7 @@ define([
"text!./res/templates/controls/selector.html",
"text!./res/templates/controls/datetime-picker.html",
"text!./res/templates/controls/datetime-field.html",
+ "text!./res/templates/preview.html",
'legacyRegistry'
], function (
UrlService,
@@ -99,6 +102,8 @@ define([
MCTSplitPane,
MCTSplitter,
MCTTree,
+ MCTPreview,
+ MCTPreviewAction,
ReverseFilter,
bottombarTemplate,
actionButtonTemplate,
@@ -119,6 +124,7 @@ define([
selectorTemplate,
datetimePickerTemplate,
datetimeFieldTemplate,
+ previewTemplate,
legacyRegistry
) {
@@ -395,6 +401,38 @@ define([
"key": "mctTree",
"implementation": MCTTree,
"depends": ['gestureService']
+ },
+ {
+ "key": "mctPreview",
+ "implementation": MCTPreview,
+ "depends": [
+ "$rootScope",
+ "$document",
+ "exportImageService",
+ "dialogService",
+ "notificationService"
+ ]
+ }
+ ],
+ "actions": [
+ {
+ "key": "mct-preview-action",
+ "implementation": MCTPreviewAction,
+ "name": "Preview",
+ "cssClass": "hide-in-t-main-view icon-eye-open",
+ "description": "Preview in large dialog",
+ "category": [
+ "contextual",
+ "view-control"
+ ],
+ "depends": [
+ "$compile",
+ "$rootScope",
+ "dialogService",
+ "notificationService",
+ "linkService"
+ ],
+ "priority": "preferred"
}
],
"constants": [
@@ -510,6 +548,10 @@ define([
{
"key": "object-inspector",
"template": objectInspectorTemplate
+ },
+ {
+ "key": "mct-preview",
+ "template": previewTemplate
}
],
"controls": [
diff --git a/platform/commonUI/general/res/sass/_global.scss b/platform/commonUI/general/res/sass/_global.scss
index 8bcfeab8a..0e0af5d18 100644
--- a/platform/commonUI/general/res/sass/_global.scss
+++ b/platform/commonUI/general/res/sass/_global.scss
@@ -225,7 +225,8 @@ a.disabled {
}
.hide,
-.hidden {
+.hidden,
+.t-main-view .hide-in-t-main-view {
display: none !important;
}
diff --git a/platform/commonUI/general/res/sass/_glyphs.scss b/platform/commonUI/general/res/sass/_glyphs.scss
index b0a40d48e..07b83bb55 100644
--- a/platform/commonUI/general/res/sass/_glyphs.scss
+++ b/platform/commonUI/general/res/sass/_glyphs.scss
@@ -33,6 +33,14 @@
}
}
+[class*="icon-"].labeled {
+ // Moved from .s-button and generalized
+ &:before {
+ // Fend off label from icon when it's included
+ margin-right: $interiorMarginSm;
+ }
+}
+
/************************** CHAR UNICODES */
$glyph-icon-alert-rect: '\e900';
diff --git a/platform/commonUI/general/res/sass/_mixins.scss b/platform/commonUI/general/res/sass/_mixins.scss
index 216b425fb..1e61683fe 100644
--- a/platform/commonUI/general/res/sass/_mixins.scss
+++ b/platform/commonUI/general/res/sass/_mixins.scss
@@ -299,7 +299,7 @@
color: $ic;
}
@if $bgHov != none {
- &:not(.disabled):hover {
+ &:not([disabled="true"]):not(.disabled):hover {
background: $bgHov;
color: $fgHov;
>.icon,
diff --git a/platform/commonUI/general/res/sass/_widgets.scss b/platform/commonUI/general/res/sass/_widgets.scss
index ae6f3da4d..b4088d6c3 100644
--- a/platform/commonUI/general/res/sass/_widgets.scss
+++ b/platform/commonUI/general/res/sass/_widgets.scss
@@ -270,37 +270,4 @@
@extend .s-summary-widget;
@extend .l-summary-widget;
padding: $interiorMarginSm $interiorMargin;
-}
-
-// Hide and show elements in the rule-header on hover
-.l-widget-rule,
-.l-widget-test-data-item {
- .grippy,
- .l-rule-action-buttons-wrapper,
- .l-condition-action-buttons-wrapper,
- .l-widget-test-data-item-action-buttons-wrapper {
- @include trans-prop-nice($props: opacity, $dur: 500ms);
- opacity: 0;
- }
- &:hover {
- .grippy,
- .l-rule-action-buttons-wrapper,
- .l-widget-test-data-item-action-buttons-wrapper {
- @include trans-prop-nice($props: opacity, $dur: 0);
- opacity: 1;
- }
- }
- .l-rule-action-buttons-wrapper {
- .t-delete {
- margin-left: 10px;
- }
- }
- .t-condition {
- &:hover {
- .l-condition-action-buttons-wrapper {
- @include trans-prop-nice($props: opacity, $dur: 0);
- opacity: 1;
- }
- }
- }
} \ No newline at end of file
diff --git a/platform/commonUI/general/res/sass/controls/_buttons.scss b/platform/commonUI/general/res/sass/controls/_buttons.scss
index d568d66ae..b54d2dfbe 100644
--- a/platform/commonUI/general/res/sass/controls/_buttons.scss
+++ b/platform/commonUI/general/res/sass/controls/_buttons.scss
@@ -34,11 +34,6 @@ $pad: $interiorMargin * $baseRatio;
line-height: $btnStdH;
padding: 0 $pad;
- &.labeled:before {
- // Icon when it's included
- margin-right: $interiorMarginSm;
- }
-
&.lg {
font-size: 1rem;
}
@@ -59,6 +54,10 @@ $pad: $interiorMargin * $baseRatio;
.label, .title-label { display: none; }
}
+ &[disabled="true"] {
+ opacity: 0.3;
+ }
+
&.pause-play {
@extend .icon-pause;
&.paused {
diff --git a/platform/commonUI/general/res/sass/controls/_controls.scss b/platform/commonUI/general/res/sass/controls/_controls.scss
index dbc586886..ae975718e 100644
--- a/platform/commonUI/general/res/sass/controls/_controls.scss
+++ b/platform/commonUI/general/res/sass/controls/_controls.scss
@@ -139,7 +139,6 @@
}
.s-local-controls {
- @include trans-prop-nice(opacity);
font-size: 0.7rem;
&.s-wrapper-transluc {
// Semi-opaque wrapper to visually distinguish a control
@@ -150,6 +149,19 @@
}
}
+.has-local-controls {
+ .local-control {
+ @include trans-prop-nice($props: opacity, $dur: 250ms);
+ opacity: 0;
+ }
+ &:hover {
+ .local-control {
+ @include trans-prop-nice($props: opacity, $dur: 10ms);
+ opacity: 1;
+ }
+ }
+}
+
/******************************************************** VIEW CONTROLS */
// Expand/collapse > and v arrows, used in tree and plot legend
// Moved this over from a tree-only context 5/18/17
@@ -338,7 +350,7 @@ input[type="text"].s-input-inline,
@include btnSubtle($bg: $colorSelectBg);
@extend .icon-arrow-down; // Context arrow
display: inline-block;
- padding: 0 $interiorMargin;
+ line-height: 180%;
overflow: hidden;
position: relative;
select {
@@ -349,8 +361,8 @@ input[type="text"].s-input-inline,
color: $colorSelectFg;
cursor: pointer;
border: none !important;
- padding: 4px 25px 2px 0px;
- width: 130%;
+ padding: 0 20px 0 $interiorMargin;
+ width: 100%;
option {
margin: $interiorMargin 0; // Firefox
}
@@ -359,6 +371,7 @@ input[type="text"].s-input-inline,
@include transform(translateY(-50%));
color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
display: block;
+ font-size: 0.8em;
pointer-events: none;
position: absolute;
right: $interiorMargin;
diff --git a/platform/commonUI/general/res/sass/features/_imagery.scss b/platform/commonUI/general/res/sass/features/_imagery.scss
index 90198aae9..2bfe05fa0 100644
--- a/platform/commonUI/general/res/sass/features/_imagery.scss
+++ b/platform/commonUI/general/res/sass/features/_imagery.scss
@@ -11,7 +11,6 @@
}
min-width: 150px;
.l-image-main {
- background-color: $colorPlotBg;
margin-bottom: $interiorMargin;
}
.l-image-main-controlbar {
@@ -76,6 +75,7 @@
}
.s-image-main {
+ background-color: $colorPlotBg;
border: 1px solid transparent;
&.paused {
@extend .s-unsynced;
diff --git a/platform/commonUI/general/res/sass/mobile/_layout.scss b/platform/commonUI/general/res/sass/mobile/_layout.scss
index fef5672eb..5c8bfbc7e 100644
--- a/platform/commonUI/general/res/sass/mobile/_layout.scss
+++ b/platform/commonUI/general/res/sass/mobile/_layout.scss
@@ -131,16 +131,18 @@ body.mobile {
}
}
-body.phone.portrait {
- .pane-tree-showing {
- .pane.left.treeview {
- width: $proporMenuOnly !important;
- }
- .pane.right.items {
- left: 0 !important;
- @include transform(translateX($proporMenuOnly));
- .holder-object-and-inspector {
- opacity: 0;
+@include phonePortrait() {
+ body.phone {
+ .pane-tree-showing {
+ .pane.left.treeview {
+ width: $proporMenuOnly !important;
+ }
+ .pane.right.items {
+ left: 0 !important;
+ @include transform(translateX($proporMenuOnly));
+ .holder-object-and-inspector {
+ opacity: 0;
+ }
}
}
}
diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss
index e72c92ef4..fb263176f 100644
--- a/platform/commonUI/general/res/sass/search/_search.scss
+++ b/platform/commonUI/general/res/sass/search/_search.scss
@@ -34,7 +34,7 @@
$iconEdgeM: 4px;
$iconD: $treeSearchInputBarH - ($iconEdgeM*2);
@extend .icon-magnify;
- font-size: 0.8em;
+ font-size: 0.8rem;
position: relative;
.search-input {
@@ -60,7 +60,7 @@
position: relative;
width: 100%;
padding-left: $iconD + $interiorMargin !important;
- padding-right: ($iconD * 2) + ($interiorMargin * 2) !important;
+ padding-right: $iconD + $interiorMargin !important;
// Make work for mct-control textfield
input {
@@ -82,8 +82,7 @@
}
.clear-input {
- // Hiding for now with addition of Cancel button
- right: $iconD + $interiorMargin;
+ right: $interiorMargin;
// Icon is visible only when there is text input
visibility: hidden;
@@ -98,16 +97,25 @@
}
}
- .menu-icon {
- // 'v' invoke menu icon
- font-size: 0.8em;
- padding-right: $iconEdgeM;
- right: $iconEdgeM;
- text-align: right;
- &:hover {
- color: pullForward($colorInputIcon, 10%);
- }
- }
+ &.search-filter-by-type {
+ .search-input {
+ padding-right: ($iconD * 2) + ($interiorMargin * 2) !important; // Allow room for menu-icon
+ }
+ .menu-icon {
+ // 'v' invoke menu icon for filtering by type
+ font-size: 0.8em;
+ padding-right: $iconEdgeM;
+ right: $iconEdgeM;
+ text-align: right;
+ &:hover {
+ color: pullForward($colorInputIcon, 10%);
+ }
+ }
+ .clear-input {
+ right: $iconD + $interiorMargin;
+ }
+
+ }
.search-menu-holder {
float: right;
diff --git a/platform/commonUI/general/res/sass/user-environ/_frame.scss b/platform/commonUI/general/res/sass/user-environ/_frame.scss
index 242b3a9e7..63833d5e6 100644
--- a/platform/commonUI/general/res/sass/user-environ/_frame.scss
+++ b/platform/commonUI/general/res/sass/user-environ/_frame.scss
@@ -158,6 +158,7 @@ body.desktop .frame {
// Hide local controls initially and show it them on hover when they're in an element that's in a frame context
// Frame template is used because we need to target the lowest nested frame
.object-browse-bar .btn-bar {
+ @include trans-prop-nice($props: opacity, $dur: 250ms);
opacity: 0;
pointer-events: none;
}
@@ -166,6 +167,7 @@ body.desktop .frame {
// Handles the case where we have layouts in layouts.
&:hover > .object-browse-bar {
.btn-bar {
+ @include trans-prop-nice($props: opacity, $dur: 10ms);
opacity: 1;
pointer-events: inherit;
}
diff --git a/platform/commonUI/general/res/templates/preview.html b/platform/commonUI/general/res/templates/preview.html
new file mode 100644
index 000000000..3b760be62
--- /dev/null
+++ b/platform/commonUI/general/res/templates/preview.html
@@ -0,0 +1,45 @@
+<!--
+ Open MCT, Copyright (c) 2014-2017, 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.
+-->
+<div class="t-frame-inner abs t-object-type-{{ domainObject.getModel().type }}" mct-preview>
+ <div class="abs object-browse-bar l-flex-row">
+ <div class="left flex-elem l-flex-row grows">
+ <mct-representation
+ key="'object-header-frame'"
+ mct-object="domainObject"
+ class="l-flex-row flex-elem object-header grows">
+ </mct-representation>
+ </div>
+ <div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
+ <mct-representation
+ key="'switcher'"
+ ng-model="representation"
+ mct-object="domainObject">
+ </mct-representation>
+ </div>
+ </div>
+ <div class="abs object-holder">
+ <mct-representation
+ key="representation.selected.key"
+ mct-object="representation.selected.key && domainObject">
+ </mct-representation>
+ </div>
+</div> \ No newline at end of file
diff --git a/platform/commonUI/general/src/actions/MCTPreviewAction.js b/platform/commonUI/general/src/actions/MCTPreviewAction.js
new file mode 100644
index 000000000..359085f5e
--- /dev/null
+++ b/platform/commonUI/general/src/actions/MCTPreviewAction.js
@@ -0,0 +1,66 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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(
+ [],
+ function () {
+
+ var PREVIEW_TEMPLATE = '<mct-representation key="\'mct-preview\'"' +
+ 'class="t-rep-frame holder"' +
+ 'mct-object="selObj">' +
+ '</mct-representation>';
+
+ function MCTPreview($compile,$rootScope,dialogService,notificationService,linkService,context) {
+ context = context || {};
+ this.domainObject = context.selectedObject || context.domainObject;
+ this.dialogService = dialogService;
+ this.notificationService = notificationService;
+ this.linkService = linkService;
+ this.$rootScope = $rootScope;
+ this.$compile = $compile;
+ }
+
+ MCTPreview.prototype.perform = function (object) {
+ var domainObj = object || this.domainObject,
+ rootScope = this.$rootScope;
+
+ rootScope.newEntryText = '';
+ this.$rootScope.selObj = domainObj;
+ this.$rootScope.selValue = "";
+
+ var newScope = rootScope.$new();
+ newScope.selObj = domainObj;
+ newScope.selValue = "";
+
+ this.$compile(PREVIEW_TEMPLATE)(newScope);
+ };
+
+ MCTPreview.appliesTo = function (context) {
+ var domainObject = (context || {}).domainObject,
+ status = domainObject.getCapability('status');
+
+ return !(status && status.get('editing'));
+ };
+
+ return MCTPreview;
+ }
+);
diff --git a/platform/commonUI/general/src/directives/MCTPreview.js b/platform/commonUI/general/src/directives/MCTPreview.js
new file mode 100644
index 000000000..69ba208e8
--- /dev/null
+++ b/platform/commonUI/general/src/directives/MCTPreview.js
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * 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(['zepto', '../services/Overlay'], function ($, Overlay) {
+ /**
+
+ */
+ function MCTPreview($rootScope,$document,exportImageService,dialogService,notificationService) {
+
+ function link($scope, $element, $attrs) {
+ var actions = $scope.domainObject.getCapability('action'),
+ notebookAction = actions.getActions({key: 'notebook-new-entry'})[0];
+
+ var notebookButton = notebookAction ?
+ [
+ {
+ class: 'icon-notebook new-notebook-entry',
+ title: 'New Notebook Entry',
+ clickHandler: function (event) {
+ event.stopPropagation();
+ notebookAction.perform();
+ }
+ }
+ ] : [];
+
+ var overlayService = new Overlay({
+ $document: $document,
+ $element: $element[0],
+ $scope: $scope,
+ browseBarButtons: notebookButton
+ });
+
+ overlayService.toggleOverlay();
+
+ $scope.$on('$destroy', function () {
+ $element.remove();
+ });
+ }
+
+ return {
+ restrict: 'A',
+ link: link
+ };
+ }
+
+ return MCTPreview;
+
+});
diff --git a/platform/commonUI/general/src/services/Overlay.js b/platform/commonUI/general/src/services/Overlay.js
new file mode 100644
index 000000000..af08533a1
--- /dev/null
+++ b/platform/commonUI/general/src/services/Overlay.js
@@ -0,0 +1,191 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2018, 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.
+ *****************************************************************************/
+
+ /**
+ * Module defining OverlayService. Created by deeptailor on 03/29/2018
+ */
+
+define(['zepto'], function ($) {
+ var OVERLAY_TEMPLATE = '' +
+' <div class="abs blocker"></div>' +
+' <div class="abs outer-holder">' +
+' <a class="close icon-x-in-circle"></a>' +
+' <div class="abs inner-holder l-flex-col">' +
+' <div class="t-contents flex-elem holder grows"></div>' +
+' <div class="bottom-bar flex-elem holder">' +
+' <a class="t-done s-button major">Done</a>' +
+' </div>' +
+' </div>' +
+' </div>';
+
+ /*
+ * An Overlay Service when instantiated creates an overlay dialog.
+ * @param {Object} options The options object required to instantiate the overlay service
+ * options = {
+ * $document: document object,
+ * $scope: angular $scope object,
+ * element: node to be injected into overlay as a view,
+ * overlayWillMount: callback executed before overlay is injected,
+ * overlayWillUnmount: callback executed before overlay is removed,
+ * overlayDidMount: callback executed after overlay is injected,
+ * overlayDidUnmount: callback executed after overlay is removed
+ * browseBarButtons: an array of desired buttons to be added to the browse bar of the overlay.
+ * the array should consist of button objects containing:
+ * a) class - css class to be added to the button div
+ * b) title - desired button title
+ * c) clickHandler - callback to be added to the click event listener of the button
+ * }
+ * $document, $scope and element are required
+ */
+
+ function Overlay(options) {
+ this.element = options.$element;
+ this.document = options.$document[0];
+ this.$scope = options.$scope;
+
+ this.overlayWillMount = options.overlayWillMount;
+ this.overlayWillUnmount = options.overlayWillUnmount;
+
+ this.overlayDidMount = options.overlayDidMount;
+ this.overlayDidUnmount = options.overlayDidUnmount;
+
+ this.browseBarButtons = options.browseBarButtons || [];
+ this.buttons = [];
+
+ this.openOverlay = this.openOverlay.bind(this);
+ this.closeOverlay = this.closeOverlay.bind(this);
+ this.toggleOverlay = this.toggleOverlay.bind(this);
+ this.removeButtons = this.removeButtons.bind(this);
+
+ this.isOverlayOpen = false;
+ }
+
+ Overlay.prototype.openOverlay = function () {
+
+ if (this.overlayWillMount && typeof this.overlayWillMount === 'function') {
+ this.overlayWillMount();
+ }
+
+ this.overlay = this.document.createElement('div');
+ $(this.overlay).addClass('abs overlay l-large-view');
+ this.overlay.innerHTML = OVERLAY_TEMPLATE;
+
+ this.overlayContainer = this.overlay.querySelector('.t-contents');
+
+ this.closeButton = this.overlay.querySelector('a.close');
+ this.closeButton.addEventListener('click', this.toggleOverlay);
+
+ this.doneButton = this.overlay.querySelector('a.t-done');
+ this.doneButton.addEventListener('click', this.toggleOverlay);
+
+ this.blocker = this.overlay.querySelector('.abs.blocker');
+ this.blocker.addEventListener('click', this.toggleOverlay);
+
+ this.document.body.appendChild(this.overlay);
+
+ this.overlayContainer.appendChild(this.element);
+
+ this.browseBar = this.overlay.querySelector('.object-browse-bar .right');
+
+ if (this.browseBarButtons && Array.isArray(this.browseBarButtons)) {
+ this.browseBarButtons.forEach(function (buttonObject) {
+ var button = newButtonTemplate(buttonObject.class, buttonObject.title);
+ this.browseBar.prepend(button);
+ button.addEventListener('click', buttonObject.clickHandler);
+ this.buttons.push(button);
+ }.bind(this));
+ }
+
+ if (this.overlayDidMount && typeof this.overlayDidMount === 'function') {
+ this.overlayDidMount();
+ }
+ };
+
+ Overlay.prototype.closeOverlay = function () {
+
+ if (this.overlayWillUnmount && typeof this.overlayWillUnmount === 'function') {
+ this.overlayWillUnmount();
+ }
+
+ this.overlayContainer.removeChild(this.element);
+ this.document.body.removeChild(this.overlay);
+
+ this.closeButton.removeEventListener('click', this.toggleOverlay);
+ this.closeButton = undefined;
+
+ this.doneButton.removeEventListener('click', this.toggleOverlay);
+ this.doneButton = undefined;
+
+ this.blocker.removeEventListener('click', this.toggleOverlay);
+ this.blocker = undefined;
+
+ this.overlayContainer = undefined;
+ this.overlay = undefined;
+
+ // if (this.notebookButton) {
+ // this.browseBar.removeChild(this.notebookButton);
+ // this.notebookButton.remove();
+ // this.notebookButton = undefined;
+ // }
+
+ this.removeButtons();
+
+ if (this.overlayDidUnmount && typeof this.overlayDidUnmount === 'function') {
+ this.overlayDidUnmount();
+ }
+ };
+
+ Overlay.prototype.toggleOverlay = function (event) {
+ if (event) {
+ event.stopPropagation();
+ }
+
+ if (!this.isOverlayOpen) {
+ this.openOverlay();
+ this.isOverlayOpen = true;
+ } else {
+ this.closeOverlay();
+ this.isOverlayOpen = false;
+ }
+ };
+
+ Overlay.prototype.removeButtons = function () {
+ this.buttons.forEach(function (button) {
+ button.remove();
+ }.bind(this));
+
+ this.buttons = [];
+ };
+
+ function newButtonTemplate(classString, title) {
+ var NEW_BUTTON_TEMPLATE = '<a class="s-button labeled' + classString + '">' +
+ '<span class="title-label">' + title + '</span>' +
+ '</a>';
+
+ var button = document.createElement('div');
+ $(button).addClass('notebook-button-container holder flex-elem');
+ button.innerHTML = NEW_BUTTON_TEMPLATE;
+ return button;
+ }
+
+ return Overlay;
+});
diff --git a/platform/features/layout/src/MCTTriggerModal.js b/platform/features/layout/src/MCTTriggerModal.js
index d7790479b..8fbe5b537 100644
--- a/platform/features/layout/src/MCTTriggerModal.js
+++ b/platform/features/layout/src/MCTTriggerModal.js
@@ -21,23 +21,12 @@
*****************************************************************************/
define([
- 'zepto'
+ 'zepto',
+ '../../../commonUI/general/src/services/Overlay'
], function (
- $
+ $,
+ Overlay
) {
-
- var OVERLAY_TEMPLATE = '' +
-' <div class="abs blocker"></div>' +
-' <div class="abs outer-holder">' +
-' <a class="close icon-x-in-circle"></a>' +
-' <div class="abs inner-holder l-flex-col">' +
-' <div class="t-contents flex-elem holder grows"></div>' +
-' <div class="bottom-bar flex-elem holder">' +
-' <a class="t-done s-button major">Done</a>' +
-' </div>' +
-' </div>' +
-' </div>';
-
/**
* MCT Trigger Modal is intended for use in only one location: inside the
* object-header to allow views in a layout to be popped out in a modal.
@@ -50,9 +39,11 @@ define([
* descendent of a `.frame` element.
*/
function MCTTriggerModal($document) {
- var document = $document[0];
function link($scope, $element) {
+ var actions = $scope.domainObject.getCapability('action'),
+ notebookAction = actions.getActions({key: 'notebook-new-entry'})[0];
+
var frame = $element.parent();
for (var i = 0; i < 10; i++) {
@@ -67,61 +58,39 @@ define([
}
frame = frame[0];
- var layoutContainer = frame.parentElement,
- isOpen = false,
- toggleOverlay,
- overlay,
- closeButton,
- doneButton,
- blocker,
- overlayContainer;
- function openOverlay() {
- // Remove frame classes from being applied in a non-frame context
- $(frame).removeClass('frame frame-template');
- overlay = document.createElement('div');
- $(overlay).addClass('abs overlay l-large-view');
- overlay.innerHTML = OVERLAY_TEMPLATE;
- overlayContainer = overlay.querySelector('.t-contents');
- closeButton = overlay.querySelector('a.close');
- closeButton.addEventListener('click', toggleOverlay);
- doneButton = overlay.querySelector('a.t-done');
- doneButton.addEventListener('click', toggleOverlay);
- blocker = overlay.querySelector('.abs.blocker');
- blocker.addEventListener('click', toggleOverlay);
- document.body.appendChild(overlay);
- layoutContainer.removeChild(frame);
- overlayContainer.appendChild(frame);
- }
+ var layoutContainer = frame.parentElement;
- function closeOverlay() {
- $(frame).addClass('frame frame-template');
- overlayContainer.removeChild(frame);
- layoutContainer.appendChild(frame);
- document.body.removeChild(overlay);
- closeButton.removeEventListener('click', toggleOverlay);
- closeButton = undefined;
- doneButton.removeEventListener('click', toggleOverlay);
- doneButton = undefined;
- blocker.removeEventListener('click', toggleOverlay);
- blocker = undefined;
- overlayContainer = undefined;
- overlay = undefined;
- }
+ var notebookButton = notebookAction ?
+ [
+ {
+ class: 'icon-notebook new-notebook-entry',
+ title: 'New Notebook Entry',
+ clickHandler: function (event) {
+ event.stopPropagation();
+ notebookAction.perform();
+ }
+ }
+ ] : [];
- toggleOverlay = function () {
- if (!isOpen) {
- openOverlay();
- isOpen = true;
- } else {
- closeOverlay();
- isOpen = false;
- }
- };
+ var overlayService = new Overlay ({
+ $document: $document,
+ $scope: $scope,
+ $element: frame,
+ overlayWillMount: function () {
+ $(frame).removeClass('frame frame-template');
+ layoutContainer.removeChild(frame);
+ },
+ overlayDidUnmount: function () {
+ $(frame).addClass('frame frame-template');
+ layoutContainer.appendChild(frame);
+ },
+ browseBarButtons: notebookButton
+ });
- $element.on('click', toggleOverlay);
+ $element.on('click', overlayService.toggleOverlay);
$scope.$on('$destroy', function () {
- $element.off('click', toggleOverlay);
+ $element.off('click', overlayService.toggleOverlay);
});
}
diff --git a/platform/features/layout/test/MCTTriggerModalSpec.js b/platform/features/layout/test/MCTTriggerModalSpec.js
index a46677853..9538a6467 100644
--- a/platform/features/layout/test/MCTTriggerModalSpec.js
+++ b/platform/features/layout/test/MCTTriggerModalSpec.js
@@ -52,6 +52,12 @@ define([
beforeEach(function () {
$scope = jasmine.createSpyObj('$scope', ['$on']);
+ $scope.domainObject = { getCapability: function () {
+ return { getActions: function () {
+ return [];
+ }};
+ }};
+
$element = jasmine.createSpyObj('$element', [
'parent',
'remove',
diff --git a/platform/features/notebook/bundle.js b/platform/features/notebook/bundle.js
new file mode 100644
index 000000000..4e2d3688c
--- /dev/null
+++ b/platform/features/notebook/bundle.js
@@ -0,0 +1,314 @@
+define([
+ "legacyRegistry",
+ "./src/controllers/NotebookController",
+ "./src/controllers/NewEntryController",
+ "./src/controllers/SelectSnapshotController",
+ "./src/controllers/LayoutNotebookController",
+ "./src/directives/MCTSnapshot",
+ "../layout/src/MCTTriggerModal",
+ "./src/directives/EntryDnd",
+ "./src/actions/ViewSnapshot",
+ "./src/actions/AnnotateSnapshot",
+ "./src/actions/RemoveEmbed",
+ "./src/actions/CreateSnapshot",
+ "./src/actions/RemoveSnapshot",
+ "./src/actions/NewEntryContextual",
+ "./src/capabilities/NotebookCapability",
+ "./src/policies/CompositionPolicy",
+ "./src/policies/ViewPolicy",
+ "text!./res/templates/layoutNotebook.html",
+ "text!./res/templates/notebook.html",
+ "text!./res/templates/entry.html",
+ "text!./res/templates/annotation.html",
+ "text!./res/templates/notifications.html",
+ "text!../layout/res/templates/frame.html",
+ "text!./res/templates/controls/embedControl.html",
+ "text!./res/templates/controls/snapSelect.html"
+], function (
+ legacyRegistry,
+ NotebookController,
+ NewEntryController,
+ SelectSnapshotController,
+ LayoutNotebookController,
+ MCTSnapshot,
+ MCTModalNotebook,
+ MCTEntryDnd,
+ ViewSnapshotAction,
+ AnnotateSnapshotAction,
+ RemoveEmbedAction,
+ CreateSnapshotAction,
+ RemoveSnapshotAction,
+ newEntryAction,
+ NotebookCapability,
+ CompositionPolicy,
+ ViewPolicy,
+ layoutNotebookTemplate,
+ notebookTemplate,
+ entryTemplate,
+ annotationTemplate,
+ notificationsTemplate,
+ frameTemplate,
+ embedControlTemplate,
+ snapSelectTemplate
+) {
+ legacyRegistry.register("platform/features/notebook", {
+ "name": "Notebook Plugin",
+ "description": "Create and save timestamped notes with embedded object snapshots.",
+ "extensions":
+ {
+ "types": [
+ {
+ "key": "notebook",
+ "name": "Notebook",
+ "cssClass": "icon-notebook",
+ "description": "Create and save timestamped notes with embedded object snapshots.",
+ "features": ["creation"],
+ "model": {
+ "entries": [],
+ "composition": [],
+ "entryTypes": []
+ }
+ }
+ ],
+ "views": [
+ {
+ "key": "notebook.view",
+ "type": "notebook",
+ "cssClass": "icon-notebook",
+ "name": "notebook",
+ "template": notebookTemplate,
+ "editable": false,
+ "uses": [
+ "composition",
+ "action"
+ ],
+ "gestures": [
+ "drop"
+ ]
+ }
+ ],
+ "controllers": [
+ {
+ "key": "NotebookController",
+ "implementation": NotebookController,
+ "depends": ["$scope",
+ "dialogService",
+ "popupService",
+ "agentService",
+ "objectService",
+ "navigationService",
+ "now",
+ "actionService",
+ "$timeout",
+ "$element",
+ "$sce"
+ ]
+ },
+ {
+ "key": "NewEntryController",
+ "implementation": NewEntryController,
+ "depends": ["$scope",
+ "$rootScope"
+ ]
+ },
+ {
+ "key": "selectSnapshotController",
+ "implementation": SelectSnapshotController,
+ "depends": ["$scope",
+ "$rootScope"
+ ]
+ },
+ {
+ "key": "LayoutNotebookController",
+ "implementation": LayoutNotebookController,
+ "depends": ["$scope"]
+ }
+ ],
+ "representations": [
+ {
+ "key": "draggedEntry",
+ "template": entryTemplate
+ },
+ {
+ "key": "frameLayoutNotebook",
+ "template": frameTemplate
+ }
+ ],
+ "templates": [
+ {
+ "key": "annotate-snapshot",
+ "template": annotationTemplate
+ },
+ {
+ "key": "notificationTemplate",
+ "template": notificationsTemplate
+ }
+ ],
+ "directives": [
+ {
+ "key": "mctSnapshot",
+ "implementation": MCTSnapshot,
+ "depends": [
+ "$rootScope",
+ "$document",
+ "exportImageService",
+ "dialogService",
+ "notificationService"
+ ]
+ },
+ {
+ "key": "mctEntryDnd",
+ "implementation": MCTEntryDnd,
+ "depends": [
+ "$rootScope",
+ "$compile",
+ "dndService",
+ "typeService",
+ "notificationService"
+ ]
+ },
+ {
+ "key": "mctModalNotebook",
+ "implementation": MCTModalNotebook,
+ "depends": [
+ "$document"
+ ]
+ }
+ ],
+ "actions": [
+ {
+ "key": "view-snapshot",
+ "implementation": ViewSnapshotAction,
+ "name": "View Snapshot",
+ "description": "View the large image in a modal",
+ "category": "embed",
+ "depends": [
+ "$compile"
+ ]
+ },
+ {
+ "key": "annotate-snapshot",
+ "implementation": AnnotateSnapshotAction,
+ "name": "Annotate Snapshot",
+ "cssClass": "icon-pencil labeled",
+ "description": "Annotate embed's snapshot",
+ "category": "embed",
+ "depends": [
+ "dialogService",
+ "dndService",
+ "$rootScope"
+ ]
+ },
+
+ {
+ "key": "remove-embed",
+ "implementation": RemoveEmbedAction,
+ "name": "Remove...",
+ "cssClass": "icon-trash labeled",
+ "description": "Remove this embed",
+ "category": [
+ "embed",
+ "embed-no-snap"
+ ],
+ "depends": [
+ "dialogService"
+ ]
+ },
+ {
+ "key": "remove-snapshot",
+ "implementation": RemoveSnapshotAction,
+ "name": "Remove Snapshot",
+ "cssClass": "icon-trash labeled",
+ "description": "Remove Snapshot of the embed",
+ "category": "embed",
+ "depends": [
+ "dialogService"
+ ]
+ },
+ {
+ "key": "create-snapshot",
+ "implementation": CreateSnapshotAction,
+ "name": "Create Snapshot",
+ "description": "Create a snapshot for the embed",
+ "category": "embed-no-snap",
+ "priority": "preferred",
+ "depends": [
+ "$compile"
+ ]
+ },
+ {
+ "key": "notebook-new-entry",
+ "implementation": newEntryAction,
+ "name": "New Notebook Entry",
+ "cssClass": "icon-notebook labeled",
+ "description": "Add a new Notebook entry",
+ "category": [
+ "contextual",
+ "view-control"
+ ],
+ "depends": [
+ "$compile",
+ "$rootScope",
+ "dialogService",
+ "notificationService",
+ "linkService"
+ ],
+ "priority": "preferred"
+ }
+ ],
+ "licenses": [
+ {
+ "name": "painterro",
+ "version": "4.1.0",
+ "author": "Mike Bostock",
+ "description": "D3 (or D3.js) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.",
+ "website": "https://d3js.org/",
+ "copyright": "Copyright 2010-2016 Mike Bostock",
+ "license": "BSD-3-Clause",
+ "link": "https://github.com/d3/d3/blob/master/LICENSE"
+ }
+ ],
+ "capabilities": [
+ {
+ "key": "notebook",
+ "name": "Notebook Capability",
+ "description": "Provides a capability for looking for a notebook domain object",
+ "implementation": NotebookCapability,
+ "depends": [
+ "typeService"
+ ]
+ }
+ ],
+ "policies": [
+ {
+ "category": "composition",
+ "implementation": CompositionPolicy,
+ "message": "Objects of this type cannot contain objects of that type."
+ }
+ ],
+ "controls": [
+ {
+ "key": "embed-control",
+ "template": embedControlTemplate
+ },
+ {
+ "key": "snapshot-select",
+ "template": snapSelectTemplate
+ }
+ ],
+ "stylesheets": [
+ {
+ "stylesheetUrl": "css/notebook.css"
+ },
+ {
+ "stylesheetUrl": "css/notebook-espresso.css",
+ "theme": "espresso"
+ },
+ {
+ "stylesheetUrl": "css/notebook-snow.css",
+ "theme": "snow"
+ }
+ ]
+ }
+ });
+});
diff --git a/platform/features/notebook/res/sass/_notebook-base.scss b/platform/features/notebook/res/sass/_notebook-base.scss
new file mode 100644
index 000000000..e0396aa5d
--- /dev/null
+++ b/platform/features/notebook/res/sass/_notebook-base.scss
@@ -0,0 +1,283 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+.w-notebook {
+ font-size: 0.8rem;
+ overflow: hidden;
+ position: absolute;
+ top: 0px;
+ right: 0px;
+ bottom: 0px;
+ left: 0px;
+ width: auto;
+ height: auto;
+}
+
+.l-notebook-drag-area {
+ padding: 10px;
+ font-style: italic;
+ cursor: pointer;
+ &:before { margin-right: 7px !important; }
+ .label {
+ @include ellipsize();
+ }
+}
+
+.frame {
+ .icon-notebook {
+ margin-right: 5px;
+ }
+}
+
+.overlay.l-dialog .title{
+ white-space: normal;
+}
+
+.w-notebook-entries {
+ //@include test($a: 0.1);
+ padding-right: $interiorMarginSm;
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ .t-entries-list {
+ }
+}
+
+.l-notebook-entry {
+ $p: $interiorMarginSm;
+ box-sizing: border-box;
+ margin-bottom: $p;
+ padding: $p $interiorMargin;
+
+ .s-notebook-entry-time,
+ .s-notebook-entry-text,
+ .notebook-entry-delete {
+ padding-top: $p;
+ padding-bottom: $p;
+ }
+
+ .s-notebook-entry-time {
+ border: 1px solid transparent; // Needed to maintain vertical alignment with s-notebook-entry-text
+ }
+
+ .l-notebook-entry-content{
+ .s-notebook-entry-text {
+ // Contenteditable div that holds text
+ min-height: 24px; // Needed in Firefox when field is blank
+ }
+ .entry-embeds{
+ flex-wrap: wrap;
+ }
+ .snap-thumb {
+ cursor: pointer;
+ }
+ }
+}
+
+.l-entry-embed {
+ $m: $interiorMarginSm;
+ position: relative;
+ margin: $m $m 0 0;
+ padding: $interiorMarginSm;
+
+ &.has-snapshot {
+ &:before {
+ position: absolute;
+ text-shadow: rgba(black, 0.7) 0 1px 5px;
+ z-index: 2;
+ }
+ }
+ .snap-thumb {
+ $d: 50px;
+ width: $d;
+ height: $d;
+ border-radius: 5px;
+ overflow: hidden;
+ img {
+ height: 100%;
+ width: 100%;
+ }
+ }
+
+ .embed-info {
+ margin-left: $interiorMargin;
+ .embed-title {
+ font-weight: bold;
+ }
+ }
+}
+
+.t-contents,
+.snap-annotation {
+ // Todo: don't write this to t-contents, add a l- class
+ overflow: hidden;
+}
+
+.notebook-filters {
+ .select {
+ margin-left: $interiorMargin;
+ }
+}
+
+/********************************************* MOBILE */
+@include phonePortrait() {
+ body.phone {
+ .w-notebook-entry-time-and-content {
+ flex-direction: column !important;
+ }
+ .s-notebook-entry-time,
+ .notebook-entry-delete {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+ }
+}
+
+/********************************************* PAINTERRO OVERRIDES */
+.annotation-dialog .abs.editor {
+ border-radius: 0;
+}
+
+#snap-annotation {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ top: 0; right: 0; bottom: 0; left: 0;
+}
+
+#snap-annotation-wrapper,
+#snap-annotation-bar {
+ position: relative;
+ top: auto; right: auto; bottom: auto; left: auto;
+}
+
+#snap-annotation-wrapper {
+ order: 2;
+ flex: 10 0 auto;
+}
+
+#snap-annotation-bar {
+ order: 1;
+ flex: 0 0 auto;
+ height: auto;
+ background-color: transparent !important;
+ margin-bottom: $interiorMargin;
+
+ > div,
+ > div > span,
+ .ptro-icon-btn,
+ .ptro-named-btn,
+ .ptro-color-btn,
+ .ptro-bordered-btn,
+ .ptro-tool-ctl-name,
+ .ptro-color-btn,
+ .tool-controls,
+ .ptro-input {
+ // Lot of resets for crappy CSS in Painterro
+ &:first-child {
+ margin-left: 0 !important;
+ }
+ $h: $btnToolbarH;
+ display: inline-block;
+ font-family: inherit;
+ font-size: auto;
+ height: $h !important;
+ margin: 0 0 0 5px;
+ position: relative;
+ width: auto !important;
+ line-height: $h !important;
+ top: auto;
+ right: auto;
+ bottom: auto;
+ left: auto;
+ vertical-align: top;
+ }
+
+ .ptro-tool-ctl-name {
+ border-radius: 0;
+ background: none;
+ top: auto;
+ font-family: inherit;
+ padding: 0;
+ }
+
+ .ptro-color-btn {
+ width: $btnToolbarH !important;
+ }
+
+ .ptro-icon-btn,
+ .ptro-named-btn {
+ // .s-button class is added via JS in AnnotateSnapshot.js
+ // TODO: redo this so that we don't need to use Zepto and JS
+ i {
+ font-size: 1.25em !important;
+ }
+ }
+
+ .tool-controls {
+ font-size: 0.8rem !important;
+ }
+
+ .ptro-info,
+ .ptro-btn-color-checkers-bar,
+ *[title="Font name"],
+ *[title="Stroke color"],
+ *[title="Stroke width"],
+ *[data-id="fontName"],
+ *[data-id="fontStrokeSize"],
+ *[data-id="stroke"] {
+ display: none;
+ }
+}
+
+/********************************************* NO IDEA WHAT THERE ARE APPLYING TO */
+.context-available {
+ outline: none;
+}
+
+.menu-element.menu-view{
+ z-index: 999;
+}
+
+.overlay.l-dialog .abs.editor {
+ padding-right: 0;
+}
+
+/*
+.overlay.l-dialog .outer-holder.annotation-dialog{
+ width: 90%;
+ height: 90%;
+}
+*/
+
+/*
+.snap-annotation-wrapper{
+ padding-top: 40px;
+}
+
+
+.t-console {
+ // Temp console-like reporting element
+ max-height: 200px;
+ box-sizing: border-box;
+ padding: 5px;
+}
+*/
diff --git a/platform/features/notebook/res/sass/_notebook-thematic.scss b/platform/features/notebook/res/sass/_notebook-thematic.scss
new file mode 100644
index 000000000..c2ebb32d2
--- /dev/null
+++ b/platform/features/notebook/res/sass/_notebook-thematic.scss
@@ -0,0 +1,92 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+.l-notebook-drag-area {
+ border: 1px dashed rgba($colorKey, 0.7);
+ border-radius: $controlCr;
+ color: rgba($colorBodyFg, 0.7);
+ &:hover {
+ background: rgba($colorKey, 0.2);
+ color: $colorBodyFg;
+ }
+ &.drag-active{
+ border-color: $colorKey;
+ }
+}
+
+.s-notebook-entry {
+ background-color: rgba($colorBodyFg, 0.1);
+ border-radius: $basicCr;
+
+ &:hover {
+ background-color: rgba($colorBodyFg, 0.2);
+ }
+
+ .s-notebook-entry-time {
+ color: rgba($colorBodyFg, 0.5);
+ }
+}
+
+.l-entry-embed {
+ border-radius: $controlCr;
+ background-color: rgba($colorBodyFg, 0.1);
+ &.has-snapshot {
+ &:before {
+ color: $colorBodyFg;
+ }
+ }
+}
+
+.s-snapshot-datetime {
+ color: rgba($colorBodyFg, 0.4);
+ font-size: 0.8em;
+}
+
+.snap-thumb {
+ border: 1px solid $colorInteriorBorder;
+}
+
+.s-status-taking-snapshot,
+.overlay.snapshot {
+ // Applied to an object view when it's in the process of being snapshotted
+ background: $colorBodyBg;
+}
+
+/********************************************* PAINTERRO OVERRIDES */
+.ptro-wrapper {
+ background: rgba($colorBodyBg, 0.3) !important;
+}
+
+#snap-annotation-bar {
+ .tool-controls {
+ color: $colorBodyFg !important;
+ }
+}
+
+.s-button.ptro-color-active-control {
+ background: $colorBtnMajorBg !important;
+ color: $colorBtnMajorFg !important;
+ &:hover {
+ background: $colorBtnMajorBgHov !important;
+ color: $colorBtnMajorFgHov !important;
+ }
+} \ No newline at end of file
diff --git a/platform/features/notebook/res/sass/notebook-espresso.scss b/platform/features/notebook/res/sass/notebook-espresso.scss
new file mode 100644
index 000000000..6f6077dac
--- /dev/null
+++ b/platform/features/notebook/res/sass/notebook-espresso.scss
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+$output-bourbon-deprecation-warnings: false;
+@import "bourbon";
+
+@import "../../../../commonUI/general/res/sass/constants";
+@import "../../../../commonUI/general/res/sass/mixins";
+@import "../../../../commonUI/general/res/sass/glyphs";
+@import "../../../../commonUI/themes/espresso/res/sass/constants";
+@import "../../../../commonUI/themes/espresso/res/sass/mixins";
+@import "notebook-thematic"; \ No newline at end of file
diff --git a/platform/features/notebook/res/sass/notebook-snow.scss b/platform/features/notebook/res/sass/notebook-snow.scss
new file mode 100644
index 000000000..b279deade
--- /dev/null
+++ b/platform/features/notebook/res/sass/notebook-snow.scss
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+$output-bourbon-deprecation-warnings: false;
+@import "bourbon";
+
+@import "../../../../commonUI/general/res/sass/constants";
+@import "../../../../commonUI/general/res/sass/mixins";
+@import "../../../../commonUI/general/res/sass/glyphs";
+@import "../../../../commonUI/themes/snow/res/sass/constants";
+@import "../../../../commonUI/themes/snow/res/sass/mixins";
+@import "notebook-thematic"; \ No newline at end of file
diff --git a/platform/features/notebook/res/sass/notebook.scss b/platform/features/notebook/res/sass/notebook.scss
new file mode 100644
index 000000000..75432c248
--- /dev/null
+++ b/platform/features/notebook/res/sass/notebook.scss
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2015, 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.
+ *****************************************************************************/
+$output-bourbon-deprecation-warnings: false;
+@import "bourbon";
+@import "../../../../commonUI/general/res/sass/constants";
+@import "../../../../commonUI/general/res/sass/mixins";
+@import "../../../../commonUI/general/res/sass/mobile/constants";
+@import "../../../../commonUI/general/res/sass/mobile/mixins";
+@import "notebook-base";
diff --git a/platform/features/notebook/res/templates/annotation.html b/platform/features/notebook/res/templates/annotation.html
new file mode 100644
index 000000000..b9cbca57a
--- /dev/null
+++ b/platform/features/notebook/res/templates/annotation.html
@@ -0,0 +1,2 @@
+<div class="snap-annotation" id="snap-annotation" ng-controller="ngModel.controller">
+</div> \ No newline at end of file
diff --git a/platform/features/notebook/res/templates/controls/embedControl.html b/platform/features/notebook/res/templates/controls/embedControl.html
new file mode 100644
index 000000000..d40702120
--- /dev/null
+++ b/platform/features/notebook/res/templates/controls/embedControl.html
@@ -0,0 +1,51 @@
+<!--
+ Open MCT, Copyright (c) 2009-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.
+-->
+<!--
+This element appears in the overlay dialog when initiating a new Notebook Entry from a view's Notebook button -->
+<div class='form-control'>
+ <ng-form name="mctControl">
+ <div class='fields' ng-controller="NewEntryController">
+ <div class="l-flex-row new-notebook-entry-embed l-entry-embed {{cssClass}}"
+ ng-class="{ 'has-snapshot' : snapToggle }">
+ <div class="holder flex-elem snap-thumb"
+ ng-if="snapToggle">
+ <img ng-src="{{snapshot.src}}" alt="{{snapshot.modified}}">
+ </div>
+
+ <div class="holder flex-elem embed-info">
+ <div class="embed-title">{{objectName}}</div>
+ <div class="embed-date"
+ ng-if="snapToggle">{{snapshot.modified| date:'yyyy-MM-dd HH:mm:ss'}}</div>
+ </div>
+
+ <div class="holder flex-elem annotate-new"
+ ng-if="snapToggle">
+ <a class="s-button flex-elem icon-pencil "
+ title="Annotate this snapshot"
+ ng-click="annotateSnapshot()">
+ <span class="title-label">Annotate</span>
+ </a>
+ </div>
+ </div>
+ </div>
+ </ng-form>
+</div>
diff --git a/platform/features/notebook/res/templates/controls/snapSelect.html b/platform/features/notebook/res/templates/controls/snapSelect.html
new file mode 100644
index 000000000..0f89fb270
--- /dev/null
+++ b/platform/features/notebook/res/templates/controls/snapSelect.html
@@ -0,0 +1,30 @@
+<!--
+ Open MCT, Copyright (c) 2014-2017, 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.
+-->
+<div class='form-control select' ng-controller="selectSnapshotController">
+ <select
+ ng-model="selectModel"
+ ng-options="opt.value as opt.name for opt in options"
+ ng-required="ngRequired"
+ name="mctControl">
+ <!-- <option value="" ng-show="!ngModel[field]">- Select One -</option> -->
+ </select>
+</div> \ No newline at end of file
diff --git a/platform/features/notebook/res/templates/entry.html b/platform/features/notebook/res/templates/entry.html
new file mode 100644
index 000000000..bd4e02aff
--- /dev/null
+++ b/platform/features/notebook/res/templates/entry.html
@@ -0,0 +1,38 @@
+<!--
+ Open MCT, Copyright (c) 2014-2017, 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.
+-->
+<div class="frame snap-frame frame-template t-frame-inner abs t-object-type-{{ representation.selected.key }}">
+ <div class="abs object-browse-bar l-flex-row">
+ <div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
+ <mct-representation
+ key="'switcher'"
+ ng-model="representation"
+ mct-object="domainObject">
+ </mct-representation>
+ </div>
+ </div>
+ <div class="abs object-holder" data-entry = "{{parameters.entry}}" data-embed = "{{parameters.embed}}" mct-snapshot ng-if="representation.selected.key">
+ <mct-representation
+ key="representation.selected.key"
+ mct-object="representation.selected.key && domainObject">
+ </mct-representation>
+ </div>
+</div>
diff --git a/platform/features/notebook/res/templates/frameLayoutNotebook.html b/platform/features/notebook/res/templates/frameLayoutNotebook.html
new file mode 100644
index 000000000..0bfbe2487
--- /dev/null
+++ b/platform/features/notebook/res/templates/frameLayoutNotebook.html
@@ -0,0 +1,54 @@
+<!--
+ Open MCT, Copyright (c) 2014-2017, 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.
+-->
+<div class="frame frame-template t-frame-inner abs t-object-type-{{ representation.selected.key }}">
+ <div class="abs object-browse-bar l-flex-row">
+ <div class="left flex-elem l-flex-row grows">
+ <mct-representation
+ key="'object-header-frame'"
+ mct-object="domainObject"
+ class="l-flex-row flex-elem object-header grows">
+ </mct-representation>
+ </div>
+ <div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
+ <a class="s-button icon-notebook"
+ title="New Notebook Entry"
+ ng-if="parameters"
+ ng-click="ngModel()">
+ </a>
+ <mct-representation
+ key="'switcher'"
+ ng-model="representation"
+ mct-object="domainObject">
+ </mct-representation>
+ <a class="s-button icon-expand t-btn-view-large"
+ title="View large"
+ mct-modal-notebook>
+ </a>
+ </div>
+ </div>
+ <div class="abs object-holder">
+ <mct-representation
+ key="representation.selected.key"
+ mct-object="representation.selected.key && domainObject">
+ </mct-representation>
+ </div>
+</div>
diff --git a/platform/features/notebook/res/templates/layoutNotebook.html b/platform/features/notebook/res/templates/layoutNotebook.html
new file mode 100644
index 000000000..c272b5713
--- /dev/null
+++ b/platform/features/notebook/res/templates/layoutNotebook.html
@@ -0,0 +1,84 @@
+<!--
+ Open MCT, Copyright (c) 2014-2017, 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.
+-->
+
+<div class="abs l-layout"
+ ng-controller="LayoutController as controller"
+ ng-click="controller.clearSelection()">
+
+ <!-- Background grid -->
+ <div class="l-grid-holder" ng-click="controller.clearSelection()">
+ <div class="l-grid l-grid-x"
+ ng-if="!controller.getGridSize()[0] < 3"
+ ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
+ <div class="l-grid l-grid-y"
+ ng-if="!controller.getGridSize()[1] < 3"
+ ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
+ </div>
+
+ <div class='abs frame t-frame-outer child-frame panel s-selectable s-moveable s-hover-border'
+ ng-class="{ 'no-frame': !controller.hasFrame(childObject), 's-selected':controller.selected(childObject) }"
+ ng-repeat="childObject in composition"
+ ng-click="controller.select($event, childObject.getId())"
+ ng-style="controller.getFrameStyle(childObject.getId())">
+
+ <div ng-controller="LayoutNotebookController as controller">
+ <mct-representation key="'frameLayoutNotebook'"
+ class="t-rep-frame holder contents abs"
+ parameters = "hasNotebookAction"
+ ng-model="newNotebook"
+ mct-object="childObject">
+ </mct-representation>
+ </div>
+
+ <!-- Drag handles -->
+ <span class="abs t-edit-handle-holder s-hover-border" ng-if="controller.selected(childObject)">
+ <span class="edit-handle edit-move"
+ mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [0,0])"
+ mct-drag="controller.continueDrag(delta)"
+ mct-drag-up="controller.endDrag()">
+ </span>
+
+ <span class="edit-corner edit-resize-nw"
+ mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [-1,-1])"
+ mct-drag="controller.continueDrag(delta)"
+ mct-drag-up="controller.endDrag()">
+ </span>
+ <span class="edit-corner edit-resize-ne"
+ mct-drag-down="controller.startDrag(childObject.getId(), [0,1], [1,-1])"
+ mct-drag="controller.continueDrag(delta)"
+ mct-drag-up="controller.endDrag()">
+ </span>
+ <span class="edit-corner edit-resize-sw"
+ mct-drag-down="controller.startDrag(childObject.getId(), [1,0], [-1,1])"
+ mct-drag="controller.continueDrag(delta)"
+ mct-drag-up="controller.endDrag()">
+ </span>
+ <span class="edit-corner edit-resize-se"
+ mct-drag-down="controller.startDrag(childObject.getId(), [0,0], [1,1])"
+ mct-drag="controller.continueDrag(delta)"
+ mct-drag-up="controller.endDrag()">
+ </span>
+ </span>
+
+ </div>
+
+</div>
diff --git a/platform/features/notebook/res/templates/notebook.html b/platform/features/notebook/res/templates/notebook.html
new file mode 100644
index 000000000..481e010c8
--- /dev/null
+++ b/platform/features/notebook/res/templates/notebook.html
@@ -0,0 +1,124 @@
+<div ng-controller="NotebookController as controller" class="mct-notebook w-notebook l-flex-col">
+ <div class="l-notebook-head holder l-flex-row flex-elem">
+ <div class="l-flex-row holder grows holder-search">
+ <div class="search-bar flex-elem l-flex-row grows"
+ ng-class="{ holder: !(entrySearch === '' || entrySearch === undefined) }">
+ <div class="holder flex-elem grows">
+ <input class="search-input"
+ type="text" tabindex="10000"
+ ng-model="entrySearch"
+ ng-keyup="controller.search()"/>
+ <a class="clear-icon clear-input icon-x-in-circle"
+ ng-class="{show: !(entrySearch === '' || entrySearch === undefined)}"
+ ng-click="entrySearch = ''; controller.search()"></a>
+ </div>
+ </div>
+ </div>
+
+ <div class="notebook-filters right l-flex-row flex-elem grows flex-justify-end">
+ <div class="select">
+ <select ng-model="showTime">
+ <option value="0" selected="selected">Show all</option>
+ <option value="1">Last hour</option>
+ <option value="8">Last 8 hours</option>
+ <option value="24">Last 24 hours</option>
+ </select>
+ </div>
+ <div class="select">
+ <select ng-model="sortEntries">
+ <option value="-createdOn" selected="selected">Newest first</option>
+ <option value="createdOn">Oldest first</option>
+ </select>
+ </div>
+ </div>
+ </div>
+
+ <!-- drag area -->
+ <div class="holder flex-elem l-flex-row icon-plus labeled l-notebook-drag-area" ng-click="newEntry($event)"
+ id="newEntry" mct-entry-dnd>
+ <span class="label">To start a new entry, click here or drag and drop any object</span>
+ </div>
+
+ <!-- entries -->
+ <div class="holder flex-elem grows w-notebook-entries t-entries-list" ng-mouseover="handleActive()">
+ <ul>
+ <li class="l-flex-row has-local-controls l-notebook-entry s-notebook-entry"
+ id="{{'entry_'+ entry.id}}"
+ ng-if="hoursFilter(showTime,entry.createdOn)"
+ ng-repeat="entry in model.entries | filter:entrySearch | orderBy: sortEntries track by $index"
+ ng-init="$last && finished(model.entries)"
+ mct-entry-dnd>
+ <div class="holder flex-elem l-flex-row grows w-notebook-entry-time-and-content" ng-click="selectContentEditable($event)">
+ <div class="holder flex-elem s-notebook-entry-time">
+ <span>{{entry.createdOn | date:'yyyy-MM-dd'}}</span>
+ <span>{{entry.createdOn | date:'HH:mm:ss'}}</span>
+ </div>
+ <div class="holder flex-elem l-flex-col grows l-notebook-entry-content">
+ <div contenteditable="true"
+ ng-blur="textBlur($event, entry.id)"
+ ng-focus="textFocus($event, entry.id)"
+ ng-model="entry.text"
+ placeholder="Enter text here"
+ class="flex-elem s-input-inline t-notebook-entry-input s-notebook-entry-text"
+ ng-bind-html="trustedHtml(entry.text)">
+ </div>
+ <!-- embeds -->
+ <div class="flex-elem entry-embeds l-flex-row">
+ <div class="l-flex-row l-entry-embed {{embed.cssClass}}"
+ ng-repeat="embed in entry.embeds track by $index"
+ ng-class="{ 'has-snapshot' : embed.snapshot }"
+ id="{{embed.id}}">
+ <div class="snap-thumb"
+ ng-if="embed.snapshot"
+ ng-click="viewSnapshot($event,embed.snapshot.src,embed.id,entry.createdOn,this,embed)">
+ <img ng-src="{{embed.snapshot.src}}" src="//:0" alt="{{embed.id}}">
+ </div>
+ <div class="embed-info l-flex-col">
+ <div class="embed-title object-header">
+ <a ng-click='navigate($event,embed.type)'>{{embed.name}}</a>
+ <a class='context-available' ng-click='openMenu($event,embed.type)'></a>
+ </div>
+ <div class="hide-menu" ng-show="false">
+ <div class="menu-element context-menu-wrapper mobile-disable-select">
+ <div class="menu context-menu">
+ <ul>
+ <li ng-repeat="menu in menuEmbed"
+ ng-click="menu.perform($event,embed.snapshot.src,embed.id,entry.createdOn,this,embed)"
+ title="{{menu.getMetadata().description}}"
+ class="{{menu.getMetadata().cssClass}}"
+ ng-if="embed.snapshot">
+ {{menu.getMetadata().name}}
+ </li>
+ <li ng-repeat="menu in menuEmbedNoSnap"
+ ng-click="menu.perform($event,embed.snapshot.src,embed.id,entry.createdOn,this)"
+ title="{{menu.getMetadata().description}}"
+ class="{{menu.getMetadata().cssClass}}"
+ ng-if="!embed.snapshot">
+ {{menu.getMetadata().name}}
+ </li>
+ <li ng-repeat="menu in embedActions"
+ ng-click="menu.perform()"
+ title="{{menu.name}}"
+ class="{{menu.cssClass}}">
+ {{menu.name}}
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <div class="embed-date"
+ ng-if="embed.snapshot">{{embed.id| date:'yyyy-MM-dd HH:mm:ss'}}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- delete entry -->
+ <div class="holder flex-elem local-control notebook-entry-delete">
+ <a class="s-icon-button icon-trash" id={{entry.id}} title="Delete Entry" ng-click="deleteEntry($event)"></a>
+ </div>
+ </li>
+ </ul>
+ </div>
+</div> \ No newline at end of file
diff --git a/platform/features/notebook/res/templates/notifications.html b/platform/features/notebook/res/templates/notifications.html
new file mode 100644
index 000000000..2a9069fa4
--- /dev/null
+++ b/platform/features/notebook/res/templates/notifications.html
@@ -0,0 +1,8 @@
+<span class="status block">
+ <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
+ <span class="status-indicator icon-bell"></span>
+ <span class="label">
+ Notifications
+ </span>
+ <span class="count"></span>
+</span>
diff --git a/platform/features/notebook/src/actions/AnnotateSnapshot.js b/platform/features/notebook/src/actions/AnnotateSnapshot.js
new file mode 100644
index 000000000..cf15dba76
--- /dev/null
+++ b/platform/features/notebook/src/actions/AnnotateSnapshot.js
@@ -0,0 +1,131 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+/**
+ * Module defining viewSnapshot (Originally NewWindowAction). Created by vwoeltje on 11/18/14.
+ */
+define(
+ ["painterro", "zepto", "../shims/painterro-shim"],
+ function (Painterro, $, painterroShim) {
+ var ANNOTATION_STRUCT = {
+ title: "Annotate Snapshot",
+ template: "annotate-snapshot",
+ options: [{
+ name: "OK",
+ key: "ok",
+ description: "save annotation"
+ },
+ {
+ name: "Cancel",
+ key: "cancel",
+ description: "cancel editing"
+ }]
+ };
+
+ function AnnotateSnapshot(dialogService,dndService,$rootScope,context) {
+ context = context || {};
+
+ // Choose the object to be opened into a new tab
+ this.domainObject = context.selectedObject || context.domainObject;
+ this.dialogService = dialogService;
+ this.dndService = dndService;
+ this.$rootScope = $rootScope;
+ }
+
+ AnnotateSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId,$scope) {
+
+ var DOMAIN_OBJECT = this.domainObject;
+ var ROOTSCOPE = this.$rootScope;
+ var painterro;
+
+ var controller = ['$scope', '$timeout', function PainterroController ($scope, $timeout) {
+ $(document.body).find('.l-dialog .outer-holder').addClass('annotation-dialog');
+ $timeout(function () {
+ painterro = Painterro({
+ id: 'snap-annotation',
+ activeColor: '#ff0000',
+ activeColorAlpha: 1.0,
+ activeFillColor: '#fff',
+ activeFillColorAlpha: 0.0,
+ backgroundFillColor: '#000',
+ backgroundFillColorAlpha: 0.0,
+ defaultFontSize: 16,
+ defaultLineWidth: 2,
+ defaultTool: 'ellipse',
+ hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
+ translation: {
+ name: 'en',
+ strings: {
+ lineColor: 'Line',
+ fillColor: 'Fill',
+ lineWidth: 'Size',
+ textColor: 'Color',
+ fontSize: 'Size',
+ fontStyle: 'Style'
+ }
+ },
+ saveHandler: function (image, done) {
+ if (entryId && embedId) {
+ var elementPos = DOMAIN_OBJECT.model.entries.map(function (x) {
+ return x.createdOn;
+ }).indexOf(entryId);
+ var entryEmbeds = DOMAIN_OBJECT.model.entries[elementPos].embeds;
+ var embedPos = entryEmbeds.map(function (x) {
+ return x.id;
+ }).indexOf(embedId);
+ $scope.saveSnap(image.asBlob(), embedPos, elementPos);
+ }else {
+ ROOTSCOPE.snapshot = {'src': image.asDataURL('image/png'),
+ 'modified': Date.now()};
+ }
+ done(true);
+ }
+ }).show(snapshot);
+ });
+ painterroShim(painterro);
+
+ $(document.body).find('.ptro-icon-btn').addClass('s-button');
+ $(document.body).find('.ptro-input').addClass('s-button');
+
+ $scope.$on('$destroy', function () {
+ painterro.removeEventHandlers();
+ });
+ }];
+
+ ANNOTATION_STRUCT.model = {'controller': controller};
+
+ function saveNotes(param) {
+ if (param === 'ok') {
+ painterro.save();
+ }else {
+ ROOTSCOPE.snapshot = "annotationCancelled";
+ }
+ }
+
+ this.dialogService.getUserChoice(ANNOTATION_STRUCT)
+ .then(saveNotes);
+
+ };
+
+ return AnnotateSnapshot;
+ }
+);
diff --git a/platform/features/notebook/src/actions/CreateSnapshot.js b/platform/features/notebook/src/actions/CreateSnapshot.js
new file mode 100644
index 000000000..8e9eac6b0
--- /dev/null
+++ b/platform/features/notebook/src/actions/CreateSnapshot.js
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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(
+ [],
+ function () {
+
+ var SNAPSHOT_TEMPLATE = '<mct-representation key="\'draggedEntry\'"' +
+ 'parameters="{entry:entryId,embed:embedId}"' +
+ 'class="t-rep-frame holder"' +
+ 'mct-object="selObj">' +
+ '</mct-representation>';
+
+ function CreateSnapshot($compile,context) {
+ context = context || {};
+ this.domainObject = context.selectedObject || context.domainObject;
+ this.context = context;
+ this.$compile = $compile;
+ }
+
+
+ CreateSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId,$scope) {
+ var compile = this.$compile;
+ var model = this.domainObject.model;
+ var elementPos = model.entries.map(function (x) {
+ return x.createdOn;
+ }).indexOf(entryId);
+ var entryEmbeds = model.entries[elementPos].embeds;
+ var embedPos = entryEmbeds.map(function (x) {
+ return x.id;
+ }).indexOf(embedId);
+ var embedType = entryEmbeds[embedPos].type;
+
+ $scope.getDomainObj(embedType).then(function (resp) {
+ if (entryId >= 0 && embedId >= 0) {
+ $scope.selObj = resp[embedType];
+ $scope.entryId = elementPos;
+ $scope.embedId = embedPos;
+ compile(SNAPSHOT_TEMPLATE)($scope);
+ }
+ });
+ };
+
+ return CreateSnapshot;
+ }
+);
diff --git a/platform/features/notebook/src/actions/NewEntryContextual.js b/platform/features/notebook/src/actions/NewEntryContextual.js
new file mode 100644
index 000000000..7ce19d8da
--- /dev/null
+++ b/platform/features/notebook/src/actions/NewEntryContextual.js
@@ -0,0 +1,193 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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(
+ [],
+ function () {
+
+ var SNAPSHOT_TEMPLATE = '<mct-representation key="\'draggedEntry\'"' +
+ 'class="t-rep-frame holder"' +
+ 'mct-object="selObj">' +
+ '</mct-representation>';
+
+ var NEW_TASK_FORM = {
+ name: "Create a Notebook Entry",
+ hint: "Please select one Notebook",
+ sections: [{
+ rows: [{
+ name: 'Entry',
+ key: 'entry',
+ control: 'textarea',
+ required: true,
+ "cssClass": "l-textarea-sm"
+ },
+ {
+ name: 'Embed Type',
+ key: 'withSnapshot',
+ control: 'snapshot-select',
+ "options": [
+ {
+ "name": "Link and Snapshot",
+ "value": true
+ },
+ {
+ "name": "Link only",
+ "value": false
+ }
+ ]
+ },
+ {
+ name: 'Embed',
+ key: 'embedObject',
+ control: 'embed-control'
+ },
+ {
+ name: 'Save in Notebook',
+ key: 'saveNotebook',
+ control: 'locator',
+ validate: validateLocation
+ }]
+ }]
+ };
+
+ function NewEntryContextual($compile,$rootScope,dialogService,notificationService,linkService,context) {
+ context = context || {};
+ this.domainObject = context.selectedObject || context.domainObject;
+ this.dialogService = dialogService;
+ this.notificationService = notificationService;
+ this.linkService = linkService;
+ this.$rootScope = $rootScope;
+ this.$compile = $compile;
+ }
+
+ function validateLocation(newParentObj) {
+ return newParentObj.model.type === 'notebook';
+ }
+
+
+ NewEntryContextual.prototype.perform = function () {
+ var self = this;
+ var domainObj = this.domainObject;
+ var notification = this.notificationService;
+ var dialogService = this.dialogService;
+ var rootScope = this.$rootScope;
+ rootScope.newEntryText = '';
+ // Create the overlay element and add it to the document's body
+ this.$rootScope.selObj = domainObj;
+ this.$rootScope.selValue = "";
+ var newScope = rootScope.$new();
+ newScope.selObj = domainObj;
+ newScope.selValue = "";
+ this.$compile(SNAPSHOT_TEMPLATE)(newScope);
+ //newScope.$destroy();
+
+ this.$rootScope.$watch("snapshot", setSnapshot);
+
+ function setSnapshot(value) {
+ if (value === "annotationCancelled") {
+ rootScope.snapshot = rootScope.lastValue;
+ rootScope.lastValue = '';
+ }else if (value && value !== rootScope.lastValue) {
+ var overlayModel = {
+ title: NEW_TASK_FORM.name,
+ message: NEW_TASK_FORM.message,
+ structure: NEW_TASK_FORM,
+ value: {'entry': rootScope.newEntryText || ""}
+ };
+
+ rootScope.currentDialog = overlayModel;
+
+ dialogService.getDialogResponse(
+ "overlay-dialog",
+ overlayModel,
+ function () {
+ return overlayModel.value;
+ }
+ ).then(addNewEntry);
+
+ rootScope.lastValue = value;
+ }
+ }
+
+ function addNewEntry(options) {
+ options.selectedModel = options.embedObject.getModel();
+ options.cssClass = options.embedObject.getCapability('type').typeDef.cssClass;
+ if (self.$rootScope.snapshot) {
+ options.snapshot = self.$rootScope.snapshot;
+ self.$rootScope.snapshot = undefined;
+ }else {
+ options.snapshot = undefined;
+ }
+
+ if (!options.withSnapshot) {
+ options.snapshot = '';
+ }
+
+ createSnap(options);
+ }
+
+ function createSnap(options) {
+ options.saveNotebook.useCapability('mutation', function (model) {
+ var entries = model.entries;
+ var lastEntry = entries[entries.length - 1];
+ var date = Date.now();
+
+ if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
+ model.entries.push({
+ 'id': date,
+ 'createdOn': date,
+ 'text': options.entry,
+ 'embeds': [{'type': options.embedObject.getId(),
+ 'id': '' + date,
+ 'cssClass': options.cssClass,
+ 'name': options.selectedModel.name,
+ 'snapshot': options.snapshot
+ }]
+ });
+ }else {
+ model.entries[entries.length - 1] = {
+ 'id': date,
+ 'createdOn': date,
+ 'text': options.entry,
+ 'embeds': [{'type': options.embedObject.getId(),
+ 'id': '' + date,
+ 'cssClass': options.cssClass,
+ 'name': options.selectedModel.name,
+ 'snapshot': options.snapshot
+ }]
+ };
+ }
+ });
+
+ notification.info({
+ title: "Notebook Entry created"
+ });
+ }
+ };
+
+ NewEntryContextual.appliesTo = function (context) {
+ var domainObject = context.domainObject;
+ return !!(domainObject && domainObject.getModel().type !== 'notebook');
+ };
+
+ return NewEntryContextual;
+ }
+);
diff --git a/platform/features/notebook/src/actions/RemoveEmbed.js b/platform/features/notebook/src/actions/RemoveEmbed.js
new file mode 100644
index 000000000..ae5132693
--- /dev/null
+++ b/platform/features/notebook/src/actions/RemoveEmbed.js
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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(
+ [],
+ function () {
+
+ function RemoveEmbed(dialogService,context) {
+ context = context || {};
+
+ this.domainObject = context.selectedObject || context.domainObject;
+ this.dialogService = dialogService;
+ }
+
+
+ RemoveEmbed.prototype.perform = function ($event,snapshot,embedId,entryId) {
+ var DOMAIN_OBJ = this.domainObject;
+ var errorDialog = this.dialogService.showBlockingMessage({
+ severity: "error",
+ title: "This action will permanently delete this Embed. Do you want to continue?",
+ minimized: true, // want the notification to be minimized initially (don't show banner)
+ options: [{
+ label: "OK",
+ callback: function () {
+ errorDialog.dismiss();
+ remove();
+ }
+ },{
+ label: "Cancel",
+ callback: function () {
+ errorDialog.dismiss();
+ }
+ }]
+ });
+
+ function remove() {
+ DOMAIN_OBJ.useCapability('mutation', function (model) {
+ var elementPos = model.entries.map(function (x) {
+ return x.createdOn;
+ }).indexOf(entryId);
+ var entryEmbeds = model.entries[elementPos].embeds;
+ var embedPos = entryEmbeds.map(function (x) {
+ return x.id;
+ }).indexOf(embedId);
+ model.entries[elementPos].embeds.splice(embedPos, 1);
+ });
+ }
+
+ };
+
+ return RemoveEmbed;
+ }
+);
diff --git a/platform/features/notebook/src/actions/RemoveSnapshot.js b/platform/features/notebook/src/actions/RemoveSnapshot.js
new file mode 100644
index 000000000..5fa4e26d6
--- /dev/null
+++ b/platform/features/notebook/src/actions/RemoveSnapshot.js
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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(
+ [],
+ function () {
+
+ function RemoveSnapshot(dialogService,context) {
+ context = context || {};
+
+ this.domainObject = context.selectedObject || context.domainObject;
+ this.dialogService = dialogService;
+ }
+
+
+
+ RemoveSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId) {
+
+ var DOMAIN_OBJ = this.domainObject;
+ var errorDialog = this.dialogService.showBlockingMessage({
+ severity: "error",
+ title: "This action will permanently delete this Snapshot. Do you want to continue?",
+ minimized: true, // want the notification to be minimized initially (don't show banner)
+ options: [{
+ label: "OK",
+ callback: function () {
+ errorDialog.dismiss();
+ remove();
+ }
+ },{
+ label: "Cancel",
+ callback: function () {
+ errorDialog.dismiss();
+ }
+ }]
+ });
+
+ function remove() {
+ DOMAIN_OBJ.useCapability('mutation', function (model) {
+ var elementPos = model.entries.map(function (x) {
+ return x.createdOn;
+ }).indexOf(entryId);
+ var entryEmbeds = model.entries[elementPos].embeds;
+ var embedPos = entryEmbeds.map(function (x) {
+ return x.id;
+ }).indexOf(embedId);
+ model.entries[elementPos].embeds[embedPos].snapshot = "";
+ });
+ }
+
+ };
+
+ return RemoveSnapshot;
+ }
+);
diff --git a/platform/features/notebook/src/actions/ViewSnapshot.js b/platform/features/notebook/src/actions/ViewSnapshot.js
new file mode 100644
index 000000000..c09888e12
--- /dev/null
+++ b/platform/features/notebook/src/actions/ViewSnapshot.js
@@ -0,0 +1,169 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+/**
+ * Module defining ViewSnapshot
+ */
+define(
+ ['zepto'],
+ function ($) {
+
+ var OVERLAY_TEMPLATE = '' +
+ ' <div class="abs blocker"></div>' +
+ ' <div class="abs outer-holder">' +
+ ' <a class="close icon-x-in-circle"></a>' +
+ ' <div class="abs inner-holder l-flex-col">' +
+ ' <div class="t-contents flex-elem holder grows"></div>' +
+ ' <div class="bottom-bar flex-elem holder">' +
+ ' <a class="t-done s-button major">Done</a>' +
+ ' </div>' +
+ ' </div>' +
+ ' </div>';
+
+ var toggleOverlay,
+ overlay,
+ closeButton,
+ doneButton,
+ blocker,
+ overlayContainer,
+ img,
+ annotateButton,
+ annotateImg;
+
+ function ViewSnapshot($compile,context) {
+ context = context || {};
+
+ this.$compile = $compile;
+ }
+
+ function openOverlay(url,header) {
+ overlay = document.createElement('div');
+ $(overlay).addClass('abs overlay l-large-view');
+ overlay.innerHTML = OVERLAY_TEMPLATE;
+ overlayContainer = overlay.querySelector('.t-contents');
+ closeButton = overlay.querySelector('a.close');
+ closeButton.addEventListener('click', toggleOverlay);
+ doneButton = overlay.querySelector('a.t-done');
+ doneButton.addEventListener('click', toggleOverlay);
+ blocker = overlay.querySelector('.abs.blocker');
+ blocker.addEventListener('click', toggleOverlay);
+ annotateButton = header.querySelector('a.icon-pencil');
+ annotateButton.addEventListener('click', annotateImg);
+ document.body.appendChild(overlay);
+ img = document.createElement('div');
+ $(img).addClass('abs object-holder t-image-holder s-image-holder');
+ img.innerHTML = '<div class="image-main s-image-main" style="background-image: url(' + url + ');"></div>';
+ overlayContainer.appendChild(header);
+ overlayContainer.appendChild(img);
+ }
+
+ function closeOverlay() {
+ overlayContainer.removeChild(img);
+ document.body.removeChild(overlay);
+ closeButton.removeEventListener('click', toggleOverlay);
+ closeButton = undefined;
+ doneButton.removeEventListener('click', toggleOverlay);
+ doneButton = undefined;
+ blocker.removeEventListener('click', toggleOverlay);
+ blocker = undefined;
+ overlayContainer = undefined;
+ overlay = undefined;
+ img = undefined;
+ }
+
+ function headerTemplate() {
+ var template = '<div class="t-snapshot abs l-view-header">' +
+ '<div class="abs object-browse-bar l-flex-row">' +
+ '<div class="left flex-elem l-flex-row grows">' +
+ '<div class="object-header flex-elem l-flex-row grows">' +
+ '<div class="type-icon flex-elem embed-icon holder" ng-class="cssClass"></div>' +
+ '<div class="title-label flex-elem holder flex-can-shrink">{{entryName}}</div>' +
+ '<a class="context-available flex-elem holder" ng-click="openMenu($event,embedType)""></a>' +
+ '<div class="hide-menu" ng-show="false">' +
+ '<div class="menu-element menu-view context-menu-wrapper mobile-disable-select">' +
+ '<div class="menu context-menu">' +
+ '<ul>' +
+ '<li ng-repeat="menu in embedActions"' +
+ 'ng-click="menuPerform(menu)"' +
+ 'title="{{menu.name}}"' +
+ 'class="{{menu.cssClass}}">' +
+ '{{menu.name}}' +
+ '</li>' +
+ '</ul>' +
+ '</div>' +
+ '</div>' +
+ '</div>' +
+ '</div><!-- closes object-header -->' +
+ '</div><!-- closes left -->' +
+ '<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">' +
+ '<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">' +
+ 'SNAPSHOT {{snapDate | date:\'yyyy-MM-dd HH:mm:ss\'}}' +
+ '</div>' +
+ '<a class="s-button icon-pencil" title="Annotate">' +
+ '<span class="title-label">Annotate</span>' +
+ '</a>' +
+ '</div><!-- closes right -->' +
+ '</div><!-- closes object-browse-bar -->' +
+ '</div><!-- closes t-snapshot -->';
+ return template;
+ }
+
+
+ ViewSnapshot.prototype.perform = function ($event,snapshot,embedId,entryId,$scope,embed) {
+ var isOpen = false;
+
+ // onclick for menu items in overlay header context menu
+ $scope.menuPerform = function (menu) {
+ menu.perform();
+ closeOverlay();
+ };
+
+ // Create the overlay element and add it to the document's body
+ $scope.cssClass = embed.cssClass;
+ $scope.embedType = embed.type;
+ $scope.entryName = embed.name;
+ $scope.snapDate = +embedId;
+ var element = this.$compile(headerTemplate())($scope);
+
+ var annotateAction = $scope.action.getActions({category: 'embed'})[1];
+
+ toggleOverlay = function () {
+ if (!isOpen) {
+ openOverlay(snapshot, element[0]);
+ isOpen = true;
+ } else {
+ closeOverlay();
+ isOpen = false;
+ }
+ };
+
+ annotateImg = function () {
+ closeOverlay();
+ annotateAction.perform($event, snapshot, embedId, entryId, $scope);
+ };
+
+ toggleOverlay();
+ };
+
+ return ViewSnapshot;
+ }
+);
diff --git a/platform/features/notebook/src/capabilities/NotebookCapability.js b/platform/features/notebook/src/capabilities/NotebookCapability.js
new file mode 100644
index 000000000..f8c4e8e4f
--- /dev/null
+++ b/platform/features/notebook/src/capabilities/NotebookCapability.js
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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(
+ function () {
+
+ /**
+ * The notebook capability allows a domain object to know whether the
+ * notebook plugin is present or not.
+ *
+ * @constructor
+ */
+ function NotebookCapability(typeService, domainObject) {
+ this.domainObject = domainObject;
+ this.typeService = typeService;
+ return this;
+ }
+
+ /**
+ * Returns true if there is a notebook domain Object.
+ *
+ * @returns {Boolean}
+ */
+ NotebookCapability.prototype.isNotebook = function () {
+ return !!this.typeService.getType('notebook');
+ };
+
+ return NotebookCapability;
+ }
+);
diff --git a/platform/features/notebook/src/controllers/LayoutNotebookController.js b/platform/features/notebook/src/controllers/LayoutNotebookController.js
new file mode 100644
index 000000000..c516f1dbb
--- /dev/null
+++ b/platform/features/notebook/src/controllers/LayoutNotebookController.js
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+/**
+ * This bundle implements object types and associated views for
+ * display-building.
+ */
+define(
+ [],
+ function () {
+
+ /**
+ * The LayoutNotebookController is responsible for supporting the
+ * notebook feature creation on theLayout view.
+ **/
+
+ function LayoutNotebookController($scope) {
+ $scope.hasNotebookAction = undefined;
+
+ $scope.newNotebook = undefined;
+
+ var actions = $scope.domainObject.getCapability('action');
+ var notebookAction = actions.getActions({'key': 'notebook-new-entry'});
+ if (notebookAction.length > 0) {
+ $scope.hasNotebookAction = true;
+ $scope.newNotebook = function () {
+ notebookAction[0].perform();
+ };
+ }
+ }
+
+ return LayoutNotebookController;
+ }
+);
+
diff --git a/platform/features/notebook/src/controllers/NewEntryController.js b/platform/features/notebook/src/controllers/NewEntryController.js
new file mode 100644
index 000000000..320884c2c
--- /dev/null
+++ b/platform/features/notebook/src/controllers/NewEntryController.js
@@ -0,0 +1,66 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+/**
+ * Module defining NewEntryController. */
+define(
+ [],
+ function () {
+
+ function NewEntryController($scope,$rootScope) {
+
+ $scope.snapshot = undefined;
+ $scope.snapToggle = true;
+ $scope.entryText = '';
+ var annotateAction = $rootScope.selObj.getCapability('action').getActions(
+ {category: 'embed'})[1];
+
+ $scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = $rootScope.selObj;
+ $scope.objectName = $rootScope.selObj.getModel().name;
+ $scope.cssClass = $rootScope.selObj.getCapability('type').typeDef.cssClass;
+
+ $scope.annotateSnapshot = function ($event) {
+ if ($rootScope.currentDialog.value) {
+ $rootScope.newEntryText = $scope.$parent.$parent.ngModel.entry;
+ $rootScope.currentDialog.cancel();
+ annotateAction.perform($event, $rootScope.snapshot.src);
+ $rootScope.currentDialog = undefined;
+ }
+ };
+
+ function updateSnapshot(img) {
+ $scope.snapshot = img;
+ }
+ // Update set of actions whenever the action capability
+ // changes or becomes available.
+ $rootScope.$watch("snapshot", updateSnapshot);
+
+ $rootScope.$watch("selValue", toggleEmbed);
+
+ function toggleEmbed(value) {
+ $scope.snapToggle = value;
+ }
+ }
+
+ return NewEntryController;
+ }
+);
diff --git a/platform/features/notebook/src/controllers/NotebookController.js b/platform/features/notebook/src/controllers/NotebookController.js
new file mode 100644
index 000000000..62b9af0c6
--- /dev/null
+++ b/platform/features/notebook/src/controllers/NotebookController.js
@@ -0,0 +1,400 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+ /*-- main controller file, here is the core functionality of the notebook plugin --*/
+
+define(
+ ['zepto'],
+ function ($) {
+
+
+ function NotebookController(
+ $scope,
+ dialogService,
+ popupService,
+ agentService,
+ objectService,
+ navigationService,
+ now,
+ actionService,
+ $timeout,
+ $element,
+ $sce
+ ) {
+
+ $scope.entriesEl = $(document.body).find('.t-entries-list');
+ $scope.sortEntries = '-createdOn';
+ $scope.showTime = "0";
+ $scope.editEntry = false;
+ $scope.entrySearch = '';
+ $scope.entryTypes = [];
+ $scope.embedActions = [];
+ $scope.currentEntryValue = '';
+
+ /*--seconds in an hour--*/
+
+ var SECONDS_IN_AN_HOUR = 60 * 60 * 1000;
+
+ this.scope = $scope;
+
+ $scope.hoursFilter = function (hours,entryTime) {
+ if (+hours) {
+ return entryTime > (Date.now() - SECONDS_IN_AN_HOUR * (+hours));
+ }else {
+ return true;
+ }
+ };
+
+ $scope.scrollToTop = function () {
+ var entriesContainer = $scope.entriesEl.parent();
+ entriesContainer[0].scrollTop = 0;
+ };
+
+ $scope.findEntryEl = function (entryId) {
+ var element = $($scope.entriesEl).find('#entry_' + entryId);
+
+ if (element[0]) {
+ return element.find("[contenteditable='true']");
+ } else {
+ return $($scope.entriesEl.children().children()[0]).find("[contenteditable='true']");
+ }
+ };
+
+ $scope.findEntryPositionById = function (id) {
+ var foundId = -1;
+
+ $scope.domainObject.model.entries.forEach(function (element, index) {
+ if (element.id === id) {
+ foundId = index;
+ return;
+ }
+ });
+
+ return foundId;
+ };
+
+ $scope.newEntry = function ($event) {
+ $scope.scrollToTop();
+
+ var entries = $scope.domainObject.model.entries,
+ lastEntry = entries[entries.length - 1],
+ id = Date.now();
+
+ if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
+ var createdEntry = {'id': id, 'createdOn': id};
+
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries.push(createdEntry);
+ });
+ } else {
+ $scope.findEntryEl(lastEntry.id).focus();
+
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries[entries.length - 1].createdOn = id;
+ });
+ }
+ $scope.entrySearch = '';
+ };
+
+
+ $scope.deleteEntry = function ($event) {
+ var delId = +$event.currentTarget.id;
+ var errorDialog = dialogService.showBlockingMessage({
+ severity: "error",
+ title: "This action will permanently delete this Notebook entry. Do you want to continue?",
+ minimized: true, // want the notification to be minimized initially (don't show banner)
+ options: [{
+ label: "OK",
+ callback: function () {
+ errorDialog.dismiss();
+ var elementPos = $scope.findEntryPositionById(delId);
+
+ if (elementPos !== -1) {
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries.splice(elementPos, 1);
+ });
+ } else {
+ window.console.log('delete error');
+ }
+
+ }
+ },{
+ label: "Cancel",
+ callback: function () {
+ errorDialog.dismiss();
+ }
+ }]
+ });
+ };
+
+ function setCaretToEndOfContenteditable(contentEditableElement) {
+ var range,selection;
+ if (document.createRange) {
+ range = document.createRange();//Create a range (a range is a like the selection but invisible)
+ range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
+ range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
+ selection = window.getSelection();//get the selection object (allows you to change selection)
+ selection.removeAllRanges();//remove any selections already made
+ selection.addRange(range);//make the range you have just created the visible selection
+ }
+ }
+
+ $scope.selectContentEditable = function ($event) {
+ var child = $($event.srcElement).children()[0];
+
+ if (child) {
+ $($event.srcElement).children()[0].focus();
+ }
+ };
+
+ $scope.textFocus = function ($event, entryId) {
+ if ($event.srcElement && $event.srcElement.innerText) {
+ /*
+ On focus, if the currentTarget isn't blank, set the global currentEntryValue = the
+ content of the current focus. This will be used at blur to determine if the
+ current entry has been modified or not.
+ Not sure this is right, would think we'd always want to set curEntVal even if blank
+ */
+ $scope.currentEntryValue = $event.srcElement.innerText;
+ setCaretToEndOfContenteditable($event.srcElement);
+ } else {
+ $event.target.innerText = '';
+ }
+ };
+
+ //On text blur(when focus is removed)
+ $scope.textBlur = function ($event, entryId) {
+ // entryId is the unique numeric based on the original createdOn
+ if ($event.target && $event.target.innerText !== "") {
+ var elementPos = $scope.findEntryPositionById(+entryId);
+
+ // If the text of an entry has been changed, then update the text and the modifiedOn numeric
+ // Otherwise, don't do anything
+ if ($scope.currentEntryValue !== $event.target.innerText) {
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries[elementPos].text = $event.target.innerText;
+ model.entries[elementPos].modified = Date.now();
+ });
+ }
+ }
+ };
+
+ $scope.finished = function (model) {
+ var lastEntry = model[model.length - 1];
+
+ if (!lastEntry.text) {
+ $scope.findEntryEl(lastEntry.id).focus();
+ }
+ };
+
+ $scope.handleActive = function () {
+ var newEntry = $scope.entriesEl.find('.active');
+ if (newEntry) {
+ newEntry.removeClass('active');
+ }
+ };
+
+
+ $scope.clearSearch = function () {
+ $scope.entrySearch = '';
+ };
+
+ $scope.viewSnapshot = function ($event,snapshot,embedId,entryId,$innerScope,domainObject) {
+ var viewAction = $scope.action.getActions({category: 'embed'})[0];
+ viewAction.perform($event, snapshot, embedId, entryId, $innerScope, domainObject);
+ };
+
+
+ $scope.parseText = function (text) {
+ if (text) {
+ return text.split(/\r\n|\r|\n/gi);
+ }
+ };
+
+ //parse text and add line breaks where needed
+ $scope.trustedHtml = function (text) {
+ if (text) {
+ return $sce.trustAsHtml(this.parseText(text).join('<br>'));
+ }
+ };
+
+ $scope.renderImage = function (img) {
+ return URL.createObjectURL(img);
+ };
+
+ $scope.getDomainObj = function (id) {
+ return objectService.getObjects([id]);
+ };
+
+ function refreshComp(change) {
+ if (change && change.length) {
+ change[0].getCapability('action').getActions({key: 'remove'})[0].perform();
+ }
+ }
+
+ $scope.actionToMenuOption = function (action) {
+ return {
+ key: action.getMetadata().key,
+ name: action.getMetadata().name,
+ cssClass: action.getMetadata().cssClass,
+ perform: action.perform
+ };
+ };
+
+ // Maintain all "conclude-editing" and "save" actions in the
+ // present context.
+ function updateActions() {
+ $scope.menuEmbed = $scope.action ?
+ $scope.action.getActions({category: 'embed'}) :
+ [];
+
+ $scope.menuEmbedNoSnap = $scope.action ?
+ $scope.action.getActions({category: 'embed-no-snap'}) :
+ [];
+
+ $scope.menuActions = $scope.action ?
+ $scope.action.getActions({key: 'window'}) :
+ [];
+ }
+
+ // Update set of actions whenever the action capability
+ // changes or becomes available.
+ $scope.$watch("action", updateActions);
+
+ $scope.navigate = function ($event,embedType) {
+ if ($event) {
+ $event.preventDefault();
+ }
+ $scope.getDomainObj(embedType).then(function (resp) {
+ navigationService.setNavigation(resp[embedType]);
+ });
+ };
+
+ $scope.saveSnap = function (url,embedPos,entryPos) {
+ var snapshot = false;
+ if (url) {
+ if (embedPos !== -1 && entryPos !== -1) {
+ var reader = new window.FileReader();
+ reader.readAsDataURL(url);
+ reader.onloadend = function () {
+ snapshot = reader.result;
+ $scope.domainObject.useCapability('mutation', function (model) {
+ if (model.entries[entryPos]) {
+ model.entries[entryPos].embeds[embedPos].snapshot = {
+ 'src': snapshot,
+ 'type': url.type,
+ 'size': url.size,
+ 'modified': Date.now()
+ };
+ model.entries[entryPos].embeds[embedPos].id = Date.now();
+ }
+ });
+ };
+ }
+ }else {
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries[entryPos].embeds[embedPos].snapshot = snapshot;
+ });
+ }
+ };
+
+ /*---popups menu embeds----*/
+
+ function getEmbedActions(embedType) {
+ if (!$scope.embedActions.length) {
+ $scope.getDomainObj(embedType).then(function (resp) {
+ $scope.embedActions = [];
+ $scope.embedActions.push($scope.actionToMenuOption(
+ $scope.action.getActions({key: 'window',selectedObject: resp[embedType]})[0]
+ ));
+ $scope.embedActions.push({
+ key: 'navigate',
+ name: 'Go to Original',
+ cssClass: '',
+ perform: function () {
+ $scope.navigate('', embedType);
+ }
+ });
+ });
+ }
+ }
+
+ $scope.openMenu = function ($event,embedType) {
+ $event.preventDefault();
+
+ getEmbedActions(embedType);
+
+ var body = $(document).find('body'),
+ initiatingEvent = agentService.isMobile() ?
+ 'touchstart' : 'mousedown',
+ dismissExistingMenu,
+ menu,
+ popup;
+
+ var container = $($event.currentTarget).parent().parent();
+
+ menu = container.find('.menu-element');
+
+ // Remove the context menu
+ function dismiss() {
+ container.find('.hide-menu').append(menu);
+ body.off("mousedown", dismiss);
+ dismissExistingMenu = undefined;
+ $scope.embedActions = [];
+ }
+
+ // Dismiss any menu which was already showing
+ if (dismissExistingMenu) {
+ dismissExistingMenu();
+ }
+
+ // ...and record the presence of this menu.
+ dismissExistingMenu = dismiss;
+
+ popup = popupService.display(menu, [$event.pageX,$event.pageY], {
+ marginX: 0,
+ marginY: -50
+ });
+
+ // Stop propagation so that clicks or touches on the menu do not close the menu
+ menu.on(initiatingEvent, function (event) {
+ event.stopPropagation();
+ $timeout(dismiss, 300);
+ });
+
+ // Dismiss the menu when body is clicked/touched elsewhere
+ // ('mousedown' because 'click' breaks left-click context menus)
+ // ('touchstart' because 'touch' breaks context menus up)
+ body.on(initiatingEvent, dismiss);
+
+ };
+
+
+ $scope.$watchCollection("composition", refreshComp);
+
+
+ $scope.$on('$destroy', function () {});
+
+ }
+
+ return NotebookController;
+ });
diff --git a/platform/features/notebook/src/controllers/SelectSnapshotController.js b/platform/features/notebook/src/controllers/SelectSnapshotController.js
new file mode 100644
index 000000000..ce0a12343
--- /dev/null
+++ b/platform/features/notebook/src/controllers/SelectSnapshotController.js
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+/**
+ * Module defining SelectSnapshotController. */
+define(
+ [],
+ function () {
+
+ function SelectSnapshotController($scope,$rootScope) {
+
+ $scope.selectModel = true;
+
+ function selectprint(value) {
+ $rootScope.selValue = value;
+ $scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = value;
+ }
+
+ $scope.$watch("selectModel", selectprint);
+
+ }
+
+ return SelectSnapshotController;
+ }
+);
diff --git a/platform/features/notebook/src/directives/EntryDnd.js b/platform/features/notebook/src/directives/EntryDnd.js
new file mode 100644
index 000000000..9dc050905
--- /dev/null
+++ b/platform/features/notebook/src/directives/EntryDnd.js
@@ -0,0 +1,126 @@
+/*****************************************************************************
+ * 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(['zepto'], function ($) {
+
+ function EntryDnd($rootScope,$compile,dndService,typeService,notificationService) {
+
+ function link($scope, $element) {
+
+ function drop(e) {
+ var selectedObject = dndService.getData('mct-domain-object');
+ var selectedModel = selectedObject.getModel();
+ var cssClass = selectedObject.getCapability('type').typeDef.cssClass;
+ var entryId = -1;
+ var embedId = -1;
+ $scope.clearSearch();
+ if ($element[0].id === 'newEntry') {
+ entryId = $scope.domainObject.model.entries.length;
+ embedId = 0;
+ var lastEntry = $scope.domainObject.model.entries[entryId - 1];
+ if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries.push({'createdOn': +Date.now(),
+ 'id': +Date.now(),
+ 'embeds': [{'type': selectedObject.getId(),
+ 'id': '' + Date.now(),
+ 'cssClass': cssClass,
+ 'name': selectedModel.name,
+ 'snapshot': ''
+ }]
+ });
+ });
+ }else {
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries[entryId - 1] =
+ {'createdOn': +Date.now(),
+ 'embeds': [{'type': selectedObject.getId(),
+ 'id': '' + Date.now(),
+ 'cssClass': cssClass,
+ 'name': selectedModel.name,
+ 'snapshot': ''
+ }]
+ };
+ });
+ }
+
+ $scope.scrollToTop();
+ notificationService.info({
+ title: "Notebook Entry created"
+ });
+
+ }else {
+ entryId = $scope.findEntryPositionById(Number($element[0].id.replace('entry_', '')));
+
+ if (!$scope.domainObject.model.entries[entryId].embeds) {
+ $scope.domainObject.model.entries[entryId].embeds = [];
+ }
+
+ $scope.domainObject.useCapability('mutation', function (model) {
+ model.entries[entryId].embeds.push({'type': selectedObject.getId(),
+ 'id': '' + Date.now(),
+ 'cssClass': cssClass,
+ 'name': selectedModel.name,
+ 'snapshot': ''
+ });
+ });
+
+ embedId = $scope.domainObject.model.entries[entryId].embeds.length - 1;
+
+ if (selectedObject) {
+ e.preventDefault();
+
+ }
+ }
+
+ if ($(e.currentTarget).hasClass('drag-active')) {
+ $(e.currentTarget).removeClass('drag-active');
+ }
+
+ }
+
+ function dragover(e) {
+ if (!$(e.currentTarget).hasClass('drag-active')) {
+ $(e.currentTarget).addClass('drag-active');
+ }
+ }
+
+ // Listen for the drop itself
+ $element.on('dragover', dragover);
+ $element.on('drop', drop);
+
+
+ $scope.$on('$destroy', function () {
+ $element.off('dragover', dragover);
+ $element.off('drop', drop);
+ });
+ }
+
+ return {
+ restrict: 'A',
+ link: link
+ };
+ }
+
+ return EntryDnd;
+
+});
diff --git a/platform/features/notebook/src/directives/MCTModalNotebook.js b/platform/features/notebook/src/directives/MCTModalNotebook.js
new file mode 100644
index 000000000..69e32c2ef
--- /dev/null
+++ b/platform/features/notebook/src/directives/MCTModalNotebook.js
@@ -0,0 +1,166 @@
+/*****************************************************************************
+ * 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([
+ 'zepto'
+], function (
+ $
+) {
+
+ var OVERLAY_TEMPLATE = '' +
+' <div class="abs blocker"></div>' +
+' <div class="abs outer-holder">' +
+' <a class="close icon-x-in-circle"></a>' +
+' <div class="abs inner-holder l-flex-col">' +
+' <div class="t-contents flex-elem holder grows"></div>' +
+' <div class="bottom-bar flex-elem holder">' +
+' <a class="t-done s-button major">Done</a>' +
+' </div>' +
+' </div>' +
+' </div>';
+
+ var NEW_NOTEBOOK_BUTTON_TEMPLATE = '<a class="s-button labeled icon-notebook new-notebook-entry" title="New Notebook Entry">' +
+ '<span class="title-label">New Notebook Entry</span>' +
+ '</a>';
+
+ /**
+ * MCT Trigger Modal is intended for use in only one location: inside the
+ * object-header to allow views in a layout to be popped out in a modal.
+ * Users can close the modal and go back to normal, and everything generally
+ * just works fine.
+ *
+ * This code is sensitive to how our html is constructed-- particularly with
+ * how it locates the the container of an element in a layout. However, it
+ * should be able to handle slight relocations so long as it is always a
+ * descendent of a `.frame` element.
+ */
+ function MCTModalNotebook($document) {
+ var document = $document[0];
+
+ function link($scope, $element) {
+ var frame = $element.parent();
+
+ for (var i = 0; i < 10; i++) {
+ if (frame.hasClass('frame')) {
+ break;
+ }
+ frame = frame.parent();
+ }
+ if (!frame.hasClass('frame')) {
+ $element.remove();
+ return;
+ }
+
+ frame = frame[0];
+ var layoutContainer = frame.parentElement,
+ isOpen = false,
+ toggleOverlay,
+ overlay,
+ closeButton,
+ doneButton,
+ notebookButton,
+ blocker,
+ overlayContainer,
+ notebookButtonEl;
+
+ function openOverlay() {
+ // Remove frame classes from being applied in a non-frame context
+ $(frame).removeClass('frame frame-template');
+ overlay = document.createElement('div');
+ $(overlay).addClass('abs overlay l-large-view');
+ overlay.innerHTML = OVERLAY_TEMPLATE;
+ overlayContainer = overlay.querySelector('.t-contents');
+ closeButton = overlay.querySelector('a.close');
+ closeButton.addEventListener('click', toggleOverlay);
+ doneButton = overlay.querySelector('a.t-done');
+ doneButton.addEventListener('click', toggleOverlay);
+ blocker = overlay.querySelector('.abs.blocker');
+ blocker.addEventListener('click', toggleOverlay);
+ document.body.appendChild(overlay);
+ layoutContainer.removeChild(frame);
+ overlayContainer.appendChild(frame);
+
+ //verify if there is a new notebook entry action
+ var actions = $scope.domainObject.getCapability('action');
+ var notebookAction = actions.getActions({'key': 'notebook-new-entry'});
+ if (notebookAction.length > 0) {
+ notebookButtonEl = document.createElement('div');
+ $(notebookButtonEl).addClass('notebook-button-container');
+ notebookButtonEl.innerHTML = NEW_NOTEBOOK_BUTTON_TEMPLATE;
+ notebookButton = frame.querySelector('.object-browse-bar .right');
+ notebookButton.prepend(notebookButtonEl);
+ // $(frame.querySelector('.object-holder')).addClass('container-notebook');
+ notebookButton.addEventListener('click', function () {
+ notebookAction[0].perform();
+ });
+ }
+
+ }
+
+ function closeOverlay() {
+ $(frame).addClass('frame frame-template');
+ overlayContainer.removeChild(frame);
+ layoutContainer.appendChild(frame);
+ document.body.removeChild(overlay);
+ closeButton.removeEventListener('click', toggleOverlay);
+ closeButton = undefined;
+ doneButton.removeEventListener('click', toggleOverlay);
+ doneButton = undefined;
+ blocker.removeEventListener('click', toggleOverlay);
+ blocker = undefined;
+ overlayContainer = undefined;
+ overlay = undefined;
+
+
+ if (notebookButton) {
+ notebookButton.removeChild(notebookButtonEl);
+ }
+
+ }
+
+ toggleOverlay = function (event) {
+ event.stopPropagation();
+
+ if (!isOpen) {
+ openOverlay();
+ isOpen = true;
+ } else {
+ closeOverlay();
+ isOpen = false;
+ }
+ };
+
+ $element.on('click', toggleOverlay);
+ $scope.$on('$destroy', function () {
+ $element.off('click', toggleOverlay);
+ });
+ }
+
+ return {
+ restrict: 'A',
+ link: link
+ };
+ }
+
+ return MCTModalNotebook;
+
+});
diff --git a/platform/features/notebook/src/directives/MCTSnapshot.js b/platform/features/notebook/src/directives/MCTSnapshot.js
new file mode 100644
index 000000000..034f20fa4
--- /dev/null
+++ b/platform/features/notebook/src/directives/MCTSnapshot.js
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * 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(['zepto', 'dom-to-image'], function ($) {
+ /**
+
+ */
+ function MCTSnapshot($rootScope,$document,exportImageService,dialogService,notificationService) {
+ var document = $document[0];
+
+ function link($scope, $element, $attrs) {
+ var objectElement = $(document.body).find('.overlay')[0] || $(document.body).find("[key='representation.selected.key']")[0],
+ takeSnapshot,
+ makeImg,
+ saveImg;
+
+ $(objectElement).addClass("s-status-taking-snapshot");
+
+ takeSnapshot = function () {
+ makeImg(objectElement);
+ };
+
+ saveImg = function (url,entryId,embedId) {
+ $scope.$parent.$parent.$parent.saveSnap(url, embedId, entryId);
+ };
+
+ makeImg = function (el) {
+ var scope = $scope;
+ var dialog = dialogService.showBlockingMessage({
+ title: "Saving...",
+ hint: "Taking Snapshot...",
+ unknownProgress: true,
+ severity: "info",
+ delay: true
+ });
+ window.setTimeout(function () {
+ window.domtoimage.toBlob(el).then(function (img) {
+ $(objectElement).removeClass("s-status-taking-snapshot");
+
+ if (img) {
+ if ($element[0].dataset.entry && $element[0].dataset.embed) {
+ saveImg(img, +$element[0].dataset.entry, +$element[0].dataset.embed);
+ } else {
+ var reader = new window.FileReader();
+ reader.readAsDataURL(img);
+ reader.onloadend = function () {
+ $($element[0]).attr("data-snapshot", reader.result);
+ $rootScope.snapshot = {
+ 'src': reader.result,
+ 'type': img.type,
+ 'size': img.size,
+ 'modified': Date.now()
+ };
+ scope.$destroy();
+ };
+ }
+ }
+
+ dialog.dismiss();
+
+ }, function (error) {
+ if (dialog) {
+ dialog.dismiss();
+ }
+ });
+
+ }, 500);
+ };
+
+ takeSnapshot();
+
+ $scope.$on('$destroy', function () {
+ $element.remove();
+ });
+ }
+
+ return {
+ restrict: 'A',
+ link: link
+ };
+ }
+
+ return MCTSnapshot;
+
+});
diff --git a/platform/features/notebook/src/policies/CompositionPolicy.js b/platform/features/notebook/src/policies/CompositionPolicy.js
new file mode 100644
index 000000000..fc6ddb2f0
--- /dev/null
+++ b/platform/features/notebook/src/policies/CompositionPolicy.js
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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.
+ *****************************************************************************/
+
+/**
+ * This bundle implements "containment" rules, which determine which objects
+ * can be contained within a notebook.
+ */
+define(
+ [],
+ function () {
+ function CompositionPolicy() {
+ }
+
+ CompositionPolicy.prototype.allow = function (parent, child) {
+ var parentDef = parent.getCapability('type').getName();
+
+ if (parentDef === 'Notebook' && child.getCapability('status').list().length) {
+ return false;
+ }
+ return true;
+ };
+
+ return CompositionPolicy;
+ }
+);
diff --git a/platform/features/notebook/src/policies/ViewPolicy.js b/platform/features/notebook/src/policies/ViewPolicy.js
new file mode 100644
index 000000000..aceaa2130
--- /dev/null
+++ b/platform/features/notebook/src/policies/ViewPolicy.js
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2017, 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(
+ function () {
+
+ function ViewPolicy() {
+ }
+
+ ViewPolicy.prototype.allow = function (view, domainObject) {
+ // if (view.key === 'layout') {
+ // return false;
+ // }
+
+ return true;
+ };
+
+ return ViewPolicy;
+ }
+);
+
diff --git a/platform/features/notebook/src/shims/painterro-shim.js b/platform/features/notebook/src/shims/painterro-shim.js
new file mode 100644
index 000000000..eb79f6c7a
--- /dev/null
+++ b/platform/features/notebook/src/shims/painterro-shim.js
@@ -0,0 +1,13 @@
+define(function () {
+ return function (painterroInstance) {
+ painterroInstance.removeEventHandlers = function() {
+ Object.keys(this.documentHandlers).forEach((key) => {
+ this.doc.removeEventListener(key, this.documentHandlers[key]);
+ });
+
+ Object.keys(this.windowHandlers).forEach((key) => {
+ window.removeEventListener(key, this.windowHandlers[key]);
+ });
+ }.bind(painterroInstance);
+ }
+}); \ No newline at end of file
diff --git a/platform/representation/src/MCTInclude.js b/platform/representation/src/MCTInclude.js
index 354c1e2c4..688ed5753 100644
--- a/platform/representation/src/MCTInclude.js
+++ b/platform/representation/src/MCTInclude.js
@@ -62,8 +62,10 @@ define(
scope.key && templateMap[scope.key]
);
- scope.$watch('key', function (key) {
- changeTemplate(key && templateMap[key]);
+ scope.$watch('key', function (newKey, oldKey) {
+ if (newKey !== oldKey) {
+ changeTemplate(newKey && templateMap[newKey]);
+ }
});
}
diff --git a/platform/search/res/templates/search.html b/platform/search/res/templates/search.html
index 20377f9b6..7447fc812 100644
--- a/platform/search/res/templates/search.html
+++ b/platform/search/res/templates/search.html
@@ -21,7 +21,7 @@
-->
<div class="angular-w l-flex-col flex-elem grows holder" ng-controller="SearchController as controller">
<div class="l-flex-col flex-elem grows holder holder-search" ng-controller="SearchMenuController as menuController">
- <div class="search-bar flex-elem l-flex-row"
+ <div class="search-bar search-filter-by-type flex-elem l-flex-row"
ng-controller="ToggleController as toggle"
ng-class="{ holder: !(ngModel.input === '' || ngModel.input === undefined) }">
<div class="holder flex-elem grows">
diff --git a/src/plugins/plot/src/services/ExportImageService.js b/src/plugins/plot/src/services/ExportImageService.js
index 5c3a6bd2c..c1f45c1c8 100644
--- a/src/plugins/plot/src/services/ExportImageService.js
+++ b/src/plugins/plot/src/services/ExportImageService.js
@@ -142,6 +142,17 @@ define(
};
/**
+ * Takes a screenshot of a DOM node in PNG format.
+ * @param {node} element to be exported
+ * @param {string} filename the exported image
+ * @returns {promise}
+ */
+
+ ExportImageService.prototype.exportPNGtoSRC = function (element) {
+ return this.renderElement(element, "png");
+ };
+
+ /**
* canvas.toBlob() not supported in IE < 10, Opera, and Safari. This polyfill
* implements the method in browsers that would not otherwise support it.
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js
index 87159d963..120b2d86e 100644
--- a/src/plugins/plugins.js
+++ b/src/plugins/plugins.js
@@ -27,6 +27,7 @@ define([
'./autoflow/AutoflowTabularPlugin',
'./timeConductor/plugin',
'../../example/imagery/plugin',
+ '../../platform/features/notebook/bundle',
'../../platform/import-export/bundle',
'./summaryWidget/plugin',
'./URLIndicatorPlugin/URLIndicatorPlugin',
@@ -40,6 +41,7 @@ define([
AutoflowPlugin,
TimeConductorPlugin,
ExampleImagery,
+ Notebook,
ImportExport,
SummaryWidget,
URLIndicatorPlugin,
@@ -53,6 +55,7 @@ define([
Espresso: 'platform/commonUI/themes/espresso',
LocalStorage: 'platform/persistence/local',
MyItems: 'platform/features/my-items',
+ Notebook: 'platform/features/notebook',
Snow: 'platform/commonUI/themes/snow'
};
diff --git a/src/plugins/summaryWidget/res/conditionTemplate.html b/src/plugins/summaryWidget/res/conditionTemplate.html
index d73c4b145..51488ae28 100644
--- a/src/plugins/summaryWidget/res/conditionTemplate.html
+++ b/src/plugins/summaryWidget/res/conditionTemplate.html
@@ -1,10 +1,10 @@
-<li class="t-condition">
+<li class="has-local-controls t-condition">
<label class="t-condition-context">when</label>
<span class="controls">
<span class="t-configuration"> </span>
<span class="t-value-inputs"> </span>
</span>
- <span class="flex-elem l-condition-action-buttons-wrapper">
+ <span class="flex-elem local-control l-condition-action-buttons-wrapper">
<a class="s-icon-button icon-duplicate t-duplicate" title="Duplicate this condition"></a>
<a class="s-icon-button icon-trash t-delete" title="Delete this condition"></a>
</span>
diff --git a/src/plugins/summaryWidget/res/ruleTemplate.html b/src/plugins/summaryWidget/res/ruleTemplate.html
index e28752018..217db4c76 100644
--- a/src/plugins/summaryWidget/res/ruleTemplate.html
+++ b/src/plugins/summaryWidget/res/ruleTemplate.html
@@ -1,9 +1,9 @@
<div>
- <div class="l-widget-rule s-widget-rule l-compact-form">
+ <div class="l-compact-form has-local-controls l-widget-rule s-widget-rule">
<div class="widget-rule-header">
<span class="flex-elem l-widget-thumb-wrapper">
<span class="grippy-holder">
- <span class="t-grippy grippy"></span>
+ <span class="t-grippy grippy local-control"></span>
</span>
<span class="view-control expanded"></span>
<span class="t-widget-thumb widget-thumb">
@@ -12,7 +12,7 @@
</span>
<span class="flex-elem rule-title">Default Title</span>
<span class="flex-elem rule-description grows">Rule description goes here</span>
- <span class="flex-elem l-rule-action-buttons-wrapper">
+ <span class="flex-elem local-control l-rule-action-buttons-wrapper">
<a class="s-icon-button icon-duplicate t-duplicate" title="Duplicate this rule"></a>
<a class="s-icon-button icon-trash t-delete" title="Delete this rule"></a>
</span>
diff --git a/src/plugins/summaryWidget/res/testDataItemTemplate.html b/src/plugins/summaryWidget/res/testDataItemTemplate.html
index 2676a313f..6c455aaec 100644
--- a/src/plugins/summaryWidget/res/testDataItemTemplate.html
+++ b/src/plugins/summaryWidget/res/testDataItemTemplate.html
@@ -1,4 +1,4 @@
-<div class="t-test-data-item l-compact-form l-widget-test-data-item s-widget-test-data-item">
+<div class="t-test-data-item l-compact-form has-local-controls l-widget-test-data-item s-widget-test-data-item">
<ul>
<li>
<label>Set </label>
@@ -7,7 +7,7 @@
<span class="equal-to hidden"> equal to </span>
<span class="t-value-inputs"></span>
</span>
- <span class="flex-elem l-widget-test-data-item-action-buttons-wrapper">
+ <span class="flex-elem local-control l-widget-test-data-item-action-buttons-wrapper">
<a class="s-icon-button icon-duplicate t-duplicate" title="Duplicate this test value"></a>
<a class="s-icon-button icon-trash t-delete" title="Delete this test value"></a>
</span>
diff --git a/test-main.js b/test-main.js
index 6fcc592d5..7493ad76a 100644
--- a/test-main.js
+++ b/test-main.js
@@ -75,7 +75,9 @@ requirejs.config({
"d3-format": "node_modules/d3-format/build/d3-format.min",
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
"d3-time": "node_modules/d3-time/build/d3-time.min",
- "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min"
+ "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
+ "dom-to-image": "node_modules/dom-to-image/dist/dom-to-image.min",
+ "painterro": "node_modules/@cristian77/painterro/build/painterro.min"
},
"shim": {
@@ -109,6 +111,9 @@ requirejs.config({
},
"d3-axis": {
"exports": "d3-axis"
+ },
+ "dom-to-image": {
+ "exports": "domtoimage"
}
},