2015-07-16 10:35:26 -07:00
|
|
|
/*****************************************************************************
|
|
|
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
|
|
|
* as represented by the Administrator of the National Aeronautics and Space
|
|
|
|
* Administration. All rights reserved.
|
|
|
|
*
|
|
|
|
* Open MCT Web 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 Web 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 define*/
|
|
|
|
|
|
|
|
/**
|
2015-07-17 11:24:33 -07:00
|
|
|
* Module defining GenericSearchProvider. Created by shale on 07/16/2015.
|
2015-07-16 10:35:26 -07:00
|
|
|
*/
|
|
|
|
define(
|
|
|
|
[],
|
|
|
|
function () {
|
|
|
|
"use strict";
|
2015-07-16 11:31:11 -07:00
|
|
|
|
2015-07-20 10:58:59 -07:00
|
|
|
var DEFAULT_MAX_RESULTS = 100,
|
|
|
|
DEFAULT_TIMEOUT = 1000,
|
|
|
|
stopTime;
|
2015-07-16 11:31:11 -07:00
|
|
|
|
2015-07-16 10:35:26 -07:00
|
|
|
/**
|
2015-07-20 10:58:59 -07:00
|
|
|
* A search service which searches through domain objects in
|
|
|
|
* the filetree without using external search implementations.
|
2015-07-16 10:35:26 -07:00
|
|
|
*
|
|
|
|
* @constructor
|
2015-08-04 10:01:54 -07:00
|
|
|
* @param $q Angular's $q, for promise consolidation.
|
|
|
|
* @param {ObjectService} objectService The service from which
|
2015-07-20 10:58:59 -07:00
|
|
|
* domain objects can be gotten.
|
2015-08-04 10:01:54 -07:00
|
|
|
* @param {WorkerService} workerService The service which allows
|
2015-07-20 10:58:59 -07:00
|
|
|
* more easy creation of web workers.
|
2015-08-04 10:01:54 -07:00
|
|
|
* @param {roots[]} roots An array of all the root domain objects.
|
2015-07-16 10:35:26 -07:00
|
|
|
*/
|
2015-07-29 15:07:13 -07:00
|
|
|
function GenericSearchProvider($q, objectService, workerService, roots) {
|
2015-07-20 10:58:59 -07:00
|
|
|
var worker = workerService.run('genericSearchWorker'),
|
2015-07-29 15:07:13 -07:00
|
|
|
pendingQueries = {};
|
|
|
|
// pendingQueries is a dictionary with the key value pairs st
|
|
|
|
// the key is the timestamp and the value is the promise
|
|
|
|
|
2015-07-29 13:17:50 -07:00
|
|
|
// Tell the web worker to add a domain object's model to its list of items.
|
2015-07-21 09:58:19 -07:00
|
|
|
function indexItem(domainObject) {
|
2015-07-29 10:59:58 -07:00
|
|
|
var message;
|
|
|
|
|
|
|
|
// undefined check
|
|
|
|
if (domainObject && domainObject.getModel) {
|
|
|
|
// Using model instead of whole domain object because
|
|
|
|
// it's a JSON object.
|
|
|
|
message = {
|
|
|
|
request: 'index',
|
|
|
|
model: domainObject.getModel(),
|
|
|
|
id: domainObject.getId()
|
|
|
|
};
|
|
|
|
worker.postMessage(message);
|
|
|
|
}
|
2015-07-21 09:58:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tell the worker to search for items it has that match this searchInput.
|
|
|
|
// Takes the searchInput, as well as a max number of results (will return
|
2015-07-28 11:33:29 -07:00
|
|
|
// less than that if there are fewer matches).
|
2015-07-30 16:35:26 -07:00
|
|
|
function workerSearch(searchInput, maxResults, timestamp, timeout) {
|
2015-07-21 09:58:19 -07:00
|
|
|
var message = {
|
2015-07-28 10:15:05 -07:00
|
|
|
request: 'search',
|
2015-07-21 09:58:19 -07:00
|
|
|
input: searchInput,
|
2015-07-28 10:15:05 -07:00
|
|
|
maxNumber: maxResults,
|
2015-07-30 16:35:26 -07:00
|
|
|
timestamp: timestamp,
|
|
|
|
timeout: timeout
|
2015-07-21 09:58:19 -07:00
|
|
|
};
|
|
|
|
worker.postMessage(message);
|
|
|
|
}
|
|
|
|
|
2015-08-04 10:01:54 -07:00
|
|
|
// Handles responses from the web worker. Namely, the results of
|
|
|
|
// a search request.
|
2015-07-20 10:58:59 -07:00
|
|
|
function handleResponse(event) {
|
2015-07-29 13:17:50 -07:00
|
|
|
var ids = [],
|
2015-07-28 10:15:05 -07:00
|
|
|
id;
|
|
|
|
|
2015-07-29 13:17:50 -07:00
|
|
|
// If we have the results from a search
|
2015-07-21 11:14:10 -07:00
|
|
|
if (event.data.request === 'search') {
|
2015-07-21 12:34:08 -07:00
|
|
|
// Convert the ids given from the web worker into domain objects
|
2015-07-28 10:15:05 -07:00
|
|
|
for (id in event.data.results) {
|
2015-07-21 14:55:44 -07:00
|
|
|
ids.push(id);
|
2015-07-21 12:34:08 -07:00
|
|
|
}
|
|
|
|
objectService.getObjects(ids).then(function (objects) {
|
2015-07-30 13:54:56 -07:00
|
|
|
var searchResults = [],
|
2015-07-29 15:22:46 -07:00
|
|
|
id;
|
2015-07-28 11:33:29 -07:00
|
|
|
|
2015-08-04 10:01:54 -07:00
|
|
|
// Create searchResult objects
|
2015-07-28 10:15:05 -07:00
|
|
|
for (id in objects) {
|
2015-07-30 13:54:56 -07:00
|
|
|
searchResults.push({
|
2015-07-21 12:44:14 -07:00
|
|
|
object: objects[id],
|
2015-07-21 14:55:44 -07:00
|
|
|
id: id,
|
2015-07-30 13:19:19 -07:00
|
|
|
score: event.data.results[id]
|
2015-07-21 12:44:14 -07:00
|
|
|
});
|
2015-07-21 12:34:08 -07:00
|
|
|
}
|
2015-07-29 15:07:13 -07:00
|
|
|
|
|
|
|
// Resove the promise corresponding to this
|
2015-08-04 10:01:54 -07:00
|
|
|
pendingQueries[event.data.timestamp].resolve({
|
|
|
|
hits: searchResults,
|
|
|
|
total: event.data.total,
|
|
|
|
timedOut: event.data.timedOut
|
|
|
|
});
|
2015-07-21 12:34:08 -07:00
|
|
|
});
|
2015-07-21 11:14:10 -07:00
|
|
|
}
|
2015-07-20 10:58:59 -07:00
|
|
|
}
|
2015-07-16 10:35:26 -07:00
|
|
|
|
2015-07-28 10:15:05 -07:00
|
|
|
worker.onmessage = handleResponse;
|
|
|
|
|
2015-08-04 10:01:54 -07:00
|
|
|
// Helper function for getItems(). Indexes the tree.
|
2015-07-16 10:35:26 -07:00
|
|
|
function itemsHelper(children, i) {
|
2015-07-29 10:59:58 -07:00
|
|
|
// Index the current node
|
|
|
|
indexItem(children[i]);
|
|
|
|
|
|
|
|
if (i >= children.length) {
|
2015-07-16 10:35:26 -07:00
|
|
|
// Done!
|
|
|
|
return children;
|
|
|
|
} else if (children[i].hasCapability('composition')) {
|
|
|
|
// This child has children
|
|
|
|
return children[i].getCapability('composition').invoke().then(function (grandchildren) {
|
|
|
|
// Add grandchildren to the end of the list
|
|
|
|
// They will also be checked for composition
|
|
|
|
return itemsHelper(children.concat(grandchildren), i + 1);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// This child is a leaf
|
|
|
|
return itemsHelper(children, i + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converts the filetree into a list
|
2015-07-20 11:21:55 -07:00
|
|
|
function getItems(timeout) {
|
2015-07-22 16:21:34 -07:00
|
|
|
// Aquire root objects
|
2015-08-04 11:48:28 -07:00
|
|
|
objectService.getObjects(roots).then(function (objectsById) {
|
2015-07-28 10:15:05 -07:00
|
|
|
var objects = [],
|
|
|
|
id;
|
2015-07-20 10:58:59 -07:00
|
|
|
|
2015-08-04 10:01:54 -07:00
|
|
|
// Get each of the domain objects in objectsById
|
2015-07-28 10:15:05 -07:00
|
|
|
for (id in objectsById) {
|
2015-07-22 16:21:34 -07:00
|
|
|
objects.push(objectsById[id]);
|
|
|
|
}
|
|
|
|
|
2015-07-29 10:59:58 -07:00
|
|
|
// Index all of the roots' descendents
|
|
|
|
itemsHelper(objects, 0);
|
2015-07-16 10:35:26 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-07-29 15:07:13 -07:00
|
|
|
|
2015-08-04 10:01:54 -07:00
|
|
|
// For documentation, see query below
|
2015-07-30 16:35:26 -07:00
|
|
|
function query(input, timestamp, maxResults, timeout) {
|
2015-07-23 16:10:03 -07:00
|
|
|
var terms = [],
|
2015-07-16 10:35:26 -07:00
|
|
|
searchResults = [],
|
2015-07-29 15:07:13 -07:00
|
|
|
defer = $q.defer();
|
|
|
|
|
2015-08-04 10:01:54 -07:00
|
|
|
// Allow us to access this promise later to resolve it later
|
2015-07-29 15:07:13 -07:00
|
|
|
pendingQueries[timestamp] = defer;
|
2015-07-16 10:35:26 -07:00
|
|
|
|
|
|
|
// Check to see if the user provided a maximum
|
2015-07-30 13:19:19 -07:00
|
|
|
// number of results to display
|
2015-07-16 10:35:26 -07:00
|
|
|
if (!maxResults) {
|
2015-08-04 10:01:54 -07:00
|
|
|
// Else, we provide a default value
|
2015-07-16 10:35:26 -07:00
|
|
|
maxResults = DEFAULT_MAX_RESULTS;
|
|
|
|
}
|
2015-07-30 16:35:26 -07:00
|
|
|
// Similarly, check if timeout was provided
|
|
|
|
if (!timeout) {
|
|
|
|
timeout = DEFAULT_TIMEOUT;
|
|
|
|
}
|
2015-07-16 10:35:26 -07:00
|
|
|
|
2015-08-04 10:01:54 -07:00
|
|
|
// Send the query to the worker
|
2015-07-30 16:35:26 -07:00
|
|
|
workerSearch(input, maxResults, timestamp, timeout);
|
2015-07-29 15:07:13 -07:00
|
|
|
|
|
|
|
return defer.promise;
|
2015-07-16 10:35:26 -07:00
|
|
|
}
|
|
|
|
|
2015-07-29 10:26:24 -07:00
|
|
|
// Index the tree's contents once at the beginning
|
2015-07-29 13:17:50 -07:00
|
|
|
getItems();
|
2015-07-29 10:26:24 -07:00
|
|
|
|
2015-07-16 10:35:26 -07:00
|
|
|
return {
|
2015-07-21 15:31:23 -07:00
|
|
|
/**
|
|
|
|
* Searches through the filetree for domain objects which match
|
|
|
|
* the search term. This function is to be used as a fallback
|
2015-07-30 13:19:19 -07:00
|
|
|
* in the case where other search services are not avaliable.
|
2015-07-30 13:54:56 -07:00
|
|
|
* Returns a promise for a result object that has the format
|
2015-07-30 16:35:26 -07:00
|
|
|
* {hits: searchResult[], total: number, timedOut: boolean}
|
2015-07-30 13:54:56 -07:00
|
|
|
* where a searchResult has the format
|
2015-08-04 11:39:09 -07:00
|
|
|
* {id: string, object: domainObject, score: number}
|
2015-07-30 13:54:56 -07:00
|
|
|
*
|
2015-07-21 15:31:23 -07:00
|
|
|
* Notes:
|
|
|
|
* * The order of the results is not guarenteed.
|
|
|
|
* * A domain object qualifies as a match for a search input if
|
|
|
|
* the object's name property contains any of the search terms
|
|
|
|
* (which are generated by splitting the input at spaces).
|
2015-08-04 10:01:54 -07:00
|
|
|
* * Scores are higher for matches that have more of the terms
|
|
|
|
* as substrings.
|
2015-07-21 15:31:23 -07:00
|
|
|
*
|
2015-07-23 16:10:03 -07:00
|
|
|
* @param input The text input that is the query.
|
2015-07-30 13:19:19 -07:00
|
|
|
* @param timestamp The time at which this function was called.
|
|
|
|
* This timestamp is used as a unique identifier for this
|
|
|
|
* query and the corresponding results.
|
|
|
|
* @param maxResults (optional) The maximum number of results
|
|
|
|
* that this function should return.
|
|
|
|
* @param timeout (optional) The time after which the search should
|
|
|
|
* stop calculations and return partial results.
|
2015-07-21 15:31:23 -07:00
|
|
|
*/
|
2015-07-30 13:19:19 -07:00
|
|
|
query: query
|
2015-07-29 15:22:46 -07:00
|
|
|
|
2015-07-16 10:35:26 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-17 11:24:33 -07:00
|
|
|
return GenericSearchProvider;
|
2015-07-16 10:35:26 -07:00
|
|
|
}
|
|
|
|
);
|