From 90a6bbc13e710e98e92a340aa939ae23b488ce82 Mon Sep 17 00:00:00 2001 From: Deep Tailor Date: Thu, 28 Jun 2018 17:13:34 -0700 Subject: [PATCH] Notebook integration deep (#1947) * NASA - OPEN MCT NOTEBOOK UI PROTOTYPE CHALLENGE https://www.topcoder.com/challenge-details/30059614/ Initial submission * Code updates: -Topcoder final fixes -NASA review fixes * drag and drop style fix, new entry focus, delete display fix * NASA reported issues fixed: objects saved in notebook, delete entry dialog, style files, and new entry from drag objects fixed. * Annotation toolbar UI style fixes, added annotation functionality on new entry dialog * painterro .map file issue fixed. * NASA review fixes: css files adjusted notebook children tree removed embed's title links to live object * CouchDB documentation added * CouchDB documentation added Screenshots added. * CouchDB setup documentation added * Test case functional and cosmetic issues fixed. * Test cases functional and cosmetic issues fixed. * updated file saver library * Code issues fixes: NotificationLaunchIndicator deleted. Inappropriate modifications to domain object models fixed. Implemented $destroy listener on entryDnd directive. Naming conventions fixed. Unnecessary changes made to platform handled. Painterro dependency handled gulp verify fix. * names and package fixes * filenames fix * [Notebook] Relocate to platform/features/notebook * [Notebook] Remove obsolete README * [Notebook] Restore original index.html * [Notebook] Expose via openmct.plugins * [Notebook] Remove demo entries * [Notebook] Run gulp fixstyle * [Notebook] Use dot notation instead of brackets ...for checkstyle * [Notebook] Remove extra comma * [Notebook] Run gulp fixstyle * [Notebook] Use dot notation instead of brackets ...for checkstyle * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Fix lint issues * [Notebook] Run gulp fixstyle * [Notebook] Include painterro for tests * [Notebook] Fix require config for painterro * [Merge] WIP markup and styling Fixes #1896 - Very much WIP, currently having issues with hovering and jiggling * [Merge] WIP markup and styling Fixes #1896 - Very much WIP, attempting to convert textarea to contenteditable; * [Merge] JS debugging Fixes #1896 - Very much WIP! * [Merge] JS debugging Fixes #1896 - Really, really WIP - DnD doesn't work properly, and drag to existing entry no longer works. * [Front-end] Notebook thematic styling; test console Fixes #1896 - Added thematic styles and config; - Really, really, really WIP!! - DnD doesn't work properly, and drag to existing entry no longer works. * [Merge] Cleanups in JS Fixes #1896 - Removed and commented out logging statements * [Merge] WIP SCSS and markup polishing Fixes #1896 - Significant style and markup changes; - Styles, layout, etc. relating to embed elements; - Fixes in both notebook.html and embedControl.html; - Class name normalization; * [Merge] WIP Mods related to MCTModalNotebook.js Fixes #1896 Fixes #1906 * fix drag and drop, delete entries * [Front-end] Refined styling of entry embeds Fixes #1896 * [Merge] Generalized hover hide/show of local controls Fixes #1896 * [Merge] Generalized labeled icon-* elements Fixes #1896 * [Frontend] CSS normalizing, apply general styles in markup Fixes #1896 - Notebook class names more individualized; - Apply .labeled and .has-local-controls general classes; - Apply .s-input-inline to contenteditable div; - Look and feel cleanups for drag area and entry elements; * added modifiedOn time for entries that are changed, and fixed issue regarding inner text being filled when new entry button clicked * [Frontend] CSS sanding and cleanups Fixes #1896 - Removing unused classes; - Finessed margin and padding; * [Frontend] Mobile styling Fixes #1896 - Mod .has-local-controls to not apply when in touch context * [Frontend] WIP Mobile styling Fixes #1896 - phone portrait entry layout optimization * fix expand in layout, which was causing snapshot at expand * [Frontend] Fixes to search control Fixes #1896 - Search control now more robust, added .search-filter-by-type class selector; * [Frontend] Fix custom Selects Fixes #1896 - Custom Selects now much more solid, handle width compression better; * remove duplicate code from MCTModalNotebook and roll changes into MCTTriggerModal * [Frontend] WIP Mobile styling Fixes #1896 - Fixed general approach to portrait orientation in mobile/_layout.scss to use media query; - Fixed portrait layout in _notebook_base.scss to use media query; * prevent multiple new notebook entry divs from being created on open overlay, instead create on initialization * [Frontend] WIP Snapshot styling Fixes #1896 - Better class names; - Moved buttons in frame layout; * remove frame layout duplicate and use frame.html * fix issue of preserving line breaks when text is received from a persisted source * add comments, clean out some code, and fix broken tests * fix export image after merging with master * include painterro in karma config * Inlined templates for notebook * disable view policy - to allow layouts to function - needs more investigation * fix layout display overload, remove viewpolicy and notebookLayout.html. Fix delete error - issues found when deploying for testathon * fix (not being able to focus on content editable div to add text, while in layout) - when in layout, the first child of the outermost div is the only one that registers a click, this was causing an issue of not being able to edit notebook entries. My fix includes finding the first child of the div that registers the click and forcing a focus event. * fix focus one new entry issue, cleanup of code related to finding elements, and write more reusable code * abstract findElementById for reusability and improve performance from O^2 to O * user findElementById in entrydnd * change snapshot library to dom-to-image * [Frontend] WIP Snapshot styling Fixes #1896 Fixes #1947 - Significant markup changes to template in ViewSnaphot.js - WIP!!! Keeping own topic branch for now * [Frontend] WIP Snapshot styling Fixes #1896 Fixes #1947 - Significant markup changes to ViewSnaphot.js; - Change in imagery.scss to move non-layout styling to appropriate class; * Removed snapshot from version number to close sprint eagle * Updated version number for Enterprise release * Lock filesaver version (#1956) Lock filesaver version as there have been a large number of broken builds from what should be non-breaking version increases. Fixes currently broken build. * [Frontend] Snapshot styling Fixes #1896 Fixes #1947 - Final tweaks after rebase from notebook-integration-deep-styling * fixes issue of overlay not closing when context menu item in clicked when viewing snapshot * [Frontend] Painterro styling Fixes #1896 Fixes #1947 - WIP - Painterro styling overrides and config - Removed commented code * [Frontend] Painterro styling Fixes #1896 Fixes #1947 - WIP - Painterro styling overrides and config * fixes issue of overlay not closing when context menu item in clicked when viewing snapshot * specify require paths for new library * [Frontend] Local controls CSS added for hide/show of trash can icons Fixes #1896 Fixes #1947 - Also updated frame.scss to use same transition timing * proper shimming * dragging objects to notebook now only creates a link, clicking on snapshot from object view takes a snapshot of the current view, without re-rendering * [Frontend] Local controls CSS added for hide/show of trash can icons Fixes #1896 Fixes #1947 - Also updated frame.scss to use same transition timing * select correct div for snapshot * [Frontend] Adding background color to snapshot Fixes #1896 Fixes #1947 * remove snapshot class after async image render * [Frontend] Adding background color to snapshot Fixes #1896 Fixes #1947 * remove snapshot button from frames in layout * remove snapshot from frame view, add it only to overlay, change mctSnapShot to accomodate taking snaps of overlay/object view * add preview action, working, need styling for notebook action on preview * fix checkstyle * change glyph for preview, use similar tempalte to frame.html * dont allow preview action on objects getting edited currently * changes to browseController and NavigationService to block navigation and show preview of object when trying to navigate to object in tree in edit mode * [Frontend] Painterro styling and config Fixes #1896 Fixes #1947 - Changes mainly related to toolbar styling and labels * [Frontend] Notebook/Preview related sanding and polishing Fixes #1947 - Changed description for notebook-new-entry * [Frontend] Notebook/Preview related sanding and polishing Fixes #1947 - Added new global "hide-in-t-main-view" class; - Apply new class to Preview action to suppress display of that button in main view of navigated object; * code cleanup * [Frontend] Notebook/Preview related sanding and polishing Fixes #1947 - Classes for Notebook Entry button spacing; * abstract overlay into a service/api - to reduce code duplication catch error produced by painterro because of async div creation by dialog service * fix broken mcttriggermodal tests * fix checkstyle and lint * add functionality of being able to add buttons to the browse bar element of overlay when instantiating the overlay service * Reduce frequency of template recompilation in mct-include * Use updated painterro library. Fixes #1981 * add save flag and call done in both cases (clicking on cancel or ok) * fixes #1951 persist modified empty entry on blur * Bump Node Version * fix checkstyle * fixes issue where annotating snapshot that is already saved in notebook does not work * fix painterro button styling issue move jquery logic inside timeout block, because buttons are asynchronously created * remove description required when saving snapshot to notebook * remove create snapshot action from embeds, and add preview action to embeds * fixes edge case for issue #1981 Add a reject callback in the edgecase that user presses the x icon or esc key to cancel annotation, which was leading to the drag drop issue * Add default sort options on creation menu of Notebook * fix auto focus on new entry when in oldest first order, both in layout and regular view * [Frontend] Notebook mobile mods - Hide entry area when mobile; - Disallow entry edit or delete in mobile; * fixes issue 2041 (#2049) * fixes issue 2041 allows user to select caret position in notebook entries while in layout * [Frontend] Restore class, refine selector Fixes #2041 Fixes #2049 - Restored .s-input-inline to editable field; - Refined pointer-events: none to properly target .title-label only; * remove unused files/code and smoke test * remove , add pre-wrap to css and use inner text * make reviewer requested changes 'in progress still' * make reviewer requested changes 'continued' * replace html2canvas with dom-to-image - add in progress dialog to export image service - add error dialog to export image service * Search UI refactored to use flex Fixes #1947 - Fixes broken search inputs in main search and Notebook; - Significant rewrite to search SCSS and markup; * Fixes for Notebook custom selects; polishes to search Fixes #1947 - Better flex styles for custom selects; - Refinements to search styling; - Much better mobile responsive layout for search and controls in portrait layout; * fix preview action for embeds, which was showing current domain object vs selected domain object * Fixed hidden search dropdown menu Fixes #1947 * Revert whitespace change Revert change to whitespace in index.html. #1947. * [Export] Use html2canvas Use html2canvas instead of dom-to-image. Fixes issues with text exports. html2canvas is better supported and under active development and is a better choice for this library. Cleaned up export code, ensure that images are properly saved as the correct types. related to feedback on #1947 * Don't show brackets when timestamp is not specified (#331) --- bower.json | 3 +- index.html | 1 + karma.conf.js | 2 + openmct.js | 14 +- package.json | 2 + .../commonUI/browse/res/templates/browse.html | 2 +- .../commonUI/browse/src/BrowseController.js | 23 +- .../src/navigation/NavigationService.js | 1 - .../dialog/res/templates/message.html | 5 +- platform/commonUI/general/bundle.js | 35 ++ .../commonUI/general/res/sass/_global.scss | 3 +- .../commonUI/general/res/sass/_glyphs.scss | 8 + .../commonUI/general/res/sass/_mixins.scss | 2 +- .../commonUI/general/res/sass/_widgets.scss | 33 -- .../general/res/sass/controls/_buttons.scss | 9 +- .../general/res/sass/controls/_controls.scss | 15 +- .../general/res/sass/features/_imagery.scss | 2 +- .../general/res/sass/mobile/_layout.scss | 23 +- .../general/res/sass/search/_search.scss | 158 ++++---- .../general/res/sass/user-environ/_frame.scss | 6 +- .../general/res/templates/preview.html | 45 +++ .../general/src/actions/MCTPreviewAction.js | 55 +++ .../general/src/directives/MCTPreview.js | 64 +++ .../commonUI/general/src/services/Overlay.js | 185 +++++++++ .../features/layout/src/MCTTriggerModal.js | 101 ++--- .../layout/test/MCTTriggerModalSpec.js | 6 + platform/features/notebook/bundle.js | 307 +++++++++++++++ .../notebook/res/sass/_notebook-base.scss | 308 +++++++++++++++ .../notebook/res/sass/_notebook-thematic.scss | 92 +++++ .../notebook/res/sass/notebook-espresso.scss | 30 ++ .../notebook/res/sass/notebook-snow.scss | 30 ++ .../features/notebook/res/sass/notebook.scss | 28 ++ .../notebook/res/templates/annotation.html | 2 + .../res/templates/controls/embedControl.html | 51 +++ .../res/templates/controls/snapSelect.html | 30 ++ .../notebook/res/templates/entry.html | 38 ++ .../notebook/res/templates/notebook.html | 118 ++++++ .../notebook/res/templates/notifications.html | 8 + .../res/templates/snapshotHeader.html | 34 ++ .../notebook/src/actions/AnnotateSnapshot.js | 164 ++++++++ .../src/actions/NewEntryContextual.js | 193 ++++++++++ .../notebook/src/actions/RemoveEmbed.js | 72 ++++ .../notebook/src/actions/RemoveSnapshot.js | 74 ++++ .../notebook/src/actions/ViewSnapshot.js | 132 +++++++ .../src/capabilities/NotebookCapability.js | 50 +++ .../controllers/LayoutNotebookController.js | 54 +++ .../src/controllers/NewEntryController.js | 66 ++++ .../src/controllers/NotebookController.js | 363 ++++++++++++++++++ .../controllers/SelectSnapshotController.js | 44 +++ .../notebook/src/directives/EntryDnd.js | 126 ++++++ .../notebook/src/directives/MCTSnapshot.js | 86 +++++ .../src/policies/CompositionPolicy.js | 44 +++ platform/representation/src/MCTInclude.js | 6 +- platform/search/res/templates/search.html | 16 +- src/plugins/plot/plugin.js | 4 +- .../plot/src/services/ExportImageService.js | 141 ++++--- src/plugins/plugins.js | 3 + .../summaryWidget/res/conditionTemplate.html | 4 +- .../summaryWidget/res/ruleTemplate.html | 6 +- .../res/testDataItemTemplate.html | 4 +- test-main.js | 8 +- 61 files changed, 3231 insertions(+), 308 deletions(-) create mode 100644 platform/commonUI/general/res/templates/preview.html create mode 100644 platform/commonUI/general/src/actions/MCTPreviewAction.js create mode 100644 platform/commonUI/general/src/directives/MCTPreview.js create mode 100644 platform/commonUI/general/src/services/Overlay.js create mode 100644 platform/features/notebook/bundle.js create mode 100644 platform/features/notebook/res/sass/_notebook-base.scss create mode 100644 platform/features/notebook/res/sass/_notebook-thematic.scss create mode 100644 platform/features/notebook/res/sass/notebook-espresso.scss create mode 100644 platform/features/notebook/res/sass/notebook-snow.scss create mode 100644 platform/features/notebook/res/sass/notebook.scss create mode 100644 platform/features/notebook/res/templates/annotation.html create mode 100644 platform/features/notebook/res/templates/controls/embedControl.html create mode 100644 platform/features/notebook/res/templates/controls/snapSelect.html create mode 100644 platform/features/notebook/res/templates/entry.html create mode 100644 platform/features/notebook/res/templates/notebook.html create mode 100644 platform/features/notebook/res/templates/notifications.html create mode 100644 platform/features/notebook/res/templates/snapshotHeader.html create mode 100644 platform/features/notebook/src/actions/AnnotateSnapshot.js create mode 100644 platform/features/notebook/src/actions/NewEntryContextual.js create mode 100644 platform/features/notebook/src/actions/RemoveEmbed.js create mode 100644 platform/features/notebook/src/actions/RemoveSnapshot.js create mode 100644 platform/features/notebook/src/actions/ViewSnapshot.js create mode 100644 platform/features/notebook/src/capabilities/NotebookCapability.js create mode 100644 platform/features/notebook/src/controllers/LayoutNotebookController.js create mode 100644 platform/features/notebook/src/controllers/NewEntryController.js create mode 100644 platform/features/notebook/src/controllers/NotebookController.js create mode 100644 platform/features/notebook/src/controllers/SelectSnapshotController.js create mode 100644 platform/features/notebook/src/directives/EntryDnd.js create mode 100644 platform/features/notebook/src/directives/MCTSnapshot.js create mode 100644 platform/features/notebook/src/policies/CompositionPolicy.js diff --git a/bower.json b/bower.json index 59ead276f7..08643e4572 100644 --- a/bower.json +++ b/bower.json @@ -22,7 +22,6 @@ "eventemitter3": "^1.2.0", "lodash": "3.10.1", "almond": "~0.3.2", - "html2canvas": "^0.4.1", "moment-timezone": "^0.5.13" } -} +} \ No newline at end of file diff --git a/index.html b/index.html index 66cd66e6c4..d0d98eab71 100644 --- a/index.html +++ b/index.html @@ -69,6 +69,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 2c8c27f93f..9003e86d26 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/painterro/build/*.js', included: false}, + {pattern: 'node_modules/html2canvas/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 645e005201..118cc0c625 100644 --- a/openmct.js +++ b/openmct.js @@ -29,7 +29,6 @@ requirejs.config({ "csv": "bower_components/comma-separated-values/csv.min", "EventEmitter": "bower_components/eventemitter3/index", "es6-promise": "bower_components/es6-promise/es6-promise.min", - "html2canvas": "bower_components/html2canvas/build/html2canvas.min", "moment": "bower_components/moment/moment", "moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format", "moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data", @@ -49,7 +48,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", + "html2canvas": "node_modules/html2canvas/dist/html2canvas.min", + "painterro": "node_modules/painterro/build/painterro.min" }, "shim": { "angular": { @@ -61,12 +62,12 @@ requirejs.config({ "EventEmitter": { "exports": "EventEmitter" }, - "html2canvas": { - "exports": "html2canvas" - }, "moment-duration-format": { "deps": ["moment"] }, + "painterro": { + "exports": "Painterro" + }, "saveAs": { "exports": "saveAs" }, @@ -88,6 +89,9 @@ requirejs.config({ }, "d3-axis": { "exports": "d3-axis" + }, + "dom-to-image": { + "exports": "domtoimage" } } }); diff --git a/package.json b/package.json index 14926efa39..47b3b5d693 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "d3-time-format": "2.1.x", "express": "^4.13.1", "minimist": "^1.1.1", + "painterro": "^0.2.65", "request": "^2.69.0", "vue": "^2.5.6" }, @@ -30,6 +31,7 @@ "gulp-requirejs-optimize": "^0.3.1", "gulp-sass": "^3.1.0", "gulp-sourcemaps": "^1.6.0", + "html2canvas": "^1.0.0-alpha.12", "jasmine-core": "^2.3.0", "jscs-html-reporter": "^0.1.0", "jsdoc": "^3.3.2", diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index d800cf4a6b..b92dea8b83 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -65,7 +65,7 @@
+ class="abs holder holder-object t-main-view">
{{ngModel.title}}
-
{{ngModel.hint + " [" + ngModel.timestamp + "]"}}
+
+ {{ngModel.hint}} + [{{ngModel.timestamp}}] +
{{ngModel.actionText}} diff --git a/platform/commonUI/general/bundle.js b/platform/commonUI/general/bundle.js index 19db4463e0..bfd1533a0e 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 ) { @@ -396,6 +402,31 @@ define([ "key": "mctTree", "implementation": MCTTree, "depends": ['gestureService'] + }, + { + "key": "mctPreview", + "implementation": MCTPreview, + "depends": [ + "$document" + ] + } + ], + "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" + ], + "priority": "preferred" } ], "constants": [ @@ -511,6 +542,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 82292f26a4..b6748847fc 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 3e8664d8c7..57c881812b 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 02809c9152..c9ac76c1c8 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 76fda063f5..82c47ba8c5 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 08978f4e3d..c1d19d18e7 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 6b090c7b58..1fa5a8a7dc 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,6 +350,7 @@ input[type="text"].s-input-inline, @include btnSubtle($bg: $colorSelectBg); @extend .icon-arrow-down; // Context arrow display: inline-block; + flex: 0 0 auto; // When used in a flex context, controls need to hold their width padding: 0 $interiorMargin; overflow: hidden; position: relative; diff --git a/platform/commonUI/general/res/sass/features/_imagery.scss b/platform/commonUI/general/res/sass/features/_imagery.scss index 67647d23ae..4312546585 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 241fedfe4d..169a0136e9 100644 --- a/platform/commonUI/general/res/sass/mobile/_layout.scss +++ b/platform/commonUI/general/res/sass/mobile/_layout.scss @@ -71,8 +71,8 @@ body.mobile { .pane.left.treeview { @include trans-prop-nice(opacity, 250ms, $delay: 250ms); @include background-image(linear-gradient(90deg, rgba(black, 0) 98%, rgba(black, 0.3) 100%)); - width: $proporMenuWithView !important; right: auto !important; + width: $proporMenuWithView !important; } // Sets the right representation when the tree is shown. .pane.right.items { @@ -136,17 +136,16 @@ body.mobile { } } -@media only screen and (max-device-width: $phoMaxW) and (orientation: portrait) { - body.mobile { - .pane-tree-showing { - .pane.left.treeview { - width: $proporMenuOnly !important; - } - .pane.right.items { - transform: translateX($proporMenuOnly); - .holder-object-and-inspector { - opacity: 0; - } +body.phone.portrait { + .pane-tree-showing { + .pane.left.treeview { + width: $proporMenuOnly !important; + } + .pane.right.items { + left: 0 !important; + 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 e6a7b2cb48..26f18cc944 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -26,87 +26,89 @@ @include trans-prop-nice((opacity, color), 150ms); } +.c-search-btn-wrapper, +.c-search { + display: flex; + flex-flow: row nowrap; + align-items: center; + position: relative; + + > * { + &:not(:first-child) { margin-left: $interiorMargin; } + } +} + +.c-search-btn-wrapper { + // Holds c-search and Cancel button + //@include test(); + &.holder { + margin-bottom: $interiorMargin; + } + +} + +.c-search { + // New approach to search and filter inputs + // Block element + // Holds magnify glass icon, html input, cancel button, etc. + $m: $interiorMarginSm; + @include nice-input(); + flex: 1 1 99%; + font-size: 0.8rem; + height: $btnStdH; + padding: 1px $interiorMargin; + + > * { + display: inline-block; + flex: 0 0 auto; + position: relative; + } + + &:before { + // Magnify glass icon + content: $glyph-icon-magnify; + font-family: symbolsfont; + opacity: 0.3; + pointer-events: none; + transition: opacity 500ms; + } + + &:hover:before { + opacity: 0.6; + } +} + +.c-search__clear-input { + // Icon is visible only when there is text input + visibility: hidden; + opacity: 0; + &.show { + visibility: visible; + opacity: 1; + } + + &:hover { + opacity: 1; + } +} + +input.c-search__search-input { + background: none !important; + box-shadow: none !important; // !important needed to override default for [input] + flex: 1 1 99%; + min-width: 10px; +} + +.c-search__search-menu-holder { + left: 100%; + position: absolute; + transform: translate(-30px, 10px); + z-index: 70; +} + .holder-search { $iconWidth: 20px; - .search-bar { - $textInputHeight: 19px; // This is equal to the default value, 19px - $iconEdgeM: 4px; - $iconD: $treeSearchInputBarH - ($iconEdgeM*2); - @extend .icon-magnify; - font-size: 0.8em; - position: relative; - - .search-input { - height: $treeSearchInputBarH; - line-height: $treeSearchInputBarH; - } - - &:before, - .clear-input, - .menu-icon { - // :before is magnify glass icon - height: $iconD; - width: $iconD; - line-height: $iconD; - text-align: center; - } - - .search-input { - position: relative; - width: 100%; - padding-left: $iconD + $interiorMargin !important; - padding-right: ($iconD * 2) + ($interiorMargin * 2) !important; - - // Make work for mct-control textfield - input { - width: inherit; // was 100% - } - } - - &:before { - // Magnify glass icon - left: $interiorMarginSm; - pointer-events: none; - z-index: 1; - } - - .clear-input { - // Hiding for now with addition of Cancel button - right: $iconD + $interiorMargin; - - // Icon is visible only when there is text input - visibility: hidden; - opacity: 0; - &.show { - visibility: visible; - opacity: 1; - } - - &:hover { - color: pullForward($colorInputIcon, 10%); - } - } - - .menu-icon { - // 'v' invoke menu icon - font-size: 0.8em; - padding-right: $iconEdgeM; - right: $iconEdgeM; - text-align: right; - &:hover { - color: pullForward($colorInputIcon, 10%); - } - } - - .search-menu-holder { - float: right; - left: -20px; - z-index: 70; - transition: visibility .05s, opacity .05s; - } - } - .results-msg { font-size: 0.8rem; } diff --git a/platform/commonUI/general/res/sass/user-environ/_frame.scss b/platform/commonUI/general/res/sass/user-environ/_frame.scss index 76652e5e4f..24d7e652f6 100644 --- a/platform/commonUI/general/res/sass/user-environ/_frame.scss +++ b/platform/commonUI/general/res/sass/user-environ/_frame.scss @@ -123,8 +123,8 @@ } } - &.t-frame-outer .s-input-inline { - // Prevent inline inputs from being edited when nested in a Layout + &.t-frame-outer .title-label.s-input-inline { + // Prevent frame titles from being edited when nested in a Layout pointer-events: none !important; } @@ -161,6 +161,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; } @@ -169,6 +170,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 0000000000..3b760be626 --- /dev/null +++ b/platform/commonUI/general/res/templates/preview.html @@ -0,0 +1,45 @@ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
\ 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 0000000000..17a058d931 --- /dev/null +++ b/platform/commonUI/general/src/actions/MCTPreviewAction.js @@ -0,0 +1,55 @@ +/***************************************************************************** + * 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 = '' + + ''; + + function MCTPreviewAction($compile, $rootScope, context) { + context = context || {}; + this.domainObject = context.selectedObject || context.domainObject; + this.$rootScope = $rootScope; + this.$compile = $compile; + } + + MCTPreviewAction.prototype.perform = function () { + var newScope = this.$rootScope.$new(); + newScope.domainObject = this.domainObject; + + this.$compile(PREVIEW_TEMPLATE)(newScope); + }; + + MCTPreviewAction.appliesTo = function (context) { + var domainObject = (context || {}).domainObject, + status = domainObject.getCapability('status'); + + return !(status && status.get('editing')); + }; + + return MCTPreviewAction; + } +); diff --git a/platform/commonUI/general/src/directives/MCTPreview.js b/platform/commonUI/general/src/directives/MCTPreview.js new file mode 100644 index 0000000000..8121ada068 --- /dev/null +++ b/platform/commonUI/general/src/directives/MCTPreview.js @@ -0,0 +1,64 @@ +/***************************************************************************** + * 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($document) { + + function link($scope, $element) { + 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 0000000000..5a59e28263 --- /dev/null +++ b/platform/commonUI/general/src/services/Overlay.js @@ -0,0 +1,185 @@ +/***************************************************************************** + * 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 = '' + +'
' + +'
' + +' ' + +'
' + +'
' + +'
' + +' Done' + +'
' + +'
' + +'
'; + + /* + * 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; + + 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 = '' + + '' + title + '' + + ''; + + var button = document.createElement('div'); + $(button).addClass('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 d7790479b6..8fbe5b537c 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 = '' + -'
' + -'
' + -' ' + -'
' + -'
' + -'
' + -' Done' + -'
' + -'
' + -'
'; - /** * 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 a466778536..9538a6467d 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 0000000000..1cd18052fb --- /dev/null +++ b/platform/features/notebook/bundle.js @@ -0,0 +1,307 @@ +define([ + "legacyRegistry", + "./src/controllers/NotebookController", + "./src/controllers/NewEntryController", + "./src/controllers/SelectSnapshotController", + "./src/controllers/LayoutNotebookController", + "./src/directives/MCTSnapshot", + "./src/directives/EntryDnd", + "./src/actions/ViewSnapshot", + "./src/actions/AnnotateSnapshot", + "./src/actions/RemoveEmbed", + "./src/actions/RemoveSnapshot", + "./src/actions/NewEntryContextual", + "./src/capabilities/NotebookCapability", + "./src/policies/CompositionPolicy", + "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, + MCTEntryDnd, + ViewSnapshotAction, + AnnotateSnapshotAction, + RemoveEmbedAction, + RemoveSnapshotAction, + newEntryAction, + NotebookCapability, + CompositionPolicy, + 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": [] + }, + "properties": [ + { + "key": "defaultSort", + "name": "Default Sort", + "control": "select", + "options": [ + { + "name": "Newest First", + "value": "-createdOn" + }, + { + "name": "Oldest First", + "value": "createdOn" + } + ], + "cssClass": "l-inline" + } + ] + } + ], + "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" + ] + } + ], + "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": "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 0000000000..8a36390df7 --- /dev/null +++ b/platform/features/notebook/res/sass/_notebook-base.scss @@ -0,0 +1,308 @@ +/***************************************************************************** + * 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; +} + +.notebook-view-controls.l-flex-row { + > * { + // filter and sort selects + &:not(:first-child) { margin-left: $interiorMargin; } + } +} + +.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 { + 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 + white-space: pre-wrap; + } + .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 */ +body.mobile { + // Hide the start entry area, and disable ability to edit or delete an entry in mobile context + .l-notebook-drag-area { + display: none; + } + + .l-notebook-entry { + pointer-events: none; + } + + &.phone.portrait { + .w-notebook-entry-time-and-content { + flex-direction: column !important; + } + .s-notebook-entry-time, + .notebook-entry-delete { + padding-top: 0; + padding-bottom: 0; + } + } +} + +body.phone.portrait { + .l-notebook-head.l-flex-row { + flex-direction: column !important; + > * { + &:not(:first-child) { margin-top: $interiorMargin; } + } + } +} + +/********************************************* 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 0000000000..c2ebb32d29 --- /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 0000000000..6f6077dacc --- /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 0000000000..b279deadea --- /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 0000000000..75432c248a --- /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 0000000000..b9cbca57a0 --- /dev/null +++ b/platform/features/notebook/res/templates/annotation.html @@ -0,0 +1,2 @@ +
+
\ 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 0000000000..d40702120d --- /dev/null +++ b/platform/features/notebook/res/templates/controls/embedControl.html @@ -0,0 +1,51 @@ + + +
+ +
+
+
+ {{snapshot.modified}} +
+ +
+
{{objectName}}
+
{{snapshot.modified| date:'yyyy-MM-dd HH:mm:ss'}}
+
+ + +
+
+
+
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 0000000000..0f89fb2705 --- /dev/null +++ b/platform/features/notebook/res/templates/controls/snapSelect.html @@ -0,0 +1,30 @@ + +
+ +
\ 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 0000000000..bd4e02affe --- /dev/null +++ b/platform/features/notebook/res/templates/entry.html @@ -0,0 +1,38 @@ + +
+
+
+ + +
+
+
+ + +
+
diff --git a/platform/features/notebook/res/templates/notebook.html b/platform/features/notebook/res/templates/notebook.html new file mode 100644 index 0000000000..470ff32c1e --- /dev/null +++ b/platform/features/notebook/res/templates/notebook.html @@ -0,0 +1,118 @@ +
+
+ +
+
+ +
+
+ +
+
+
+ + +
+ To start a new entry, click here or drag and drop any object +
+ + +
+
    +
  • +
    +
    + {{entry.createdOn | date:'yyyy-MM-dd'}} + {{entry.createdOn | date:'HH:mm:ss'}} +
    +
    +
    +
    + +
    +
    +
    + {{embed.id}} +
    +
    + +
    + +
    +
    {{embed.id| date:'yyyy-MM-dd HH:mm:ss'}} +
    +
    +
    +
    +
    +
    + +
    + +
    +
  • +
+
+
\ 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 0000000000..2a9069fa45 --- /dev/null +++ b/platform/features/notebook/res/templates/notifications.html @@ -0,0 +1,8 @@ + + + + + Notifications + + + diff --git a/platform/features/notebook/res/templates/snapshotHeader.html b/platform/features/notebook/res/templates/snapshotHeader.html new file mode 100644 index 0000000000..e382ee1eaa --- /dev/null +++ b/platform/features/notebook/res/templates/snapshotHeader.html @@ -0,0 +1,34 @@ +
+
+
+
+
+
{{entryName}}
+ +
+ +
+
+
+ +
+
+ SNAPSHOT {{snapDate | date:'yyyy-MM-dd HH:mm:ss'}} +
+ + Annotate + +
+
+
\ No newline at end of file diff --git a/platform/features/notebook/src/actions/AnnotateSnapshot.js b/platform/features/notebook/src/actions/AnnotateSnapshot.js new file mode 100644 index 0000000000..b67d7e09d6 --- /dev/null +++ b/platform/features/notebook/src/actions/AnnotateSnapshot.js @@ -0,0 +1,164 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2017, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +/** + * Module defining viewSnapshot (Originally NewWindowAction). Created by vwoeltje on 11/18/14. + */ +define( + ["painterro", "zepto"], + function (Painterro, $) { + var annotationStruct = { + 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) { + + var DOMAIN_OBJECT = this.domainObject; + var ROOTSCOPE = this.$rootScope; + var painterro; + var save = false; + + var controller = ['$scope', '$timeout', function PainterroController($scope, $timeout) { + $(document.body).find('.l-dialog .outer-holder').addClass('annotation-dialog'); + + // Timeout is necessary because Painterro uses document.getElementById, and mct-include + // hasn't added the dialog to the DOM yet. + $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 (save) { + 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); + + saveSnap(image.asBlob(), embedPos, elementPos, DOMAIN_OBJECT); + }else { + ROOTSCOPE.snapshot = {'src': image.asDataURL('image/png'), + 'modified': Date.now()}; + } + } + done(true); + } + }).show(snapshot); + + $(document.body).find('.ptro-icon-btn').addClass('s-button'); + $(document.body).find('.ptro-input').addClass('s-button'); + }); + }]; + + annotationStruct.model = {'controller': controller}; + + function saveNotes(param) { + if (param === 'ok') { + save = true; + }else { + save = false; + ROOTSCOPE.snapshot = "annotationCancelled"; + } + painterro.save(); + } + + function rejectNotes() { + save = false; + ROOTSCOPE.snapshot = "annotationCancelled"; + painterro.save(); + } + + function saveSnap(url, embedPos, entryPos, domainObject) { + var snap = false; + + if (embedPos !== -1 && entryPos !== -1) { + var reader = new window.FileReader(); + reader.readAsDataURL(url); + reader.onloadend = function () { + snap = reader.result; + domainObject.useCapability('mutation', function (model) { + if (model.entries[entryPos]) { + model.entries[entryPos].embeds[embedPos].snapshot = { + 'src': snap, + 'type': url.type, + 'size': url.size, + 'modified': Date.now() + }; + model.entries[entryPos].embeds[embedPos].id = Date.now(); + } + }); + }; + } + } + + this.dialogService.getUserChoice(annotationStruct) + .then(saveNotes, rejectNotes); + + }; + + return AnnotateSnapshot; + } +); diff --git a/platform/features/notebook/src/actions/NewEntryContextual.js b/platform/features/notebook/src/actions/NewEntryContextual.js new file mode 100644 index 0000000000..70e7edaf2e --- /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 = '' + + ''; + + var NEW_TASK_FORM = { + name: "Create a Notebook Entry", + hint: "Please select one Notebook", + sections: [{ + rows: [{ + name: 'Entry', + key: 'entry', + control: 'textarea', + required: false, + "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); + + 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 0000000000..b809859fdd --- /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 domainObject = 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() { + domainObject.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 0000000000..a675f09f2f --- /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 domainObject = 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() { + domainObject.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 0000000000..30160cb53c --- /dev/null +++ b/platform/features/notebook/src/actions/ViewSnapshot.js @@ -0,0 +1,132 @@ +/***************************************************************************** + * 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 + */ + +var OVERLAY_TEMPLATE = '' + + '
' + + '
' + + ' ' + + '
' + + '
' + + '
' + + ' Done' + + '
' + + '
' + + '
'; + +define([ + 'zepto', + "text!../../res/templates/snapshotHeader.html" + ], + function ($, headerTemplate) { + + var toggleOverlay, + overlay, + closeButton, + doneButton, + blocker, + overlayContainer, + img, + annotateButton, + annotateImg; + + function ViewSnapshot($compile) { + 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 = '
'; + 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; + } + + 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 0000000000..f8c4e8e4f4 --- /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 0000000000..c516f1dbb1 --- /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 0000000000..320884c2c5 --- /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 0000000000..5c187b10e6 --- /dev/null +++ b/platform/features/notebook/src/controllers/NotebookController.js @@ -0,0 +1,363 @@ +/***************************************************************************** + * 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 = $scope.domainObject.getModel().defaultSort || "-createdOn"; + $scope.showTime = "0"; + $scope.editEntry = false; + $scope.entrySearch = ''; + $scope.entryTypes = []; + $scope.embedActions = []; + $scope.currentEntryValue = ''; + + 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 { + var entries = $scope.entriesEl.children().children(), + lastOrFirst = $scope.sortEntries === "-createdOn" ? 0 : (entries.length - 1); + + return $(entries[lastOrFirst]).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(); + } + }] + }); + }; + + $scope.textFocus = function ($event, entryId) { + if ($event.srcElement) { + $scope.currentEntryValue = $event.srcElement.innerText; + } 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) { + 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.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: 'mct-preview-action', selectedObject: resp[embedType]})[0] + )); + $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 0000000000..ce0a123439 --- /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 0000000000..9dc0509051 --- /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/MCTSnapshot.js b/platform/features/notebook/src/directives/MCTSnapshot.js new file mode 100644 index 0000000000..58ef585afc --- /dev/null +++ b/platform/features/notebook/src/directives/MCTSnapshot.js @@ -0,0 +1,86 @@ +/***************************************************************************** + * 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 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"); + + saveImg = function (url, entryId, embedId) { + $scope.$parent.$parent.$parent.saveSnap(url, embedId, entryId); + }; + + makeImg = function (el) { + var scope = $scope; + + exportImageService.exportPNGtoSRC(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(); + }; + } + } + }); + }; + + takeSnapshot = function () { + makeImg(objectElement); + }; + + 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 0000000000..fc6ddb2f0d --- /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/representation/src/MCTInclude.js b/platform/representation/src/MCTInclude.js index 10c1210523..bbe986c647 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 9cf25c216c..56ba63bcca 100644 --- a/platform/search/res/templates/search.html +++ b/platform/search/res/templates/search.html @@ -21,33 +21,31 @@ -->