Compare commits
	
		
			8 Commits
		
	
	
		
			version-1.
			...
			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-menu.html",
 | 
			
		||||
    "raw-loader!./src/services/GenericSearchWorker.js",
 | 
			
		||||
    "raw-loader!./src/services/BareBonesSearchWorker.js",
 | 
			
		||||
    'legacyRegistry'
 | 
			
		||||
], function (
 | 
			
		||||
    SearchController,
 | 
			
		||||
@@ -39,6 +40,7 @@ define([
 | 
			
		||||
    searchTemplate,
 | 
			
		||||
    searchMenuTemplate,
 | 
			
		||||
    searchWorkerText,
 | 
			
		||||
    BareBonesSearchWorkerText,
 | 
			
		||||
    legacyRegistry
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
@@ -115,6 +117,10 @@ define([
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "workers": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "bareBonesSearchWorker",
 | 
			
		||||
                    "scriptText": BareBonesSearchWorkerText
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "genericSearchWorker",
 | 
			
		||||
                    "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.useBareBones = true;
 | 
			
		||||
 | 
			
		||||
        this.worker = this.startWorker(workerService);
 | 
			
		||||
        this.indexOnMutation(topic);
 | 
			
		||||
 | 
			
		||||
@@ -101,8 +103,14 @@ define([
 | 
			
		||||
     * @returns worker the created search worker.
 | 
			
		||||
     */
 | 
			
		||||
    GenericSearchProvider.prototype.startWorker = function (workerService) {
 | 
			
		||||
        var worker = workerService.run('genericSearchWorker'),
 | 
			
		||||
            provider = this;
 | 
			
		||||
        var provider = this,
 | 
			
		||||
            worker;
 | 
			
		||||
 | 
			
		||||
        if (this.useBareBones) {
 | 
			
		||||
            worker = workerService.run('bareBonesSearchWorker');
 | 
			
		||||
        } else {
 | 
			
		||||
            worker = workerService.run('genericSearchWorker');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        worker.addEventListener('message', function (messageEvent) {
 | 
			
		||||
            provider.onWorkerMessage(messageEvent);
 | 
			
		||||
@@ -242,18 +250,34 @@ define([
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var pendingQuery = this.pendingQueries[event.data.queryId],
 | 
			
		||||
        var pendingQuery,
 | 
			
		||||
            modelResults;
 | 
			
		||||
 | 
			
		||||
        if (this.useBareBones) {
 | 
			
		||||
            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
 | 
			
		||||
            modelResults.hits = event.data.results.map(function (hit) {
 | 
			
		||||
                return {
 | 
			
		||||
                    id: hit.id
 | 
			
		||||
                };
 | 
			
		||||
            });
 | 
			
		||||
        } 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);
 | 
			
		||||
        delete this.pendingQueries[event.data.queryId];
 | 
			
		||||
 
 | 
			
		||||
@@ -144,6 +144,8 @@
 | 
			
		||||
        message.results = results
 | 
			
		||||
            .slice(0, data.maxResults);
 | 
			
		||||
 | 
			
		||||
        console.log(message);
 | 
			
		||||
 | 
			
		||||
        return message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,47 @@
 | 
			
		||||
                    <span class="c-tree__item__label">Loading...</span>
 | 
			
		||||
                </div>
 | 
			
		||||
            </li>
 | 
			
		||||
            <tree-item v-for="child in children"
 | 
			
		||||
                       :key="child.id"
 | 
			
		||||
                       :node="child">
 | 
			
		||||
            </tree-item>
 | 
			
		||||
 | 
			
		||||
            <template v-if="children.length">
 | 
			
		||||
 | 
			
		||||
                <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>
 | 
			
		||||
    </li>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -29,6 +66,9 @@
 | 
			
		||||
<script>
 | 
			
		||||
    import viewControl from '../components/viewControl.vue';
 | 
			
		||||
    import ObjectLabel from '../components/ObjectLabel.vue';
 | 
			
		||||
    import Search from '../components/search.vue';
 | 
			
		||||
 | 
			
		||||
    const PAGE_THRESHOLD = 50;
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        name: 'tree-item',
 | 
			
		||||
@@ -44,7 +84,13 @@
 | 
			
		||||
                loaded: false,
 | 
			
		||||
                isNavigated: this.navigateToPath === this.openmct.router.currentLocation.path,
 | 
			
		||||
                children: [],
 | 
			
		||||
                expanded: false
 | 
			
		||||
                expanded: false,
 | 
			
		||||
                page: 1,
 | 
			
		||||
                page_threshold: PAGE_THRESHOLD,
 | 
			
		||||
                searchValue: '',
 | 
			
		||||
                filteredChildren: [],
 | 
			
		||||
                scrollTop: 0,
 | 
			
		||||
                showSearchComponent: false
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
@@ -55,6 +101,44 @@
 | 
			
		||||
                }
 | 
			
		||||
                let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
 | 
			
		||||
                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() {
 | 
			
		||||
@@ -97,6 +181,11 @@
 | 
			
		||||
                    this.composition.load().then(this.finishLoading);
 | 
			
		||||
                    this.isLoading = true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!isExpanded) {
 | 
			
		||||
                    this.page = 1;
 | 
			
		||||
                    this.showSearchComponent = false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
@@ -126,11 +215,53 @@
 | 
			
		||||
                } else if (oldPath === this.navigateToPath) {
 | 
			
		||||
                    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: {
 | 
			
		||||
            viewControl,
 | 
			
		||||
            ObjectLabel
 | 
			
		||||
            ObjectLabel,
 | 
			
		||||
            Search
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user