mirror of
https://github.com/nasa/openmct.git
synced 2025-06-27 11:32:13 +00:00
Compare commits
8 Commits
git-error-
...
tree-pagin
Author | SHA1 | Date | |
---|---|---|---|
9015028f81 | |||
38d78990da | |||
e0d2c85740 | |||
29ab9bdf02 | |||
0b433ccb50 | |||
e2ecd106f6 | |||
7debe89f8b | |||
a396f50acd |
@ -29,6 +29,7 @@ define([
|
|||||||
"./res/templates/search.html",
|
"./res/templates/search.html",
|
||||||
"./res/templates/search-menu.html",
|
"./res/templates/search-menu.html",
|
||||||
"raw-loader!./src/services/GenericSearchWorker.js",
|
"raw-loader!./src/services/GenericSearchWorker.js",
|
||||||
|
"raw-loader!./src/services/BareBonesSearchWorker.js",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
SearchController,
|
SearchController,
|
||||||
@ -39,6 +40,7 @@ define([
|
|||||||
searchTemplate,
|
searchTemplate,
|
||||||
searchMenuTemplate,
|
searchMenuTemplate,
|
||||||
searchWorkerText,
|
searchWorkerText,
|
||||||
|
BareBonesSearchWorkerText,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -115,6 +117,10 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"workers": [
|
"workers": [
|
||||||
|
{
|
||||||
|
"key": "bareBonesSearchWorker",
|
||||||
|
"scriptText": BareBonesSearchWorkerText
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "genericSearchWorker",
|
"key": "genericSearchWorker",
|
||||||
"scriptText": searchWorkerText
|
"scriptText": searchWorkerText
|
||||||
|
80
platform/search/src/services/BareBonesSearchWorker.js
Normal file
80
platform/search/src/services/BareBonesSearchWorker.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*global self*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining GenericSearchWorker. Created by shale on 07/21/2015.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
// An array of objects composed of domain object IDs and models
|
||||||
|
// {id: domainObject's ID, model: domainObject's model}
|
||||||
|
var indexedItems = [];
|
||||||
|
|
||||||
|
function indexItem(id, model) {
|
||||||
|
indexedItems.push({
|
||||||
|
id: id,
|
||||||
|
name: model.name.toLowerCase()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets search results from the indexedItems based on provided search
|
||||||
|
* input. Returns matching results from indexedItems
|
||||||
|
*
|
||||||
|
* @param data An object which contains:
|
||||||
|
* * input: The original string which we are searching with
|
||||||
|
* * maxResults: The maximum number of search results desired
|
||||||
|
* * queryId: an id identifying this query, will be returned.
|
||||||
|
*/
|
||||||
|
function search(data) {
|
||||||
|
// This results dictionary will have domain object ID keys which
|
||||||
|
// point to the value the domain object's score.
|
||||||
|
var results,
|
||||||
|
input = data.input.trim().toLowerCase(),
|
||||||
|
message = {
|
||||||
|
request: 'search',
|
||||||
|
results: {},
|
||||||
|
total: 0,
|
||||||
|
queryId: data.queryId
|
||||||
|
};
|
||||||
|
|
||||||
|
results = indexedItems.filter((indexedItem) => {
|
||||||
|
return indexedItem.name.includes(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
message.total = results.length;
|
||||||
|
message.results = results
|
||||||
|
.slice(0, data.maxResults);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.onmessage = function (event) {
|
||||||
|
if (event.data.request === 'index') {
|
||||||
|
indexItem(event.data.id, event.data.model);
|
||||||
|
} else if (event.data.request === 'search') {
|
||||||
|
self.postMessage(search(event.data));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}());
|
@ -58,6 +58,8 @@ define([
|
|||||||
|
|
||||||
this.pendingQueries = {};
|
this.pendingQueries = {};
|
||||||
|
|
||||||
|
this.useBareBones = true;
|
||||||
|
|
||||||
this.worker = this.startWorker(workerService);
|
this.worker = this.startWorker(workerService);
|
||||||
this.indexOnMutation(topic);
|
this.indexOnMutation(topic);
|
||||||
|
|
||||||
@ -101,8 +103,14 @@ define([
|
|||||||
* @returns worker the created search worker.
|
* @returns worker the created search worker.
|
||||||
*/
|
*/
|
||||||
GenericSearchProvider.prototype.startWorker = function (workerService) {
|
GenericSearchProvider.prototype.startWorker = function (workerService) {
|
||||||
var worker = workerService.run('genericSearchWorker'),
|
var provider = this,
|
||||||
provider = this;
|
worker;
|
||||||
|
|
||||||
|
if (this.useBareBones) {
|
||||||
|
worker = workerService.run('bareBonesSearchWorker');
|
||||||
|
} else {
|
||||||
|
worker = workerService.run('genericSearchWorker');
|
||||||
|
}
|
||||||
|
|
||||||
worker.addEventListener('message', function (messageEvent) {
|
worker.addEventListener('message', function (messageEvent) {
|
||||||
provider.onWorkerMessage(messageEvent);
|
provider.onWorkerMessage(messageEvent);
|
||||||
@ -242,18 +250,34 @@ define([
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pendingQuery = this.pendingQueries[event.data.queryId],
|
var pendingQuery,
|
||||||
|
modelResults;
|
||||||
|
|
||||||
|
if (this.useBareBones) {
|
||||||
|
pendingQuery = this.pendingQueries[event.data.queryId];
|
||||||
modelResults = {
|
modelResults = {
|
||||||
total: event.data.total
|
total: event.data.total
|
||||||
};
|
};
|
||||||
|
|
||||||
modelResults.hits = event.data.results.map(function (hit) {
|
modelResults.hits = event.data.results.map(function (hit) {
|
||||||
return {
|
return {
|
||||||
id: hit.item.id,
|
id: hit.id
|
||||||
model: hit.item.model,
|
};
|
||||||
score: hit.matchCount
|
});
|
||||||
|
} else {
|
||||||
|
pendingQuery = this.pendingQueries[event.data.queryId];
|
||||||
|
modelResults = {
|
||||||
|
total: event.data.total
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
modelResults.hits = event.data.results.map(function (hit) {
|
||||||
|
return {
|
||||||
|
id: hit.item.id,
|
||||||
|
model: hit.item.model,
|
||||||
|
score: hit.matchCount
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pendingQuery.resolve(modelResults);
|
pendingQuery.resolve(modelResults);
|
||||||
delete this.pendingQueries[event.data.queryId];
|
delete this.pendingQueries[event.data.queryId];
|
||||||
|
@ -144,6 +144,8 @@
|
|||||||
message.results = results
|
message.results = results
|
||||||
.slice(0, data.maxResults);
|
.slice(0, data.maxResults);
|
||||||
|
|
||||||
|
console.log(message);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,10 +18,47 @@
|
|||||||
<span class="c-tree__item__label">Loading...</span>
|
<span class="c-tree__item__label">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<tree-item v-for="child in children"
|
|
||||||
:key="child.id"
|
<template v-if="children.length">
|
||||||
:node="child">
|
|
||||||
</tree-item>
|
<template v-if="children.length > page_threshold">
|
||||||
|
<li v-show="!showSearchComponent"
|
||||||
|
@click="toggleSearchComponent"
|
||||||
|
class="c-tree__item-h"
|
||||||
|
style="font-size: 0.5em;">
|
||||||
|
<div class="c-tree__item icon-magnify">
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li v-show="showSearchComponent"
|
||||||
|
class="c-tree__item-h"
|
||||||
|
style="font-size: 0.7em">
|
||||||
|
<div class="c-tree__item">
|
||||||
|
<a class="c-tree__item__label c-object-label">
|
||||||
|
<search
|
||||||
|
:value="searchValue"
|
||||||
|
@input="searchChildren"
|
||||||
|
@clear="searchChildren"
|
||||||
|
style="min-width: 80%;">
|
||||||
|
</search>
|
||||||
|
<div style="padding: 2px; margin-left: 10%;"
|
||||||
|
class="icon-x"
|
||||||
|
@click="toggleSearchComponent">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div :style="style"
|
||||||
|
@scroll="scrollPage"
|
||||||
|
ref="scrollParent">
|
||||||
|
<tree-item v-for="child in filteredAndPagedChildren"
|
||||||
|
:key="child.id"
|
||||||
|
:node="child">
|
||||||
|
</tree-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
@ -29,6 +66,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import viewControl from '../components/viewControl.vue';
|
import viewControl from '../components/viewControl.vue';
|
||||||
import ObjectLabel from '../components/ObjectLabel.vue';
|
import ObjectLabel from '../components/ObjectLabel.vue';
|
||||||
|
import Search from '../components/search.vue';
|
||||||
|
|
||||||
|
const PAGE_THRESHOLD = 50;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'tree-item',
|
name: 'tree-item',
|
||||||
@ -44,7 +84,13 @@
|
|||||||
loaded: false,
|
loaded: false,
|
||||||
isNavigated: this.navigateToPath === this.openmct.router.currentLocation.path,
|
isNavigated: this.navigateToPath === this.openmct.router.currentLocation.path,
|
||||||
children: [],
|
children: [],
|
||||||
expanded: false
|
expanded: false,
|
||||||
|
page: 1,
|
||||||
|
page_threshold: PAGE_THRESHOLD,
|
||||||
|
searchValue: '',
|
||||||
|
filteredChildren: [],
|
||||||
|
scrollTop: 0,
|
||||||
|
showSearchComponent: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -55,6 +101,44 @@
|
|||||||
}
|
}
|
||||||
let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
|
let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
|
||||||
return parentKeyString !== this.node.object.location;
|
return parentKeyString !== this.node.object.location;
|
||||||
|
},
|
||||||
|
filteredAndPagedChildren() {
|
||||||
|
if (this.searchValue) {
|
||||||
|
this.filteredChildren = this.children.filter((child) => {
|
||||||
|
let searchLowCase = this.searchValue.toLowerCase(),
|
||||||
|
nameLowerCase = child.object.name.toLowerCase();
|
||||||
|
|
||||||
|
return nameLowerCase.includes(searchLowCase);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.filteredChildren = this.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.filteredChildren.length > this.page_threshold) {
|
||||||
|
let maxIndex = this.page * this.page_threshold,
|
||||||
|
minIndex = maxIndex - this.page_threshold;
|
||||||
|
|
||||||
|
return this.filteredChildren.slice(minIndex, maxIndex);
|
||||||
|
} else {
|
||||||
|
return this.filteredChildren;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lastPage() {
|
||||||
|
return Math.floor(this.filteredChildren.length / this.page_threshold);
|
||||||
|
},
|
||||||
|
style() {
|
||||||
|
let numChildren = this.filteredChildren.length;
|
||||||
|
|
||||||
|
if (!this.$refs.scrollParent || numChildren === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((numChildren * 20) > this.$refs.scrollParent.offsetHeight) {
|
||||||
|
return {
|
||||||
|
"overflow-y": 'scroll',
|
||||||
|
"max-height": (this.page_threshold * 10) + 'px'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -97,6 +181,11 @@
|
|||||||
this.composition.load().then(this.finishLoading);
|
this.composition.load().then(this.finishLoading);
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isExpanded) {
|
||||||
|
this.page = 1;
|
||||||
|
this.showSearchComponent = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -126,11 +215,53 @@
|
|||||||
} else if (oldPath === this.navigateToPath) {
|
} else if (oldPath === this.navigateToPath) {
|
||||||
this.isNavigated = false;
|
this.isNavigated = false;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
nextPage() {
|
||||||
|
if (this.page < this.lastPage) {
|
||||||
|
this.page += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
previousPage() {
|
||||||
|
if (this.page >= 1) {
|
||||||
|
this.page -= 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
searchChildren(input) {
|
||||||
|
this.searchValue = input;
|
||||||
|
this.page = 1;
|
||||||
|
},
|
||||||
|
scrollPage(event) {
|
||||||
|
let offsetHeight = event.target.offsetHeight,
|
||||||
|
scrollTop = event.target.scrollTop,
|
||||||
|
changePage = true;
|
||||||
|
|
||||||
|
window.clearTimeout(this.scrollLoading);
|
||||||
|
|
||||||
|
if (scrollTop > this.scrollTop && scrollTop > offsetHeight) {
|
||||||
|
this.scrollLoading = window.setTimeout(() => {
|
||||||
|
if (this.page < this.lastPage) {
|
||||||
|
this.nextPage();
|
||||||
|
event.target.scrollTop = 1;
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
} else if (this.scrollTop <= this.scrollTop && scrollTop <= 0) {
|
||||||
|
this.scrollLoading = window.setTimeout(() => {
|
||||||
|
if (this.page > 1) {
|
||||||
|
this.previousPage();
|
||||||
|
event.target.scrollTop = offsetHeight - 1;
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
this.scrollTop = scrollTop;
|
||||||
|
},
|
||||||
|
toggleSearchComponent() {
|
||||||
|
this.showSearchComponent = !this.showSearchComponent;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
viewControl,
|
viewControl,
|
||||||
ObjectLabel
|
ObjectLabel,
|
||||||
|
Search
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Reference in New Issue
Block a user