diff --git a/src/MCT.js b/src/MCT.js index 1d97e19a3a..e747cc992e 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -223,6 +223,8 @@ define([ this.Dialog = api.Dialog; + this.editor = new api.EditorAPI.default(this); + this.legacyRegistry = defaultRegistry; this.install(this.plugins.Plot()); this.install(this.plugins.TelemetryTable()); @@ -310,13 +312,17 @@ define([ this.$injector.get('objectService'); var appLayout = new Vue({ - mixins: [Layout.default], + components: { + 'Layout': Layout.default + }, provide: { openmct: this - } + }, + template: '' }); domElement.appendChild(appLayout.$mount().$el); - this.layout = appLayout; + + this.layout = appLayout.$refs.layout; Browse(this); this.router.start(); this.emit('start'); diff --git a/src/api/Editor.js b/src/api/Editor.js new file mode 100644 index 0000000000..f5590b949f --- /dev/null +++ b/src/api/Editor.js @@ -0,0 +1,83 @@ + +/***************************************************************************** + * 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. + *****************************************************************************/ + +import EventEmitter from 'EventEmitter'; + +export default class Editor extends EventEmitter { + constructor(openmct) { + super(); + this.editing = false; + this.openmct = openmct; + } + + /** + * Initiate an editing session. This will start a transaction during + * which any persist operations will be deferred until either save() + * or finish() are called. + */ + edit() { + this.editing = true; + this.getTransactionService().startTransaction(); + this.emit('isEditing', true); + } + + /** + * @returns true if the application is in edit mode, false otherwise. + */ + isEditing() { + return this.editing; + } + + /** + * Save any unsaved changes from this editing session. This will + * end the current transaction. + */ + save() { + return this.getTransactionService().commit().then((result)=>{ + this.editing = false; + this.emit('isEditing', false); + return result + }).catch((error)=>{ + throw error; + }); + } + + /** + * End the currently active transaction and discard unsaved changes. + */ + cancel() { + this.getTransactionService().cancel(); + this.editing = false; + this.emit('isEditing', false); + } + + /** + * @private + */ + getTransactionService() { + if (!this.transactionService) { + this.transactionService = this.openmct.$injector.get('transactionService'); + } + return this.transactionService; + } +} diff --git a/src/api/api.js b/src/api/api.js index f29a13f0c0..82a6464ff8 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -28,7 +28,9 @@ define([ './ui/Dialog', './ui/GestureAPI', './telemetry/TelemetryAPI', - './indicators/IndicatorAPI' + './indicators/IndicatorAPI', + './Editor' + ], function ( TimeAPI, ObjectAPI, @@ -37,7 +39,8 @@ define([ Dialog, GestureAPI, TelemetryAPI, - IndicatorAPI + IndicatorAPI, + EditorAPI ) { return { TimeAPI: TimeAPI, @@ -47,6 +50,7 @@ define([ TypeRegistry: TypeRegistry, GestureAPI: GestureAPI, TelemetryAPI: TelemetryAPI, - IndicatorAPI: IndicatorAPI + IndicatorAPI: IndicatorAPI, + EditorAPI: EditorAPI }; }); diff --git a/src/plugins/telemetryTable/TableConfigurationViewProvider.js b/src/plugins/telemetryTable/TableConfigurationViewProvider.js index fe21c1c262..1460be1262 100644 --- a/src/plugins/telemetryTable/TableConfigurationViewProvider.js +++ b/src/plugins/telemetryTable/TableConfigurationViewProvider.js @@ -33,30 +33,6 @@ define([ ) { function TableConfigurationViewProvider(openmct) { - let instantiateService; - - function isBeingEdited(object) { - let oldStyleObject = getOldStyleObject(object); - - return oldStyleObject.hasCapability('editor') && - oldStyleObject.getCapability('editor').inEditContext(); - } - - function getOldStyleObject(object) { - let oldFormatModel = objectUtils.toOldFormat(object); - let oldFormatId = objectUtils.makeKeyString(object.identifier); - - return instantiate(oldFormatModel, oldFormatId); - } - - function instantiate(model, id) { - if (!instantiateService) { - instantiateService = openmct.$injector.get('instantiate'); - } - return instantiateService(model, id); - } - - return { key: 'table-configuration', name: 'Telemetry Table Configuration', @@ -65,8 +41,7 @@ define([ return false; } let object = selection[0].context.item; - return object.type === 'table' && - isBeingEdited(object); + return object.type === 'table'; }, view: function (selection) { let component; @@ -86,7 +61,7 @@ define([ el: element }); }, - destroy: function (element) { + destroy: function () { component.$destroy(); component = undefined; } diff --git a/src/plugins/telemetryTable/TelemetryTableConfiguration.js b/src/plugins/telemetryTable/TelemetryTableConfiguration.js index e29a9715c9..c6d5cb6219 100644 --- a/src/plugins/telemetryTable/TelemetryTableConfiguration.js +++ b/src/plugins/telemetryTable/TelemetryTableConfiguration.js @@ -23,10 +23,10 @@ define([ 'lodash', 'EventEmitter', - './TelemetryTableColumn', + './TelemetryTableColumn' ], function (_, EventEmitter, TelemetryTableColumn) { - class TelemetryTableConfiguration extends EventEmitter{ + class TelemetryTableConfiguration extends EventEmitter { constructor(domainObject, openmct) { super(); @@ -37,6 +37,8 @@ define([ this.addColumnsForObject = this.addColumnsForObject.bind(this); this.removeColumnsForObject = this.removeColumnsForObject.bind(this); this.objectMutated = this.objectMutated.bind(this); + //Make copy of configuration, otherwise change detection is impossible if shared instance is being modified. + this.oldConfiguration = JSON.parse(JSON.stringify(this.getConfiguration())); this.unlistenFromMutation = openmct.objects.observe(domainObject, '*', this.objectMutated); } @@ -56,11 +58,11 @@ define([ * @param {*} object */ objectMutated(object) { - let oldConfiguration = this.domainObject.configuration; - //Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible. - this.domainObject = JSON.parse(JSON.stringify(object)); - if (!_.eq(object.configuration, oldConfiguration)){ + this.domainObject = object; + if (!_.eq(object.configuration, this.oldConfiguration)) { + //Make copy of configuration, otherwise change detection is impossible if shared instance is being modified. + this.oldConfiguration = JSON.parse(JSON.stringify(this.getConfiguration())); this.emit('change', object.configuration); } } diff --git a/src/plugins/telemetryTable/components/table-configuration.vue b/src/plugins/telemetryTable/components/table-configuration.vue index 57f6152e79..18946993f0 100644 --- a/src/plugins/telemetryTable/components/table-configuration.vue +++ b/src/plugins/telemetryTable/components/table-configuration.vue @@ -1,14 +1,12 @@ @@ -21,6 +19,7 @@ export default { data() { return { headers: {}, + isEditing: this.openmct.editor.isEditing(), configuration: this.tableConfiguration.getConfiguration() } }, @@ -41,11 +40,14 @@ export default { removeObject(objectIdentifier) { this.tableConfiguration.removeColumnsForObject(objectIdentifier, true); this.updateHeaders(this.tableConfiguration.getAllHeaders()); + }, + toggleEdit(isEditing) { + this.isEditing = isEditing; } - }, mounted() { this.unlisteners = []; + this.openmct.editor.on('isEditing', this.toggleEdit); let compositionCollection = this.openmct.composition.get(this.tableConfiguration.domainObject); compositionCollection.load() @@ -62,6 +64,7 @@ export default { }, destroyed() { this.tableConfiguration.destroy(); + this.openmct.editor.off('isEditing', this.toggleEdit); this.unlisteners.forEach((unlisten) => unlisten()); } } diff --git a/src/selection/Selection.js b/src/selection/Selection.js index 6f294c93b9..3e9cbeb542 100644 --- a/src/selection/Selection.js +++ b/src/selection/Selection.js @@ -58,7 +58,7 @@ define(['EventEmitter'], function (EventEmitter) { this.selected[0].element.classList.remove('s-selected'); } - if (this.selected[1]) { + if (this.selected[1] && this.selected[1].element) { this.selected[1].element.classList.remove('s-selected-parent'); } @@ -66,7 +66,7 @@ define(['EventEmitter'], function (EventEmitter) { selectable[0].element.classList.add('s-selected'); } - if (selectable[1]) { + if (selectable[1] && selectable[1].element) { selectable[1].element.classList.add('s-selected-parent'); } @@ -132,7 +132,7 @@ define(['EventEmitter'], function (EventEmitter) { } return function () { - element.removeEventListener('click', capture); + element.removeEventListener('click', capture, true); element.removeEventListener('click', selectCapture); if (unlisten) { diff --git a/src/ui/components/inspector/InspectorView.vue b/src/ui/components/inspector/InspectorView.vue index 02830871dc..f96119e95b 100644 --- a/src/ui/components/inspector/InspectorView.vue +++ b/src/ui/components/inspector/InspectorView.vue @@ -1,5 +1,6 @@