mirror of
https://github.com/nasa/openmct.git
synced 2025-06-29 12:13:03 +00:00
Compare commits
16 Commits
angular-up
...
mutation-o
Author | SHA1 | Date | |
---|---|---|---|
f8884cef62 | |||
3262b810b3 | |||
790a929d66 | |||
2920e58b07 | |||
1613975048 | |||
dae58e0ad9 | |||
a5826f5d45 | |||
4480956bab | |||
dd4d55b422 | |||
705ec5b753 | |||
48177082f1 | |||
4c65062ce9 | |||
c4d9b1cf41 | |||
56dbbd894a | |||
f3d14be034 | |||
018f3e7749 |
@ -215,7 +215,7 @@ define([
|
|||||||
* @memberof module:openmct.MCT#
|
* @memberof module:openmct.MCT#
|
||||||
* @name objects
|
* @name objects
|
||||||
*/
|
*/
|
||||||
this.objects = new api.ObjectAPI();
|
this.objects = new api.ObjectAPI(this.types);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for retrieving and interpreting telemetry data associated
|
* An interface for retrieving and interpreting telemetry data associated
|
||||||
|
@ -60,7 +60,8 @@ define([
|
|||||||
var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId()),
|
var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId()),
|
||||||
keystring = utils.makeKeyString(newStyleObject.identifier);
|
keystring = utils.makeKeyString(newStyleObject.identifier);
|
||||||
|
|
||||||
this.eventEmitter.emit(keystring + ":*", newStyleObject);
|
this.eventEmitter.emit(keystring + ':$_synchronize_model', newStyleObject);
|
||||||
|
this.eventEmitter.emit(keystring + ':*', newStyleObject);
|
||||||
this.eventEmitter.emit('mutation', newStyleObject);
|
this.eventEmitter.emit('mutation', newStyleObject);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'lodash'
|
'lodash',
|
||||||
|
'../objects/MutableDomainObject'
|
||||||
], function (
|
], function (
|
||||||
_
|
_,
|
||||||
|
MutableDomainObject
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* A CompositionCollection represents the list of domain objects contained
|
* A CompositionCollection represents the list of domain objects contained
|
||||||
@ -60,6 +62,17 @@ define([
|
|||||||
};
|
};
|
||||||
this.onProviderAdd = this.onProviderAdd.bind(this);
|
this.onProviderAdd = this.onProviderAdd.bind(this);
|
||||||
this.onProviderRemove = this.onProviderRemove.bind(this);
|
this.onProviderRemove = this.onProviderRemove.bind(this);
|
||||||
|
this.mutables = {};
|
||||||
|
|
||||||
|
if (this.domainObject instanceof MutableDomainObject.default &&
|
||||||
|
this.publicAPI.objects.isMutable(this.domainObject)) {
|
||||||
|
this.returnMutables = true;
|
||||||
|
this.domainObject.$observe('$_destroy', () => {
|
||||||
|
Object.values(this.mutables).forEach(mutable => {
|
||||||
|
mutable.$destroy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,9 +87,6 @@ define([
|
|||||||
if (!this.listeners[event]) {
|
if (!this.listeners[event]) {
|
||||||
throw new Error('Event not supported by composition: ' + event);
|
throw new Error('Event not supported by composition: ' + event);
|
||||||
}
|
}
|
||||||
if (!this.mutationListener) {
|
|
||||||
this._synchronize();
|
|
||||||
}
|
|
||||||
if (this.provider.on && this.provider.off) {
|
if (this.provider.on && this.provider.off) {
|
||||||
if (event === 'add') {
|
if (event === 'add') {
|
||||||
this.provider.on(
|
this.provider.on(
|
||||||
@ -132,8 +142,6 @@ define([
|
|||||||
|
|
||||||
this.listeners[event].splice(index, 1);
|
this.listeners[event].splice(index, 1);
|
||||||
if (this.listeners[event].length === 0) {
|
if (this.listeners[event].length === 0) {
|
||||||
this._destroy();
|
|
||||||
|
|
||||||
// Remove provider listener if this is the last callback to
|
// Remove provider listener if this is the last callback to
|
||||||
// be removed.
|
// be removed.
|
||||||
if (this.provider.off && this.provider.on) {
|
if (this.provider.off && this.provider.on) {
|
||||||
@ -182,6 +190,13 @@ define([
|
|||||||
}
|
}
|
||||||
this.provider.add(this.domainObject, child.identifier);
|
this.provider.add(this.domainObject, child.identifier);
|
||||||
} else {
|
} else {
|
||||||
|
if (this.returnMutables && this.publicAPI.objects.isMutable(child)) {
|
||||||
|
let keyString = this.publicAPI.objects.makeKeyString(child.identifier);
|
||||||
|
if (this.publicAPI.objects.isMutable(child)) {
|
||||||
|
child = this.publicAPI.objects.mutable(child);
|
||||||
|
this.mutables[keyString] = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.emit('add', child);
|
this.emit('add', child);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -195,6 +210,7 @@ define([
|
|||||||
* @name load
|
* @name load
|
||||||
*/
|
*/
|
||||||
CompositionCollection.prototype.load = function () {
|
CompositionCollection.prototype.load = function () {
|
||||||
|
this.cleanUpMutables();
|
||||||
return this.provider.load(this.domainObject)
|
return this.provider.load(this.domainObject)
|
||||||
.then(function (children) {
|
.then(function (children) {
|
||||||
return Promise.all(children.map((c) => this.publicAPI.objects.get(c)));
|
return Promise.all(children.map((c) => this.publicAPI.objects.get(c)));
|
||||||
@ -225,6 +241,13 @@ define([
|
|||||||
if (!skipMutate) {
|
if (!skipMutate) {
|
||||||
this.provider.remove(this.domainObject, child.identifier);
|
this.provider.remove(this.domainObject, child.identifier);
|
||||||
} else {
|
} else {
|
||||||
|
if (this.returnMutables && this.publicAPI.objects.isMutable(child)) {
|
||||||
|
let keyString = this.publicAPI.objects.makeKeyString(child);
|
||||||
|
if (this.mutables[keyString] !== undefined) {
|
||||||
|
this.mutables[keyString].$destroy();
|
||||||
|
delete this.mutables[keyString];
|
||||||
|
}
|
||||||
|
}
|
||||||
this.emit('remove', child);
|
this.emit('remove', child);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -271,19 +294,6 @@ define([
|
|||||||
this.remove(child, true);
|
this.remove(child, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
CompositionCollection.prototype._synchronize = function () {
|
|
||||||
this.mutationListener = this.publicAPI.objects.observe(this.domainObject, '*', (newDomainObject) => {
|
|
||||||
this.domainObject = JSON.parse(JSON.stringify(newDomainObject));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
CompositionCollection.prototype._destroy = function () {
|
|
||||||
if (this.mutationListener) {
|
|
||||||
this.mutationListener();
|
|
||||||
delete this.mutationListener;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit events.
|
* Emit events.
|
||||||
* @private
|
* @private
|
||||||
@ -298,5 +308,11 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CompositionCollection.prototype.cleanUpMutables = function () {
|
||||||
|
Object.values(this.mutables).forEach(mutable => {
|
||||||
|
mutable.$destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return CompositionCollection;
|
return CompositionCollection;
|
||||||
});
|
});
|
||||||
|
105
src/api/objects/MutableDomainObject.js
Normal file
105
src/api/objects/MutableDomainObject.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2019, 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 _ from 'lodash';
|
||||||
|
import utils from './object-utils.js';
|
||||||
|
|
||||||
|
const ANY_OBJECT_EVENT = 'mutation';
|
||||||
|
|
||||||
|
class MutableDomainObject {
|
||||||
|
constructor(eventEmitter) {
|
||||||
|
Object.defineProperties(this, {
|
||||||
|
_eventEmitter: {
|
||||||
|
value: eventEmitter,
|
||||||
|
// Property should not be serialized
|
||||||
|
enumerable: false
|
||||||
|
},
|
||||||
|
_observers: {
|
||||||
|
value: [],
|
||||||
|
// Property should not be serialized
|
||||||
|
enumerable: false
|
||||||
|
},
|
||||||
|
isMutable: {
|
||||||
|
value: true,
|
||||||
|
// Property should not be serialized
|
||||||
|
enumerable: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$observe(path, callback) {
|
||||||
|
var fullPath = qualifiedEventName(this, path);
|
||||||
|
var eventOff =
|
||||||
|
this._eventEmitter.off.bind(this._eventEmitter, fullPath, callback);
|
||||||
|
|
||||||
|
this._eventEmitter.on(fullPath, callback);
|
||||||
|
this._observers.push(eventOff);
|
||||||
|
|
||||||
|
return eventOff;
|
||||||
|
}
|
||||||
|
$set(path, value) {
|
||||||
|
_.set(this, path, value);
|
||||||
|
_.set(this, 'modified', Date.now());
|
||||||
|
|
||||||
|
//Emit secret synchronization event first, so that all objects are in sync before subsequent events fired.
|
||||||
|
this._eventEmitter.emit(qualifiedEventName(this, '$_synchronize_model'), this);
|
||||||
|
|
||||||
|
//Emit a general "any object" event
|
||||||
|
this._eventEmitter.emit(ANY_OBJECT_EVENT, this);
|
||||||
|
//Emit wildcard event, with path so that callback knows what changed
|
||||||
|
this._eventEmitter.emit(qualifiedEventName(this, '*'), this, path, value);
|
||||||
|
|
||||||
|
//Emit events specific to properties affected
|
||||||
|
let parentPropertiesList = path.split('.');
|
||||||
|
for (let index = parentPropertiesList.length; index > 0; index--) {
|
||||||
|
let parentPropertyPath = parentPropertiesList.slice(0, index).join('.');
|
||||||
|
this._eventEmitter.emit(qualifiedEventName(this, parentPropertyPath), _.get(this, parentPropertyPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Emit events for listeners of child properties when parent changes.
|
||||||
|
// Do it at observer time - also register observers for parent attribute path.
|
||||||
|
}
|
||||||
|
$destroy() {
|
||||||
|
this._observers.forEach(observer => observer());
|
||||||
|
delete this._eventEmitter;
|
||||||
|
delete this._observers;
|
||||||
|
this._eventEmitter.emit(qualifiedEventName(this, '$_destroy'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static createMutable(object, mutationTopic) {
|
||||||
|
let mutable = Object.create(new MutableDomainObject(mutationTopic));
|
||||||
|
Object.assign(mutable, object);
|
||||||
|
mutable.$observe('$_synchronize_model', (updatedObject) => {
|
||||||
|
let clone = JSON.parse(JSON.stringify(updatedObject));
|
||||||
|
let deleted = _.difference(Object.keys(updatedObject), Object.keys(updatedObject));
|
||||||
|
deleted.forEach((propertyName) => delete mutable[propertyName]);
|
||||||
|
Object.assign(mutable, clone);
|
||||||
|
})
|
||||||
|
return mutable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function qualifiedEventName(object, eventName) {
|
||||||
|
var keystring = utils.makeKeyString(object.identifier);
|
||||||
|
|
||||||
|
return [keystring, eventName].join(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MutableDomainObject;
|
@ -1,102 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* 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([
|
|
||||||
'./object-utils.js',
|
|
||||||
'lodash'
|
|
||||||
], function (
|
|
||||||
utils,
|
|
||||||
_
|
|
||||||
) {
|
|
||||||
var ANY_OBJECT_EVENT = "mutation";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The MutableObject wraps a DomainObject and provides getters and
|
|
||||||
* setters for
|
|
||||||
* @param eventEmitter
|
|
||||||
* @param object
|
|
||||||
* @interface MutableObject
|
|
||||||
*/
|
|
||||||
function MutableObject(eventEmitter, object) {
|
|
||||||
this.eventEmitter = eventEmitter;
|
|
||||||
this.object = object;
|
|
||||||
this.unlisteners = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function qualifiedEventName(object, eventName) {
|
|
||||||
var keystring = utils.makeKeyString(object.identifier);
|
|
||||||
|
|
||||||
return [keystring, eventName].join(':');
|
|
||||||
}
|
|
||||||
|
|
||||||
MutableObject.prototype.stopListening = function () {
|
|
||||||
this.unlisteners.forEach(function (unlisten) {
|
|
||||||
unlisten();
|
|
||||||
});
|
|
||||||
this.unlisteners = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Observe changes to this domain object.
|
|
||||||
* @param {string} path the property to observe
|
|
||||||
* @param {Function} callback a callback to invoke when new values for
|
|
||||||
* this property are observed
|
|
||||||
* @method on
|
|
||||||
* @memberof module:openmct.MutableObject#
|
|
||||||
*/
|
|
||||||
MutableObject.prototype.on = function (path, callback) {
|
|
||||||
var fullPath = qualifiedEventName(this.object, path);
|
|
||||||
var eventOff =
|
|
||||||
this.eventEmitter.off.bind(this.eventEmitter, fullPath, callback);
|
|
||||||
|
|
||||||
this.eventEmitter.on(fullPath, callback);
|
|
||||||
this.unlisteners.push(eventOff);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modify this domain object.
|
|
||||||
* @param {string} path the property to modify
|
|
||||||
* @param {*} value the new value for this property
|
|
||||||
* @method set
|
|
||||||
* @memberof module:openmct.MutableObject#
|
|
||||||
*/
|
|
||||||
MutableObject.prototype.set = function (path, value) {
|
|
||||||
_.set(this.object, path, value);
|
|
||||||
_.set(this.object, 'modified', Date.now());
|
|
||||||
|
|
||||||
var handleRecursiveMutation = function (newObject) {
|
|
||||||
this.object = newObject;
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
//Emit wildcard event
|
|
||||||
this.eventEmitter.emit(qualifiedEventName(this.object, '*'), this.object);
|
|
||||||
//Emit a general "any object" event
|
|
||||||
this.eventEmitter.emit(ANY_OBJECT_EVENT, this.object);
|
|
||||||
|
|
||||||
this.eventEmitter.on(qualifiedEventName(this.object, '*'), handleRecursiveMutation);
|
|
||||||
//Emit event specific to property
|
|
||||||
this.eventEmitter.emit(qualifiedEventName(this.object, path), value);
|
|
||||||
this.eventEmitter.off(qualifiedEventName(this.object, '*'), handleRecursiveMutation);
|
|
||||||
};
|
|
||||||
|
|
||||||
return MutableObject;
|
|
||||||
});
|
|
@ -23,14 +23,14 @@
|
|||||||
define([
|
define([
|
||||||
'lodash',
|
'lodash',
|
||||||
'./object-utils',
|
'./object-utils',
|
||||||
'./MutableObject',
|
'./MutableDomainObject',
|
||||||
'./RootRegistry',
|
'./RootRegistry',
|
||||||
'./RootObjectProvider',
|
'./RootObjectProvider',
|
||||||
'EventEmitter'
|
'EventEmitter'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
utils,
|
utils,
|
||||||
MutableObject,
|
MutableDomainObject,
|
||||||
RootRegistry,
|
RootRegistry,
|
||||||
RootObjectProvider,
|
RootObjectProvider,
|
||||||
EventEmitter
|
EventEmitter
|
||||||
@ -43,7 +43,8 @@ define([
|
|||||||
* @memberof module:openmct
|
* @memberof module:openmct
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ObjectAPI() {
|
function ObjectAPI(typeRegistry) {
|
||||||
|
this.typeRegistry = typeRegistry;
|
||||||
this.eventEmitter = new EventEmitter();
|
this.eventEmitter = new EventEmitter();
|
||||||
this.providers = {};
|
this.providers = {};
|
||||||
this.rootRegistry = new RootRegistry();
|
this.rootRegistry = new RootRegistry();
|
||||||
@ -157,6 +158,19 @@ define([
|
|||||||
return provider.get(identifier);
|
return provider.get(identifier);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will fetch object, returning it as a MutableDomainObject IF the object is mutable.
|
||||||
|
*/
|
||||||
|
ObjectAPI.prototype.getAsMutable = function (identifier) {
|
||||||
|
return this.get(identifier).then((object) => {
|
||||||
|
if (this.isMutable(object)) {
|
||||||
|
return this.mutable(object);
|
||||||
|
} else {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ObjectAPI.prototype.delete = function () {
|
ObjectAPI.prototype.delete = function () {
|
||||||
throw new Error('Delete not implemented');
|
throw new Error('Delete not implemented');
|
||||||
};
|
};
|
||||||
@ -177,6 +191,20 @@ define([
|
|||||||
this.rootRegistry.addRoot(key);
|
this.rootRegistry.addRoot(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ObjectAPI.prototype.mutable = function (object) {
|
||||||
|
if (!this.isMutable) {
|
||||||
|
throw `Error: Attempted to create mutable from immutable object ${object.name}`;
|
||||||
|
}
|
||||||
|
return MutableDomainObject.default.createMutable(object, this.eventEmitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectAPI.prototype.isMutable = function (object) {
|
||||||
|
// Checking for mutability is a bit broken right now. This is an 80% solution,
|
||||||
|
// but does not work in many cases.
|
||||||
|
const type = this.typeRegistry.get(object.type);
|
||||||
|
return type && type.definition.creatable === true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modify a domain object.
|
* Modify a domain object.
|
||||||
* @param {module:openmct.DomainObject} object the object to mutate
|
* @param {module:openmct.DomainObject} object the object to mutate
|
||||||
@ -186,9 +214,17 @@ define([
|
|||||||
* @memberof module:openmct.ObjectAPI#
|
* @memberof module:openmct.ObjectAPI#
|
||||||
*/
|
*/
|
||||||
ObjectAPI.prototype.mutate = function (domainObject, path, value) {
|
ObjectAPI.prototype.mutate = function (domainObject, path, value) {
|
||||||
var mutableObject =
|
if (!this.isMutable(domainObject)) {
|
||||||
new MutableObject(this.eventEmitter, domainObject);
|
throw `Error: Attempted to mutate immutable object ${domainObject.name}`;
|
||||||
return mutableObject.set(path, value);
|
}
|
||||||
|
console.warn('DEPRECATION WARNING: The .mutate() function in the Object API is now deprecated. Please use mutable() ');
|
||||||
|
if (domainObject instanceof MutableDomainObject.default) {
|
||||||
|
domainObject.$set(path, value);
|
||||||
|
} else {
|
||||||
|
let mutable = this.mutable(domainObject);
|
||||||
|
mutable.$set(path, value);
|
||||||
|
mutable.$destroy();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -201,10 +237,14 @@ define([
|
|||||||
* @memberof module:openmct.ObjectAPI#
|
* @memberof module:openmct.ObjectAPI#
|
||||||
*/
|
*/
|
||||||
ObjectAPI.prototype.observe = function (domainObject, path, callback) {
|
ObjectAPI.prototype.observe = function (domainObject, path, callback) {
|
||||||
var mutableObject =
|
console.warn('DEPRECATION WARNING: The .observe() function in the Object API is now deprecated. Please use mutable() ');
|
||||||
new MutableObject(this.eventEmitter, domainObject);
|
if (domainObject instanceof MutableDomainObject.default) {
|
||||||
mutableObject.on(path, callback);
|
return domainObject.$observe(path, callback);
|
||||||
return mutableObject.stopListening.bind(mutableObject);
|
} else {
|
||||||
|
let mutable = this.mutable(domainObject);
|
||||||
|
mutable.$observe(path, callback);
|
||||||
|
return () => mutable.$destroy();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
121
src/api/objects/ObjectAPISpec.js
Normal file
121
src/api/objects/ObjectAPISpec.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2019, 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([
|
||||||
|
'./ObjectAPI'
|
||||||
|
], function (
|
||||||
|
ObjectAPI
|
||||||
|
) {
|
||||||
|
fdescribe('The Object API', function () {
|
||||||
|
describe('Mutable Object', function () {
|
||||||
|
let testObject;
|
||||||
|
let mutable;
|
||||||
|
let objectAPI;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
objectAPI = new ObjectAPI();
|
||||||
|
testObject = {
|
||||||
|
identifier: {
|
||||||
|
namespace: 'test-namespace',
|
||||||
|
key: 'test-key'
|
||||||
|
},
|
||||||
|
otherAttribute: 'other-attribute-value',
|
||||||
|
objectAttribute: {
|
||||||
|
embeddedObject: {
|
||||||
|
embeddedKey: 'embedded-value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mutable = objectAPI.mutable(testObject);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('retains own properties', function () {
|
||||||
|
expect(mutable.hasOwnProperty('identifier')).toBe(true);
|
||||||
|
expect(mutable.hasOwnProperty('otherAttribute')).toBe(true);
|
||||||
|
expect(mutable.identifier).toEqual(testObject.identifier);
|
||||||
|
expect(mutable.otherAttribute).toEqual(testObject.otherAttribute);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is identical to original object when serialized', function () {
|
||||||
|
expect(JSON.stringify(mutable)).toEqual(JSON.stringify(testObject));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is identical to original object when serialized', function () {
|
||||||
|
expect(JSON.stringify(mutable)).toEqual(JSON.stringify(testObject));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('uses events', function () {
|
||||||
|
let testObjectDuplicate;
|
||||||
|
let mutableSecondInstance;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
// Duplicate object to guarantee we are not sharing object instance, which would invalidate test
|
||||||
|
testObjectDuplicate = JSON.parse(JSON.stringify(testObject));
|
||||||
|
mutableSecondInstance = objectAPI.mutable(testObjectDuplicate);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('to stay synchronized when mutated', function () {
|
||||||
|
mutable.$set('otherAttribute', 'new-attribute-value');
|
||||||
|
expect(mutableSecondInstance.otherAttribute).toBe('new-attribute-value');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('to indicate when a property changes', function () {
|
||||||
|
let mutationCallback = jasmine.createSpy('mutation-callback');
|
||||||
|
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
mutationCallback.and.callFake(resolve);
|
||||||
|
mutableSecondInstance.observe('otherAttribute', mutationCallback);
|
||||||
|
mutable.$set('otherAttribute', 'some-new-value')
|
||||||
|
}).then(function () {
|
||||||
|
expect(mutationCallback).toHaveBeenCalledWith('some-new-value');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('to indicate when a child property has changed', function () {
|
||||||
|
let embeddedKeyCallback = jasmine.createSpy('embeddedKeyCallback');
|
||||||
|
let embeddedObjectCallback = jasmine.createSpy('embeddedObjectCallback');
|
||||||
|
let objectAttributeCallback = jasmine.createSpy('objectAttribute');
|
||||||
|
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
objectAttributeCallback.and.callFake(resolve);
|
||||||
|
|
||||||
|
mutableSecondInstance.observe('objectAttribute.embeddedObject.embeddedKey', embeddedKeyCallback);
|
||||||
|
mutableSecondInstance.observe('objectAttribute.embeddedObject', embeddedObjectCallback);
|
||||||
|
mutableSecondInstance.observe('objectAttribute', objectAttributeCallback);
|
||||||
|
|
||||||
|
mutable.$set('objectAttribute.embeddedObject.embeddedKey', 'updated-embedded-value');
|
||||||
|
}).then(function () {
|
||||||
|
expect(embeddedKeyCallback).toHaveBeenCalledWith('updated-embedded-value');
|
||||||
|
expect(embeddedObjectCallback).toHaveBeenCalledWith({
|
||||||
|
embeddedKey: 'updated-embedded-value'
|
||||||
|
});
|
||||||
|
expect(objectAttributeCallback).toHaveBeenCalledWith({
|
||||||
|
embeddedObject: {
|
||||||
|
embeddedKey: 'updated-embedded-value'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<tr @contextmenu.prevent="showContextMenu">
|
<tr @contextmenu.prevent="showContextMenu">
|
||||||
<td>{{name}}</td>
|
<td>{{domainObject.name}}</td>
|
||||||
<td>{{timestamp}}</td>
|
<td>{{timestamp}}</td>
|
||||||
<td :class="valueClass">
|
<td :class="valueClass">
|
||||||
{{value}}
|
{{value}}
|
||||||
@ -50,7 +50,6 @@ export default {
|
|||||||
currentObjectPath.unshift(this.domainObject);
|
currentObjectPath.unshift(this.domainObject);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: this.domainObject.name,
|
|
||||||
timestamp: '---',
|
timestamp: '---',
|
||||||
value: '---',
|
value: '---',
|
||||||
valueClass: '',
|
valueClass: '',
|
||||||
@ -70,9 +69,6 @@ export default {
|
|||||||
this.valueClass = '';
|
this.valueClass = '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateName(name){
|
|
||||||
this.name = name;
|
|
||||||
},
|
|
||||||
updateTimeSystem(timeSystem) {
|
updateTimeSystem(timeSystem) {
|
||||||
this.value = '---';
|
this.value = '---';
|
||||||
this.timestamp = '---';
|
this.timestamp = '---';
|
||||||
@ -98,14 +94,6 @@ export default {
|
|||||||
.telemetry
|
.telemetry
|
||||||
.limitEvaluator(this.domainObject);
|
.limitEvaluator(this.domainObject);
|
||||||
|
|
||||||
this.stopWatchingMutation = openmct
|
|
||||||
.objects
|
|
||||||
.observe(
|
|
||||||
this.domainObject,
|
|
||||||
'*',
|
|
||||||
this.updateName
|
|
||||||
);
|
|
||||||
|
|
||||||
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
||||||
|
|
||||||
this.timestampKey = this.openmct.time.timeSystem().key;
|
this.timestampKey = this.openmct.time.timeSystem().key;
|
||||||
@ -126,7 +114,6 @@ export default {
|
|||||||
.then((array) => this.updateValues(array[array.length - 1]));
|
.then((array) => this.updateValues(array[array.length - 1]));
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.stopWatchingMutation();
|
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
this.openmct.off('timeSystem', this.updateTimeSystem);
|
this.openmct.off('timeSystem', this.updateTimeSystem);
|
||||||
}
|
}
|
||||||
|
@ -176,9 +176,8 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
|
|
||||||
return {
|
return {
|
||||||
internalDomainObject: domainObject,
|
internalDomainObject: this.domainObject,
|
||||||
initSelectIndex: undefined,
|
initSelectIndex: undefined,
|
||||||
selection: []
|
selection: []
|
||||||
};
|
};
|
||||||
@ -566,9 +565,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.unlisten = this.openmct.objects.observe(this.internalDomainObject, '*', function (obj) {
|
|
||||||
this.internalDomainObject = JSON.parse(JSON.stringify(obj));
|
|
||||||
}.bind(this));
|
|
||||||
this.openmct.selection.on('change', this.setSelection);
|
this.openmct.selection.on('change', this.setSelection);
|
||||||
this.initializeItems();
|
this.initializeItems();
|
||||||
this.composition = this.openmct.composition.get(this.internalDomainObject);
|
this.composition = this.openmct.composition.get(this.internalDomainObject);
|
||||||
@ -580,7 +576,6 @@
|
|||||||
this.openmct.selection.off('change', this.setSelection);
|
this.openmct.selection.off('change', this.setSelection);
|
||||||
this.composition.off('add', this.addChild);
|
this.composition.off('add', this.addChild);
|
||||||
this.composition.off('remove', this.removeChild);
|
this.composition.off('remove', this.removeChild);
|
||||||
this.unlisten();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -113,10 +113,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.openmct.objects.get(this.item.identifier)
|
this.openmct.objects.getAsMutable(this.item.identifier)
|
||||||
.then(this.setObject);
|
.then(this.setObject);
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
|
if (this.domainObject.$destroy) {
|
||||||
|
this.domainObject.$destroy();
|
||||||
|
}
|
||||||
if (this.removeSelectable) {
|
if (this.removeSelectable) {
|
||||||
this.removeSelectable();
|
this.removeSelectable();
|
||||||
}
|
}
|
||||||
|
@ -248,12 +248,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.openmct.objects.get(this.item.identifier)
|
this.openmct.objects.getAsMutable(this.item.identifier)
|
||||||
.then(this.setObject);
|
.then(this.setObject);
|
||||||
this.openmct.time.on("bounds", this.refreshData);
|
this.openmct.time.on("bounds", this.refreshData);
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.removeSubscription();
|
this.removeSubscription();
|
||||||
|
this.domainObject.$destroy();
|
||||||
|
|
||||||
if (this.removeSelectable) {
|
if (this.removeSelectable) {
|
||||||
this.removeSelectable();
|
this.removeSelectable();
|
||||||
|
@ -152,24 +152,25 @@
|
|||||||
},
|
},
|
||||||
getGlobalFiltersToRemove(keyString) {
|
getGlobalFiltersToRemove(keyString) {
|
||||||
let filtersToRemove = new Set();
|
let filtersToRemove = new Set();
|
||||||
|
if (this.children[keyString]){
|
||||||
|
this.children[keyString].metadataWithFilters.forEach(metadatum => {
|
||||||
|
let keepFilter = false
|
||||||
|
Object.keys(this.children).forEach(childKeyString => {
|
||||||
|
if (childKeyString !== keyString) {
|
||||||
|
let filterMatched = this.children[childKeyString].metadataWithFilters.some(childMetadatum => childMetadatum.key === metadatum.key);
|
||||||
|
|
||||||
this.children[keyString].metadataWithFilters.forEach(metadatum => {
|
if (filterMatched) {
|
||||||
let keepFilter = false
|
keepFilter = true;
|
||||||
Object.keys(this.children).forEach(childKeyString => {
|
return;
|
||||||
if (childKeyString !== keyString) {
|
}
|
||||||
let filterMatched = this.children[childKeyString].metadataWithFilters.some(childMetadatum => childMetadatum.key === metadatum.key);
|
|
||||||
|
|
||||||
if (filterMatched) {
|
|
||||||
keepFilter = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!keepFilter) {
|
||||||
|
filtersToRemove.add(metadatum.key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
if (!keepFilter) {
|
|
||||||
filtersToRemove.add(metadatum.key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Array.from(filtersToRemove);
|
return Array.from(filtersToRemove);
|
||||||
},
|
},
|
||||||
@ -234,16 +235,14 @@
|
|||||||
this.composition.on('add', this.addChildren);
|
this.composition.on('add', this.addChildren);
|
||||||
this.composition.on('remove', this.removeChildren);
|
this.composition.on('remove', this.removeChildren);
|
||||||
this.composition.load();
|
this.composition.load();
|
||||||
this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
|
this.unobserve = this.providedObject.$observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
|
||||||
this.unobserveGlobalFilters = this.openmct.objects.observe(this.providedObject, 'configuration.globalFilters', this.updateGlobalFilters);
|
this.unobserveGlobalFilters = this.providedObject.$observe(this.providedObject, 'configuration.globalFilters', this.updateGlobalFilters);
|
||||||
this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.composition.off('add', this.addChildren);
|
this.composition.off('add', this.addChildren);
|
||||||
this.composition.off('remove', this.removeChildren);
|
this.composition.off('remove', this.removeChildren);
|
||||||
this.unobserve();
|
this.unobserve();
|
||||||
this.unobserveGlobalFilters();
|
this.unobserveGlobalFilters();
|
||||||
this.unobserveAllMutation();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -629,9 +629,6 @@ export default {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateDomainObject(newDomainObject) {
|
|
||||||
this.domainObject = newDomainObject;
|
|
||||||
},
|
|
||||||
moveContainer(toIndex, event) {
|
moveContainer(toIndex, event) {
|
||||||
let containerId = event.dataTransfer.getData('containerid');
|
let containerId = event.dataTransfer.getData('containerid');
|
||||||
let container = this.containers.filter(c => c.id === containerId)[0];
|
let container = this.containers.filter(c => c.id === containerId)[0];
|
||||||
@ -664,14 +661,10 @@ export default {
|
|||||||
this.composition.on('add', this.addFrame);
|
this.composition.on('add', this.addFrame);
|
||||||
|
|
||||||
this.RemoveAction = new RemoveAction(this.openmct);
|
this.RemoveAction = new RemoveAction(this.openmct);
|
||||||
|
|
||||||
this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.composition.off('remove', this.removeChildObject);
|
this.composition.off('remove', this.removeChildObject);
|
||||||
this.composition.off('add', this.addFrame);
|
this.composition.off('add', this.addFrame);
|
||||||
|
|
||||||
this.unobserve();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -108,7 +108,7 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.frame.domainObjectIdentifier) {
|
if (this.frame.domainObjectIdentifier) {
|
||||||
this.openmct.objects.get(this.frame.domainObjectIdentifier).then((object)=>{
|
this.openmct.objects.getAsMutable(this.frame.domainObjectIdentifier).then((object)=>{
|
||||||
this.setDomainObject(object);
|
this.setDomainObject(object);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -116,6 +116,10 @@ export default {
|
|||||||
this.dragGhost = document.getElementById('js-fl-drag-ghost');
|
this.dragGhost = document.getElementById('js-fl-drag-ghost');
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
if (this.domainObject.$destroy) {
|
||||||
|
this.domainObject.$destroy();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.unsubscribeSelection) {
|
if (this.unsubscribeSelection) {
|
||||||
this.unsubscribeSelection();
|
this.unsubscribeSelection();
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,8 @@ define([
|
|||||||
this.columns = {};
|
this.columns = {};
|
||||||
|
|
||||||
this.removeColumnsForObject = this.removeColumnsForObject.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);
|
this.unlistenFromMutation = domainObject.$observe('configuration', configuration => this.updateListeners(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfiguration() {
|
getConfiguration() {
|
||||||
@ -60,15 +57,8 @@ define([
|
|||||||
* @private
|
* @private
|
||||||
* @param {*} object
|
* @param {*} object
|
||||||
*/
|
*/
|
||||||
objectMutated(object) {
|
updateListeners(configuration) {
|
||||||
//Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
|
this.emit('change', configuration);
|
||||||
this.domainObject = object;
|
|
||||||
//Was it the configuration that changed?
|
|
||||||
if (object.configuration !== undefined && !_.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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addSingleColumnForObject(telemetryObject, column, position) {
|
addSingleColumnForObject(telemetryObject, column, position) {
|
||||||
|
@ -23,11 +23,13 @@
|
|||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'EventEmitter',
|
'EventEmitter',
|
||||||
'lodash'
|
'lodash',
|
||||||
|
'../api/objects/MutableDomainObject.js'
|
||||||
],
|
],
|
||||||
function (
|
function (
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
_
|
_,
|
||||||
|
MutableDomainObject
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,6 +77,10 @@ define(
|
|||||||
this.selected = [selectable];
|
this.selected = [selectable];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.temporaryMutables) {
|
||||||
|
this.temporaryMutables.forEach(mutable => mutable.$destroy());
|
||||||
|
}
|
||||||
|
|
||||||
this.emit('change', this.selected);
|
this.emit('change', this.selected);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -233,12 +239,6 @@ define(
|
|||||||
element.addEventListener('click', capture, true);
|
element.addEventListener('click', capture, true);
|
||||||
element.addEventListener('click', selectCapture);
|
element.addEventListener('click', selectCapture);
|
||||||
|
|
||||||
if (context.item) {
|
|
||||||
var unlisten = this.openmct.objects.observe(context.item, "*", function (newItem) {
|
|
||||||
context.item = newItem;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (select) {
|
if (select) {
|
||||||
element.click();
|
element.click();
|
||||||
}
|
}
|
||||||
@ -246,10 +246,6 @@ define(
|
|||||||
return function () {
|
return function () {
|
||||||
element.removeEventListener('click', capture, true);
|
element.removeEventListener('click', capture, true);
|
||||||
element.removeEventListener('click', selectCapture);
|
element.removeEventListener('click', selectCapture);
|
||||||
|
|
||||||
if (unlisten) {
|
|
||||||
unlisten();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,12 +68,6 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.observedObject) {
|
|
||||||
let removeListener = this.openmct.objects.observe(this.observedObject, '*', (newObject) => {
|
|
||||||
this.observedObject = newObject;
|
|
||||||
});
|
|
||||||
this.$once('hook:destroyed', removeListener);
|
|
||||||
}
|
|
||||||
this.previewAction = new PreviewAction(this.openmct);
|
this.previewAction = new PreviewAction(this.openmct);
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -59,10 +59,6 @@ export default {
|
|||||||
delete this.removeSelectable;
|
delete this.removeSelectable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.composition) {
|
|
||||||
this.composition._destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.openmct.objectViews.off('clearData', this.clearData);
|
this.openmct.objectViews.off('clearData', this.clearData);
|
||||||
},
|
},
|
||||||
invokeEditModeHandler(editMode) {
|
invokeEditModeHandler(editMode) {
|
||||||
@ -80,7 +76,6 @@ export default {
|
|||||||
|
|
||||||
this.composition = this.openmct.composition.get(this.currentObject);
|
this.composition = this.openmct.composition.get(this.currentObject);
|
||||||
if (this.composition) {
|
if (this.composition) {
|
||||||
this.composition._synchronize();
|
|
||||||
this.loadComposition();
|
this.loadComposition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,20 +125,17 @@ export default {
|
|||||||
delete this.removeSelectable;
|
delete this.removeSelectable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.composition) {
|
|
||||||
this.composition._destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentObject = object;
|
this.currentObject = object;
|
||||||
|
|
||||||
|
this.composition = this.openmct.composition.get(this.currentObject);
|
||||||
|
if (this.composition) {
|
||||||
|
this.loadComposition();
|
||||||
|
}
|
||||||
|
|
||||||
if (currentObjectPath) {
|
if (currentObjectPath) {
|
||||||
this.currentObjectPath = currentObjectPath;
|
this.currentObjectPath = currentObjectPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.unlisten = this.openmct.objects.observe(this.currentObject, '*', (mutatedObject) => {
|
|
||||||
this.currentObject = mutatedObject;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.viewKey = viewKey;
|
this.viewKey = viewKey;
|
||||||
this.updateView(immediatelySelect);
|
this.updateView(immediatelySelect);
|
||||||
},
|
},
|
||||||
|
@ -118,9 +118,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.parentObject) {
|
if (this.parentObject) {
|
||||||
this.mutationUnobserver = this.openmct.objects.observe(this.parentObject, '*', (updatedModel) => {
|
|
||||||
this.parentObject = updatedModel;
|
|
||||||
});
|
|
||||||
this.composition = this.openmct.composition.get(this.parentObject);
|
this.composition = this.openmct.composition.get(this.parentObject);
|
||||||
|
|
||||||
if (this.composition) {
|
if (this.composition) {
|
||||||
@ -141,8 +138,7 @@ export default {
|
|||||||
},
|
},
|
||||||
addElement(element) {
|
addElement(element) {
|
||||||
let keyString = this.openmct.objects.makeKeyString(element.identifier);
|
let keyString = this.openmct.objects.makeKeyString(element.identifier);
|
||||||
this.elementsCache[keyString] =
|
this.elementsCache[keyString] = element;
|
||||||
JSON.parse(JSON.stringify(element));
|
|
||||||
this.applySearch(this.currentSearch);
|
this.applySearch(this.currentSearch);
|
||||||
},
|
},
|
||||||
reorderElements() {
|
reorderElements() {
|
||||||
@ -182,9 +178,6 @@ export default {
|
|||||||
this.openmct.editor.off('isEditing', this.setEditState);
|
this.openmct.editor.off('isEditing', this.setEditState);
|
||||||
this.openmct.selection.off('change', this.showSelection);
|
this.openmct.selection.off('change', this.showSelection);
|
||||||
|
|
||||||
if (this.mutationUnobserver) {
|
|
||||||
this.mutationUnobserver();
|
|
||||||
}
|
|
||||||
if (this.compositionUnlistener) {
|
if (this.compositionUnlistener) {
|
||||||
this.compositionUnlistener();
|
this.compositionUnlistener();
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,9 @@ const PLACEHOLDER_OBJECT = {};
|
|||||||
this.showSaveMenu = false;
|
this.showSaveMenu = false;
|
||||||
},
|
},
|
||||||
updateName(event) {
|
updateName(event) {
|
||||||
|
// TODO: handle isssues with contenteditable text escaping.
|
||||||
if (event.target.innerText !== this.domainObject.name && event.target.innerText.match(/\S/)) {
|
if (event.target.innerText !== this.domainObject.name && event.target.innerText.match(/\S/)) {
|
||||||
this.openmct.objects.mutate(this.domainObject, 'name', event.target.innerText);
|
this.domainObject.$set('name', event.target.innerText);
|
||||||
} else {
|
} else {
|
||||||
event.target.innerText = this.domainObject.name;
|
event.target.innerText = this.domainObject.name;
|
||||||
}
|
}
|
||||||
@ -223,20 +224,7 @@ const PLACEHOLDER_OBJECT = {};
|
|||||||
this.isEditing = isEditing;
|
this.isEditing = isEditing;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
domainObject() {
|
|
||||||
if (this.mutationObserver) {
|
|
||||||
this.mutationObserver();
|
|
||||||
}
|
|
||||||
this.mutationObserver = this.openmct.objects.observe(this.domainObject, '*', (domainObject) => {
|
|
||||||
this.domainObject = domainObject;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy: function () {
|
beforeDestroy: function () {
|
||||||
if (this.mutationObserver) {
|
|
||||||
this.mutationObserver();
|
|
||||||
}
|
|
||||||
document.removeEventListener('click', this.closeViewAndSaveMenu);
|
document.removeEventListener('click', this.closeViewAndSaveMenu);
|
||||||
window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
|
window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
|
||||||
}
|
}
|
||||||
|
@ -207,6 +207,7 @@
|
|||||||
getAllChildren() {
|
getAllChildren() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.openmct.objects.get('ROOT')
|
this.openmct.objects.get('ROOT')
|
||||||
|
.then(root => this.openmct.objects.mutable(root))
|
||||||
.then(root => {
|
.then(root => {
|
||||||
return this.openmct.composition.get(root).load()
|
return this.openmct.composition.get(root).load()
|
||||||
})
|
})
|
||||||
@ -223,8 +224,18 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
getFilteredChildren() {
|
getFilteredChildren() {
|
||||||
|
if (this.filteredTreeItems) {
|
||||||
|
this.filteredTreeItems.forEach(filteredTreeItem => filteredTreeItem.destroy());
|
||||||
|
}
|
||||||
|
|
||||||
this.searchService.query(this.searchValue).then(children => {
|
this.searchService.query(this.searchValue).then(children => {
|
||||||
this.filteredTreeItems = children.hits.map(child => {
|
this.filteredTreeItems = children.hits
|
||||||
|
.map(child => {
|
||||||
|
if (this.openmct.objects.isMutable(child)) {
|
||||||
|
this.openmct.objects.mutable(child);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(child => {
|
||||||
|
|
||||||
let context = child.object.getCapability('context'),
|
let context = child.object.getCapability('context'),
|
||||||
object = child.object.useCapability('adapter'),
|
object = child.object.useCapability('adapter'),
|
||||||
|
@ -66,11 +66,7 @@
|
|||||||
// TODO: set isAlias per tree-item
|
// TODO: set isAlias per tree-item
|
||||||
|
|
||||||
this.domainObject = this.node.object;
|
this.domainObject = this.node.object;
|
||||||
let removeListener = this.openmct.objects.observe(this.domainObject, '*', (newObject) => {
|
|
||||||
this.domainObject = newObject;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$once('hook:destroyed', removeListener);
|
|
||||||
if (this.openmct.composition.get(this.node.object)) {
|
if (this.openmct.composition.get(this.node.object)) {
|
||||||
this.hasChildren = true;
|
this.hasChildren = true;
|
||||||
}
|
}
|
||||||
@ -82,6 +78,7 @@
|
|||||||
if (this.composition) {
|
if (this.composition) {
|
||||||
this.composition.off('add', this.addChild);
|
this.composition.off('add', this.addChild);
|
||||||
this.composition.off('remove', this.removeChild);
|
this.composition.off('remove', this.removeChild);
|
||||||
|
this.children.forEach(child => child.object.$destroy());
|
||||||
delete this.composition;
|
delete this.composition;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -101,6 +98,9 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addChild (child) {
|
addChild (child) {
|
||||||
|
if (this.openmct.objects.isMutable(child)) {
|
||||||
|
child = this.openmct.objects.mutable(child);
|
||||||
|
}
|
||||||
this.children.push({
|
this.children.push({
|
||||||
id: this.openmct.objects.makeKeyString(child.identifier),
|
id: this.openmct.objects.makeKeyString(child.identifier),
|
||||||
object: child,
|
object: child,
|
||||||
@ -110,8 +110,16 @@
|
|||||||
},
|
},
|
||||||
removeChild(identifier) {
|
removeChild(identifier) {
|
||||||
let removeId = this.openmct.objects.makeKeyString(identifier);
|
let removeId = this.openmct.objects.makeKeyString(identifier);
|
||||||
|
let removed = [];
|
||||||
this.children = this.children
|
this.children = this.children
|
||||||
.filter(c => c.id !== removeId);
|
.filter(c => {
|
||||||
|
if(c.id !== removeId) {
|
||||||
|
removed.push(c);
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
removed.forEach(removedChild => removedChild.object.$destroy());
|
||||||
},
|
},
|
||||||
finishLoading () {
|
finishLoading () {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
@ -7,13 +7,14 @@ define([
|
|||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
let navigateCall = 0;
|
let navigateCall = 0;
|
||||||
let browseObject;
|
let browseObject;
|
||||||
let unobserve = undefined;
|
let mutable;
|
||||||
let currentObjectPath;
|
let currentObjectPath;
|
||||||
|
|
||||||
openmct.router.route(/^\/browse\/?$/, navigateToFirstChildOfRoot);
|
openmct.router.route(/^\/browse\/?$/, navigateToFirstChildOfRoot);
|
||||||
|
|
||||||
openmct.router.route(/^\/browse\/(.*)$/, (path, results, params) => {
|
openmct.router.route(/^\/browse\/(.*)$/, (path, results, params) => {
|
||||||
let navigatePath = results[1];
|
let navigatePath = results[1];
|
||||||
|
clearMutationListeners();
|
||||||
navigateToPath(navigatePath, params.view);
|
navigateToPath(navigatePath, params.view);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -27,10 +28,17 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
function viewObject(object, viewProvider) {
|
function viewObject(object, viewProvider) {
|
||||||
|
if (mutable) {
|
||||||
|
mutable.$destroy();
|
||||||
|
mutable = undefined;
|
||||||
|
}
|
||||||
|
if (openmct.objects.isMutable(object)) {
|
||||||
|
mutable = openmct.objects.mutable(object);
|
||||||
|
}
|
||||||
currentObjectPath = openmct.router.path;
|
currentObjectPath = openmct.router.path;
|
||||||
|
|
||||||
openmct.layout.$refs.browseObject.show(object, viewProvider.key, true, currentObjectPath);
|
openmct.layout.$refs.browseObject.show(mutable || object, viewProvider.key, true, currentObjectPath);
|
||||||
openmct.layout.$refs.browseBar.domainObject = object;
|
openmct.layout.$refs.browseBar.domainObject = mutable || object;
|
||||||
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,37 +46,26 @@ define([
|
|||||||
navigateCall++;
|
navigateCall++;
|
||||||
let currentNavigation = navigateCall;
|
let currentNavigation = navigateCall;
|
||||||
|
|
||||||
if (unobserve) {
|
|
||||||
unobserve();
|
|
||||||
unobserve = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Split path into object identifiers
|
//Split path into object identifiers
|
||||||
if (!Array.isArray(path)) {
|
if (!Array.isArray(path)) {
|
||||||
path = path.split('/');
|
path = path.split('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathToObjects(path).then((objects)=>{
|
return pathToObjects(path).then((objects) => {
|
||||||
if (currentNavigation !== navigateCall) {
|
if (currentNavigation !== navigateCall) {
|
||||||
return; // Prevent race.
|
return; // Prevent race.
|
||||||
}
|
}
|
||||||
|
|
||||||
let navigatedObject = objects[objects.length - 1];
|
|
||||||
|
|
||||||
// FIXME: this is a hack to support create action, intended to
|
// FIXME: this is a hack to support create action, intended to
|
||||||
// expose the current routed path. We need to rewrite the
|
// expose the current routed path. We need to rewrite the
|
||||||
// navigation service and router to expose a clear and minimal
|
// navigation service and router to expose a clear and minimal
|
||||||
// API for this.
|
// API for this.
|
||||||
openmct.router.path = objects.reverse();
|
objects = objects.reverse();
|
||||||
|
openmct.router.path = objects;
|
||||||
|
|
||||||
unobserve = this.openmct.objects.observe(openmct.router.path[0], '*', (newObject) => {
|
browseObject = objects[0];
|
||||||
openmct.router.path[0] = newObject;
|
openmct.layout.$refs.browseBar.domainObject = browseObject;
|
||||||
});
|
|
||||||
|
|
||||||
openmct.layout.$refs.browseBar.domainObject = navigatedObject;
|
if (!browseObject) {
|
||||||
browseObject = navigatedObject;
|
|
||||||
|
|
||||||
if (!navigatedObject) {
|
|
||||||
openmct.layout.$refs.browseObject.clear();
|
openmct.layout.$refs.browseObject.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -78,12 +75,12 @@ define([
|
|||||||
|
|
||||||
document.title = browseObject.name; //change document title to current object in main view
|
document.title = browseObject.name; //change document title to current object in main view
|
||||||
|
|
||||||
if (currentProvider && currentProvider.canView(navigatedObject)) {
|
if (currentProvider && currentProvider.canView(browseObject)) {
|
||||||
viewObject(navigatedObject, currentProvider);
|
viewObject(browseObject, currentProvider);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let defaultProvider = openmct.objectViews.get(navigatedObject)[0];
|
let defaultProvider = openmct.objectViews.get(browseObject)[0];
|
||||||
if (defaultProvider) {
|
if (defaultProvider) {
|
||||||
openmct.router.updateParams({
|
openmct.router.updateParams({
|
||||||
view: defaultProvider.key
|
view: defaultProvider.key
|
||||||
@ -99,7 +96,7 @@ define([
|
|||||||
|
|
||||||
function pathToObjects(path) {
|
function pathToObjects(path) {
|
||||||
return Promise.all(path.map((keyString)=>{
|
return Promise.all(path.map((keyString)=>{
|
||||||
return openmct.objects.get(keyString);
|
return openmct.objects.getAsMutable(keyString);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,5 +114,15 @@ define([
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearMutationListeners() {
|
||||||
|
if (openmct.router.path !== undefined) {
|
||||||
|
openmct.router.path.forEach((pathObject) => {
|
||||||
|
if (pathObject.$destroy) {
|
||||||
|
pathObject.$destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -81,8 +81,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
observeObject(domainObject, id) {
|
observeObject(domainObject, id) {
|
||||||
let unobserveObject = this.openmct.objects.observe(domainObject, '*', function(newObject) {
|
let unobserveObject = domainObject.$observe('*', function(newObject) {
|
||||||
this.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject));
|
this.domainObjectsById[id].newObject = newObject;
|
||||||
this.updateToolbarAfterMutation();
|
this.updateToolbarAfterMutation();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
this.unObserveObjects.push(unobserveObject);
|
this.unObserveObjects.push(unobserveObject);
|
||||||
|
Reference in New Issue
Block a user