Compare commits
	
		
			2 Commits
		
	
	
		
			trac-code-
			...
			testathon-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | fe9d5fa578 | ||
|   | 52208d390f | 
| @@ -25,4 +25,4 @@ | ||||
|     "html2canvas": "^0.4.1", | ||||
|     "moment-timezone": "^0.5.13" | ||||
|   } | ||||
| } | ||||
| } | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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}, | ||||
|   | ||||
							
								
								
									
										10
									
								
								openmct.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								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" | ||||
|         } | ||||
|     } | ||||
| }); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|   "version": "0.13.3-SNAPSHOT", | ||||
|   "description": "The Open MCT core platform", | ||||
|   "dependencies": { | ||||
|     "@cristian77/painterro": "^0.2.48", | ||||
|     "d3-array": "^1.0.2", | ||||
|     "d3-axis": "^1.0.4", | ||||
|     "d3-collection": "^1.0.2", | ||||
| @@ -13,6 +14,7 @@ | ||||
|     "d3-selection": "^1.0.3", | ||||
|     "d3-time": "^1.0.4", | ||||
|     "d3-time-format": "^2.0.3", | ||||
|     "dom-to-image": "^2.6.0", | ||||
|     "express": "^4.13.1", | ||||
|     "minimist": "^1.1.1", | ||||
|     "request": "^2.69.0", | ||||
|   | ||||
| @@ -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'; | ||||
|   | ||||
| @@ -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; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|         } | ||||
|   | ||||
| @@ -38,6 +38,10 @@ define([ | ||||
| '       </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. | ||||
| @@ -74,9 +78,28 @@ define([ | ||||
|                 closeButton, | ||||
|                 doneButton, | ||||
|                 blocker, | ||||
|                 overlayContainer; | ||||
|                 overlayContainer, | ||||
|                 notebookButtonEl, | ||||
|                 notebookButton, | ||||
|                 actions = $scope.domainObject.getCapability('action'), | ||||
|                 notebookAction = actions.getActions({'key': 'notebook-new-entry'}); | ||||
|  | ||||
|             if (notebookAction) { | ||||
|                 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 openOverlay() { | ||||
|  | ||||
|                 // Remove frame classes from being applied in a non-frame context | ||||
|                 $(frame).removeClass('frame frame-template'); | ||||
|                 overlay = document.createElement('div'); | ||||
| @@ -109,7 +132,11 @@ define([ | ||||
|                 overlay = undefined; | ||||
|             } | ||||
|  | ||||
|             toggleOverlay = function () { | ||||
|             toggleOverlay = function (event) { | ||||
|                 if (event) { | ||||
|                     event.stopPropagation(); | ||||
|                 } | ||||
|  | ||||
|                 if (!isOpen) { | ||||
|                     openOverlay(); | ||||
|                     isOpen = true; | ||||
|   | ||||
| @@ -52,6 +52,12 @@ define([ | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             $scope = jasmine.createSpyObj('$scope', ['$on']); | ||||
|             $scope.domainObject = { getCapability: function () { | ||||
|                 return { getActions: function () { | ||||
|  | ||||
|                 }}; | ||||
|             }}; | ||||
|  | ||||
|             $element = jasmine.createSpyObj('$element', [ | ||||
|                 'parent', | ||||
|                 'remove', | ||||
|   | ||||
							
								
								
									
										314
									
								
								platform/features/notebook/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								platform/features/notebook/bundle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 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" | ||||
|                 } | ||||
|           ] | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										271
									
								
								platform/features/notebook/res/sass/_notebook-base.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								platform/features/notebook/res/sass/_notebook-base.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,271 @@ | ||||
| /***************************************************************************** | ||||
|  * 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 | ||||
|         i { | ||||
|             font-size: 1.25em !important; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .tool-controls .ptro-btn-color-checkers-bar, | ||||
|     .ptro-info { | ||||
|         display: none; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /********************************************* New Notebook Entry from Large View overlay */ | ||||
| .notebook-button-container { | ||||
|     //margin-right: $interiorMargin; // TODO: change to apply margin-left to view switcher button in Large View | ||||
| } | ||||
|  | ||||
| /********************************************* 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; | ||||
| } | ||||
| */ | ||||
							
								
								
									
										76
									
								
								platform/features/notebook/res/sass/_notebook-thematic.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								platform/features/notebook/res/sass/_notebook-thematic.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /***************************************************************************** | ||||
|  * 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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .overlay.snapshot { | ||||
|     // Applied in overlay when taking a snapshot | ||||
|     background: $colorBodyBg; | ||||
| } | ||||
|  | ||||
| .s-snapshot-datetime { | ||||
|     color: rgba($colorBodyFg, 0.4); | ||||
|     font-size: 0.8em; | ||||
| } | ||||
|  | ||||
| .snap-thumb { | ||||
|     border: 1px solid $colorInteriorBorder; | ||||
| } | ||||
|  | ||||
| /********************************************* PAINTERRO OVERRIDES */ | ||||
| .ptro-wrapper { | ||||
|     background: rgba($colorBodyBg, 0.3) !important; | ||||
| } | ||||
							
								
								
									
										30
									
								
								platform/features/notebook/res/sass/notebook-espresso.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								platform/features/notebook/res/sass/notebook-espresso.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -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"; | ||||
							
								
								
									
										30
									
								
								platform/features/notebook/res/sass/notebook-snow.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								platform/features/notebook/res/sass/notebook-snow.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -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"; | ||||
							
								
								
									
										28
									
								
								platform/features/notebook/res/sass/notebook.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								platform/features/notebook/res/sass/notebook.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -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"; | ||||
							
								
								
									
										2
									
								
								platform/features/notebook/res/templates/annotation.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								platform/features/notebook/res/templates/annotation.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| <div class="snap-annotation" id="snap-annotation" ng-init="ngModel.tracker()"> | ||||
| </div> | ||||
| @@ -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> | ||||
| @@ -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> | ||||
							
								
								
									
										38
									
								
								platform/features/notebook/res/templates/entry.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								platform/features/notebook/res/templates/entry.html
									
									
									
									
									
										Normal file
									
								
							| @@ -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> | ||||
| @@ -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> | ||||
							
								
								
									
										84
									
								
								platform/features/notebook/res/templates/layoutNotebook.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								platform/features/notebook/res/templates/layoutNotebook.html
									
									
									
									
									
										Normal file
									
								
							| @@ -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> | ||||
							
								
								
									
										124
									
								
								platform/features/notebook/res/templates/notebook.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								platform/features/notebook/res/templates/notebook.html
									
									
									
									
									
										Normal file
									
								
							| @@ -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> | ||||
| @@ -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> | ||||
							
								
								
									
										125
									
								
								platform/features/notebook/src/actions/AnnotateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								platform/features/notebook/src/actions/AnnotateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| /***************************************************************************** | ||||
|  * 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"], | ||||
|     function (Painterro, $) { | ||||
|  | ||||
|         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; | ||||
|  | ||||
|             this.dialogService.getUserChoice(ANNOTATION_STRUCT) | ||||
|                         .then(saveNotes); | ||||
|  | ||||
|             var painterro; | ||||
|  | ||||
|             var tracker = function () { | ||||
|                 $(document.body).find('.l-dialog .outer-holder').addClass('annotation-dialog'); | ||||
|                 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', 'scale'], | ||||
|                     toolbarPosition: 'top', | ||||
|                     // colorScheme: { | ||||
|                     //     main: '#333', | ||||
|                     //     control: '#ffcc00' | ||||
|                     // }, | ||||
|                     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); | ||||
|                 $(document.body).find('.ptro-icon-btn').addClass('s-button'); | ||||
|                 $(document.body).find('.ptro-input').addClass('s-button'); | ||||
|             }; | ||||
|  | ||||
|             ANNOTATION_STRUCT.model = {'tracker': tracker}; | ||||
|  | ||||
|  | ||||
|  | ||||
|             function saveNotes(param) { | ||||
|                 if (param === 'ok') { | ||||
|                     painterro.save(); | ||||
|                 }else { | ||||
|                     ROOTSCOPE.snapshot = "annotationCancelled"; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         return AnnotateSnapshot; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										65
									
								
								platform/features/notebook/src/actions/CreateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								platform/features/notebook/src/actions/CreateSnapshot.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										195
									
								
								platform/features/notebook/src/actions/NewEntryContextual.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								platform/features/notebook/src/actions/NewEntryContextual.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | ||||
| /***************************************************************************** | ||||
|  * 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.hasCapability("notebook") && | ||||
|                 domainObject.getCapability("notebook").isNotebook(); | ||||
|         }; | ||||
|  | ||||
|         return NewEntryContextual; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										72
									
								
								platform/features/notebook/src/actions/RemoveEmbed.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								platform/features/notebook/src/actions/RemoveEmbed.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										74
									
								
								platform/features/notebook/src/actions/RemoveSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								platform/features/notebook/src/actions/RemoveSnapshot.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										169
									
								
								platform/features/notebook/src/actions/ViewSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								platform/features/notebook/src/actions/ViewSnapshot.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| ); | ||||
| @@ -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; | ||||
|     } | ||||
| ); | ||||
| @@ -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; | ||||
|     } | ||||
| ); | ||||
|  | ||||
| @@ -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; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										400
									
								
								platform/features/notebook/src/controllers/NotebookController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								platform/features/notebook/src/controllers/NotebookController.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     }); | ||||
| @@ -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; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										138
									
								
								platform/features/notebook/src/directives/EntryDnd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								platform/features/notebook/src/directives/EntryDnd.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| /***************************************************************************** | ||||
|  * 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 SNAPSHOT_TEMPLATE = '<mct-representation key="\'draggedEntry\'"' + | ||||
|                                     'parameters="{entry:entryId,embed:embedId}"' + | ||||
|                                     'class="t-rep-frame holder"' + | ||||
|                                     'mct-object="selObj">' + | ||||
|                                 '</mct-representation>'; | ||||
|  | ||||
|     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 (entryId >= 0 && embedId >= 0) { | ||||
|                     $scope.selObj = selectedObject; | ||||
|                     $scope.entryId = entryId; | ||||
|                     $scope.embedId = embedId; | ||||
|                     $compile(SNAPSHOT_TEMPLATE)($scope); | ||||
|                 } | ||||
|  | ||||
|                 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; | ||||
|  | ||||
| }); | ||||
							
								
								
									
										166
									
								
								platform/features/notebook/src/directives/MCTModalNotebook.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								platform/features/notebook/src/directives/MCTModalNotebook.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|  | ||||
| }); | ||||
							
								
								
									
										130
									
								
								platform/features/notebook/src/directives/MCTSnapshot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								platform/features/notebook/src/directives/MCTSnapshot.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| /***************************************************************************** | ||||
|  * 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 element = $element[0]; | ||||
|             var layoutContainer = element.parentElement, | ||||
|                 toggleOverlay, | ||||
|                 makeImg, | ||||
|                 saveImg, | ||||
|                 snapshot = document.createElement('div'); | ||||
|  | ||||
|             function openOverlay() { | ||||
|                 // Remove frame classes from being applied in a non-frame context | ||||
|                 $(snapshot).addClass('abs overlay l-large-view snapshot'); | ||||
|                 snapshot.appendChild(element); | ||||
|                 document.body.appendChild(snapshot); | ||||
|             } | ||||
|  | ||||
|             function closeOverlay() { | ||||
|                 if (snapshot) { | ||||
|                     snapshot.removeChild(element); | ||||
|                     layoutContainer.remove(); | ||||
|                 } | ||||
|                 document.body.removeChild(snapshot); | ||||
|                 snapshot = undefined; | ||||
|                 $element.remove(); | ||||
|             } | ||||
|  | ||||
|             toggleOverlay = function () { | ||||
|                 openOverlay(); | ||||
|                 makeImg(element); | ||||
|             }; | ||||
|  | ||||
|             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) { | ||||
|  | ||||
|                         if (img) { | ||||
|                             if (dialog) { | ||||
|                                 dialog.dismiss(); | ||||
|                             } | ||||
|                             if ($element[0].dataset.entry && $element[0].dataset.embed) { | ||||
|                                 saveImg(img, +$element[0].dataset.entry, +$element[0].dataset.embed); | ||||
|                                 closeOverlay(); | ||||
|                             } 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() | ||||
|                                                               }; | ||||
|                                         closeOverlay(false); | ||||
|                                         scope.$destroy(); | ||||
|                                     }; | ||||
|  | ||||
|                             } | ||||
|  | ||||
|                         } else { | ||||
|                             dialog.dismiss(); | ||||
|                         } | ||||
|  | ||||
|                     }, function (error) { | ||||
|                         if (dialog) { | ||||
|                             dialog.dismiss(); | ||||
|                         } | ||||
|                         closeOverlay(); | ||||
|                     }); | ||||
|                 }, 500); | ||||
|             }; | ||||
|  | ||||
|             saveImg = function (url,entryId,embedId) { | ||||
|                 $scope.$parent.$parent.$parent.saveSnap(url, embedId, entryId); | ||||
|             }; | ||||
|  | ||||
|             if ($(document.body).find('.overlay.snapshot').length === 0) { | ||||
|                 toggleOverlay(); | ||||
|             } | ||||
|  | ||||
|             $scope.$on('$destroy', function () { | ||||
|                 $element.off('click', toggleOverlay); | ||||
|                 $element.remove(); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         return { | ||||
|             restrict: 'A', | ||||
|             link: link | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     return MCTSnapshot; | ||||
|  | ||||
| }); | ||||
							
								
								
									
										44
									
								
								platform/features/notebook/src/policies/CompositionPolicy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								platform/features/notebook/src/policies/CompositionPolicy.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										40
									
								
								platform/features/notebook/src/policies/ViewPolicy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								platform/features/notebook/src/policies/ViewPolicy.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| ); | ||||
|  | ||||
| @@ -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"> | ||||
|   | ||||
| @@ -141,6 +141,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. | ||||
|   | ||||
| @@ -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' | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,14 @@ | ||||
| define(['./src/SummaryWidget', './SummaryWidgetsCompositionPolicy'], function (SummaryWidget, SummaryWidgetsCompositionPolicy) { | ||||
| define([ | ||||
|     './SummaryWidgetsCompositionPolicy', | ||||
|     './src/telemetry/SummaryWidgetMetadataProvider', | ||||
|     './src/telemetry/SummaryWidgetTelemetryProvider', | ||||
|     './src/views/SummaryWidgetViewProvider' | ||||
| ], function ( | ||||
|     SummaryWidgetsCompositionPolicy, | ||||
|     SummaryWidgetMetadataProvider, | ||||
|     SummaryWidgetTelemetryProvider, | ||||
|     SummaryWidgetViewProvider | ||||
| ) { | ||||
|  | ||||
|     function plugin() { | ||||
|  | ||||
| @@ -9,8 +19,40 @@ define(['./src/SummaryWidget', './SummaryWidgetsCompositionPolicy'], function (S | ||||
|             cssClass: 'icon-summary-widget', | ||||
|             initialize: function (domainObject) { | ||||
|                 domainObject.composition = []; | ||||
|                 domainObject.configuration = {}; | ||||
|                 domainObject.configuration = { | ||||
|                     ruleOrder: ['default'], | ||||
|                     ruleConfigById: { | ||||
|                         default: { | ||||
|                             name: 'Default', | ||||
|                             label: 'Unnamed Rule', | ||||
|                             message: '', | ||||
|                             id: 'default', | ||||
|                             icon: ' ', | ||||
|                             style: { | ||||
|                                 'color': '#ffffff', | ||||
|                                 'background-color': '#38761d', | ||||
|                                 'border-color': 'rgba(0,0,0,0)' | ||||
|                             }, | ||||
|                             description: 'Default appearance for the widget', | ||||
|                             conditions: [{ | ||||
|                                 object: '', | ||||
|                                 key: '', | ||||
|                                 operation: '', | ||||
|                                 values: [] | ||||
|                             }], | ||||
|                             jsCondition: '', | ||||
|                             trigger: 'any', | ||||
|                             expanded: 'true' | ||||
|                         } | ||||
|                     }, | ||||
|                     testDataConfig: [{ | ||||
|                         object: '', | ||||
|                         key: '', | ||||
|                         value: '' | ||||
|                     }] | ||||
|                 }; | ||||
|                 domainObject.openNewTab = 'thisTab'; | ||||
|                 domainObject.telemetry = {}; | ||||
|             }, | ||||
|             form: [ | ||||
|                 { | ||||
| @@ -40,26 +82,14 @@ define(['./src/SummaryWidget', './SummaryWidgetsCompositionPolicy'], function (S | ||||
|             ] | ||||
|         }; | ||||
|  | ||||
|         function initViewProvider(openmct) { | ||||
|             return { | ||||
|                 name: 'Widget View', | ||||
|                 view: function (domainObject) { | ||||
|                     return new SummaryWidget(domainObject, openmct); | ||||
|                 }, | ||||
|                 canView: function (domainObject) { | ||||
|                     return (domainObject.type === 'summary-widget'); | ||||
|                 }, | ||||
|                 editable: true, | ||||
|                 key: 'summaryWidgets' | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         return function install(openmct) { | ||||
|             openmct.types.addType('summary-widget', widgetType); | ||||
|             openmct.objectViews.addProvider(initViewProvider(openmct)); | ||||
|             openmct.legacyExtension('policies', {category: 'composition', | ||||
|                 implementation: SummaryWidgetsCompositionPolicy, depends: ['openmct'] | ||||
|             }); | ||||
|             openmct.telemetry.addProvider(new SummaryWidgetMetadataProvider(openmct)); | ||||
|             openmct.telemetry.addProvider(new SummaryWidgetTelemetryProvider(openmct)); | ||||
|             openmct.objectViews.addProvider(new SummaryWidgetViewProvider(openmct)); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| define ([ | ||||
|     './ConditionEvaluator', | ||||
|     '../../../api/objects/object-utils', | ||||
|     'EventEmitter', | ||||
|     'zepto', | ||||
|     'lodash' | ||||
| ], function ( | ||||
|     ConditionEvaluator, | ||||
|     objectUtils, | ||||
|     EventEmitter, | ||||
|     $, | ||||
|     _ | ||||
| @@ -123,21 +125,23 @@ define ([ | ||||
|      *                   has completed and types have been parsed | ||||
|      */ | ||||
|     ConditionManager.prototype.parsePropertyTypes = function (object) { | ||||
|         var telemetryAPI = this.openmct.telemetry, | ||||
|             key, | ||||
|             type, | ||||
|             self = this; | ||||
|         var objectId = objectUtils.makeKeyString(object.identifier); | ||||
|  | ||||
|         self.telemetryTypesById[object.identifier.key] = {}; | ||||
|         return telemetryAPI.request(object, {size: 1, strategy: 'latest'}).then(function (telemetry) { | ||||
|             Object.entries(telemetry[telemetry.length - 1]).forEach(function (telem) { | ||||
|                 key = telem[0]; | ||||
|                 type = typeof telem[1]; | ||||
|                 self.telemetryTypesById[object.identifier.key][key] = type; | ||||
|                 self.subscriptionCache[object.identifier.key][key] = telem[1]; | ||||
|                 self.addGlobalPropertyType(key, type); | ||||
|             }); | ||||
|         }); | ||||
|         this.telemetryTypesById[objectId] = {}; | ||||
|         Object.values(this.telemetryMetadataById[objectId]).forEach(function (valueMetadata) { | ||||
|             var type; | ||||
|             if (valueMetadata.hints.hasOwnProperty('range')) { | ||||
|                 type = 'number'; | ||||
|             } else if (valueMetadata.hints.hasOwnProperty('domain')) { | ||||
|                 type = 'number'; | ||||
|             } else if (valueMetadata.key === 'name') { | ||||
|                 type = 'string'; | ||||
|             } else { | ||||
|                 type = 'string'; | ||||
|             } | ||||
|             this.telemetryTypesById[objectId][valueMetadata.key] = type; | ||||
|             this.addGlobalPropertyType(valueMetadata.key, type); | ||||
|         }, this); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
| @@ -147,23 +151,9 @@ define ([ | ||||
|      *                   and property types parsed | ||||
|      */ | ||||
|     ConditionManager.prototype.parseAllPropertyTypes = function () { | ||||
|         var self = this, | ||||
|             index = 0, | ||||
|             objs = Object.values(self.compositionObjs), | ||||
|             promise = new Promise(function (resolve, reject) { | ||||
|                 if (objs.length === 0) { | ||||
|                     resolve(); | ||||
|                 } | ||||
|                 objs.forEach(function (obj) { | ||||
|                     self.parsePropertyTypes(obj).then(function () { | ||||
|                         if (index === objs.length - 1) { | ||||
|                             resolve(); | ||||
|                         } | ||||
|                         index += 1; | ||||
|                     }); | ||||
|                 }); | ||||
|             }); | ||||
|         return promise; | ||||
|         Object.values(this.compositionObjs).forEach(this.parsePropertyTypes, this); | ||||
|         this.metadataLoadComplete = true; | ||||
|         this.eventEmitter.emit('metadata'); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
| @@ -187,7 +177,7 @@ define ([ | ||||
|     ConditionManager.prototype.onCompositionAdd = function (obj) { | ||||
|         var compositionKeys, | ||||
|             telemetryAPI = this.openmct.telemetry, | ||||
|             objId = obj.identifier.key, | ||||
|             objId = objectUtils.makeKeyString(obj.identifier), | ||||
|             telemetryMetadata, | ||||
|             self = this; | ||||
|  | ||||
| @@ -195,10 +185,9 @@ define ([ | ||||
|             self.compositionObjs[objId] = obj; | ||||
|             self.telemetryMetadataById[objId] = {}; | ||||
|  | ||||
|             compositionKeys = self.domainObject.composition.map(function (object) { | ||||
|                 return object.key; | ||||
|             }); | ||||
|             if (!compositionKeys.includes(obj.identifier.key)) { | ||||
|             // FIXME: this should just update based on listener. | ||||
|             compositionKeys = self.domainObject.composition.map(objectUtils.makeKeyString); | ||||
|             if (!compositionKeys.includes(objId)) { | ||||
|                 self.domainObject.composition.push(obj.identifier); | ||||
|             } | ||||
|  | ||||
| @@ -212,6 +201,12 @@ define ([ | ||||
|             self.subscriptions[objId] = telemetryAPI.subscribe(obj, function (datum) { | ||||
|                 self.handleSubscriptionCallback(objId, datum); | ||||
|             }, {}); | ||||
|             telemetryAPI.request(obj, {strategy: 'latest', size: 1}) | ||||
|                 .then(function (results) { | ||||
|                     if (results && results.length) { | ||||
|                         self.handleSubscriptionCallback(objId, results[results.length - 1]); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|             /** | ||||
|              * if this is the initial load, parsing property types will be postponed | ||||
| @@ -234,11 +229,14 @@ define ([ | ||||
|      * @private | ||||
|      */ | ||||
|     ConditionManager.prototype.onCompositionRemove = function (identifier) { | ||||
|         var objectId = objectUtils.makeKeyString(identifier); | ||||
|         // FIXME: this should just update by listener. | ||||
|         _.remove(this.domainObject.composition, function (id) { | ||||
|             return id.key === identifier.key; | ||||
|             return id.key === identifier.key && | ||||
|                 id.namespace === identifier.namespace; | ||||
|         }); | ||||
|         delete this.compositionObjs[identifier.key]; | ||||
|         this.subscriptions[identifier.key](); //unsubscribe from telemetry source | ||||
|         delete this.compositionObjs[objectId]; | ||||
|         this.subscriptions[objectId](); //unsubscribe from telemetry source | ||||
|         this.eventEmitter.emit('remove', identifier); | ||||
|  | ||||
|         if (_.isEmpty(this.compositionObjs)) { | ||||
| @@ -253,13 +251,9 @@ define ([ | ||||
|      * @private | ||||
|      */ | ||||
|     ConditionManager.prototype.onCompositionLoad = function () { | ||||
|         var self = this; | ||||
|         self.loadComplete = true; | ||||
|         self.eventEmitter.emit('load'); | ||||
|         self.parseAllPropertyTypes().then(function () { | ||||
|             self.metadataLoadComplete = true; | ||||
|             self.eventEmitter.emit('metadata'); | ||||
|         }); | ||||
|         this.loadComplete = true; | ||||
|         this.eventEmitter.emit('load'); | ||||
|         this.parseAllPropertyTypes(); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -1,4 +1,10 @@ | ||||
| define(['./Select'], function (Select) { | ||||
| define([ | ||||
|     './Select', | ||||
|     '../../../../api/objects/object-utils' | ||||
| ], function ( | ||||
|     Select, | ||||
|     objectUtils | ||||
| ) { | ||||
|  | ||||
|     /** | ||||
|      * Create a {Select} element whose composition is dynamically updated with | ||||
| @@ -37,7 +43,7 @@ define(['./Select'], function (Select) { | ||||
|          * @private | ||||
|          */ | ||||
|         function onCompositionAdd(obj) { | ||||
|             self.select.addOption(obj.identifier.key, obj.name); | ||||
|             self.select.addOption(objectUtils.makeKeyString(obj.identifier), obj.name); | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @@ -75,7 +81,7 @@ define(['./Select'], function (Select) { | ||||
|      */ | ||||
|     ObjectSelect.prototype.generateOptions = function () { | ||||
|         var items = Object.values(this.compositionObjs).map(function (obj) { | ||||
|             return [obj.identifier.key, obj.name]; | ||||
|             return [objectUtils.makeKeyString(obj.identifier), obj.name]; | ||||
|         }); | ||||
|         this.baseOptions.forEach(function (option, index) { | ||||
|             items.splice(index, 0, option); | ||||
|   | ||||
							
								
								
									
										64
									
								
								src/plugins/summaryWidget/src/telemetry/EvaluatorPool.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/plugins/summaryWidget/src/telemetry/EvaluatorPool.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './SummaryWidgetEvaluator', | ||||
|     '../../../../api/objects/object-utils' | ||||
| ], function ( | ||||
|     SummaryWidgetEvaluator, | ||||
|     objectUtils | ||||
| ) { | ||||
|  | ||||
|     function EvaluatorPool(openmct) { | ||||
|         this.openmct = openmct; | ||||
|         this.byObjectId = {}; | ||||
|         this.byEvaluator = new WeakMap(); | ||||
|     } | ||||
|  | ||||
|     EvaluatorPool.prototype.get = function (domainObject) { | ||||
|         var objectId = objectUtils.makeKeyString(domainObject.identifier); | ||||
|         var poolEntry = this.byObjectId[objectId]; | ||||
|         if (!poolEntry) { | ||||
|             poolEntry = { | ||||
|                 leases: 0, | ||||
|                 objectId: objectId, | ||||
|                 evaluator: new SummaryWidgetEvaluator(domainObject, this.openmct) | ||||
|             }; | ||||
|             this.byEvaluator.set(poolEntry.evaluator, poolEntry); | ||||
|             this.byObjectId[objectId] = poolEntry; | ||||
|         } | ||||
|         poolEntry.leases += 1; | ||||
|         return poolEntry.evaluator; | ||||
|     }; | ||||
|  | ||||
|     EvaluatorPool.prototype.release = function (evaluator) { | ||||
|         var poolEntry = this.byEvaluator.get(evaluator); | ||||
|         poolEntry.leases -= 1; | ||||
|         if (poolEntry.leases === 0) { | ||||
|             evaluator.destroy(); | ||||
|             this.byEvaluator.delete(evaluator); | ||||
|             delete this.byObjectId[poolEntry.objectId]; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     return EvaluatorPool; | ||||
| }); | ||||
							
								
								
									
										102
									
								
								src/plugins/summaryWidget/src/telemetry/EvaluatorPoolSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/plugins/summaryWidget/src/telemetry/EvaluatorPoolSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './EvaluatorPool', | ||||
|     './SummaryWidgetEvaluator' | ||||
| ], function ( | ||||
|     EvaluatorPool, | ||||
|     SummaryWidgetEvaluator | ||||
| ) { | ||||
|     describe('EvaluatorPool', function () { | ||||
|         var pool; | ||||
|         var openmct; | ||||
|         var objectA; | ||||
|         var objectB; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             openmct = { | ||||
|                 composition: jasmine.createSpyObj('compositionAPI', ['get']), | ||||
|                 objects: jasmine.createSpyObj('objectAPI', ['observe']) | ||||
|             }; | ||||
|             openmct.composition.get.andCallFake(function () { | ||||
|                 var compositionCollection = jasmine.createSpyObj( | ||||
|                     'compositionCollection', | ||||
|                     [ | ||||
|                         'load', | ||||
|                         'on', | ||||
|                         'off' | ||||
|                     ] | ||||
|                 ); | ||||
|                 compositionCollection.load.andReturn(Promise.resolve()); | ||||
|                 return compositionCollection; | ||||
|             }); | ||||
|             openmct.objects.observe.andCallFake(function () { | ||||
|                 return function () {}; | ||||
|             }); | ||||
|             pool = new EvaluatorPool(openmct); | ||||
|             objectA = { | ||||
|                 identifier: { | ||||
|                     namespace: 'someNamespace', | ||||
|                     key: 'someKey' | ||||
|                 }, | ||||
|                 configuration: { | ||||
|                     ruleOrder: [] | ||||
|                 } | ||||
|             }; | ||||
|             objectB = { | ||||
|                 identifier: { | ||||
|                     namespace: 'otherNamespace', | ||||
|                     key: 'otherKey' | ||||
|                 }, | ||||
|                 configuration: { | ||||
|                     ruleOrder: [] | ||||
|                 } | ||||
|             }; | ||||
|         }); | ||||
|  | ||||
|         it('returns new evaluators for different objects', function () { | ||||
|             var evaluatorA = pool.get(objectA); | ||||
|             var evaluatorB = pool.get(objectB); | ||||
|             expect(evaluatorA).not.toBe(evaluatorB); | ||||
|         }); | ||||
|  | ||||
|         it('returns the same evaluator for the same object', function () { | ||||
|             var evaluatorA = pool.get(objectA); | ||||
|             var evaluatorB = pool.get(objectA); | ||||
|             expect(evaluatorA).toBe(evaluatorB); | ||||
|  | ||||
|             var evaluatorC = pool.get(JSON.parse(JSON.stringify(objectA))); | ||||
|             expect(evaluatorA).toBe(evaluatorC); | ||||
|         }); | ||||
|  | ||||
|         it('returns new evaluator when old is released', function () { | ||||
|             var evaluatorA = pool.get(objectA); | ||||
|             var evaluatorB = pool.get(objectA); | ||||
|             expect(evaluatorA).toBe(evaluatorB); | ||||
|             pool.release(evaluatorA); | ||||
|             pool.release(evaluatorB); | ||||
|             var evaluatorC = pool.get(objectA); | ||||
|             expect(evaluatorA).not.toBe(evaluatorC); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -0,0 +1,80 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './operations' | ||||
| ], function ( | ||||
|     OPERATIONS | ||||
| ) { | ||||
|  | ||||
|     function SummaryWidgetCondition(definition) { | ||||
|         this.object = definition.object; | ||||
|         this.key = definition.key; | ||||
|         this.values = definition.values; | ||||
|         if (!definition.operation) { | ||||
|             // TODO: better handling for default rule. | ||||
|             this.evaluate = function () { | ||||
|                 return true; | ||||
|             }; | ||||
|         } else { | ||||
|             this.comparator = OPERATIONS[definition.operation].operation; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     SummaryWidgetCondition.prototype.evaluate = function (telemetryState) { | ||||
|         var stateKeys = Object.keys(telemetryState); | ||||
|         var state; | ||||
|         var result; | ||||
|         var i; | ||||
|  | ||||
|         if (this.object === 'any') { | ||||
|             for (i = 0; i < stateKeys.length; i++) { | ||||
|                 state = telemetryState[stateKeys[i]]; | ||||
|                 result = this.evaluateState(state); | ||||
|                 if (result) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } else if (this.object === 'all') { | ||||
|             for (i = 0; i < stateKeys.length; i++) { | ||||
|                 state = telemetryState[stateKeys[i]]; | ||||
|                 result = this.evaluateState(state); | ||||
|                 if (!result) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } else { | ||||
|             return this.evaluateState(telemetryState[this.object]); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetCondition.prototype.evaluateState = function (state) { | ||||
|         var testValues = [ | ||||
|             state.formats[this.key].parse(state.lastDatum) | ||||
|         ].concat(this.values); | ||||
|         return this.comparator(testValues); | ||||
|     }; | ||||
|  | ||||
|     return SummaryWidgetCondition; | ||||
| }); | ||||
| @@ -0,0 +1,142 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './SummaryWidgetCondition' | ||||
| ], function ( | ||||
|     SummaryWidgetCondition | ||||
| ) { | ||||
|  | ||||
|     describe('SummaryWidgetCondition', function () { | ||||
|         var condition; | ||||
|         var telemetryState; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             // Format map intentionally uses different keys than those present | ||||
|             // in datum, which serves to verify conditions use format map to get | ||||
|             // data. | ||||
|             var formatMap = { | ||||
|                 adjusted: { | ||||
|                     parse: function (datum) { | ||||
|                         return datum.value + 10; | ||||
|                     } | ||||
|                 }, | ||||
|                 raw: { | ||||
|                     parse: function (datum) { | ||||
|                         return datum.value; | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             telemetryState = { | ||||
|                 objectId: { | ||||
|                     formats: formatMap, | ||||
|                     lastDatum: { | ||||
|                     } | ||||
|                 }, | ||||
|                 otherObjectId: { | ||||
|                     formats: formatMap, | ||||
|                     lastDatum: { | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|         }); | ||||
|  | ||||
|         it('can evaluate if a single object matches', function () { | ||||
|             condition = new SummaryWidgetCondition({ | ||||
|                 object: 'objectId', | ||||
|                 key: 'raw', | ||||
|                 operation: 'greaterThan', | ||||
|                 values: [ | ||||
|                     10 | ||||
|                 ] | ||||
|             }); | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(true); | ||||
|         }); | ||||
|  | ||||
|         it('can evaluate if a single object matches (alternate keys)', function () { | ||||
|             condition = new SummaryWidgetCondition({ | ||||
|                 object: 'objectId', | ||||
|                 key: 'adjusted', | ||||
|                 operation: 'greaterThan', | ||||
|                 values: [ | ||||
|                     10 | ||||
|                 ] | ||||
|             }); | ||||
|             telemetryState.objectId.lastDatum.value = -5; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(true); | ||||
|         }); | ||||
|  | ||||
|         it('can evaluate "if all objects match"', function () { | ||||
|             condition = new SummaryWidgetCondition({ | ||||
|                 object: 'all', | ||||
|                 key: 'raw', | ||||
|                 operation: 'greaterThan', | ||||
|                 values: [ | ||||
|                     10 | ||||
|                 ] | ||||
|             }); | ||||
|             telemetryState.objectId.lastDatum.value = 0; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 0; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 0; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 15; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 0; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 15; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(true); | ||||
|         }); | ||||
|  | ||||
|         it('can evalute "if any object matches"', function () { | ||||
|             condition = new SummaryWidgetCondition({ | ||||
|                 object: 'any', | ||||
|                 key: 'raw', | ||||
|                 operation: 'greaterThan', | ||||
|                 values: [ | ||||
|                     10 | ||||
|                 ] | ||||
|             }); | ||||
|             telemetryState.objectId.lastDatum.value = 0; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 0; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 0; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 15; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(true); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 0; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(true); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 15; | ||||
|             expect(condition.evaluate(telemetryState)).toBe(true); | ||||
|         }); | ||||
|  | ||||
|     }); | ||||
| }); | ||||
| @@ -0,0 +1,264 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './SummaryWidgetRule', | ||||
|     '../eventHelpers', | ||||
|     '../../../../api/objects/object-utils', | ||||
|     'lodash' | ||||
| ], function ( | ||||
|     SummaryWidgetRule, | ||||
|     eventHelpers, | ||||
|     objectUtils, | ||||
|     _ | ||||
| ) { | ||||
|  | ||||
|     /** | ||||
|      * evaluates rules defined in a summary widget against either lad or | ||||
|      * realtime state. | ||||
|      * | ||||
|      */ | ||||
|     function SummaryWidgetEvaluator(domainObject, openmct) { | ||||
|         this.openmct = openmct; | ||||
|         this.baseState = {}; | ||||
|  | ||||
|         this.updateRules(domainObject); | ||||
|         this.removeObserver = openmct.objects.observe( | ||||
|             domainObject, | ||||
|             '*', | ||||
|             this.updateRules.bind(this) | ||||
|         ); | ||||
|  | ||||
|         var composition = openmct.composition.get(domainObject); | ||||
|  | ||||
|         this.listenTo(composition, 'add', this.addChild, this); | ||||
|         this.listenTo(composition, 'remove', this.removeChild, this); | ||||
|  | ||||
|         this.loadPromise = composition.load(); | ||||
|     } | ||||
|  | ||||
|     eventHelpers.extend(SummaryWidgetEvaluator.prototype); | ||||
|  | ||||
|     /** | ||||
|      * Subscribes to realtime telemetry for the given summary widget. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.subscribe = function (callback) { | ||||
|         var active = true; | ||||
|         var unsubscribes = []; | ||||
|  | ||||
|         this.getBaseStateClone() | ||||
|             .then(function (realtimeStates) { | ||||
|                 if (!active) { | ||||
|                     return; | ||||
|                 } | ||||
|                 var updateCallback = function () { | ||||
|                     var datum = this.evaluateState( | ||||
|                         realtimeStates, | ||||
|                         this.openmct.time.timeSystem().key | ||||
|                     ); | ||||
|                     callback(datum); | ||||
|                 }.bind(this); | ||||
|  | ||||
|                 unsubscribes = _.map( | ||||
|                     realtimeStates, | ||||
|                     this.subscribeToObjectState.bind(this, updateCallback) | ||||
|                 ); | ||||
|             }.bind(this)); | ||||
|  | ||||
|         return function () { | ||||
|             active = false; | ||||
|             unsubscribes.forEach(function (unsubscribe) { | ||||
|                 unsubscribe(); | ||||
|             }); | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Returns a promise for a telemetry datum obtained by evaluating the | ||||
|      * current lad data. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.requestLatest = function (options) { | ||||
|         return this.getBaseStateClone() | ||||
|             .then(function (ladState) { | ||||
|                 var promises = Object.values(ladState) | ||||
|                     .map(this.updateObjectStateFromLAD.bind(this, options)); | ||||
|  | ||||
|                 return Promise.all(promises) | ||||
|                     .then(function () { | ||||
|                         return ladState; | ||||
|                     }); | ||||
|             }.bind(this)) | ||||
|             .then(function (ladStates) { | ||||
|                 return this.evaluateState(ladStates, options.domain); | ||||
|             }.bind(this)); | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetEvaluator.prototype.updateRules = function (domainObject) { | ||||
|         this.rules = domainObject.configuration.ruleOrder.map(function (ruleId) { | ||||
|             return new SummaryWidgetRule(domainObject.configuration.ruleConfigById[ruleId]); | ||||
|         }); | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetEvaluator.prototype.addChild = function (childObject) { | ||||
|         var childId = objectUtils.makeKeyString(childObject.identifier); | ||||
|         var metadata = this.openmct.telemetry.getMetadata(childObject); | ||||
|         var formats = this.openmct.telemetry.getFormatMap(metadata); | ||||
|  | ||||
|         this.baseState[childId] = { | ||||
|             id: childId, | ||||
|             domainObject: childObject, | ||||
|             metadata: metadata, | ||||
|             formats: formats | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetEvaluator.prototype.removeChild = function (childObject) { | ||||
|         var childId = objectUtils.makeKeyString(childObject.identifier); | ||||
|         delete this.baseState[childId]; | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetEvaluator.prototype.load = function () { | ||||
|         return this.loadPromise; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * return a promise for a clone of the base state object. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.getBaseStateClone = function () { | ||||
|         return this.load() | ||||
|             .then(function () { | ||||
|                 return _(this.baseState) | ||||
|                     .values() | ||||
|                     .map(_.clone) | ||||
|                     .indexBy('id') | ||||
|                     .value(); | ||||
|             }.bind(this)); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Subscribes to realtime updates for a given objectState, and invokes | ||||
|      * the supplied callback when objectState has been updated.  Returns | ||||
|      * a function to unsubscribe. | ||||
|      * @private. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.subscribeToObjectState = function (callback, objectState) { | ||||
|         return this.openmct.telemetry.subscribe( | ||||
|             objectState.domainObject, | ||||
|             function (datum) { | ||||
|                 objectState.lastDatum = datum; | ||||
|                 objectState.timestamps = this.getTimestamps(objectState.id, datum); | ||||
|                 callback(); | ||||
|             }.bind(this) | ||||
|         ); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Given an object state, will return a promise that is resolved when the | ||||
|      * object state has been updated from the LAD. | ||||
|      * @private. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.updateObjectStateFromLAD = function (options, objectState) { | ||||
|         options = _.extend({}, options, { | ||||
|             strategy: 'latest', | ||||
|             size: 1 | ||||
|         }); | ||||
|         return this.openmct | ||||
|             .telemetry | ||||
|             .request( | ||||
|                 objectState.domainObject, | ||||
|                 options | ||||
|             ) | ||||
|             .then(function (results) { | ||||
|                 objectState.lastDatum = results[results.length - 1]; | ||||
|                 objectState.timestamps = this.getTimestamps( | ||||
|                     objectState.id, | ||||
|                     objectState.lastDatum | ||||
|                 ); | ||||
|             }.bind(this)); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Returns an object containing all domain values in a datum. | ||||
|      * @private. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.getTimestamps = function (childId, datum) { | ||||
|         var timestampedDatum = {}; | ||||
|         this.openmct.time.getAllTimeSystems().forEach(function (timeSystem) { | ||||
|             timestampedDatum[timeSystem.key] = | ||||
|                 this.baseState[childId].formats[timeSystem.key].parse(datum); | ||||
|         }, this); | ||||
|         return timestampedDatum; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Given a base datum(containing timestamps) and rule index, adds values | ||||
|      * from the matching rule. | ||||
|      * @private | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.makeDatumFromRule = function (ruleIndex, baseDatum) { | ||||
|         var rule = this.rules[ruleIndex]; | ||||
|  | ||||
|         baseDatum.ruleLabel = rule.label; | ||||
|         baseDatum.ruleName = rule.name; | ||||
|         baseDatum.message = rule.message; | ||||
|         baseDatum.ruleIndex = ruleIndex; | ||||
|         baseDatum.backgroundColor = rule.style['background-color']; | ||||
|         baseDatum.textColor = rule.style.color; | ||||
|         baseDatum.borderColor = rule.style['border-color']; | ||||
|         baseDatum.icon = rule.icon; | ||||
|  | ||||
|         return baseDatum; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * evaluate a state object and return a summary widget telemetry datum. | ||||
|      * Will use the specified timestampKey to decide which timestamps to apply. | ||||
|      * @private. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.evaluateState = function (state, timestampKey) { | ||||
|         var latestTimestamp = _(state) | ||||
|             .map('timestamps') | ||||
|             .sortBy(timestampKey) | ||||
|             .first(); | ||||
|  | ||||
|         latestTimestamp = _.clone(latestTimestamp); | ||||
|  | ||||
|         for (var i = this.rules.length - 1; i > 0; i--) { | ||||
|             if (this.rules[i].evaluate(state, false)) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return this.makeDatumFromRule(i, latestTimestamp); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * remove all listeners and clean up any resources. | ||||
|      */ | ||||
|     SummaryWidgetEvaluator.prototype.destroy = function () { | ||||
|         this.stopListening(); | ||||
|         this.removeObserver(); | ||||
|     }; | ||||
|  | ||||
|     return SummaryWidgetEvaluator; | ||||
|  | ||||
| }); | ||||
| @@ -0,0 +1,119 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|  | ||||
| ], function ( | ||||
|  | ||||
| ) { | ||||
|  | ||||
|     function SummaryWidgetMetadataProvider(openmct) { | ||||
|         this.openmct = openmct; | ||||
|     } | ||||
|  | ||||
|     SummaryWidgetMetadataProvider.prototype.supportsMetadata = function (domainObject) { | ||||
|         return domainObject.type === 'summary-widget'; | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetMetadataProvider.prototype.getDomains = function (domainObject) { | ||||
|         return this.openmct.time.getAllTimeSystems().map(function (ts, i) { | ||||
|             return { | ||||
|                 key: ts.key, | ||||
|                 name: 'UTC', | ||||
|                 format: ts.timeFormat, | ||||
|                 hints: { | ||||
|                     domain: i | ||||
|                 } | ||||
|             }; | ||||
|         }); | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetMetadataProvider.prototype.getMetadata = function (domainObject) { | ||||
|         var ruleOrder = domainObject.configuration.ruleOrder || []; | ||||
|         var enumerations = ruleOrder | ||||
|             .filter(function (ruleId) { | ||||
|                 return !!domainObject.configuration.ruleConfigById[ruleId]; | ||||
|             }) | ||||
|             .map(function (ruleId, ruleIndex) { | ||||
|                 return { | ||||
|                     string: domainObject.configuration.ruleConfigById[ruleId].label, | ||||
|                     value: ruleIndex | ||||
|                 }; | ||||
|             }); | ||||
|  | ||||
|         var metadata = { | ||||
|             // Generally safe assumption is that we have one domain per timeSystem. | ||||
|             values: this.getDomains().concat([ | ||||
|                 { | ||||
|                     name: 'state', | ||||
|                     key: 'state', | ||||
|                     source: 'ruleIndex', | ||||
|                     format: 'enum', | ||||
|                     enumerations: enumerations, | ||||
|                     hints: { | ||||
|                         range: 1 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'Rule Label', | ||||
|                     key: 'ruleLabel', | ||||
|                     format: 'string' | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'Rule Name', | ||||
|                     key: 'ruleName', | ||||
|                     format: 'string' | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'Message', | ||||
|                     key: 'message', | ||||
|                     format: 'string' | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'Background Color', | ||||
|                     key: 'backgroundColor', | ||||
|                     format: 'string' | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'Text Color', | ||||
|                     key: 'textColor', | ||||
|                     format: 'string' | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'Border Color', | ||||
|                     key: 'borderColor', | ||||
|                     format: 'string' | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'Display Icon', | ||||
|                     key: 'icon', | ||||
|                     format: 'string' | ||||
|                 } | ||||
|             ]) | ||||
|         }; | ||||
|  | ||||
|         return metadata; | ||||
|     }; | ||||
|  | ||||
|     return SummaryWidgetMetadataProvider; | ||||
|  | ||||
| }); | ||||
							
								
								
									
										73
									
								
								src/plugins/summaryWidget/src/telemetry/SummaryWidgetRule.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/plugins/summaryWidget/src/telemetry/SummaryWidgetRule.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './SummaryWidgetCondition' | ||||
| ], function ( | ||||
|     SummaryWidgetCondition | ||||
| ) { | ||||
|     function SummaryWidgetRule(definition) { | ||||
|         this.name = definition.name; | ||||
|         this.label = definition.label; | ||||
|         this.id = definition.id; | ||||
|         this.icon = definition.icon; | ||||
|         this.style = definition.style; | ||||
|         this.message = definition.message; | ||||
|         this.description = definition.description; | ||||
|         this.conditions = definition.conditions.map(function (cDefinition) { | ||||
|             return new SummaryWidgetCondition(cDefinition); | ||||
|         }); | ||||
|         this.trigger = definition.trigger; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Evaluate the given rule against a telemetryState and return true if it | ||||
|      * matches. | ||||
|      */ | ||||
|     SummaryWidgetRule.prototype.evaluate = function (telemetryState) { | ||||
|         var i; | ||||
|         var result; | ||||
|  | ||||
|         if (this.trigger === 'all') { | ||||
|             for (i = 0; i < this.conditions.length; i++) { | ||||
|                 result = this.conditions[i].evaluate(telemetryState); | ||||
|                 if (!result) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } else if (this.trigger === 'any') { | ||||
|             for (i = 0; i < this.conditions.length; i++) { | ||||
|                 result = this.conditions[i].evaluate(telemetryState); | ||||
|                 if (result) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } else { | ||||
|             throw new Error('Invalid rule trigger: ' + this.trigger); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     return SummaryWidgetRule; | ||||
| }); | ||||
|  | ||||
							
								
								
									
										163
									
								
								src/plugins/summaryWidget/src/telemetry/SummaryWidgetRuleSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/plugins/summaryWidget/src/telemetry/SummaryWidgetRuleSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './SummaryWidgetRule' | ||||
| ], function ( | ||||
|     SummaryWidgetRule | ||||
| ) { | ||||
|     describe('SummaryWidgetRule', function () { | ||||
|  | ||||
|         var rule; | ||||
|         var telemetryState; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             var formatMap = { | ||||
|                 raw: { | ||||
|                     parse: function (datum) { | ||||
|                         return datum.value; | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             telemetryState = { | ||||
|                 objectId: { | ||||
|                     formats: formatMap, | ||||
|                     lastDatum: { | ||||
|                     } | ||||
|                 }, | ||||
|                 otherObjectId: { | ||||
|                     formats: formatMap, | ||||
|                     lastDatum: { | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|         }); | ||||
|  | ||||
|         it('allows single condition rules with any', function () { | ||||
|             rule = new SummaryWidgetRule({ | ||||
|                 trigger: 'any', | ||||
|                 conditions: [{ | ||||
|                     object: 'objectId', | ||||
|                     key: 'raw', | ||||
|                     operation: 'greaterThan', | ||||
|                     values: [ | ||||
|                         10 | ||||
|                     ] | ||||
|                 }] | ||||
|             }); | ||||
|  | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(true); | ||||
|         }); | ||||
|  | ||||
|         it('allows single condition rules with all', function () { | ||||
|             rule = new SummaryWidgetRule({ | ||||
|                 trigger: 'all', | ||||
|                 conditions: [{ | ||||
|                     object: 'objectId', | ||||
|                     key: 'raw', | ||||
|                     operation: 'greaterThan', | ||||
|                     values: [ | ||||
|                         10 | ||||
|                     ] | ||||
|                 }] | ||||
|             }); | ||||
|  | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(true); | ||||
|         }); | ||||
|  | ||||
|         it('can combine multiple conditions with all', function () { | ||||
|             rule = new SummaryWidgetRule({ | ||||
|                 trigger: 'all', | ||||
|                 conditions: [{ | ||||
|                     object: 'objectId', | ||||
|                     key: 'raw', | ||||
|                     operation: 'greaterThan', | ||||
|                     values: [ | ||||
|                         10 | ||||
|                     ] | ||||
|                 }, { | ||||
|                     object: 'otherObjectId', | ||||
|                     key: 'raw', | ||||
|                     operation: 'greaterThan', | ||||
|                     values: [ | ||||
|                         20 | ||||
|                     ] | ||||
|                 }] | ||||
|             }); | ||||
|  | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 5; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 25; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 5; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 25; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(true); | ||||
|  | ||||
|         }); | ||||
|  | ||||
|         it('can combine multiple conditions with any', function () { | ||||
|             rule = new SummaryWidgetRule({ | ||||
|                 trigger: 'any', | ||||
|                 conditions: [{ | ||||
|                     object: 'objectId', | ||||
|                     key: 'raw', | ||||
|                     operation: 'greaterThan', | ||||
|                     values: [ | ||||
|                         10 | ||||
|                     ] | ||||
|                 }, { | ||||
|                     object: 'otherObjectId', | ||||
|                     key: 'raw', | ||||
|                     operation: 'greaterThan', | ||||
|                     values: [ | ||||
|                         20 | ||||
|                     ] | ||||
|                 }] | ||||
|             }); | ||||
|  | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 5; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(false); | ||||
|             telemetryState.objectId.lastDatum.value = 5; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 25; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(true); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 5; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(true); | ||||
|             telemetryState.objectId.lastDatum.value = 15; | ||||
|             telemetryState.otherObjectId.lastDatum.value = 25; | ||||
|             expect(rule.evaluate(telemetryState)).toBe(true); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -0,0 +1,64 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './EvaluatorPool' | ||||
| ], function ( | ||||
|     EvaluatorPool | ||||
| ) { | ||||
|  | ||||
|     function SummaryWidgetTelemetryProvider(openmct) { | ||||
|         this.pool = new EvaluatorPool(openmct); | ||||
|     } | ||||
|  | ||||
|     SummaryWidgetTelemetryProvider.prototype.supportsRequest = function (domainObject, options) { | ||||
|         return domainObject.type === 'summary-widget'; | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetTelemetryProvider.prototype.request = function (domainObject, options) { | ||||
|         if (options.strategy !== 'latest' && options.size !== 1) { | ||||
|             return Promise.resolve([]); | ||||
|         } | ||||
|  | ||||
|         var evaluator = this.pool.get(domainObject); | ||||
|         return evaluator.requestLatest(options) | ||||
|             .then(function (latestDatum) { | ||||
|                 this.pool.release(evaluator); | ||||
|                 return [latestDatum]; | ||||
|             }.bind(this)); | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetTelemetryProvider.prototype.supportsSubscribe = function (domainObject) { | ||||
|         return domainObject.type === 'summary-widget'; | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetTelemetryProvider.prototype.subscribe = function (domainObject, callback) { | ||||
|         var evaluator = this.pool.get(domainObject); | ||||
|         var unsubscribe = evaluator.subscribe(callback); | ||||
|         return function () { | ||||
|             this.pool.release(evaluator); | ||||
|             unsubscribe(); | ||||
|         }.bind(this); | ||||
|     }; | ||||
|  | ||||
|     return SummaryWidgetTelemetryProvider; | ||||
| }); | ||||
							
								
								
									
										197
									
								
								src/plugins/summaryWidget/src/telemetry/operations.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/plugins/summaryWidget/src/telemetry/operations.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|  | ||||
| ], function ( | ||||
|  | ||||
| ) { | ||||
|     var OPERATIONS = { | ||||
|         equalTo: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] === input[1]; | ||||
|             }, | ||||
|             text: 'is equal to', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' == ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         notEqualTo: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] !== input[1]; | ||||
|             }, | ||||
|             text: 'is not equal to', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' != ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         greaterThan: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] > input[1]; | ||||
|             }, | ||||
|             text: 'is greater than', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' > ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         lessThan: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] < input[1]; | ||||
|             }, | ||||
|             text: 'is less than', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' < ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         greaterThanOrEq: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] >= input[1]; | ||||
|             }, | ||||
|             text: 'is greater than or equal to', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' >= ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         lessThanOrEq: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] <= input[1]; | ||||
|             }, | ||||
|             text: 'is less than or equal to', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' <= ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         between: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] > input[1] && input[0] < input[2]; | ||||
|             }, | ||||
|             text: 'is between', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 2, | ||||
|             getDescription: function (values) { | ||||
|                 return ' between ' + values[0] + ' and ' + values[1]; | ||||
|             } | ||||
|         }, | ||||
|         notBetween: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] < input[1] || input[0] > input[2]; | ||||
|             }, | ||||
|             text: 'is not between', | ||||
|             appliesTo: ['number'], | ||||
|             inputCount: 2, | ||||
|             getDescription: function (values) { | ||||
|                 return ' not between ' + values[0] + ' and ' + values[1]; | ||||
|             } | ||||
|         }, | ||||
|         textContains: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] && input[1] && input[0].includes(input[1]); | ||||
|             }, | ||||
|             text: 'text contains', | ||||
|             appliesTo: ['string'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' contains ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         textDoesNotContain: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] && input[1] && !input[0].includes(input[1]); | ||||
|             }, | ||||
|             text: 'text does not contain', | ||||
|             appliesTo: ['string'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' does not contain ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         textStartsWith: { | ||||
|             operation: function (input) { | ||||
|                 return input[0].startsWith(input[1]); | ||||
|             }, | ||||
|             text: 'text starts with', | ||||
|             appliesTo: ['string'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' starts with ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         textEndsWith: { | ||||
|             operation: function (input) { | ||||
|                 return input[0].endsWith(input[1]); | ||||
|             }, | ||||
|             text: 'text ends with', | ||||
|             appliesTo: ['string'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' ends with ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         textIsExactly: { | ||||
|             operation: function (input) { | ||||
|                 return input[0] === input[1]; | ||||
|             }, | ||||
|             text: 'text is exactly', | ||||
|             appliesTo: ['string'], | ||||
|             inputCount: 1, | ||||
|             getDescription: function (values) { | ||||
|                 return ' is exactly ' + values[0]; | ||||
|             } | ||||
|         }, | ||||
|         isUndefined: { | ||||
|             operation: function (input) { | ||||
|                 return typeof input[0] === 'undefined'; | ||||
|             }, | ||||
|             text: 'is undefined', | ||||
|             appliesTo: ['string', 'number'], | ||||
|             inputCount: 0, | ||||
|             getDescription: function () { | ||||
|                 return ' is undefined'; | ||||
|             } | ||||
|         }, | ||||
|         isDefined: { | ||||
|             operation: function (input) { | ||||
|                 return typeof input[0] !== 'undefined'; | ||||
|             }, | ||||
|             text: 'is defined', | ||||
|             appliesTo: ['string', 'number'], | ||||
|             inputCount: 0, | ||||
|             getDescription: function () { | ||||
|                 return ' is defined'; | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     return OPERATIONS; | ||||
| }); | ||||
							
								
								
									
										82
									
								
								src/plugins/summaryWidget/src/views/SummaryWidgetView.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/plugins/summaryWidget/src/views/SummaryWidgetView.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| define([ | ||||
|     'text!./summary-widget.html' | ||||
| ], function ( | ||||
|     summaryWidgetTemplate | ||||
| ) { | ||||
|     function SummaryWidgetView(domainObject, openmct) { | ||||
|         this.openmct = openmct; | ||||
|         this.domainObject = domainObject; | ||||
|         this.hasUpdated = false; | ||||
|     } | ||||
|  | ||||
|     SummaryWidgetView.prototype.updateState = function (datum) { | ||||
|         this.hasUpdated = true; | ||||
|         this.widget.style.color = datum.textColor; | ||||
|         this.widget.style.backgroundColor = datum.backgroundColor; | ||||
|         this.widget.style.borderColor = datum.borderColor; | ||||
|         this.widget.title = datum.message; | ||||
|         this.label.innerHTML = datum.ruleLabel; | ||||
|         this.label.className = 'label widget-label ' + datum.icon; | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetView.prototype.render = function (domainObject) { | ||||
|         if (this.unsubscribe) { | ||||
|             this.unsubscribe(); | ||||
|         } | ||||
|         this.hasUpdated = false; | ||||
|  | ||||
|         this.container.innerHTML = summaryWidgetTemplate; | ||||
|         this.widget = this.container.querySelector('a'); | ||||
|         this.label = this.container.querySelector('.widget-label'); | ||||
|  | ||||
|  | ||||
|         if (domainObject.url) { | ||||
|             this.widget.setAttribute('href', domainObject.url); | ||||
|         } else { | ||||
|             this.widget.removeAttribute('href'); | ||||
|         } | ||||
|  | ||||
|         if (domainObject.openNewTab === 'newTab') { | ||||
|             this.widget.setAttribute('target', '_blank'); | ||||
|         } else { | ||||
|             this.widget.removeAttribute('target'); | ||||
|         } | ||||
|         var renderTracker = {}; | ||||
|         this.renderTracker = renderTracker; | ||||
|         this.openmct.telemetry.request(this.domainObject, { | ||||
|             strategy: 'latest', | ||||
|             size: 1 | ||||
|         }).then(function (results) { | ||||
|             if (this.hasUpdated || this.renderTracker !== renderTracker) { | ||||
|                 return; | ||||
|             } | ||||
|             this.updateState(results[results.length - 1]); | ||||
|         }.bind(this)); | ||||
|  | ||||
|         this.unsubscribe = this.openmct | ||||
|             .telemetry | ||||
|             .subscribe(domainObject, this.updateState.bind(this)); | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetView.prototype.show = function (container) { | ||||
|         this.container = container; | ||||
|         this.render(this.domainObject); | ||||
|         this.removeMutationListener = this.openmct.objects.observe( | ||||
|             this.domainObject, | ||||
|             '*', | ||||
|             this.render.bind(this) | ||||
|         ); | ||||
|     }; | ||||
|  | ||||
|     SummaryWidgetView.prototype.destroy = function (container) { | ||||
|         this.unsubscribe(); | ||||
|         this.removeMutationListener(); | ||||
|         delete this.widget; | ||||
|         delete this.label; | ||||
|         delete this.openmct; | ||||
|         delete this.domainObject; | ||||
|     }; | ||||
|  | ||||
|     return SummaryWidgetView; | ||||
|  | ||||
| }); | ||||
| @@ -0,0 +1,42 @@ | ||||
| define([ | ||||
|     '../SummaryWidget', | ||||
|     './SummaryWidgetView', | ||||
|     '../../../../api/objects/object-utils' | ||||
| ], function ( | ||||
|     SummaryWidgetEditView, | ||||
|     SummaryWidgetView, | ||||
|     objectUtils | ||||
| ) { | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      */ | ||||
|     function SummaryWidgetViewProvider(openmct) { | ||||
|         return { | ||||
|             key: 'summary-widget-viewer', | ||||
|             name: 'Widget View', | ||||
|             canView: function (domainObject) { | ||||
|                 return domainObject.type === 'summary-widget'; | ||||
|             }, | ||||
|             view: function (domainObject) { | ||||
|                 var statusService = openmct.$injector.get('statusService'); | ||||
|                 var objectId = objectUtils.makeKeyString(domainObject.identifier); | ||||
|                 var statuses = statusService.listStatuses(objectId); | ||||
|                 var isEditing = statuses.indexOf('editing') !== -1; | ||||
|  | ||||
|                 if (isEditing) { | ||||
|                     return new SummaryWidgetEditView(domainObject, openmct); | ||||
|                 } else { | ||||
|                     return new SummaryWidgetView(domainObject, openmct); | ||||
|                 } | ||||
|             }, | ||||
|             editable: true, | ||||
|             priority: function (domainObject) { | ||||
|                 return 1; | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     return SummaryWidgetViewProvider; | ||||
| }); | ||||
							
								
								
									
										5
									
								
								src/plugins/summaryWidget/src/views/summary-widget.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/plugins/summaryWidget/src/views/summary-widget.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| <div class="w-summary-widget s-status-no-data"> | ||||
|     <a class="t-summary-widget l-summary-widget s-summary-widget labeled"> | ||||
|         <span class="label widget-label">Loading...</span> | ||||
|     </a> | ||||
| </div> | ||||
| @@ -19,6 +19,7 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|             removeCallbackSpy, | ||||
|             telemetryCallbackSpy, | ||||
|             metadataCallbackSpy, | ||||
|             telemetryRequests, | ||||
|             mockTelemetryValues, | ||||
|             mockTelemetryValues2, | ||||
|             mockConditionEvaluator; | ||||
| @@ -61,31 +62,43 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|                 mockCompObject1: { | ||||
|                     property1: { | ||||
|                         key: 'property1', | ||||
|                         name: 'Property 1' | ||||
|                         name: 'Property 1', | ||||
|                         format: 'string', | ||||
|                         hints: {} | ||||
|                     }, | ||||
|                     property2: { | ||||
|                         key: 'property2', | ||||
|                         name: 'Property 2' | ||||
|                         name: 'Property 2', | ||||
|                         hints: { | ||||
|                             domain: 1 | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 mockCompObject2: { | ||||
|                     property3: { | ||||
|                         key: 'property3', | ||||
|                         name: 'Property 3' | ||||
|                         name: 'Property 3', | ||||
|                         format: 'string', | ||||
|                         hints: {} | ||||
|                     }, | ||||
|                     property4: { | ||||
|                         key: 'property4', | ||||
|                         name: 'Property 4' | ||||
|                         name: 'Property 4', | ||||
|                         hints: { | ||||
|                             range: 1 | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 mockCompObject3: { | ||||
|                     property1: { | ||||
|                         key: 'property1', | ||||
|                         name: 'Property 1' | ||||
|                         name: 'Property 1', | ||||
|                         hints: {} | ||||
|                     }, | ||||
|                     property2: { | ||||
|                         key: 'property2', | ||||
|                         name: 'Property 2' | ||||
|                         name: 'Property 2', | ||||
|                         hints: {} | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
| @@ -160,22 +173,20 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|                 unregisterSpies[event](); | ||||
|             }); | ||||
|             mockComposition.load.andCallFake(function () { | ||||
|                 mockEventCallbacks.add(mockCompObject1); | ||||
|                 mockEventCallbacks.add(mockCompObject2); | ||||
|                 mockEventCallbacks.load(); | ||||
|                 mockComposition.triggerCallback('add', mockCompObject1); | ||||
|                 mockComposition.triggerCallback('add', mockCompObject2); | ||||
|                 mockComposition.triggerCallback('load'); | ||||
|             }); | ||||
|             mockComposition.triggerCallback.andCallFake(function (event) { | ||||
|             mockComposition.triggerCallback.andCallFake(function (event, obj) { | ||||
|                 if (event === 'add') { | ||||
|                     mockEventCallbacks.add(mockCompObject3); | ||||
|                     mockEventCallbacks.add(obj); | ||||
|                 } else if (event === 'remove') { | ||||
|                     mockEventCallbacks.remove({ | ||||
|                         key: 'mockCompObject2' | ||||
|                     }); | ||||
|                     mockEventCallbacks.remove(obj.identifier); | ||||
|                 } else { | ||||
|                     mockEventCallbacks[event](); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             telemetryRequests = []; | ||||
|             mockTelemetryAPI = jasmine.createSpyObj('telemetryAPI', [ | ||||
|                 'request', | ||||
|                 'isTelemetryObject', | ||||
| @@ -184,9 +195,15 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|                 'triggerTelemetryCallback' | ||||
|             ]); | ||||
|             mockTelemetryAPI.request.andCallFake(function (obj) { | ||||
|                 return new Promise(function (resolve, reject) { | ||||
|                     resolve(mockTelemetryValues[obj.identifer.key]); | ||||
|                 var req = { | ||||
|                     object: obj | ||||
|                 }; | ||||
|                 req.promise = new Promise(function (resolve, reject) { | ||||
|                     req.resolve = resolve; | ||||
|                     req.reject = reject; | ||||
|                 }); | ||||
|                 telemetryRequests.push(req); | ||||
|                 return req.promise; | ||||
|             }); | ||||
|             mockTelemetryAPI.isTelemetryObject.andReturn(true); | ||||
|             mockTelemetryAPI.getMetadata.andCallFake(function (obj) { | ||||
| @@ -245,41 +262,50 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|             var allKeys = { | ||||
|                 property1: { | ||||
|                     key: 'property1', | ||||
|                     name: 'Property 1' | ||||
|                     name: 'Property 1', | ||||
|                     format: 'string', | ||||
|                     hints: {} | ||||
|                 }, | ||||
|                 property2: { | ||||
|                     key: 'property2', | ||||
|                     name: 'Property 2' | ||||
|                     name: 'Property 2', | ||||
|                     hints: { | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, | ||||
|                 property3: { | ||||
|                     key: 'property3', | ||||
|                     name: 'Property 3' | ||||
|                     name: 'Property 3', | ||||
|                     format: 'string', | ||||
|                     hints: {} | ||||
|                 }, | ||||
|                 property4: { | ||||
|                     key: 'property4', | ||||
|                     name: 'Property 4' | ||||
|                     name: 'Property 4', | ||||
|                     hints: { | ||||
|                         range: 1 | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|             expect(conditionManager.getTelemetryMetadata('all')).toEqual(allKeys); | ||||
|             expect(conditionManager.getTelemetryMetadata('any')).toEqual(allKeys); | ||||
|             mockComposition.triggerCallback('add'); | ||||
|             mockComposition.triggerCallback('add', mockCompObject3); | ||||
|             expect(conditionManager.getTelemetryMetadata('all')).toEqual(allKeys); | ||||
|             expect(conditionManager.getTelemetryMetadata('any')).toEqual(allKeys); | ||||
|         }); | ||||
|  | ||||
|         it('loads and gets telemetry property types', function () { | ||||
|             conditionManager.parseAllPropertyTypes().then(function () { | ||||
|                 expect(conditionManager.getTelemetryPropertyType('mockCompObject1', 'property1')) | ||||
|                     .toEqual('string'); | ||||
|                 expect(conditionManager.getTelemetryPropertyType('mockCompObject2', 'property4')) | ||||
|                     .toEqual('number'); | ||||
|                 expect(conditionManager.metadataLoadComplete()).toEqual(true); | ||||
|                 expect(metadataCallbackSpy).toHaveBeenCalled(); | ||||
|             }); | ||||
|             conditionManager.parseAllPropertyTypes(); | ||||
|             expect(conditionManager.getTelemetryPropertyType('mockCompObject1', 'property1')) | ||||
|                 .toEqual('string'); | ||||
|             expect(conditionManager.getTelemetryPropertyType('mockCompObject2', 'property4')) | ||||
|                 .toEqual('number'); | ||||
|             expect(conditionManager.metadataLoadCompleted()).toEqual(true); | ||||
|             expect(metadataCallbackSpy).toHaveBeenCalled(); | ||||
|         }); | ||||
|  | ||||
|         it('responds to a composition add event and invokes the appropriate handlers', function () { | ||||
|             mockComposition.triggerCallback('add'); | ||||
|             mockComposition.triggerCallback('add', mockCompObject3); | ||||
|             expect(addCallbackSpy).toHaveBeenCalledWith(mockCompObject3); | ||||
|             expect(conditionManager.getComposition()).toEqual({ | ||||
|                 mockCompObject1: mockCompObject1, | ||||
| @@ -289,7 +315,7 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|         }); | ||||
|  | ||||
|         it('responds to a composition remove event and invokes the appropriate handlers', function () { | ||||
|             mockComposition.triggerCallback('remove'); | ||||
|             mockComposition.triggerCallback('remove', mockCompObject2); | ||||
|             expect(removeCallbackSpy).toHaveBeenCalledWith({ | ||||
|                 key: 'mockCompObject2' | ||||
|             }); | ||||
| @@ -300,7 +326,7 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|         }); | ||||
|  | ||||
|         it('unregisters telemetry subscriptions and composition listeners on destroy', function () { | ||||
|             mockComposition.triggerCallback('add'); | ||||
|             mockComposition.triggerCallback('add', mockCompObject3); | ||||
|             conditionManager.destroy(); | ||||
|             Object.values(unsubscribeSpies).forEach(function (spy) { | ||||
|                 expect(spy).toHaveBeenCalled(); | ||||
| @@ -311,7 +337,19 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|         }); | ||||
|  | ||||
|         it('populates its LAD cache with historial data on load, if available', function () { | ||||
|             conditionManager.parseAllPropertyTypes().then(function () { | ||||
|             expect(telemetryRequests.length).toBe(2); | ||||
|             expect(telemetryRequests[0].object).toBe(mockCompObject1); | ||||
|             expect(telemetryRequests[1].object).toBe(mockCompObject2); | ||||
|  | ||||
|             expect(telemetryCallbackSpy).not.toHaveBeenCalled(); | ||||
|  | ||||
|             telemetryRequests[0].resolve([mockTelemetryValues.mockCompObject1]); | ||||
|             telemetryRequests[1].resolve([mockTelemetryValues.mockCompObject2]); | ||||
|  | ||||
|             waitsFor(function () { | ||||
|                 return telemetryCallbackSpy.calls.length === 2; | ||||
|             }); | ||||
|             runs(function () { | ||||
|                 expect(conditionManager.subscriptionCache.mockCompObject1.property1).toEqual('Its a string'); | ||||
|                 expect(conditionManager.subscriptionCache.mockCompObject2.property4).toEqual(66); | ||||
|             }); | ||||
| @@ -352,12 +390,10 @@ define(['../src/ConditionManager'], function (ConditionManager) { | ||||
|         }); | ||||
|  | ||||
|         it('gets the human-readable name of a telemetry field', function () { | ||||
|             conditionManager.parseAllPropertyTypes().then(function () { | ||||
|                 expect(conditionManager.getTelemetryPropertyName('mockCompObject1', 'property1')) | ||||
|                     .toEqual('Property 1'); | ||||
|                 expect(conditionManager.getTelemetryPropertyName('mockCompObject2', 'property4')) | ||||
|                     .toEqual('Property 4'); | ||||
|             }); | ||||
|             expect(conditionManager.getTelemetryPropertyName('mockCompObject1', 'property1')) | ||||
|                 .toEqual('Property 1'); | ||||
|             expect(conditionManager.getTelemetryPropertyName('mockCompObject2', 'property4')) | ||||
|                 .toEqual('Property 4'); | ||||
|         }); | ||||
|  | ||||
|         it('gets its associated ConditionEvaluator', function () { | ||||
|   | ||||
| @@ -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" | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user