Compare commits
	
		
			16 Commits
		
	
	
		
			4777-plots
			...
			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#
 | 
			
		||||
         * @name objects
 | 
			
		||||
         */
 | 
			
		||||
        this.objects = new api.ObjectAPI();
 | 
			
		||||
        this.objects = new api.ObjectAPI(this.types);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * An interface for retrieving and interpreting telemetry data associated
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,8 @@ define([
 | 
			
		||||
            var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId()),
 | 
			
		||||
                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);
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,11 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    'lodash'
 | 
			
		||||
    'lodash',
 | 
			
		||||
    '../objects/MutableDomainObject'
 | 
			
		||||
], function (
 | 
			
		||||
    _
 | 
			
		||||
    _,
 | 
			
		||||
    MutableDomainObject
 | 
			
		||||
) {
 | 
			
		||||
    /**
 | 
			
		||||
     * A CompositionCollection represents the list of domain objects contained
 | 
			
		||||
@@ -60,6 +62,17 @@ define([
 | 
			
		||||
        };
 | 
			
		||||
        this.onProviderAdd = this.onProviderAdd.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]) {
 | 
			
		||||
            throw new Error('Event not supported by composition: ' + event);
 | 
			
		||||
        }
 | 
			
		||||
        if (!this.mutationListener) {
 | 
			
		||||
            this._synchronize();
 | 
			
		||||
        }
 | 
			
		||||
        if (this.provider.on && this.provider.off) {
 | 
			
		||||
            if (event === 'add') {
 | 
			
		||||
                this.provider.on(
 | 
			
		||||
@@ -132,8 +142,6 @@ define([
 | 
			
		||||
 | 
			
		||||
        this.listeners[event].splice(index, 1);
 | 
			
		||||
        if (this.listeners[event].length === 0) {
 | 
			
		||||
            this._destroy();
 | 
			
		||||
 | 
			
		||||
            // Remove provider listener if this is the last callback to
 | 
			
		||||
            // be removed.
 | 
			
		||||
            if (this.provider.off && this.provider.on) {
 | 
			
		||||
@@ -182,6 +190,13 @@ define([
 | 
			
		||||
            }
 | 
			
		||||
            this.provider.add(this.domainObject, child.identifier);
 | 
			
		||||
        } 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);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@@ -195,6 +210,7 @@ define([
 | 
			
		||||
     * @name load
 | 
			
		||||
     */
 | 
			
		||||
    CompositionCollection.prototype.load = function () {
 | 
			
		||||
        this.cleanUpMutables();
 | 
			
		||||
        return this.provider.load(this.domainObject)
 | 
			
		||||
            .then(function (children) {
 | 
			
		||||
                return Promise.all(children.map((c) => this.publicAPI.objects.get(c)));
 | 
			
		||||
@@ -225,6 +241,13 @@ define([
 | 
			
		||||
        if (!skipMutate) {
 | 
			
		||||
            this.provider.remove(this.domainObject, child.identifier);
 | 
			
		||||
        } 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);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@@ -271,19 +294,6 @@ define([
 | 
			
		||||
        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.
 | 
			
		||||
     * @private
 | 
			
		||||
@@ -298,5 +308,11 @@ define([
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CompositionCollection.prototype.cleanUpMutables = function () {
 | 
			
		||||
        Object.values(this.mutables).forEach(mutable => {
 | 
			
		||||
            mutable.$destroy();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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([
 | 
			
		||||
    'lodash',
 | 
			
		||||
    './object-utils',
 | 
			
		||||
    './MutableObject',
 | 
			
		||||
    './MutableDomainObject',
 | 
			
		||||
    './RootRegistry',
 | 
			
		||||
    './RootObjectProvider',
 | 
			
		||||
    'EventEmitter'
 | 
			
		||||
], function (
 | 
			
		||||
    _,
 | 
			
		||||
    utils,
 | 
			
		||||
    MutableObject,
 | 
			
		||||
    MutableDomainObject,
 | 
			
		||||
    RootRegistry,
 | 
			
		||||
    RootObjectProvider,
 | 
			
		||||
    EventEmitter
 | 
			
		||||
@@ -43,7 +43,8 @@ define([
 | 
			
		||||
     * @memberof module:openmct
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function ObjectAPI() {
 | 
			
		||||
    function ObjectAPI(typeRegistry) {
 | 
			
		||||
        this.typeRegistry = typeRegistry;
 | 
			
		||||
        this.eventEmitter = new EventEmitter();
 | 
			
		||||
        this.providers = {};
 | 
			
		||||
        this.rootRegistry = new RootRegistry();
 | 
			
		||||
@@ -157,6 +158,19 @@ define([
 | 
			
		||||
        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 () {
 | 
			
		||||
        throw new Error('Delete not implemented');
 | 
			
		||||
    };
 | 
			
		||||
@@ -177,6 +191,20 @@ define([
 | 
			
		||||
        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.
 | 
			
		||||
     * @param {module:openmct.DomainObject} object the object to mutate
 | 
			
		||||
@@ -186,9 +214,17 @@ define([
 | 
			
		||||
     * @memberof module:openmct.ObjectAPI#
 | 
			
		||||
     */
 | 
			
		||||
    ObjectAPI.prototype.mutate = function (domainObject, path, value) {
 | 
			
		||||
        var mutableObject =
 | 
			
		||||
            new MutableObject(this.eventEmitter, domainObject);
 | 
			
		||||
        return mutableObject.set(path, value);
 | 
			
		||||
        if (!this.isMutable(domainObject)) {
 | 
			
		||||
            throw `Error: Attempted to mutate immutable object ${domainObject.name}`;
 | 
			
		||||
        }
 | 
			
		||||
        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#
 | 
			
		||||
     */
 | 
			
		||||
    ObjectAPI.prototype.observe = function (domainObject, path, callback) {
 | 
			
		||||
        var mutableObject =
 | 
			
		||||
            new MutableObject(this.eventEmitter, domainObject);
 | 
			
		||||
        mutableObject.on(path, callback);
 | 
			
		||||
        return mutableObject.stopListening.bind(mutableObject);
 | 
			
		||||
        console.warn('DEPRECATION WARNING: The .observe() function in the Object API is now deprecated. Please use mutable() ');
 | 
			
		||||
        if (domainObject instanceof MutableDomainObject.default) {
 | 
			
		||||
            return domainObject.$observe(path, callback);
 | 
			
		||||
        } 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>
 | 
			
		||||
    <tr @contextmenu.prevent="showContextMenu">
 | 
			
		||||
        <td>{{name}}</td>
 | 
			
		||||
        <td>{{domainObject.name}}</td>
 | 
			
		||||
        <td>{{timestamp}}</td>
 | 
			
		||||
        <td :class="valueClass">
 | 
			
		||||
            {{value}}
 | 
			
		||||
@@ -50,7 +50,6 @@ export default {
 | 
			
		||||
        currentObjectPath.unshift(this.domainObject);
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            name: this.domainObject.name,
 | 
			
		||||
            timestamp: '---',
 | 
			
		||||
            value: '---',
 | 
			
		||||
            valueClass: '',
 | 
			
		||||
@@ -70,9 +69,6 @@ export default {
 | 
			
		||||
                this.valueClass = '';
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        updateName(name){
 | 
			
		||||
            this.name = name;
 | 
			
		||||
        },
 | 
			
		||||
        updateTimeSystem(timeSystem) {
 | 
			
		||||
            this.value = '---';
 | 
			
		||||
            this.timestamp = '---';
 | 
			
		||||
@@ -98,14 +94,6 @@ export default {
 | 
			
		||||
            .telemetry
 | 
			
		||||
            .limitEvaluator(this.domainObject);
 | 
			
		||||
 | 
			
		||||
        this.stopWatchingMutation = openmct
 | 
			
		||||
            .objects
 | 
			
		||||
            .observe(
 | 
			
		||||
                this.domainObject,
 | 
			
		||||
                '*',
 | 
			
		||||
                this.updateName
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        this.openmct.time.on('timeSystem', this.updateTimeSystem);
 | 
			
		||||
 | 
			
		||||
        this.timestampKey = this.openmct.time.timeSystem().key;
 | 
			
		||||
@@ -126,7 +114,6 @@ export default {
 | 
			
		||||
            .then((array) => this.updateValues(array[array.length - 1]));
 | 
			
		||||
    },
 | 
			
		||||
    destroyed() {
 | 
			
		||||
        this.stopWatchingMutation();
 | 
			
		||||
        this.unsubscribe();
 | 
			
		||||
        this.openmct.off('timeSystem', this.updateTimeSystem);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -176,9 +176,8 @@
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        data() {
 | 
			
		||||
            let domainObject = JSON.parse(JSON.stringify(this.domainObject));
 | 
			
		||||
            return {
 | 
			
		||||
                internalDomainObject: domainObject,
 | 
			
		||||
                internalDomainObject: this.domainObject,
 | 
			
		||||
                initSelectIndex: undefined,
 | 
			
		||||
                selection: []
 | 
			
		||||
            };
 | 
			
		||||
@@ -566,9 +565,6 @@
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        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.initializeItems();
 | 
			
		||||
            this.composition = this.openmct.composition.get(this.internalDomainObject);
 | 
			
		||||
@@ -580,7 +576,6 @@
 | 
			
		||||
            this.openmct.selection.off('change', this.setSelection);
 | 
			
		||||
            this.composition.off('add', this.addChild);
 | 
			
		||||
            this.composition.off('remove', this.removeChild);
 | 
			
		||||
            this.unlisten();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -113,10 +113,13 @@
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
            this.openmct.objects.get(this.item.identifier)
 | 
			
		||||
            this.openmct.objects.getAsMutable(this.item.identifier)
 | 
			
		||||
                .then(this.setObject);
 | 
			
		||||
        },
 | 
			
		||||
        destroyed() {
 | 
			
		||||
            if (this.domainObject.$destroy) {
 | 
			
		||||
                this.domainObject.$destroy();
 | 
			
		||||
            }
 | 
			
		||||
            if (this.removeSelectable) {
 | 
			
		||||
                this.removeSelectable();
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -248,12 +248,13 @@
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
            this.openmct.objects.get(this.item.identifier)
 | 
			
		||||
            this.openmct.objects.getAsMutable(this.item.identifier)
 | 
			
		||||
                .then(this.setObject);
 | 
			
		||||
            this.openmct.time.on("bounds", this.refreshData);
 | 
			
		||||
        },
 | 
			
		||||
        destroyed() {
 | 
			
		||||
            this.removeSubscription();
 | 
			
		||||
            this.domainObject.$destroy();
 | 
			
		||||
 | 
			
		||||
            if (this.removeSelectable) {
 | 
			
		||||
                this.removeSelectable();
 | 
			
		||||
 
 | 
			
		||||
@@ -152,24 +152,25 @@
 | 
			
		||||
            },
 | 
			
		||||
            getGlobalFiltersToRemove(keyString) {
 | 
			
		||||
                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 => {
 | 
			
		||||
                    let keepFilter = false
 | 
			
		||||
                    Object.keys(this.children).forEach(childKeyString => {
 | 
			
		||||
                        if (childKeyString !== keyString) {
 | 
			
		||||
                            let filterMatched = this.children[childKeyString].metadataWithFilters.some(childMetadatum => childMetadatum.key === metadatum.key);
 | 
			
		||||
 | 
			
		||||
                            if (filterMatched) {
 | 
			
		||||
                                keepFilter = true;
 | 
			
		||||
                                return;
 | 
			
		||||
                                if (filterMatched) {
 | 
			
		||||
                                    keepFilter = true;
 | 
			
		||||
                                    return;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        if (!keepFilter) {
 | 
			
		||||
                            filtersToRemove.add(metadatum.key);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    if (!keepFilter) {
 | 
			
		||||
                        filtersToRemove.add(metadatum.key);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return Array.from(filtersToRemove);
 | 
			
		||||
            },
 | 
			
		||||
@@ -234,16 +235,14 @@
 | 
			
		||||
            this.composition.on('add', this.addChildren);
 | 
			
		||||
            this.composition.on('remove', this.removeChildren);
 | 
			
		||||
            this.composition.load();
 | 
			
		||||
            this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
 | 
			
		||||
            this.unobserveGlobalFilters = this.openmct.objects.observe(this.providedObject, 'configuration.globalFilters', this.updateGlobalFilters);
 | 
			
		||||
            this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
 | 
			
		||||
            this.unobserve = this.providedObject.$observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
 | 
			
		||||
            this.unobserveGlobalFilters = this.providedObject.$observe(this.providedObject, 'configuration.globalFilters', this.updateGlobalFilters);
 | 
			
		||||
        },
 | 
			
		||||
        beforeDestroy() {
 | 
			
		||||
            this.composition.off('add', this.addChildren);
 | 
			
		||||
            this.composition.off('remove', this.removeChildren);
 | 
			
		||||
            this.unobserve();
 | 
			
		||||
            this.unobserveGlobalFilters();
 | 
			
		||||
            this.unobserveAllMutation();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -629,9 +629,6 @@ export default {
 | 
			
		||||
                return size;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        updateDomainObject(newDomainObject) {
 | 
			
		||||
            this.domainObject = newDomainObject;
 | 
			
		||||
        },
 | 
			
		||||
        moveContainer(toIndex, event) {
 | 
			
		||||
            let containerId = event.dataTransfer.getData('containerid');
 | 
			
		||||
            let container = this.containers.filter(c => c.id === containerId)[0];
 | 
			
		||||
@@ -664,14 +661,10 @@ export default {
 | 
			
		||||
        this.composition.on('add', this.addFrame);
 | 
			
		||||
 | 
			
		||||
        this.RemoveAction = new RemoveAction(this.openmct);
 | 
			
		||||
 | 
			
		||||
        this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
        this.composition.off('remove', this.removeChildObject);
 | 
			
		||||
        this.composition.off('add', this.addFrame);
 | 
			
		||||
 | 
			
		||||
        this.unobserve();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ export default {
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        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);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
@@ -116,6 +116,10 @@ export default {
 | 
			
		||||
        this.dragGhost = document.getElementById('js-fl-drag-ghost');
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
        if (this.domainObject.$destroy) {
 | 
			
		||||
            this.domainObject.$destroy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.unsubscribeSelection) {
 | 
			
		||||
            this.unsubscribeSelection();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -34,11 +34,8 @@ define([
 | 
			
		||||
            this.columns = {};
 | 
			
		||||
 | 
			
		||||
            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() {
 | 
			
		||||
@@ -60,15 +57,8 @@ define([
 | 
			
		||||
         * @private
 | 
			
		||||
         * @param {*} object
 | 
			
		||||
         */
 | 
			
		||||
        objectMutated(object) {
 | 
			
		||||
            //Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
 | 
			
		||||
            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);
 | 
			
		||||
            }
 | 
			
		||||
        updateListeners(configuration) {
 | 
			
		||||
            this.emit('change', configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addSingleColumnForObject(telemetryObject, column, position) {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,11 +23,13 @@
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        'EventEmitter',
 | 
			
		||||
        'lodash'
 | 
			
		||||
        'lodash',
 | 
			
		||||
        '../api/objects/MutableDomainObject.js'
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        EventEmitter,
 | 
			
		||||
        _
 | 
			
		||||
        _,
 | 
			
		||||
        MutableDomainObject
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
@@ -75,6 +77,10 @@ define(
 | 
			
		||||
                this.selected = [selectable];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (this.temporaryMutables) {
 | 
			
		||||
                this.temporaryMutables.forEach(mutable => mutable.$destroy());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.emit('change', this.selected);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -233,12 +239,6 @@ define(
 | 
			
		||||
            element.addEventListener('click', capture, true);
 | 
			
		||||
            element.addEventListener('click', selectCapture);
 | 
			
		||||
 | 
			
		||||
            if (context.item) {
 | 
			
		||||
                var unlisten = this.openmct.objects.observe(context.item, "*", function (newItem) {
 | 
			
		||||
                    context.item = newItem;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (select) {
 | 
			
		||||
                element.click();
 | 
			
		||||
            }
 | 
			
		||||
@@ -246,10 +246,6 @@ define(
 | 
			
		||||
            return function () {
 | 
			
		||||
                element.removeEventListener('click', capture, true);
 | 
			
		||||
                element.removeEventListener('click', selectCapture);
 | 
			
		||||
 | 
			
		||||
                if (unlisten) {
 | 
			
		||||
                    unlisten();
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -68,12 +68,6 @@ export default {
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    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);
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
 
 | 
			
		||||
@@ -59,10 +59,6 @@ export default {
 | 
			
		||||
                delete this.removeSelectable;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (this.composition) {
 | 
			
		||||
                this.composition._destroy();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.openmct.objectViews.off('clearData', this.clearData);
 | 
			
		||||
        },
 | 
			
		||||
        invokeEditModeHandler(editMode) {
 | 
			
		||||
@@ -80,7 +76,6 @@ export default {
 | 
			
		||||
            
 | 
			
		||||
            this.composition = this.openmct.composition.get(this.currentObject);
 | 
			
		||||
            if (this.composition) {
 | 
			
		||||
                this.composition._synchronize();
 | 
			
		||||
                this.loadComposition();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -130,20 +125,17 @@ export default {
 | 
			
		||||
                delete this.removeSelectable;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (this.composition) {
 | 
			
		||||
                this.composition._destroy();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.currentObject = object;
 | 
			
		||||
 | 
			
		||||
            this.composition = this.openmct.composition.get(this.currentObject);
 | 
			
		||||
            if (this.composition) {
 | 
			
		||||
                this.loadComposition();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (currentObjectPath) {
 | 
			
		||||
                this.currentObjectPath = currentObjectPath;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.unlisten = this.openmct.objects.observe(this.currentObject, '*', (mutatedObject) => {
 | 
			
		||||
                this.currentObject = mutatedObject;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.viewKey = viewKey;
 | 
			
		||||
            this.updateView(immediatelySelect);
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -118,9 +118,6 @@ export default {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (this.parentObject) {
 | 
			
		||||
                this.mutationUnobserver = this.openmct.objects.observe(this.parentObject, '*', (updatedModel) => {
 | 
			
		||||
                    this.parentObject = updatedModel;
 | 
			
		||||
                });
 | 
			
		||||
                this.composition = this.openmct.composition.get(this.parentObject);
 | 
			
		||||
 | 
			
		||||
                if (this.composition) {
 | 
			
		||||
@@ -141,8 +138,7 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
        addElement(element) {
 | 
			
		||||
            let keyString = this.openmct.objects.makeKeyString(element.identifier);
 | 
			
		||||
            this.elementsCache[keyString] = 
 | 
			
		||||
                JSON.parse(JSON.stringify(element));
 | 
			
		||||
            this.elementsCache[keyString] = element;
 | 
			
		||||
            this.applySearch(this.currentSearch);
 | 
			
		||||
        },
 | 
			
		||||
        reorderElements() {
 | 
			
		||||
@@ -182,9 +178,6 @@ export default {
 | 
			
		||||
        this.openmct.editor.off('isEditing', this.setEditState);
 | 
			
		||||
        this.openmct.selection.off('change', this.showSelection);
 | 
			
		||||
 | 
			
		||||
        if (this.mutationUnobserver) {
 | 
			
		||||
            this.mutationUnobserver();
 | 
			
		||||
        }
 | 
			
		||||
        if (this.compositionUnlistener) {
 | 
			
		||||
            this.compositionUnlistener();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -77,8 +77,9 @@ const PLACEHOLDER_OBJECT = {};
 | 
			
		||||
                this.showSaveMenu = false;
 | 
			
		||||
            },
 | 
			
		||||
            updateName(event) {
 | 
			
		||||
                // TODO: handle isssues with contenteditable text escaping.
 | 
			
		||||
                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 {
 | 
			
		||||
                    event.target.innerText = this.domainObject.name;
 | 
			
		||||
                }
 | 
			
		||||
@@ -223,20 +224,7 @@ const PLACEHOLDER_OBJECT = {};
 | 
			
		||||
                this.isEditing = isEditing;
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        watch: {
 | 
			
		||||
            domainObject() {
 | 
			
		||||
                if (this.mutationObserver) {
 | 
			
		||||
                    this.mutationObserver();
 | 
			
		||||
                }
 | 
			
		||||
                this.mutationObserver = this.openmct.objects.observe(this.domainObject, '*', (domainObject) => {
 | 
			
		||||
                    this.domainObject = domainObject;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        beforeDestroy: function () {
 | 
			
		||||
            if (this.mutationObserver) {
 | 
			
		||||
                this.mutationObserver();
 | 
			
		||||
            }
 | 
			
		||||
            document.removeEventListener('click', this.closeViewAndSaveMenu);
 | 
			
		||||
            window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -207,6 +207,7 @@
 | 
			
		||||
            getAllChildren() {
 | 
			
		||||
                this.isLoading = true;
 | 
			
		||||
                this.openmct.objects.get('ROOT')
 | 
			
		||||
                    .then(root => this.openmct.objects.mutable(root))
 | 
			
		||||
                    .then(root => {
 | 
			
		||||
                        return this.openmct.composition.get(root).load()
 | 
			
		||||
                    })
 | 
			
		||||
@@ -223,8 +224,18 @@
 | 
			
		||||
                    });
 | 
			
		||||
            },
 | 
			
		||||
            getFilteredChildren() {
 | 
			
		||||
                if (this.filteredTreeItems) {
 | 
			
		||||
                    this.filteredTreeItems.forEach(filteredTreeItem => filteredTreeItem.destroy());
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                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'),
 | 
			
		||||
                            object = child.object.useCapability('adapter'),
 | 
			
		||||
 
 | 
			
		||||
@@ -66,11 +66,7 @@
 | 
			
		||||
            // TODO: set isAlias per tree-item
 | 
			
		||||
 | 
			
		||||
            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)) {
 | 
			
		||||
                this.hasChildren = true;
 | 
			
		||||
            }
 | 
			
		||||
@@ -82,6 +78,7 @@
 | 
			
		||||
            if (this.composition) {
 | 
			
		||||
                this.composition.off('add', this.addChild);
 | 
			
		||||
                this.composition.off('remove', this.removeChild);
 | 
			
		||||
                this.children.forEach(child => child.object.$destroy());
 | 
			
		||||
                delete this.composition;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
@@ -101,6 +98,9 @@
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
            addChild (child) {
 | 
			
		||||
                if (this.openmct.objects.isMutable(child)) {
 | 
			
		||||
                    child = this.openmct.objects.mutable(child);
 | 
			
		||||
                }
 | 
			
		||||
                this.children.push({
 | 
			
		||||
                    id: this.openmct.objects.makeKeyString(child.identifier),
 | 
			
		||||
                    object: child,
 | 
			
		||||
@@ -110,8 +110,16 @@
 | 
			
		||||
            },
 | 
			
		||||
            removeChild(identifier) {
 | 
			
		||||
                let removeId = this.openmct.objects.makeKeyString(identifier);
 | 
			
		||||
                let removed = [];
 | 
			
		||||
                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 () {
 | 
			
		||||
                this.isLoading = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,14 @@ define([
 | 
			
		||||
    return function install(openmct) {
 | 
			
		||||
        let navigateCall = 0;
 | 
			
		||||
        let browseObject;
 | 
			
		||||
        let unobserve = undefined;
 | 
			
		||||
        let mutable;
 | 
			
		||||
        let currentObjectPath;
 | 
			
		||||
 | 
			
		||||
        openmct.router.route(/^\/browse\/?$/, navigateToFirstChildOfRoot);
 | 
			
		||||
 | 
			
		||||
        openmct.router.route(/^\/browse\/(.*)$/, (path, results, params) => {
 | 
			
		||||
            let navigatePath = results[1];
 | 
			
		||||
            clearMutationListeners();
 | 
			
		||||
            navigateToPath(navigatePath, params.view);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -27,10 +28,17 @@ define([
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        function viewObject(object, viewProvider) {
 | 
			
		||||
            if (mutable) {
 | 
			
		||||
                mutable.$destroy();
 | 
			
		||||
                mutable = undefined;
 | 
			
		||||
            }
 | 
			
		||||
            if (openmct.objects.isMutable(object)) {
 | 
			
		||||
                mutable = openmct.objects.mutable(object);
 | 
			
		||||
            }
 | 
			
		||||
            currentObjectPath = openmct.router.path;
 | 
			
		||||
 | 
			
		||||
            openmct.layout.$refs.browseObject.show(object, viewProvider.key, true, currentObjectPath);
 | 
			
		||||
            openmct.layout.$refs.browseBar.domainObject = object;
 | 
			
		||||
            openmct.layout.$refs.browseObject.show(mutable || object, viewProvider.key, true, currentObjectPath);
 | 
			
		||||
            openmct.layout.$refs.browseBar.domainObject = mutable || object;
 | 
			
		||||
            openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -38,37 +46,26 @@ define([
 | 
			
		||||
            navigateCall++;
 | 
			
		||||
            let currentNavigation = navigateCall;
 | 
			
		||||
 | 
			
		||||
            if (unobserve) {
 | 
			
		||||
                unobserve();
 | 
			
		||||
                unobserve = undefined;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Split path into object identifiers
 | 
			
		||||
            if (!Array.isArray(path)) {
 | 
			
		||||
                path = path.split('/');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return pathToObjects(path).then((objects)=>{
 | 
			
		||||
            return pathToObjects(path).then((objects) => {
 | 
			
		||||
                if (currentNavigation !== navigateCall) {
 | 
			
		||||
                    return; // Prevent race.
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let navigatedObject = objects[objects.length - 1];
 | 
			
		||||
 | 
			
		||||
                // FIXME: this is a hack to support create action, intended to
 | 
			
		||||
                // expose the current routed path.  We need to rewrite the
 | 
			
		||||
                // navigation service and router to expose a clear and minimal
 | 
			
		||||
                // 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) => {
 | 
			
		||||
                    openmct.router.path[0] = newObject;
 | 
			
		||||
                });
 | 
			
		||||
                browseObject = objects[0];
 | 
			
		||||
                openmct.layout.$refs.browseBar.domainObject = browseObject;
 | 
			
		||||
 | 
			
		||||
                openmct.layout.$refs.browseBar.domainObject = navigatedObject;
 | 
			
		||||
                browseObject = navigatedObject;
 | 
			
		||||
 | 
			
		||||
                if (!navigatedObject) {
 | 
			
		||||
                if (!browseObject) {
 | 
			
		||||
                    openmct.layout.$refs.browseObject.clear();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
@@ -78,12 +75,12 @@ define([
 | 
			
		||||
 | 
			
		||||
                document.title = browseObject.name; //change document title to current object in main view
 | 
			
		||||
 | 
			
		||||
                if (currentProvider && currentProvider.canView(navigatedObject)) {
 | 
			
		||||
                    viewObject(navigatedObject,  currentProvider);
 | 
			
		||||
                if (currentProvider && currentProvider.canView(browseObject)) {
 | 
			
		||||
                    viewObject(browseObject,  currentProvider);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let defaultProvider = openmct.objectViews.get(navigatedObject)[0];
 | 
			
		||||
                let defaultProvider = openmct.objectViews.get(browseObject)[0];
 | 
			
		||||
                if (defaultProvider) {
 | 
			
		||||
                    openmct.router.updateParams({
 | 
			
		||||
                        view: defaultProvider.key
 | 
			
		||||
@@ -99,7 +96,7 @@ define([
 | 
			
		||||
 | 
			
		||||
        function pathToObjects(path) {
 | 
			
		||||
            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) {
 | 
			
		||||
                let unobserveObject = this.openmct.objects.observe(domainObject, '*', function(newObject) {
 | 
			
		||||
                    this.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject));
 | 
			
		||||
                let unobserveObject = domainObject.$observe('*', function(newObject) {
 | 
			
		||||
                    this.domainObjectsById[id].newObject = newObject;
 | 
			
		||||
                    this.updateToolbarAfterMutation();
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
                this.unObserveObjects.push(unobserveObject);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user