diff --git a/src/ui/layout/mct-tree.scss b/src/ui/layout/mct-tree.scss
index b632d79705..592ec592c9 100644
--- a/src/ui/layout/mct-tree.scss
+++ b/src/ui/layout/mct-tree.scss
@@ -26,6 +26,10 @@
overflow: hidden;
transition: all;
+ .c-tree__item-h {
+ width: 100%;
+ }
+
&__scrollable-children {
overflow: auto;
}
diff --git a/src/ui/layout/mct-tree.vue b/src/ui/layout/mct-tree.vue
index 5ad05f5242..3ff04ace5e 100644
--- a/src/ui/layout/mct-tree.vue
+++ b/src/ui/layout/mct-tree.vue
@@ -1,9 +1,10 @@
-
+
-
+
-
Searching...
-
+
No results found
-
-
-
+
+
-
+
+
@@ -108,15 +133,12 @@ import _ from 'lodash';
import treeItem from './tree-item.vue';
import search from '../components/search.vue';
import objectUtils from 'objectUtils';
+import uuid from 'uuid';
const LOCAL_STORAGE_KEY__TREE_EXPANDED__OLD = 'mct-tree-expanded';
const LOCAL_STORAGE_KEY__EXPANDED_TREE_NODE = 'mct-expanded-tree-node';
-const ROOT_PATH = '/browse/';
+const ROOT_PATH = 'browse';
const ITEM_BUFFER = 5;
-const RECHECK_DELAY = 100;
-const RESIZE_FIRE_DELAY_MS = 500;
-let windowResizeId = undefined;
-let windowResizing = false;
export default {
inject: ['openmct'],
@@ -132,59 +154,54 @@ export default {
}
},
data() {
- let isMobile = this.openmct.$injector.get('agentService');
-
return {
+ root: undefined,
isLoading: false,
+ mainTreeHeight: undefined,
searchLoading: false,
searchValue: '',
- allTreeItems: [],
+ childItems: [],
searchResultItems: [],
visibleItems: [],
ancestors: [],
+ tempAncestors: [],
childrenSlideClass: 'down',
- availableContainerHeight: 0,
updatingView: false,
- itemHeightCalculated: false,
- itemHeight: 28,
+ itemHeight: 27,
itemOffset: 0,
- scrollable: undefined,
activeSearch: false,
- shouldEmitHeight: false,
- isMobile: isMobile.mobileName,
multipleRootChildren: false,
- noVisibleItems: false,
observedAncestors: {},
- mainTreeTopMargin: undefined,
- syncingNavigation: false
+ mainTreeTopMargin: undefined
};
},
computed: {
- currentNavigatedPath() {
- let ancestorsCopy = [...this.ancestors];
- if (this.multipleRootChildren) {
- ancestorsCopy.shift(); // remove root
- }
-
- return ancestorsCopy
+ currentTreePath() {
+ let path = [...this.ancestors]
.map((ancestor) => ancestor.id)
.join('/');
- },
- currentObjectPath() {
- let ancestorsCopy = [...this.ancestors];
- return ancestorsCopy
- .reverse()
- .map((ancestor) => ancestor.object);
+ // if not multiRootChildren, then need to add in root ('browse')
+ if (!this.multipleRootChildren) {
+ path = ROOT_PATH + '/' + path;
+ // if multiRootChldren, need to replace root id with 'browse'
+ } else {
+ path = path.replace('ROOT', ROOT_PATH);
+ }
+
+ return path;
},
focusedItems() {
- return this.activeSearch ? this.searchResultItems : this.allTreeItems;
+ return this.activeSearch ? this.searchResultItems : this.childItems;
+ },
+ focusedAncestors() {
+ return this.isLoading ? this.tempAncestors : this.ancestors;
},
itemLeftOffset() {
return this.activeSearch ? '0px' : this.ancestors.length * 10 + 'px';
},
indicatorLeftOffset() {
- let offset = ((this.ancestors.length + 1) * 10);
+ let offset = ((this.focusedAncestors.length + 1) * 10);
return {
paddingLeft: offset + 'px'
@@ -204,62 +221,48 @@ export default {
let childrenCount = this.focusedItems.length || 1;
return (this.itemHeight * childrenCount) - this.mainTreeTopMargin; // 5px margin
+ },
+ availableContainerHeight() {
+ return this.mainTreeHeight - this.ancestorsHeight;
+ },
+ showNoItems() {
+ return this.visibleItems.length === 0 && !this.activeSearch;
+ },
+ showNoSearchResults() {
+ return this.searchValue && this.searchResultItems.length === 0 && !this.searchLoading;
+ },
+ showChildContainer() {
+ return !this.isLoading && !this.searchLoading;
}
},
watch: {
syncTreeNavigation() {
- this.isLoading = true;
- const AND_SAVE_PATH = true;
- this.syncingNavigation = true;
- let currentLocationPath = this.openmct.router.currentLocation.path;
- let hasParent = this.currentlyViewedObjectParentPath() || (this.multipleRootChildren && !this.currentlyViewedObjectParentPath());
- // if there's a current location path,
- // if there's a parent of the currently viewed object
- // and we're not in the parent of the currently viewed object
- let jumpAndScroll = currentLocationPath
- && hasParent
- && !this.currentPathIsActivePath();
- // if the object being viewed is in the current path
- let justScroll = this.currentPathIsActivePath();
+ this.searchValue = '';
- if (this.searchValue) {
- this.searchValue = '';
+ if (!this.openmct.router.path) {
+ return;
}
- if (jumpAndScroll) {
- this.allTreeItems = [];
- this.scrollTo = this.currentlyViewedObjectId();
- this.jumpPath = this.currentlyViewedObjectParentPath();
-
- if (this.multipleRootChildren) {
- if (!this.jumpPath) {
- this.jumpPath = 'ROOT';
- this.ancestors = [];
- } else {
- this.ancestors = [this.ancestors[0]];
- }
- } else {
- this.ancestors = [];
- }
-
- this.jumpToPath(AND_SAVE_PATH);
- } else if (justScroll) {
- this.scrollTo = this.currentlyViewedObjectId();
+ if (this.currentPathIsActivePath() && !this.isLoading) {
+ this.skipScroll = false;
this.autoScroll();
- this.isLoading = false;
+
+ return;
}
+
+ let routePath = [...this.openmct.router.path];
+ routePath.shift(); // remove the child, so it navigates to the parent
+ routePath.push(this.root); // adding root
+ this.beginNavigationRequest('jumpTo', [...routePath].reverse());
},
searchValue() {
if (this.searchValue !== '' && !this.activeSearch) {
- this.searchActivated();
+ this.activeSearch = true;
+ this.$refs.scrollable.scrollTop = 0;
+ this.skipScroll = true;
} else if (this.searchValue === '') {
- this.searchDeactivated();
- }
- },
- allTreeItems() {
- // catches an edge case when new items are added (ex. folder)
- if (!this.isLoading) {
- this.setContainerHeight();
+ this.activeSearch = false;
+ this.skipScroll = false;
}
},
ancestors() {
@@ -273,58 +276,28 @@ export default {
}
},
async mounted() {
+ this.initialize();
- // only reliable way to get final tree top margin
- this.readyStateCheck();
+ let savedPath = this.getStoredTreePath();
+ let rootComposition = await this.loadRoot();
- this.backwardsCompatibilityCheck();
-
- let savedPath = this.getSavedNavigatedPath();
- this.searchService = this.openmct.$injector.get('searchService');
- window.addEventListener('resize', this.handleWindowResize);
- this.isLoading = true;
- let root = await this.openmct.objects.get('ROOT');
-
- if (root.identifier !== undefined) {
- let rootNode = this.buildTreeItem(root);
- let rootCompositionCollection = this.openmct.composition.get(root);
- let rootComposition = await rootCompositionCollection.load();
-
- // if more than one root item, set multipleRootChildren to true and add root to ancestors
- if (rootComposition && rootComposition.length > 1) {
- this.ancestors.push(rootNode);
- if (!this.itemHeightCalculated) {
- await this.calculateItemHeight();
- }
-
- this.multipleRootChildren = true;
- } else if (!savedPath && rootComposition[0] !== undefined) {
- // needed if saved path is not set, need to set it to the only root child
- savedPath = rootComposition[0].identifier;
- }
-
- if (savedPath) {
- let scrollIfApplicable = () => {
- if (this.currentPathIsActivePath()) {
- this.scrollTo = this.currentlyViewedObjectId();
- }
- };
-
- this.jumpPath = savedPath;
- this.afterJump = scrollIfApplicable;
- }
-
- this.getAllChildren(rootNode);
+ if (!rootComposition) {
+ return;
}
+
+ if (!savedPath) {
+ savedPath = ROOT_PATH;
+ if (!this.multipleRootChildren && rootComposition[0]) {
+ let id = this.openmct.objects.makeKeyString(rootComposition[0].identifier);
+ savedPath += '/' + id;
+ }
+ }
+
+ this.beginNavigationRequest('jumpTo', savedPath);
},
created() {
this.getSearchResults = _.debounce(this.getSearchResults, 400);
- this.setContainerHeight = _.debounce(this.setContainerHeight, 200);
- },
- updated() {
- this.$nextTick(() => {
- this.setContainerHeight();
- });
+ this.handleWindowResize = _.debounce(this.handleWindowResize, 500);
},
destroyed() {
window.removeEventListener('resize', this.handleWindowResize);
@@ -332,18 +305,225 @@ export default {
document.removeEventListener('readystatechange', this.setTreeTopMargin);
},
methods: {
+ initialize() {
+ this.searchService = this.openmct.$injector.get('searchService');
+ window.addEventListener('resize', this.handleWindowResize);
+ this.readyStateCheck();
+ this.backwardsCompatibilityCheck();
+ },
readyStateCheck() {
if (document.readyState !== 'complete') {
- document.addEventListener('readystatechange', this.setTreeTopMargin);
+ document.addEventListener('readystatechange', this.onReadyState);
} else {
- this.setTreeTopMargin();
+ this.onReadyState();
}
},
- setTreeTopMargin() {
+ onReadyState() {
if (document.readyState === 'complete') {
- this.mainTreeTopMargin = this.getElementStyleValue(this.$refs.mainTree, 'marginTop');
+ this.calculateHeights();
}
},
+ backwardsCompatibilityCheck() {
+ let oldTreeExpanded = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED__OLD));
+
+ if (oldTreeExpanded) {
+ localStorage.removeItem(LOCAL_STORAGE_KEY__TREE_EXPANDED__OLD);
+ }
+
+ let newTreeExpanded = this.getStoredTreePath();
+
+ if (newTreeExpanded) {
+ // see if it's in a deprecated format
+ if (newTreeExpanded.indexOf('mine') === 0) {
+ localStorage.setItem(LOCAL_STORAGE_KEY__EXPANDED_TREE_NODE, JSON.stringify('browse/' + newTreeExpanded));
+ }
+ }
+ },
+ async loadRoot() {
+ this.root = await this.openmct.objects.get('ROOT');
+
+ if (!this.root.identifier) {
+ return false;
+ }
+
+ let rootCompositionCollection = this.openmct.composition.get(this.root);
+ let rootComposition = await rootCompositionCollection.load();
+
+ if (rootComposition.length > 1) {
+ this.multipleRootChildren = true;
+ }
+
+ return rootComposition;
+ },
+ async beginNavigationRequest(type, request) {
+ let requestId = uuid();
+
+ this.isLoading = true;
+ this.latestNavigationRequest = requestId;
+
+ if (['handleReset', 'handleExpanded'].indexOf(type) !== -1) {
+ this.skipScroll = true;
+ } else {
+ this.skipScroll = false;
+ }
+
+ let success = await this[type](request, requestId);
+
+ if (success && this.isLatestNavigationRequest(requestId)) {
+ this.isLoading = false;
+ this.storeCurrentTreePath();
+ }
+ },
+ isLatestNavigationRequest(requestId) {
+ return this.latestNavigationRequest === requestId;
+ },
+ // will jump to an object path or a string path
+ async jumpTo(path, requestId) {
+ if (!this.isLatestNavigationRequest(requestId)) {
+ return false;
+ }
+
+ // if path string, build object string
+ if (typeof path === 'string') {
+ path = await this.buildObjectPathFromString(path, requestId);
+
+ if (!path) {
+ return false;
+ }
+ }
+
+ // build ancestors tree items from objects
+ this.tempAncestors = [];
+
+ for (let i = 0; i < path.length; i++) {
+ let builtAncestor = this.buildTreeItem(path[i], path.slice(0, i));
+ this.tempAncestors.push(builtAncestor);
+ }
+
+ // load children for last ancestor
+ let childrenItems = await this.getChildrenAsTreeItems(this.tempAncestors[this.tempAncestors.length - 1], path, requestId);
+
+ // if all is good, return true for successful navigation
+ return this.updateTree(this.tempAncestors, childrenItems, requestId);
+ },
+ async handleReset(node, requestId) {
+ if (!this.isLatestNavigationRequest(requestId)) {
+ return false;
+ }
+
+ this.childrenSlideClass = 'up';
+
+ this.tempAncestors = [...this.ancestors];
+ this.tempAncestors.splice(this.tempAncestors.indexOf(node) + 1);
+
+ let objectPath = this.ancestorsAsObjects();
+ objectPath.splice(objectPath.indexOf(node.object) + 1);
+
+ let childrenItems = await this.getChildrenAsTreeItems(node, objectPath, requestId);
+
+ // if all is good, return true for successful navigation
+ return this.updateTree(this.tempAncestors, childrenItems, requestId);
+ },
+ async handleExpanded(node, requestId) {
+ if (!this.isLatestNavigationRequest(requestId)) {
+ return false;
+ }
+
+ this.childrenSlideClass = 'down';
+
+ this.tempAncestors = [...this.ancestors];
+ this.tempAncestors.push(node);
+
+ let objectPath = this.ancestorsAsObjects().concat(node.object);
+
+ let childrenItems = await this.getChildrenAsTreeItems(node, objectPath, requestId);
+
+ // if all is good, return true for successful navigation
+ return this.updateTree(this.tempAncestors, childrenItems, requestId);
+
+ },
+ ancestorsAsObjects() {
+ let ancestorsCopy = [...this.ancestors];
+
+ if (this.multipleRootChildren && ancestorsCopy[0].id === 'ROOT') {
+ // no root for object paths
+ ancestorsCopy.shift();
+ }
+
+ return ancestorsCopy.map(item => item.object);
+ },
+ async buildObjectPathFromString(path, requestId) {
+ let pathNodes = path.split('/');
+ let objectPath = [this.root];
+
+ // skip first element, it's root "browse" path, handled above
+ for (let i = 1; i < pathNodes.length; i++) {
+ let domainObject = await this.openmct.objects.get(pathNodes[i]);
+ objectPath.push(domainObject);
+
+ if (!this.isLatestNavigationRequest(requestId)) {
+ return false;
+ }
+ }
+
+ return objectPath;
+ },
+ async getChildrenAsTreeItems(item, parentObjectPath, requestId) {
+ if (!this.isLatestNavigationRequest(requestId)) {
+ return false;
+ }
+
+ if (this.composition) {
+ this.composition.off('add', this.addChild);
+ this.composition.off('remove', this.removeChild);
+ delete this.composition;
+ }
+
+ this.childItems = [];
+ let tempComposition = this.openmct.composition.get(item.object);
+ let children = await tempComposition.load();
+
+ if (!this.isLatestNavigationRequest(requestId)) {
+ return false;
+ }
+
+ this.composition = tempComposition;
+
+ return children.map((child) => {
+ return this.buildTreeItem(child, parentObjectPath);
+ });
+ },
+ async updateTree(ancestors, children, requestId) {
+ if (!this.isLatestNavigationRequest(requestId)) {
+ return false;
+ }
+
+ // show or don't show root
+ if (!this.multipleRootChildren && ancestors[0].id === 'ROOT') {
+ ancestors.shift();
+ }
+
+ await this.clearVisibleItems();
+
+ this.ancestors = ancestors;
+ this.childItems = children;
+
+ // any new items added or removed handled here
+ this.composition.on('add', this.addChild);
+ this.composition.on('remove', this.removeChild);
+
+ return true;
+ },
+ // domainObject: from composition add event
+ addChild(domainObject) {
+ let item = this.buildTreeItem(domainObject, this.ancestorsAsObjects());
+ this.childItems.push(item);
+ },
+ removeChild(identifier) {
+ let removeId = this.openmct.objects.makeKeyString(identifier);
+ this.childItems = this.childItems
+ .filter(c => c.id !== removeId);
+ },
updateVisibleItems() {
if (this.updatingView) {
return;
@@ -377,21 +557,10 @@ export default {
this.itemOffset = start;
this.visibleItems = this.focusedItems.slice(start, end);
- this.noVisibleItems = false;
this.updatingView = false;
});
},
- setContainerHeight() {
- let mainTree = this.$refs.mainTree;
- let mainTreeHeight = mainTree && mainTree.clientHeight ? mainTree.clientHeight : 0;
-
- if (mainTreeHeight !== 0) {
- this.availableContainerHeight = mainTreeHeight - this.ancestorsHeight;
- } else {
- window.setTimeout(this.setContainerHeight, RECHECK_DELAY);
- }
- },
calculateFirstVisibleItem() {
if (!this.$refs.scrollable) {
return;
@@ -410,92 +579,59 @@ export default {
return Math.ceil(scrollBottom / this.itemHeight);
},
- calculateItemHeight() {
- this.shouldEmitHeight = true;
-
- return new Promise((resolve, reject) => {
- this.itemHeightResolve = resolve;
- });
- },
- async setItemHeight(height) {
-
- if (this.itemHeightCalculated) {
- return;
- }
-
- await this.$nextTick();
-
- this.itemHeight = height;
- this.itemHeightCalculated = true;
- this.shouldEmitHeight = false;
-
- this.itemHeightResolve();
+ scrollItems(event) {
+ this.updateVisibleItems();
},
handleWindowResize() {
- if (!windowResizing) {
- windowResizing = true;
- window.clearTimeout(windowResizeId);
- windowResizeId = window.setTimeout(() => {
- this.setContainerHeight();
- windowResizing = false;
- }, RESIZE_FIRE_DELAY_MS);
- }
+ this.calculateHeights();
},
- async getAllChildren(node, after) {
- let currentNavigationRequest = this.openmct.objects.makeKeyString(node.object.identifier);
- this.latestNavigationRequest = currentNavigationRequest;
+ // domainObject: we're building a tree item for this
+ // objects: domainObject array up to parent of domainObject, excluding domainObject for item being built
+ buildTreeItem(domainObject, objects) {
+ let objectPath = [...objects];
- await this.clearVisibleItems();
-
- if (this.composition) {
- this.composition.off('add', this.addChild);
- this.composition.off('remove', this.removeChild);
- delete this.composition;
+ // remove root (if present) for object path
+ if (objectPath[0] && objectPath[0].type === 'root') {
+ objectPath.shift();
}
- this.allTreeItems = [];
- this.composition = this.openmct.composition.get(node.object);
- this.composition.on('add', this.addChild);
- this.composition.on('remove', this.removeChild);
-
- if (currentNavigationRequest === this.latestNavigationRequest) {
- if (after && typeof after === 'function') {
- after();
- }
-
- await this.composition.load();
- this.finishLoading();
- }
- },
- buildTreeItem(domainObject, path, objectPath) {
- let currentPath = path || this.currentNavigatedPath;
- let currentObjectPath = objectPath || this.currentObjectPath;
-
- let navToParent = ROOT_PATH + currentPath;
- if (navToParent === ROOT_PATH) {
- navToParent = navToParent.slice(0, -1);
- }
+ let navigationPath = this.buildNavigationPath(domainObject, objectPath);
+ let builtObjectPath = [...objectPath].reverse();
return {
id: this.openmct.objects.makeKeyString(domainObject.identifier),
object: domainObject,
- objectPath: [domainObject].concat(currentObjectPath),
- navigateToParent: navToParent
+ objectPath: [domainObject].concat(builtObjectPath),
+ navigationPath
};
},
+ // domainObject: the item we're building the path for (will be used in url and links)
+ // objects: array of domainObjects representing path to domainobject passed in
+ buildNavigationPath(domainObject, objects) {
+ let path = [...objects]
+ .map(object => this.openmct.objects.makeKeyString(object.identifier));
+
+ return '/' + [
+ ROOT_PATH,
+ ...path,
+ this.openmct.objects.makeKeyString(domainObject.identifier)
+ ].join('/');
+ },
observeAncestors() {
let observedAncestorIds = Object.keys(this.observedAncestors);
// observe any ancestors, not currently being observed
- this.ancestors.forEach((ancestor) => {
- let ancestorObject = ancestor.object;
- let ancestorKeyString = this.openmct.objects.makeKeyString(ancestorObject.identifier);
- let index = observedAncestorIds.indexOf(ancestorKeyString);
+ this.ancestors.forEach((ancestor, index) => {
+ // skip last ancestor as it's children are currently being watched
+ if (index !== this.ancestors.length - 1) {
+ let ancestorKeyString = this.openmct.objects.makeKeyString(ancestor.object.identifier);
+ let ancestorIndex = observedAncestorIds.indexOf(ancestorKeyString);
- if (index !== -1) { // currently observed
- observedAncestorIds.splice(index, 1); // remove all active ancestors from id tracking
- } else { // not observed, observe it
- this.observeAncestor(ancestorKeyString, ancestorObject);
+ if (ancestorIndex !== -1) { // currently observed
+ observedAncestorIds.splice(ancestorIndex, 1); // remove all active ancestors from id tracking
+ } else { // not observed, observe it
+ this.observeAncestor(ancestorKeyString, ancestor);
+ }
}
});
@@ -504,121 +640,63 @@ export default {
},
stopObservingAncestors(ids = Object.keys(this.observedAncestors)) {
ids.forEach((id) => {
- this.observedAncestors[id]();
+ this.observedAncestors[id].composition.off('add', this.observedAncestors[id].addChild);
+ this.observedAncestors[id].composition.off('remove', this.observedAncestors[id].removeChild);
+ this.observedAncestors[id].removeChild = undefined;
+ this.observedAncestors[id].addChild = undefined;
+ this.observedAncestors[id].composition = undefined;
+
+ // remove tracking for this id
this.observedAncestors[id] = undefined;
delete this.observedAncestors[id];
});
},
- observeAncestor(id, object) {
- this.observedAncestors[id] = this.openmct.objects.observe(object, 'location',
- (location) => {
- let ancestorObjects = this.ancestors.map(ancestor => ancestor.object);
- // ancestor has been removed from tree, reset to it's parent
- if (location === null) {
- let index = ancestorObjects.indexOf(object);
- let parentIndex = index - 1;
- if (this.ancestors[parentIndex]) {
- this.handleReset(this.ancestors[parentIndex]);
- }
- }
+ async observeAncestor(id, ancestorNode) {
+ this.observedAncestors[id] = {};
+
+ this.observedAncestors[id].composition = this.openmct.composition.get(ancestorNode.object);
+ await this.observedAncestors[id].composition.load();
+ this.observedAncestors[id].addChild = this.ancestorAdd(ancestorNode);
+ this.observedAncestors[id].removeChild = this.ancestorRemove(ancestorNode);
+ this.observedAncestors[id].composition.on('add', this.observedAncestors[id].addChild);
+ this.observedAncestors[id].composition.on('remove', this.observedAncestors[id].removeChild);
+ // }
+ },
+ ancestorAdd(ancestor) {
+ return (node) => {
+ // no use case for this as of yet since ancestors do not show siblings
+ // and the main ancestor being viewed currently has it's composition watched elsewhere
+ };
+ },
+ ancestorRemove(ancestorNode) {
+ return (identifier) => {
+ // check if this item is showing in the tree currently
+ let index = this.ancestors.findIndex(treeAncestor => {
+ let treeAncestorIdentifier = this.openmct.objects.makeKeyString(treeAncestor.object.identifier);
+ let removedItemIdentifier = this.openmct.objects.makeKeyString(identifier);
+
+ return treeAncestorIdentifier === removedItemIdentifier;
});
- },
- buildNavigationPath(objects) {
- let objectsCopy = [...objects];
- if (this.multipleRootChildren) {
- objectsCopy.shift(); // remove root
- }
- return objectsCopy
- .map((object) => object.id)
- .join('/');
- },
- buildObjectPath(objects) {
- let objectsCopy = [...objects];
-
- return objectsCopy
- .reverse()
- .map((object) => object.object);
- },
- addChild(child) {
- let item = this.buildTreeItem(child);
- this.allTreeItems.push(item);
- },
- removeChild(identifier) {
- let removeId = this.openmct.objects.makeKeyString(identifier);
- this.allTreeItems = this.allTreeItems
- .filter(c => c.id !== removeId);
- this.setContainerHeight();
- },
- finishLoading() {
- if (this.jumpPath) {
- this.jumpToPath();
- }
-
- this.autoScroll();
- this.isLoading = false;
- this.syncingNavigation = false;
- this.setContainerHeight();
- },
- async jumpToPath(saveExpandedPath = false) {
- // switching back and forth between multiple root children can cause issues,
- // this checks for one of those issues
- if (this.jumpPath.key) {
- this.jumpPath = this.jumpPath.key;
- }
-
- let nodes = this.jumpPath.split('/');
- let tempAncestors = [...this.ancestors];
- let newParent;
-
- for (let i = 0; i < nodes.length; i++) {
- let currentNode = await this.openmct.objects.get(nodes[i]);
- let path = this.buildNavigationPath(tempAncestors);
- let objectPath = this.buildObjectPath(tempAncestors);
- newParent = this.buildTreeItem(currentNode, path, objectPath);
- tempAncestors.push(newParent);
-
- if (!this.itemHeightCalculated) {
- this.ancestors.push(newParent); // add for calculations
- await this.calculateItemHeight();
- this.ancestors.pop(); // remove after
+ if (index !== -1) {
+ let ancestorIndex = this.ancestors.indexOf(ancestorNode);
+ this.beginNavigationRequest('handleReset', this.ancestors[ancestorIndex]);
}
- }
-
- this.jumpPath = '';
- this.getAllChildren(newParent, async () => {
- this.ancestors = tempAncestors; // reset ancestors
- if (this.afterJump) {
- await this.$nextTick();
- this.afterJump();
- delete this.afterJump;
- }
-
- if (saveExpandedPath) {
- this.setCurrentNavigatedPath();
- }
- });
+ };
},
- async autoScroll() {
- if (!this.scrollTo) {
- return;
- }
-
- if (this.$refs.scrollable) {
- let indexOfScroll = this.indexOfItemById(this.scrollTo);
+ autoScroll() {
+ if (this.currentPathIsActivePath() && !this.skipScroll && this.$refs.scrollable) {
+ let indexOfScroll = this.indexOfItemById(this.currentlyViewedObjectId());
let scrollTopAmount = indexOfScroll * this.itemHeight;
-
- await this.$nextTick();
-
- this.$refs.scrollable.scrollTop = scrollTopAmount;
- this.scrollTo = undefined;
- } else {
- window.setTimeout(this.autoScroll, RECHECK_DELAY);
+ this.$refs.scrollable.scrollTo({
+ top: scrollTopAmount,
+ behavior: 'smooth'
+ });
}
},
indexOfItemById(id) {
- for (let i = 0; i < this.allTreeItems.length; i++) {
- if (this.allTreeItems[i].id === id) {
+ for (let i = 0; i < this.childItems.length; i++) {
+ if (this.childItems[i].id === id) {
return i;
}
}
@@ -630,22 +708,22 @@ export default {
for (let i = 0; i < results.hits.length; i++) {
let result = results.hits[i];
let newStyleObject = objectUtils.toNewFormat(result.object.getModel(), result.object.getId());
- let objectPath = [];
- let navigateToParent;
+ let objectPath = await this.openmct.objects.getOriginalPath(newStyleObject.identifier);
- objectPath = await this.openmct.objects.getOriginalPath(newStyleObject.identifier);
- objectPath.pop(); // remove root
+ // removing the item itself, as the path we pass to buildTreeItem is a parent path
+ objectPath.shift();
- navigateToParent = objectPath.slice(1)
- .map((parent) => this.openmct.objects.makeKeyString(parent.identifier));
- navigateToParent = ROOT_PATH + navigateToParent.reverse().join('/');
+ // if root, remove, we're not using in object path for tree
+ let lastObject = objectPath.length ? objectPath[objectPath.length - 1] : false;
+ if (lastObject && lastObject.type === 'root') {
+ objectPath.pop();
+ }
- this.searchResultItems.push({
- id: this.openmct.objects.makeKeyString(newStyleObject.identifier),
- object: newStyleObject,
- objectPath,
- navigateToParent
- });
+ // we reverse the objectPath in the tree, so have to do it here first,
+ // since this one is already in the correct direction
+ let resultObject = this.buildTreeItem(newStyleObject, objectPath.reverse());
+
+ this.searchResultItems.push(resultObject);
}
this.searchLoading = false;
@@ -660,76 +738,40 @@ export default {
this.searchLoading = false;
}
},
- searchActivated() {
- this.activeSearch = true;
- this.$refs.scrollable.scrollTop = 0;
- },
- async searchDeactivated() {
- this.activeSearch = false;
- await this.$nextTick();
- this.$refs.scrollable.scrollTop = 0;
- },
- handleReset(node) {
- this.isLoading = true;
-
- this.getAllChildren(node, () => {
- this.childrenSlideClass = 'up';
- this.ancestors.splice(this.ancestors.indexOf(node) + 1);
- this.setCurrentNavigatedPath();
- });
- },
- handleExpanded(node) {
- this.isLoading = true;
-
- let newParent = this.buildTreeItem(node);
-
- this.getAllChildren(newParent, () => {
- this.childrenSlideClass = 'down';
- this.ancestors.push(newParent);
- this.setCurrentNavigatedPath();
- });
- },
- getSavedNavigatedPath() {
+ getStoredTreePath() {
return JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY__EXPANDED_TREE_NODE));
},
- setCurrentNavigatedPath() {
+ storeCurrentTreePath() {
if (!this.searchValue) {
- localStorage.setItem(LOCAL_STORAGE_KEY__EXPANDED_TREE_NODE, JSON.stringify(this.currentNavigatedPath));
+ localStorage.setItem(LOCAL_STORAGE_KEY__EXPANDED_TREE_NODE, JSON.stringify(this.currentTreePath));
}
},
currentPathIsActivePath() {
- return this.getSavedNavigatedPath() === this.currentlyViewedObjectParentPath();
+ return this.getStoredTreePath() === this.currentlyViewedObjectParentPath();
},
currentlyViewedObjectId() {
let currentPath = this.openmct.router.currentLocation.path;
if (currentPath) {
- currentPath = currentPath.split(ROOT_PATH)[1];
-
return currentPath.split('/').pop();
}
},
currentlyViewedObjectParentPath() {
let currentPath = this.openmct.router.currentLocation.path;
+
if (currentPath) {
- currentPath = currentPath.split(ROOT_PATH)[1];
currentPath = currentPath.split('/');
- currentPath.pop();
+ currentPath.shift(); // remove empty array element from initial '/'
+ currentPath.pop(); // remove current child
return currentPath.join('/');
}
},
async clearVisibleItems() {
- this.noVisibleItems = true;
this.visibleItems = [];
await this.$nextTick(); // prevents "ghost" image of visibleItems
return;
},
- scrollItems(event) {
- if (!windowResizing) {
- this.updateVisibleItems();
- }
- },
childrenListStyles() {
return { position: 'relative' };
},
@@ -744,12 +786,12 @@ export default {
return Number(styleString.slice(0, index));
},
- backwardsCompatibilityCheck() {
- let oldTreeExpanded = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED__OLD));
-
- if (oldTreeExpanded) {
- localStorage.removeItem(LOCAL_STORAGE_KEY__TREE_EXPANDED__OLD);
- }
+ calculateHeights() {
+ this.mainTreeTopMargin = this.getElementStyleValue(this.$refs.mainTree, 'marginTop');
+ this.mainTreeHeight = this.$el.offsetHeight
+ - this.$refs.search.offsetHeight
+ - this.mainTreeTopMargin;
+ this.itemHeight = this.getElementStyleValue(this.$refs.dummyItem, 'height');
}
}
};
diff --git a/src/ui/layout/tree-item.vue b/src/ui/layout/tree-item.vue
index 75a83265c1..a05baee895 100644
--- a/src/ui/layout/tree-item.vue
+++ b/src/ui/layout/tree-item.vue
@@ -1,5 +1,5 @@
-
-
+