diff --git a/platform/features/notebook/bundle.js b/platform/features/notebook/bundle.js deleted file mode 100644 index 28677ee219..0000000000 --- a/platform/features/notebook/bundle.js +++ /dev/null @@ -1,294 +0,0 @@ -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", - "./res/templates/notebook.html", - "./res/templates/entry.html", - "./res/templates/annotation.html", - "./res/templates/notifications.html", - "../layout/res/templates/frame.html", - "./res/templates/controls/embedControl.html", - "./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": [], - "defaultSort": "-createdOn" - }, - "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": [ - "view-control" - ], - "depends": [ - "$compile", - "$rootScope", - "dialogService", - "notificationService", - "linkService" - ], - "priority": "preferred" - } - ], - "licenses": [ - { - "name": "painterro", - "version": "0.2.65", - "author": "Ivan Borshchov", - "description": "Painterro is JavaScript paint widget which allows editing images directly in a browser.", - "website": "https://github.com/ivictbor/painterro", - "copyright": "Copyright 2017 Ivan Borshchov", - "license": "MIT", - "link": "https://github.com/ivictbor/painterro/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 - } - ] - } - }); -}); diff --git a/platform/features/notebook/res/templates/notebook.html b/platform/features/notebook/res/templates/notebook.html deleted file mode 100644 index 53cb8ed4b3..0000000000 --- a/platform/features/notebook/res/templates/notebook.html +++ /dev/null @@ -1,118 +0,0 @@ -
-
- -
-
- -
-
- -
-
-
- - -
- To start a new entry, click here or drag and drop any object -
- - -
- -
-
\ No newline at end of file diff --git a/platform/features/notebook/res/templates/notifications.html b/platform/features/notebook/res/templates/notifications.html deleted file mode 100644 index 2a9069fa45..0000000000 --- a/platform/features/notebook/res/templates/notifications.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - Notifications - - - diff --git a/platform/features/notebook/res/templates/snapshotHeader.html b/platform/features/notebook/res/templates/snapshotHeader.html deleted file mode 100644 index e382ee1eaa..0000000000 --- a/platform/features/notebook/res/templates/snapshotHeader.html +++ /dev/null @@ -1,34 +0,0 @@ -
-
-
-
-
-
{{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/RemoveEmbed.js b/platform/features/notebook/src/actions/RemoveEmbed.js deleted file mode 100644 index b809859fdd..0000000000 --- a/platform/features/notebook/src/actions/RemoveEmbed.js +++ /dev/null @@ -1,72 +0,0 @@ -/***************************************************************************** - * 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 deleted file mode 100644 index a675f09f2f..0000000000 --- a/platform/features/notebook/src/actions/RemoveSnapshot.js +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - * 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 deleted file mode 100644 index a5111bd546..0000000000 --- a/platform/features/notebook/src/actions/ViewSnapshot.js +++ /dev/null @@ -1,132 +0,0 @@ -/***************************************************************************** - * 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', - "../../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 deleted file mode 100644 index f8c4e8e4f4..0000000000 --- a/platform/features/notebook/src/capabilities/NotebookCapability.js +++ /dev/null @@ -1,50 +0,0 @@ -/***************************************************************************** - * 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/NotebookController.js b/platform/features/notebook/src/controllers/NotebookController.js deleted file mode 100644 index ffd5d1bc0d..0000000000 --- a/platform/features/notebook/src/controllers/NotebookController.js +++ /dev/null @@ -1,367 +0,0 @@ -/***************************************************************************** - * 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; - $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; - - 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; - - 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.$watch('domainObject.getModel().defaultSort', function (newDefaultSort, oldDefaultSort) { - if (newDefaultSort !== oldDefaultSort) { - $scope.sortEntries = newDefaultSort; - } - }); - - $scope.$on('$destroy', function () {}); - - } - - return NotebookController; - }); diff --git a/platform/features/notebook/src/policies/CompositionPolicy.js b/platform/features/notebook/src/policies/CompositionPolicy.js deleted file mode 100644 index fc6ddb2f0d..0000000000 --- a/platform/features/notebook/src/policies/CompositionPolicy.js +++ /dev/null @@ -1,44 +0,0 @@ -/****************************************************************************** - * 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/src/plugins/notebook/plugin.js b/src/plugins/notebook/plugin.js new file mode 100644 index 0000000000..82630b7bdb --- /dev/null +++ b/src/plugins/notebook/plugin.js @@ -0,0 +1,215 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define([ + "./src/controllers/NotebookController", + "./src/controllers/NewEntryController", + "./src/controllers/SelectSnapshotController", + "./src/actions/NewEntryContextual", + "./src/actions/AnnotateSnapshot", + "./src/directives/MCTSnapshot", + "./src/directives/EntryDnd", + "./res/templates/controls/snapSelect.html", + "./res/templates/controls/embedControl.html", + "./res/templates/annotation.html", + "./res/templates/draggedEntry.html" +], function ( + NotebookController, + NewEntryController, + SelectSnapshotController, + newEntryAction, + AnnotateSnapshotAction, + MCTSnapshotDirective, + EntryDndDirective, + snapSelectTemplate, + embedControlTemplate, + annotationTemplate, + draggedEntryTemplate +) { + var installed = false; + + function NotebookPlugin() { + return function install(openmct) { + if (installed) { + return; + } + + installed = true; + + openmct.legacyRegistry.register('notebook', { + name: 'Notebook Plugin', + 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: [], + defaultSort: '-createdOn' + }, + properties: [ + { + key: 'defaultSort', + name: 'Default Sort', + control: 'select', + options: [ + { + name: 'Newest First', + value: "-createdOn", + }, + { + name: 'Oldest First', + value: "createdOn" + } + ], + cssClass: 'l-inline' + } + ] + } + ], + actions: [ + { + "key": "notebook-new-entry", + "implementation": newEntryAction, + "name": "New Notebook Entry", + "cssClass": "icon-notebook labeled", + "description": "Add a new Notebook entry", + "category": [ + "view-control" + ], + "depends": [ + "$compile", + "$rootScope", + "dialogService", + "notificationService", + "linkService" + ], + "priority": "preferred" + }, + { + "key": "annotate-snapshot", + "implementation": AnnotateSnapshotAction, + "name": "Annotate Snapshot", + "cssClass": "icon-pencil labeled", + "description": "Annotate embed's snapshot", + "category": "embed", + "depends": [ + "dialogService", + "dndService", + "$rootScope" + ] + } + ], + controllers: [ + { + "key": "NewEntryController", + "implementation": NewEntryController, + "depends": ["$scope", + "$rootScope" + ] + }, + { + "key": "selectSnapshotController", + "implementation": SelectSnapshotController, + "depends": ["$scope", + "$rootScope" + ] + } + ], + controls: [ + { + "key": "snapshot-select", + "template": snapSelectTemplate + }, + { + "key": "embed-control", + "template": embedControlTemplate + } + ], + templates: [ + { + "key": "annotate-snapshot", + "template": annotationTemplate + } + ], + directives: [ + { + "key": "mctSnapshot", + "implementation": MCTSnapshotDirective, + "depends": [ + "$rootScope", + "$document", + "exportImageService", + "dialogService", + "notificationService" + ] + }, + { + "key": "mctEntryDnd", + "implementation": EntryDndDirective, + "depends": [ + "$rootScope", + "$compile", + "dndService", + "typeService", + "notificationService" + ] + } + ], + representations: [ + { + "key": "draggedEntry", + "template": draggedEntryTemplate + } + ] + } + }); + + openmct.legacyRegistry.enable('notebook'); + + openmct.objectViews.addProvider({ + key: 'notebook-vue', + name: 'Notebook View', + cssClass: 'icon-notebook', + canView: function (domainObject) { + return domainObject.type === 'notebook'; + }, + view: function (domainObject) { + var controller = new NotebookController (openmct, domainObject); + + return { + show: controller.show, + destroy: controller.destroy + }; + } + }); + }; + + } + + return NotebookPlugin; +}); diff --git a/platform/features/notebook/res/templates/annotation.html b/src/plugins/notebook/res/templates/annotation.html similarity index 100% rename from platform/features/notebook/res/templates/annotation.html rename to src/plugins/notebook/res/templates/annotation.html diff --git a/platform/features/notebook/res/templates/controls/embedControl.html b/src/plugins/notebook/res/templates/controls/embedControl.html similarity index 100% rename from platform/features/notebook/res/templates/controls/embedControl.html rename to src/plugins/notebook/res/templates/controls/embedControl.html diff --git a/platform/features/notebook/res/templates/controls/snapSelect.html b/src/plugins/notebook/res/templates/controls/snapSelect.html similarity index 93% rename from platform/features/notebook/res/templates/controls/snapSelect.html rename to src/plugins/notebook/res/templates/controls/snapSelect.html index 0f89fb2705..8f4bf64cb5 100644 --- a/platform/features/notebook/res/templates/controls/snapSelect.html +++ b/src/plugins/notebook/res/templates/controls/snapSelect.html @@ -25,6 +25,5 @@ ng-options="opt.value as opt.name for opt in options" ng-required="ngRequired" name="mctControl"> - \ No newline at end of file diff --git a/platform/features/notebook/res/templates/entry.html b/src/plugins/notebook/res/templates/draggedEntry.html similarity index 100% rename from platform/features/notebook/res/templates/entry.html rename to src/plugins/notebook/res/templates/draggedEntry.html diff --git a/src/plugins/notebook/res/templates/embed.html b/src/plugins/notebook/res/templates/embed.html new file mode 100644 index 0000000000..7aaa2c6ea7 --- /dev/null +++ b/src/plugins/notebook/res/templates/embed.html @@ -0,0 +1,36 @@ +
+ +
+ +
+ +
+ + + + +
+ {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}} +
+
+
\ No newline at end of file diff --git a/src/plugins/notebook/res/templates/entry.html b/src/plugins/notebook/res/templates/entry.html new file mode 100644 index 0000000000..209f03c10f --- /dev/null +++ b/src/plugins/notebook/res/templates/entry.html @@ -0,0 +1,35 @@ +
  • + +
    +
    + {{formatTime(entry.createdOn, 'YYYY-MM-DD')}} + {{formatTime(entry.createdOn, 'HH:mm:ss')}} +
    + +
    +
    +
    + +
    + +
    +
    + +
    + +
    +
    +
  • \ No newline at end of file diff --git a/src/plugins/notebook/res/templates/notebook.html b/src/plugins/notebook/res/templates/notebook.html new file mode 100644 index 0000000000..5992277468 --- /dev/null +++ b/src/plugins/notebook/res/templates/notebook.html @@ -0,0 +1,46 @@ +
    +
    + + +
    +
    + +
    +
    + +
    +
    +
    + + +
    + To start a new entry, click here or drag and drop any object +
    + + +
    + +
    +
    \ No newline at end of file diff --git a/src/plugins/notebook/res/templates/viewSnapshot.html b/src/plugins/notebook/res/templates/viewSnapshot.html new file mode 100644 index 0000000000..77b23f11b5 --- /dev/null +++ b/src/plugins/notebook/res/templates/viewSnapshot.html @@ -0,0 +1,50 @@ +
    +
    + +
    + + + + +
    +
    + +
    +
    +
    +
    +
    +
    {{embed.name}}
    +
    +
    +
    +
    + +
    +
    + SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}} +
    + + Annotate + +
    + +
    +
    +
    +
    +
    + +
    + + Done +
    +
    +
    +
    \ No newline at end of file diff --git a/platform/features/notebook/src/actions/AnnotateSnapshot.js b/src/plugins/notebook/src/actions/AnnotateSnapshot.js similarity index 99% rename from platform/features/notebook/src/actions/AnnotateSnapshot.js rename to src/plugins/notebook/src/actions/AnnotateSnapshot.js index b58973be80..5cbd48dfb2 100644 --- a/platform/features/notebook/src/actions/AnnotateSnapshot.js +++ b/src/plugins/notebook/src/actions/AnnotateSnapshot.js @@ -26,6 +26,7 @@ define( ["painterro", "zepto"], function (Painterro, $) { + var annotationStruct = { title: "Annotate Snapshot", template: "annotate-snapshot", diff --git a/platform/features/notebook/src/actions/NewEntryContextual.js b/src/plugins/notebook/src/actions/NewEntryContextual.js similarity index 98% rename from platform/features/notebook/src/actions/NewEntryContextual.js rename to src/plugins/notebook/src/actions/NewEntryContextual.js index 08be83d59c..1dfbaea325 100644 --- a/platform/features/notebook/src/actions/NewEntryContextual.js +++ b/src/plugins/notebook/src/actions/NewEntryContextual.js @@ -90,7 +90,7 @@ define( var dialogService = this.dialogService; var rootScope = this.$rootScope; rootScope.newEntryText = ''; - // Create the overlay element and add it to the document's body + // // Create the overlay element and add it to the document's body this.$rootScope.selObj = domainObj; this.$rootScope.selValue = ""; var newScope = rootScope.$new(); @@ -187,7 +187,7 @@ define( var domainObject = context.domainObject; if (domainObject) { - if (domainObject.getModel().type === 'Notebook') { + if (domainObject.getModel().type === 'notebook') { // do not allow in context of a notebook return false; } else if (domainObject.getModel().type.includes('imagery')) { diff --git a/src/plugins/notebook/src/actions/snapshotAction.js b/src/plugins/notebook/src/actions/snapshotAction.js new file mode 100644 index 0000000000..9f3451dd03 --- /dev/null +++ b/src/plugins/notebook/src/actions/snapshotAction.js @@ -0,0 +1,130 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ +define( + ['zepto'], + function ($) { + + function SnapshotAction (exportImageService, dialogService, context) { + this.exportImageService = exportImageService; + this.dialogService = dialogService; + this.domainObject = context.domainObject; + } + + SnapshotAction.prototype.perform = function () { + var elementToSnapshot = + $(document.body).find(".overlay .object-holder")[0] || + $(document.body).find("[key='representation.selected.key']")[0]; + + $(elementToSnapshot).addClass("s-status-taking-snapshot"); + + this.exportImageService.exportPNGtoSRC(elementToSnapshot).then(function (blob) { + $(elementToSnapshot).removeClass("s-status-taking-snapshot"); + + if (blob) { + var reader = new window.FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = function () { + this.saveSnapshot(reader.result, blob.type, blob.size); + }.bind(this); + } + + }.bind(this)); + }; + + SnapshotAction.prototype.saveSnapshot = function (imageURL, imageType, imageSize) { + var taskForm = this.generateTaskForm(), + domainObject = this.domainObject, + domainObjectId = domainObject.getId(), + cssClass = domainObject.getCapability('type').typeDef.cssClass, + name = domainObject.model.name; + + this.dialogService.getDialogResponse( + 'overlay-dialog', + taskForm, + function () { + return taskForm.value; + } + ).then(function (options) { + var snapshotObject = { + src: imageURL, + type: imageType, + size: imageSize + }; + + options.notebook.useCapability('mutation', function (model) { + var date = Date.now(); + + model.entries.push({ + id: 'entry-' + date, + createdOn: date, + text: options.entry, + embeds: [{ + name: name, + cssClass: cssClass, + type: domainObjectId, + id: 'embed-' + date, + createdOn: date, + snapshot: snapshotObject + }] + }); + }); + }); + }; + + SnapshotAction.prototype.generateTaskForm = function () { + var taskForm = { + name: "Create a Notebook Entry", + hint: "Please select a Notebook", + sections: [{ + rows: [{ + name: 'Entry', + key: 'entry', + control: 'textarea', + required: false, + "cssClass": "l-textarea-sm" + }, + { + name: 'Save in Notebook', + key: 'notebook', + control: 'locator', + validate: validateLocation + }] + }] + }; + + var overlayModel = { + title: taskForm.name, + message: 'AHAHAH', + structure: taskForm, + value: {'entry': ""} + }; + + function validateLocation(newParentObj) { + return newParentObj.model.type === 'notebook'; + } + + return overlayModel; + }; + + return SnapshotAction; + } +); diff --git a/src/plugins/notebook/src/controllers/EmbedController.js b/src/plugins/notebook/src/controllers/EmbedController.js new file mode 100644 index 0000000000..5080206e15 --- /dev/null +++ b/src/plugins/notebook/src/controllers/EmbedController.js @@ -0,0 +1,198 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define([ + 'moment', + 'zepto', + '../utils/SnapshotOverlay', +], +function ( + Moment, + $, + SnapshotOverlay +) { + function EmbedController (openmct, domainObject) { + this.openmct = openmct; + this.domainObject = domainObject; + this.objectService = openmct.$injector.get('objectService'); + this.navigationService = openmct.$injector.get('navigationService'); + this.popupService = openmct.$injector.get('popupService'); + this.agentService = openmct.$injector.get('agentService'); + this.dialogService = openmct.$injector.get('dialogService'); + + + this.navigate = this.navigate.bind(this); + this.exposedData = this.exposedData.bind(this); + this.exposedMethods = this.exposedMethods.bind(this); + this.toggleActionMenu = this.toggleActionMenu.bind(this); + } + + EmbedController.prototype.navigate = function (embedType) { + this.objectService.getObjects([embedType]).then(function (objects) { + this.navigationService.setNavigation(objects[embedType]); + }.bind(this)); + }; + + EmbedController.prototype.openSnapshot = function () { + if (!this.snapshotOverlay) { + this.snapShotOverlay = new SnapshotOverlay(this.embed, this.formatTime); + } else { + this.snapShotOverlay = undefined; + } + }; + + EmbedController.prototype.formatTime = function (unixTime, timeFormat) { + return Moment(unixTime).format(timeFormat); + }; + + EmbedController.prototype.findInArray = function (array, id) { + var foundId = -1; + + array.forEach(function (element, index) { + if (element.id === id) { + foundId = index; + return; + } + }); + + return foundId; + }; + + EmbedController.prototype.actionToMenuDecorator = function (action) { + return { + name: action.getMetadata().name, + cssClass: action.getMetadata().cssClass, + perform: action.perform + }; + }; + + EmbedController.prototype.populateActionMenu = function (objectService, actionService) { + return function () { + var self = this; + + objectService.getObjects([self.embed.type]).then(function (resp) { + var domainObject = resp[self.embed.type], + previewAction = actionService.getActions({key: 'mct-preview-action', domainObject: domainObject})[0]; + + self.actions.push(self.actionToMenuDecorator(previewAction)); + }); + }; + }; + + EmbedController.prototype.removeEmbedAction = function () { + var self = this; + + return { + name: 'Remove Embed', + cssClass: 'icon-trash', + perform: function (embed, entry) { + var entryPosition = self.findInArray(self.domainObject.entries, entry.id), + embedPosition = self.findInArray(entry.embeds, embed.id); + + var warningDialog = self.dialogService.showBlockingMessage({ + severity: "error", + title: "This action will permanently delete this embed. Do you wish to continue?", + options: [{ + label: "OK", + callback: function () { + entry.embeds.splice(embedPosition, 1); + var dirString = 'entries[' + entryPosition + '].embeds'; + + self.openmct.objects.mutate(self.domainObject, dirString, entry.embeds); + + warningDialog.dismiss(); + } + },{ + label: "Cancel", + callback: function () { + warningDialog.dismiss(); + } + }] + }); + } + }; + }; + + EmbedController.prototype.toggleActionMenu = function (event) { + event.preventDefault(); + + var body = $(document.body), + container = $(event.target.parentElement.parentElement), + initiatingEvent = this.agentService.isMobile() ? + 'touchstart' : 'mousedown', + menu = container.find('.menu-element'), + dismissExistingMenu; + + // Remove the context menu + function dismiss() { + container.find('.hide-menu').append(menu); + body.off(initiatingEvent, dismiss); + menu.off(initiatingEvent, menuClickHandler); + dismissExistingMenu = undefined; + } + + function menuClickHandler(e) { + e.stopPropagation(); + window.setTimeout(dismiss, 300); + } + + // Dismiss any menu which was already showing + if (dismissExistingMenu) { + dismissExistingMenu(); + } + + // ...and record the presence of this menu. + dismissExistingMenu = dismiss; + + this.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, menuClickHandler); + + body.on(initiatingEvent, dismiss); + + }; + + EmbedController.prototype.exposedData = function () { + return { + actions: [this.removeEmbedAction()], + showActionMenu: false + }; + }; + + EmbedController.prototype.exposedMethods = function () { + var self = this; + + return { + navigate: self.navigate, + openSnapshot: self.openSnapshot, + formatTime: self.formatTime, + toggleActionMenu: self.toggleActionMenu, + actionToMenuDecorator: self.actionToMenuDecorator + }; + }; + + return EmbedController; +}); diff --git a/src/plugins/notebook/src/controllers/EntryController.js b/src/plugins/notebook/src/controllers/EntryController.js new file mode 100644 index 0000000000..7c1475fd11 --- /dev/null +++ b/src/plugins/notebook/src/controllers/EntryController.js @@ -0,0 +1,150 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define([ + 'moment' +], +function ( + Moment +) { + + function EntryController (openmct, domainObject) { + this.openmct = openmct; + this.domainObject = domainObject; + this.dndService = this.openmct.$injector.get('dndService'); + this.dialogService = this.openmct.$injector.get('dialogService'); + + this.currentEntryValue = ''; + + this.exposedMethods = this.exposedMethods.bind(this); + this.exposedData = this.exposedData.bind(this); + } + + EntryController.prototype.entryPosById = function (entryId) { + var foundId = -1; + + this.domainObject.entries.forEach(function (element, index) { + if (element.id === entryId) { + foundId = index; + return; + } + }); + + return foundId; + }; + + EntryController.prototype.textFocus = function ($event) { + if ($event.target) { + this.currentEntryValue = $event.target.innerText; + } else { + $event.target.innerText = ''; + } + }; + + EntryController.prototype.textBlur = function ($event, entryId) { + if ($event.target) { + var entryPos = this.entryPosById(entryId); + + if (this.currentEntryValue !== $event.target.innerText) { + this.openmct.objects.mutate(this.domainObject, 'entries[' + entryPos + '].text', $event.target.innerText); + } + } + }; + + EntryController.prototype.formatTime = function (unixTime, timeFormat) { + return Moment(unixTime).format(timeFormat); + }; + + EntryController.prototype.deleteEntry = function () { + var entryPos = this.entryPosById(this.entry.id), + domainObject = this.domainObject, + openmct = this.openmct; + + if (entryPos !== -1) { + + var errorDialog = this.dialogService.showBlockingMessage({ + severity: "error", + title: "This action will permanently delete this Notebook entry. Do you wish to continue?", + options: [{ + label: "OK", + callback: function () { + domainObject.entries.splice(entryPos, 1); + openmct.objects.mutate(domainObject, 'entries', domainObject.entries); + + errorDialog.dismiss(); + } + },{ + label: "Cancel", + callback: function () { + errorDialog.dismiss(); + } + }] + }); + } + }; + + EntryController.prototype.dropOnEntry = function (entryId) { + var selectedObject = this.dndService.getData('mct-domain-object'), + selectedObjectId = selectedObject.getId(), + selectedModel = selectedObject.getModel(), + cssClass = selectedObject.getCapability('type').typeDef.cssClass, + entryPos = this.entryPosById(entryId), + currentEntryEmbeds = this.domainObject.entries[entryPos].embeds, + newEmbed = { + type: selectedObjectId, + id: '' + Date.now(), + cssClass: cssClass, + name: selectedModel.name, + snapshot: '' + }; + + currentEntryEmbeds.push(newEmbed); + this.openmct.objects.mutate(this.domainObject, 'entries[' + entryPos + '].embeds', currentEntryEmbeds); + }; + + EntryController.prototype.dragoverOnEntry = function () { + + }; + + EntryController.prototype.exposedData = function () { + return { + openmct: this.openmct, + domainObject: this.domainObject, + dndService: this.dndService, + dialogService: this.dialogService, + currentEntryValue: this.currentEntryValue + }; + }; + + EntryController.prototype.exposedMethods = function () { + return { + entryPosById: this.entryPosById, + textFocus: this.textFocus, + textBlur: this.textBlur, + formatTime: this.formatTime, + deleteEntry: this.deleteEntry, + dropOnEntry: this.dropOnEntry, + dragoverOnEntry: this.dragoverOnEntry + }; + }; + return EntryController; +}); diff --git a/platform/features/notebook/src/controllers/NewEntryController.js b/src/plugins/notebook/src/controllers/NewEntryController.js similarity index 95% rename from platform/features/notebook/src/controllers/NewEntryController.js rename to src/plugins/notebook/src/controllers/NewEntryController.js index 6df17225e7..3c092c8b9a 100644 --- a/platform/features/notebook/src/controllers/NewEntryController.js +++ b/src/plugins/notebook/src/controllers/NewEntryController.js @@ -31,8 +31,7 @@ define( $scope.snapshot = undefined; $scope.snapToggle = true; $scope.entryText = ''; - var annotateAction = $rootScope.selObj.getCapability('action').getActions( - {category: 'embed'})[1]; + var annotateAction = $rootScope.selObj.getCapability('action').getActions({key: 'annotate-snapshot'})[0]; $scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = $rootScope.selObj; $scope.objectName = $rootScope.selObj.getModel().name; diff --git a/src/plugins/notebook/src/controllers/NotebookController.js b/src/plugins/notebook/src/controllers/NotebookController.js new file mode 100644 index 0000000000..123673d175 --- /dev/null +++ b/src/plugins/notebook/src/controllers/NotebookController.js @@ -0,0 +1,174 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define([ + 'vue', + './EntryController', + './EmbedController', + '../../res/templates/notebook.html', + '../../res/templates/entry.html', + '../../res/templates/embed.html' +], +function ( + Vue, + EntryController, + EmbedController, + NotebookTemplate, + EntryTemplate, + EmbedTemplate +) { + + function NotebookController(openmct, domainObject) { + this.openmct = openmct; + this.domainObject = domainObject; + this.entrySearch = ''; + this.objectService = openmct.$injector.get('objectService'); + this.actionService = openmct.$injector.get('actionService'); + + this.show = this.show.bind(this); + this.destroy = this.destroy.bind(this); + this.newEntry = this.newEntry.bind(this); + this.entryPosById = this.entryPosById.bind(this); + } + + NotebookController.prototype.initializeVue = function (container) { + var self = this, + entryController = new EntryController(this.openmct, this.domainObject), + embedController = new EmbedController(this.openmct, this.domainObject); + + this.container = container; + + var notebookEmbed = { + props:['embed', 'entry'], + template: EmbedTemplate, + data: embedController.exposedData, + methods: embedController.exposedMethods(), + beforeMount: embedController.populateActionMenu(self.objectService, self.actionService) + }; + + var entryComponent = { + props:['entry'], + template: EntryTemplate, + components: { + 'notebook-embed': notebookEmbed + }, + data: entryController.exposedData, + methods: entryController.exposedMethods(), + mounted: self.focusOnEntry + }; + + var notebookVue = Vue.extend({ + template: NotebookTemplate, + components: { + 'notebook-entry': entryComponent + }, + data: function () { + return { + entrySearch: self.entrySearch, + showTime: '0', + sortEntries: '-createdOn', + entries: self.domainObject.entries, + currentEntryValue: '' + }; + }, + methods: { + search: function (event) { + if (event.target.value) { + this.entrySearch = event.target.value; + } + }, + newEntry: self.newEntry, + filterBySearch: self.filterBySearch + } + }); + + this.NotebookVue = new notebookVue(); + container.appendChild(this.NotebookVue.$mount().$el); + }; + + NotebookController.prototype.newEntry = function (event) { + + var entries = this.domainObject.entries, + lastEntryIndex = entries.length - 1, + lastEntry = entries[lastEntryIndex], + date = Date.now(); + + if (lastEntry === undefined || lastEntry.text || lastEntry.embeds.length) { + var createdEntry = {'id': 'entry-' + date, 'createdOn': date, 'embeds':[]}; + + entries.push(createdEntry); + this.openmct.objects.mutate(this.domainObject, 'entries', entries); + } else { + lastEntry.createdOn = date; + + this.openmct.objects.mutate(this.domainObject, 'entries[entries.length-1]', lastEntry); + this.focusOnEntry.bind(this.NotebookVue.$children[lastEntryIndex])(); + } + + this.entrySearch = ''; + }; + + NotebookController.prototype.entryPosById = function (entryId) { + var foundId = -1; + + this.domainObject.entries.forEach(function (element, index) { + if (element.id === entryId) { + foundId = index; + return; + } + }); + + return foundId; + }; + + NotebookController.prototype.focusOnEntry = function () { + if (!this.entry.text) { + this.$refs.contenteditable.focus(); + } + }; + + NotebookController.prototype.filterBySearch = function (entryArray, filterString) { + if (filterString) { + var lowerCaseFilterString = filterString.toLowerCase(); + + return entryArray.filter(function (entry) { + if (entry.text) { + return entry.text.toLowerCase().includes(lowerCaseFilterString); + } else { + return false; + } + }); + } else { + return entryArray; + } + }; + + NotebookController.prototype.show = function (container) { + this.initializeVue(container); + }; + + NotebookController.prototype.destroy = function (container) { + this.NotebookVue.$destroy(true); + }; + + return NotebookController; +}); diff --git a/platform/features/notebook/src/controllers/SelectSnapshotController.js b/src/plugins/notebook/src/controllers/SelectSnapshotController.js similarity index 100% rename from platform/features/notebook/src/controllers/SelectSnapshotController.js rename to src/plugins/notebook/src/controllers/SelectSnapshotController.js diff --git a/platform/features/notebook/src/directives/EntryDnd.js b/src/plugins/notebook/src/directives/EntryDnd.js similarity index 70% rename from platform/features/notebook/src/directives/EntryDnd.js rename to src/plugins/notebook/src/directives/EntryDnd.js index 49612ba2b7..9dc0509051 100644 --- a/platform/features/notebook/src/directives/EntryDnd.js +++ b/src/plugins/notebook/src/directives/EntryDnd.js @@ -31,32 +31,34 @@ define(['zepto'], function ($) { 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': '' - }] - }); + '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': '' - }] + 'embeds': [{'type': selectedObject.getId(), + 'id': '' + Date.now(), + 'cssClass': cssClass, + 'name': selectedModel.name, + 'snapshot': '' + }] }; }); } @@ -75,13 +77,15 @@ define(['zepto'], function ($) { $scope.domainObject.useCapability('mutation', function (model) { model.entries[entryId].embeds.push({'type': selectedObject.getId(), - 'id': '' + Date.now(), - 'cssClass': cssClass, - 'name': selectedModel.name, - 'snapshot': '' - }); + 'id': '' + Date.now(), + 'cssClass': cssClass, + 'name': selectedModel.name, + 'snapshot': '' + }); }); + embedId = $scope.domainObject.model.entries[entryId].embeds.length - 1; + if (selectedObject) { e.preventDefault(); diff --git a/platform/features/notebook/src/directives/MCTSnapshot.js b/src/plugins/notebook/src/directives/MCTSnapshot.js similarity index 100% rename from platform/features/notebook/src/directives/MCTSnapshot.js rename to src/plugins/notebook/src/directives/MCTSnapshot.js diff --git a/platform/features/notebook/src/controllers/LayoutNotebookController.js b/src/plugins/notebook/src/utils/SnapshotOverlay.js similarity index 50% rename from platform/features/notebook/src/controllers/LayoutNotebookController.js rename to src/plugins/notebook/src/utils/SnapshotOverlay.js index c516f1dbb1..b0af26c048 100644 --- a/platform/features/notebook/src/controllers/LayoutNotebookController.js +++ b/src/plugins/notebook/src/utils/SnapshotOverlay.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2017, United States Government + * Open MCT, Copyright (c) 2014-2018, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -20,35 +20,47 @@ * 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. - **/ +define([ + 'vue', + '../../res/templates/viewSnapshot.html' +], function ( + Vue, + snapshotOverlayTemplate +) { + function SnapshotOverlay (embedObject, formatTime) { + this.embedObject = embedObject; - 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(); + this.snapshotOverlayVue = new Vue({ + template: snapshotOverlayTemplate, + data: function () { + return { + embed: embedObject }; + }, + methods: { + close: this.close.bind(this), + formatTime: formatTime } - } + }); - return LayoutNotebookController; + this.open(); } -); + SnapshotOverlay.prototype.open = function () { + this.overlay = document.createElement('div'); + this.overlay.classList.add('abs'); + + document.body.appendChild(this.overlay); + + this.overlay.appendChild(this.snapshotOverlayVue.$mount().$el); + }; + + SnapshotOverlay.prototype.close = function (event) { + event.stopPropagation(); + this.snapshotOverlayVue.$destroy(); + this.overlay.parentNode.removeChild(this.overlay); + }; + + return SnapshotOverlay; +}); diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index e404e8ebca..84922015ba 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -27,14 +27,14 @@ define([ './autoflow/AutoflowTabularPlugin', './timeConductor/plugin', '../../example/imagery/plugin', - '../../platform/features/notebook/bundle', '../../platform/import-export/bundle', './summaryWidget/plugin', './URLIndicatorPlugin/URLIndicatorPlugin', './telemetryMean/plugin', './plot/plugin', './telemetryTable/plugin', - './staticRootPlugin/plugin' + './staticRootPlugin/plugin', + './notebook/plugin' ], function ( _, UTCTimeSystem, @@ -42,19 +42,18 @@ define([ AutoflowPlugin, TimeConductorPlugin, ExampleImagery, - Notebook, ImportExport, SummaryWidget, URLIndicatorPlugin, TelemetryMean, PlotPlugin, TelemetryTablePlugin, - StaticRootPlugin + StaticRootPlugin, + Notebook ) { var bundleMap = { LocalStorage: 'platform/persistence/local', - MyItems: 'platform/features/my-items', - Notebook: 'platform/features/notebook' + MyItems: 'platform/features/my-items' }; var plugins = _.mapValues(bundleMap, function (bundleName, pluginName) { @@ -155,10 +154,11 @@ define([ plugins.ExampleImagery = ExampleImagery; plugins.Plot = PlotPlugin; plugins.TelemetryTable = TelemetryTablePlugin; - + plugins.SummaryWidget = SummaryWidget; plugins.TelemetryMean = TelemetryMean; plugins.URLIndicator = URLIndicatorPlugin; + plugins.Notebook = Notebook; return plugins; }); diff --git a/src/styles-new/legacy-styles.scss b/src/styles-new/legacy-styles.scss index 14c816fa04..44547f5bcc 100644 --- a/src/styles-new/legacy-styles.scss +++ b/src/styles-new/legacy-styles.scss @@ -75,4 +75,5 @@ //!********************************* APP STARTUP *! //@import "../styles/app-start"; -@import "../styles/conductor/time-conductor-snow"; \ No newline at end of file +@import "../styles/conductor/time-conductor-snow"; +@import "../styles/notebook/notebook-snow"; \ No newline at end of file