2015-07-16 17:35:26 +00: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 18:24:33 +00:00
|
|
|
* Module defining GenericSearchProvider. Created by shale on 07/16/2015.
|
2015-07-16 17:35:26 +00:00
|
|
|
*/
|
|
|
|
define(
|
|
|
|
[],
|
|
|
|
function () {
|
|
|
|
"use strict";
|
2015-07-16 18:31:11 +00:00
|
|
|
|
2015-07-20 17:58:59 +00:00
|
|
|
var DEFAULT_MAX_RESULTS = 100,
|
|
|
|
DEFAULT_TIMEOUT = 1000,
|
|
|
|
stopTime;
|
2015-07-16 18:31:11 +00:00
|
|
|
|
2015-07-16 17:35:26 +00:00
|
|
|
/**
|
2015-07-20 17:58:59 +00:00
|
|
|
* A search service which searches through domain objects in
|
|
|
|
* the filetree without using external search implementations.
|
2015-07-16 17:35:26 +00:00
|
|
|
*
|
|
|
|
* @constructor
|
2015-07-20 17:58:59 +00:00
|
|
|
* @param {ObjectService} objectService the service from which
|
|
|
|
* domain objects can be gotten.
|
|
|
|
* @param {WorkerService} workerService the service which allows
|
|
|
|
* more easy creation of web workers.
|
2015-07-16 17:35:26 +00:00
|
|
|
*/
|
2015-07-20 18:21:55 +00:00
|
|
|
function GenericSearchProvider($rootScope, objectService, workerService) {
|
2015-07-21 16:41:08 +00:00
|
|
|
var validType = function () {return true;};
|
|
|
|
|
2015-07-20 17:58:59 +00:00
|
|
|
var worker = workerService.run('genericSearchWorker'),
|
|
|
|
lastestItems;
|
|
|
|
|
2015-07-21 16:58:19 +00:00
|
|
|
/*
|
2015-07-20 17:58:59 +00:00
|
|
|
function requestItems() {
|
|
|
|
// Aquire My Items (root folder)
|
|
|
|
// I don't think we can do this part in the webworker because of the objectService
|
|
|
|
return objectService.getObjects(['mine']).then(function (objects) {
|
|
|
|
// Get the webworker to go through the tree
|
|
|
|
console.log('about to post');
|
|
|
|
console.log('objects.mine', objects.mine);
|
|
|
|
console.log('objects.mine stringify', JSON.stringify(objects.mine));
|
|
|
|
console.log('objectService', objectService);
|
|
|
|
console.log('objectService stringify', JSON.stringify(objectService));
|
|
|
|
|
|
|
|
// Testing making JSON object
|
|
|
|
var jsonObj = {};
|
|
|
|
var getC = JSON.stringify(objects.mine.getCapability);
|
|
|
|
console.log('empty json', jsonObj);
|
|
|
|
jsonObj = {
|
|
|
|
getCapability: getC,
|
|
|
|
getId: objects.mine.getId,
|
|
|
|
getModel: objects.mine.getModel,
|
|
|
|
hasCapability: objects.mine.hasCapability,
|
|
|
|
useCapability: objects.mine.useCapability
|
|
|
|
};
|
|
|
|
console.log('json', jsonObj);
|
|
|
|
|
|
|
|
worker.postMessage(jsonObj); // Not working :(
|
|
|
|
console.log('posted');
|
|
|
|
});
|
|
|
|
//counter += 1;
|
|
|
|
}
|
2015-07-21 00:02:08 +00:00
|
|
|
*/
|
2015-07-20 17:58:59 +00:00
|
|
|
|
2015-07-21 16:58:19 +00:00
|
|
|
// Tell the web worker to add a new item's model to its list of items.
|
|
|
|
function indexItem(domainObject) {
|
|
|
|
var message = {
|
|
|
|
request: 'index',
|
2015-07-21 17:10:34 +00:00
|
|
|
model: domainObject.getModel(),
|
|
|
|
id: domainObject.getId()
|
2015-07-21 16:58:19 +00:00
|
|
|
};
|
|
|
|
// Note that getModel() by definition returns a JavaScript object
|
|
|
|
// that can be losslesly converted to a JSON object.
|
|
|
|
worker.postMessage(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// less than that if there are fewer matches).
|
|
|
|
function workerSearch(searchInput, numberOfResults) {
|
|
|
|
var message = {
|
|
|
|
request: 'search',
|
|
|
|
input: searchInput,
|
2015-07-21 17:35:33 +00:00
|
|
|
maxNumber: numberOfResults
|
2015-07-21 16:58:19 +00:00
|
|
|
};
|
|
|
|
worker.postMessage(message);
|
|
|
|
}
|
|
|
|
|
2015-07-20 17:58:59 +00:00
|
|
|
function handleResponse(event) {
|
2015-07-21 16:58:19 +00:00
|
|
|
//latest = event.data;
|
2015-07-21 17:10:34 +00:00
|
|
|
console.log('handleResponse', event.data);
|
2015-07-21 16:58:19 +00:00
|
|
|
//$rootScope.$apply();
|
2015-07-20 17:58:59 +00:00
|
|
|
//requestNext();
|
|
|
|
}
|
2015-07-16 17:35:26 +00:00
|
|
|
|
|
|
|
// Recursive helper function for getItems()
|
|
|
|
function itemsHelper(children, i) {
|
2015-07-20 17:58:59 +00:00
|
|
|
var date = new Date;
|
2015-07-20 18:21:55 +00:00
|
|
|
if (stopTime && date.getTime() >= stopTime) {
|
2015-07-20 17:58:59 +00:00
|
|
|
// This indexing of items has timed out
|
|
|
|
return children;
|
|
|
|
} else if (i >= children.length) {
|
2015-07-16 17:35:26 +00: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 18:21:55 +00:00
|
|
|
function getItems(timeout) {
|
2015-07-16 17:35:26 +00:00
|
|
|
// Aquire My Items (root folder)
|
|
|
|
return objectService.getObjects(['mine']).then(function (objects) {
|
|
|
|
// Get all of its descendents
|
2015-07-20 17:58:59 +00:00
|
|
|
|
2015-07-20 18:21:55 +00:00
|
|
|
if (timeout) {
|
|
|
|
// Set a timeout for itemsHelper
|
|
|
|
var date = new Date;
|
|
|
|
stopTime = date.getTime() + timeout;
|
|
|
|
}
|
|
|
|
// If there was no timeout provided, leave undefined
|
|
|
|
// itemsHelper should just treat this as having no timeout
|
2015-07-20 17:58:59 +00:00
|
|
|
|
2015-07-16 20:08:05 +00:00
|
|
|
return itemsHelper([objects.mine], 0).then(function (items) {
|
|
|
|
// Turn them into searchResult objects (object, id, and score)
|
|
|
|
var searchResultItems = [];
|
|
|
|
|
|
|
|
for (var i = 0; i < items.length; i += 1) {
|
2015-07-21 17:10:34 +00:00
|
|
|
// Test out calling worker indexItem
|
|
|
|
indexItem(items[i]);
|
|
|
|
|
2015-07-16 20:08:05 +00:00
|
|
|
searchResultItems.push({
|
|
|
|
id: items[i].getId(),
|
|
|
|
object: items[i],
|
2015-07-21 00:02:08 +00:00
|
|
|
score: 0 // Assign actual score when filtering for term
|
2015-07-16 20:08:05 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
//console.log('searchResultItems (in Everything)', searchResultItems);
|
|
|
|
return searchResultItems;
|
2015-07-16 17:35:26 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-07-17 20:49:09 +00:00
|
|
|
// Process the search input. Makes an array of search terms
|
|
|
|
// by splitting up the input at spaces.
|
|
|
|
function process(input) {
|
2015-07-17 21:06:14 +00:00
|
|
|
return input.toLocaleLowerCase().split(' ');
|
2015-07-16 21:36:02 +00:00
|
|
|
}
|
|
|
|
|
2015-07-17 20:49:09 +00:00
|
|
|
// Generate a score for an item based on its similarity to a search term.
|
|
|
|
// The score is equal to the number of terms that are a substring of the
|
|
|
|
// object name.
|
|
|
|
function score(item, terms, originalInput) {
|
|
|
|
var name = item.object.getModel().name.toLocaleLowerCase(),
|
2015-07-17 21:06:14 +00:00
|
|
|
weight = .65,
|
|
|
|
score = 0;
|
|
|
|
|
|
|
|
// Make the score really big if the item name and
|
|
|
|
// the original search input are the same
|
|
|
|
if (name === originalInput.toLocaleLowerCase()) {
|
|
|
|
score = 42;
|
|
|
|
}
|
2015-07-16 23:50:07 +00:00
|
|
|
|
2015-07-17 20:49:09 +00:00
|
|
|
for (var i = 0; i < terms.length; i++) {
|
|
|
|
// Increase the score if the term is in the item name
|
|
|
|
if (name.includes(terms[i])) {
|
|
|
|
score++;
|
2015-07-17 21:06:14 +00:00
|
|
|
|
|
|
|
// Add extra to the score if the search term exists
|
|
|
|
// as its own term within the items
|
|
|
|
if (name.split(' ').indexOf(terms[i]) !== -1) {
|
|
|
|
score += .5;
|
|
|
|
}
|
2015-07-17 20:49:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-17 21:06:14 +00:00
|
|
|
return score * weight;
|
2015-07-16 23:50:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:36:02 +00:00
|
|
|
// Filter through a list of searchResults based on a search term
|
2015-07-21 16:41:08 +00:00
|
|
|
function filterResults(results, originalInput, resultsLength) {
|
2015-07-17 20:49:09 +00:00
|
|
|
var terms,
|
|
|
|
searchResults = [],
|
2015-07-16 23:50:07 +00:00
|
|
|
itemModel;
|
2015-07-16 21:36:02 +00:00
|
|
|
|
2015-07-17 20:49:09 +00:00
|
|
|
// Split the original search input into search terms
|
|
|
|
terms = process(originalInput);
|
|
|
|
|
2015-07-16 21:36:02 +00:00
|
|
|
for (var i = 0; i < resultsLength; i += 1) {
|
|
|
|
// Prevent errors from getModel not being defined
|
|
|
|
if (results[i].object.getModel) {
|
2015-07-17 20:49:09 +00:00
|
|
|
results[i].score = score(results[i], terms, originalInput);
|
|
|
|
// Include any items that match the terms and are of valid type
|
|
|
|
if (results[i].score > 0 && validType(results[i].object.getModel())) {
|
2015-07-16 21:36:02 +00:00
|
|
|
// Add the result to the result list
|
|
|
|
searchResults.push(results[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return searchResults;
|
|
|
|
}
|
|
|
|
|
2015-07-16 17:35:26 +00:00
|
|
|
/**
|
|
|
|
* Searches through the filetree for domain objects which match
|
|
|
|
* the search term. This function is to be used as a fallback
|
|
|
|
* in the case where other search services are not avaliable.
|
|
|
|
* Notes:
|
|
|
|
* * The order of the results is not guarenteed.
|
|
|
|
* * A domain object qualifies as a match for a search term if
|
|
|
|
* the object's name property contains the exact search term
|
|
|
|
* as a substring.
|
|
|
|
* * Wildcards are not supported.
|
|
|
|
*
|
|
|
|
* @param inputID the name of the ID property of the html text
|
|
|
|
* input where this funcion should find the search term
|
2015-07-21 16:41:08 +00:00
|
|
|
* @param passedValidType (optional) a function which takes a
|
|
|
|
* model for an object and determines if it is a valid type to
|
|
|
|
* include in the final list of results; default returns true
|
2015-07-16 17:35:26 +00:00
|
|
|
* @param maxResults (optional) the maximum number of results
|
|
|
|
* that this function should return
|
2015-07-20 18:21:55 +00:00
|
|
|
* @param timeout (optional) the time after which the search should
|
|
|
|
* stop calculations and return partial results
|
2015-07-16 17:35:26 +00:00
|
|
|
*/
|
2015-07-21 16:41:08 +00:00
|
|
|
function queryGeneric(inputID, passedValidType, maxResults, timeout) {
|
2015-07-17 20:49:09 +00:00
|
|
|
var input,
|
|
|
|
terms = [],
|
2015-07-16 17:35:26 +00:00
|
|
|
searchResults = [],
|
2015-07-16 21:36:02 +00:00
|
|
|
resultsLength;
|
2015-07-16 17:35:26 +00:00
|
|
|
|
|
|
|
// Check to see if the user provided a maximum
|
|
|
|
// number of results to display
|
|
|
|
if (!maxResults) {
|
|
|
|
// Else, we provide a default value.
|
|
|
|
maxResults = DEFAULT_MAX_RESULTS;
|
|
|
|
}
|
|
|
|
|
2015-07-21 16:41:08 +00:00
|
|
|
// Check to see if a valid type function was provided
|
|
|
|
if (passedValidType) {
|
|
|
|
validType = passedValidType;
|
|
|
|
}
|
|
|
|
|
2015-07-20 18:21:55 +00:00
|
|
|
|
2015-07-16 17:35:26 +00:00
|
|
|
// Get the user input
|
2015-07-17 20:49:09 +00:00
|
|
|
input = document.getElementById(inputID).value;
|
2015-07-16 17:35:26 +00:00
|
|
|
|
|
|
|
// Get items list
|
2015-07-20 17:58:59 +00:00
|
|
|
//requestItems(); // Test out the worker
|
2015-07-20 18:21:55 +00:00
|
|
|
return getItems(timeout).then(function (searchResultItems) {
|
2015-07-16 17:35:26 +00:00
|
|
|
// Keep track of the number of results to display
|
2015-07-16 20:08:05 +00:00
|
|
|
if (searchResultItems.length < maxResults) {
|
|
|
|
resultsLength = searchResultItems.length;
|
2015-07-16 17:35:26 +00:00
|
|
|
} else {
|
|
|
|
resultsLength = maxResults;
|
|
|
|
}
|
2015-07-21 17:10:34 +00:00
|
|
|
|
|
|
|
// Test out calling the web worker search
|
|
|
|
workerSearch(input, maxResults);
|
2015-07-16 17:35:26 +00:00
|
|
|
|
|
|
|
// Then filter through the items list
|
2015-07-21 16:41:08 +00:00
|
|
|
searchResults = filterResults(searchResultItems, input, resultsLength);
|
2015-07-16 17:35:26 +00:00
|
|
|
|
2015-07-21 00:02:08 +00:00
|
|
|
//console.log('filtered searchResults (in Everything)', searchResults);
|
|
|
|
return searchResults;
|
2015-07-16 17:35:26 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2015-07-17 20:49:09 +00:00
|
|
|
query: queryGeneric
|
2015-07-16 17:35:26 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-17 18:24:33 +00:00
|
|
|
return GenericSearchProvider;
|
2015-07-16 17:35:26 +00:00
|
|
|
}
|
|
|
|
);
|