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