From 5870248617b1e2323845d5acbad6ca8ce57c36b8 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 8 Jul 2015 15:32:20 -0700 Subject: [PATCH 001/195] [Search] Search framework Created a basic framework for a search view. It consists of a search bar and a results list. --- bundles.json | 1 + platform/features/search/bundle.json | 22 +++++++++ .../search/res/templates/search-item.html | 48 ++++++++++++++++++ .../features/search/res/templates/search.html | 38 ++++++++++++++ .../features/search/src/SearchController.js | 49 +++++++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 platform/features/search/bundle.json create mode 100644 platform/features/search/res/templates/search-item.html create mode 100644 platform/features/search/res/templates/search.html create mode 100644 platform/features/search/src/SearchController.js diff --git a/bundles.json b/bundles.json index f69e127eec..3ded09421b 100644 --- a/bundles.json +++ b/bundles.json @@ -16,6 +16,7 @@ "platform/features/pages", "platform/features/plot", "platform/features/scrolling", + "platform/features/search", "platform/features/events", "platform/forms", "platform/persistence/queue", diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json new file mode 100644 index 0000000000..e1bd267914 --- /dev/null +++ b/platform/features/search/bundle.json @@ -0,0 +1,22 @@ +{ + "name": "Search View", + "description": "Allows the user to search through the file three.", + "extensions": { + "views": [ + { + "key": "search", + "name": "Search", + "glyph": "5", + "description": "Search functionality.", + "templateUrl": "templates/search.html" + } + ], + "controllers": [ + { + "key": "SearchController", + "implementation": "SearchController.js", + "depends": [ "$scope" ] + } + ] + } +} \ No newline at end of file diff --git a/platform/features/search/res/templates/search-item.html b/platform/features/search/res/templates/search-item.html new file mode 100644 index 0000000000..c51b5172e1 --- /dev/null +++ b/platform/features/search/res/templates/search-item.html @@ -0,0 +1,48 @@ + + + +
+
+
+
+ +
+
+ +
P
+
+
+
+
{{type.getGlyph()}}
+
}
+
+
+
{{model.name}}
+
+ + {{model.composition.length}} Items + +
+
+
+
\ No newline at end of file diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html new file mode 100644 index 0000000000..9e7b6d503e --- /dev/null +++ b/platform/features/search/res/templates/search.html @@ -0,0 +1,38 @@ + + +
+ +
+
+ Search in this folder:
+ + +
+
+ + + + +
\ No newline at end of file diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js new file mode 100644 index 0000000000..9cdc3d4bc4 --- /dev/null +++ b/platform/features/search/src/SearchController.js @@ -0,0 +1,49 @@ +/***************************************************************************** + * 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,Promise*/ + +/** + * Module defining ListController. Created by vwoeltje on 11/18/14. + */ +define(function () { + + function SearchController($scope) { + var items = [], + searchResults = []; + + // Indexes the filetree into a searchable format + function indexTree() { + var persistence = $scope.domainObject.getCapability('persistence'); + return persistence && persistence.persist(); + } + + // Search through items for items which have the search term + // in the title + function search(term) { + // modify searchResults + } + + // When the search view is opened, call indexTree() + // When the search button is pressed, call search() + } + return SearchController; +}); \ No newline at end of file From 845b9a2faa39a5371208a320cf987a201bc4b391 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 8 Jul 2015 15:34:09 -0700 Subject: [PATCH 002/195] [Search] Fixed comments --- platform/features/search/src/SearchController.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 9cdc3d4bc4..5c479bda71 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -22,7 +22,7 @@ /*global define,Promise*/ /** - * Module defining ListController. Created by vwoeltje on 11/18/14. + * Module defining SearchController. Created by shale on 07/08/2015. */ define(function () { @@ -32,8 +32,7 @@ define(function () { // Indexes the filetree into a searchable format function indexTree() { - var persistence = $scope.domainObject.getCapability('persistence'); - return persistence && persistence.persist(); + } // Search through items for items which have the search term From 32eaf3893a10b2d94e3ab79ba9acc6111dd739bd Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 8 Jul 2015 16:20:12 -0700 Subject: [PATCH 003/195] [Search] Display search items The search view now very rudimentarily displays some 'search-item's. --- platform/features/search/bundle.json | 8 +++++++ .../search/res/templates/search-item.html | 3 ++- .../features/search/res/templates/search.html | 23 ++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index e1bd267914..3089027111 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -17,6 +17,14 @@ "implementation": "SearchController.js", "depends": [ "$scope" ] } + ], + "representations": [ + { + "key": "search-item", + "templateUrl": "templates/search-item.html", + "uses": [ "type", "action" ], + "gestures": [ "info", "menu" ] + } ] } } \ No newline at end of file diff --git a/platform/features/search/res/templates/search-item.html b/platform/features/search/res/templates/search-item.html index c51b5172e1..1de0db25e9 100644 --- a/platform/features/search/res/templates/search-item.html +++ b/platform/features/search/res/templates/search-item.html @@ -21,7 +21,8 @@ --> -
+
+ ITEM
diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 9e7b6d503e..83019c4515 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -21,18 +21,29 @@ -->
+ -
+
Search in this folder:
- + + +
+ - - +
    +
  • + +
  • +
  • + +
  • +
+
\ No newline at end of file From 94b306e129882a20dcb76a5386c8996c88b54715 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 9 Jul 2015 11:16:55 -0700 Subject: [PATCH 004/195] [Search] Listify filetree SearchController now attempts to convert the filetree into a list format. Still needs to be modified to be asynchronous. --- platform/features/search/bundle.json | 6 +- .../search/res/templates/search-item.html | 4 +- .../features/search/res/templates/search.html | 21 +++-- .../features/search/src/SearchController.js | 77 +++++++++++++++++-- 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 3089027111..e391934114 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -1,6 +1,6 @@ { "name": "Search View", - "description": "Allows the user to search through the file three.", + "description": "Allows the user to search through the file tree.", "extensions": { "views": [ { @@ -15,14 +15,14 @@ { "key": "SearchController", "implementation": "SearchController.js", - "depends": [ "$scope" ] + "depends": [ "$scope", "objectService" ] } ], "representations": [ { "key": "search-item", "templateUrl": "templates/search-item.html", - "uses": [ "type", "action" ], + "uses": [ "type", "action", "composition" ], "gestures": [ "info", "menu" ] } ] diff --git a/platform/features/search/res/templates/search-item.html b/platform/features/search/res/templates/search-item.html index 1de0db25e9..765a64c813 100644 --- a/platform/features/search/res/templates/search-item.html +++ b/platform/features/search/res/templates/search-item.html @@ -23,7 +23,7 @@
ITEM -
+
\ No newline at end of file diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 83019c4515..87de36a0d2 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -20,14 +20,23 @@ at runtime from the About dialog for additional information. --> -
+
-
+
+
+ + +
+ +
+ +
+
@@ -42,7 +51,9 @@ mct-object="childObject"-->
  • - +
  • diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 5c479bda71..7f623c8473 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -19,30 +19,95 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/*global define,Promise*/ +/*global define*/ /** * Module defining SearchController. Created by shale on 07/08/2015. */ define(function () { + "use strict"; - function SearchController($scope) { + function SearchController($scope, objectService) { var items = [], searchResults = []; - // Indexes the filetree into a searchable format - function indexTree() { + // Get the root object + /* + objectService.getObjects(['root']).then(function (objects) { + console.log('rootObject 1', rootObject); + rootObject = objects.root; + console.log('rootObject 2', rootObject); + + + console.log('hasCapability("editor") ', rootObject.hasCapability('editor')); + console.log('getModel() ', rootObject.getModel()); + console.log('getId() ', rootObject.getId()); + + // Get the children of the root object + console.log('hasCapability("composition") ', rootObject.hasCapability('composition')); + if (rootObject.hasCapability('composition')) { + rootComposition = rootObject.getCapability('composition').invoke(); + console.log('rootComposition ', rootComposition); + } + }); + console.log('rootObject 3', rootObject); + */ + + + + // Converts the filetree into a list + // Eventually, plan to call search service + // (but do here for now) + function listify() { + // For now, we want this view to only be in the My Items folder + if ($scope.domainObject.getId() === 'mine') { + var out = listHelper($scope.domainObject); + //console.log('out', out); + return out; + } + // Fallback if we aren't in My Items + return items; + } + // Recursive helper function to go through the tree + function listHelper(current) { + //console.log('current', current); + //console.log('current.getID', current.getId()); + var composition; + if (current.hasCapability('composition')) { + composition = current.getCapability('composition'); + } else { + //console.log('does not have capability'); + return current; + } + composition.invoke().then(function (children) { + if (children === []) { + return current; + } else { + var subList = [current], + i; + for (i = 0; i < children.length; i += 1) { + subList.concat(listHelper(children[i])); + } + //console.log('subList ', subList); //////////// + return subList; + } + }); } // Search through items for items which have the search term // in the title function search(term) { // modify searchResults + + return searchResults; } - // When the search view is opened, call indexTree() + // When the search view is opened, call listify() // When the search button is pressed, call search() + + $scope.items = listify(); + $scope.results = search(); } - return SearchController; + return SearchController; }); \ No newline at end of file From e339ee1dd1b0e3540f4b923c0233a1f3f6e792c5 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 9 Jul 2015 14:40:52 -0700 Subject: [PATCH 005/195] [Search] Asynchronous recursion The list creation now sucessfully goes 1 level deep into the tree for objects. Still needs more work to delve into subfolders. --- .../features/search/src/SearchController.js | 126 ++++++++++-------- 1 file changed, 70 insertions(+), 56 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 7f623c8473..f37b32d503 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -31,6 +31,75 @@ define(function () { var items = [], searchResults = []; + // Converts the filetree into a list + // Eventually, plan to call search service + // (but do here for now) + function listify() { + // For now, we want this view to only be in the My Items folder + if ($scope.domainObject.getId() === 'mine') { + var list = listHelper($scope.domainObject); + //debugger; + //console.log('out ', out); + return list.then(function (c) { + //console.log('c ', c); + return c; + }); + } + // Fallback if we aren't in My Items + return items; + } + + // Recursive helper function to go through the tree + function listHelper(current) { + var composition; + + if (current.hasCapability('composition')) { + composition = current.getCapability('composition'); + } else { + // Base case. + return current; + } + + // Recursive case. Is asynchronous. + return composition.invoke().then(function (children) { + + var subList = [current], + i; + for (i = 0; i < children.length; i += 1) { + subList.push(listHelper(children[i])); + //console.log('subList', subList, 'index', i); + } + //console.log('sublist ', subList); + return subList; + + /* + var array = [current].concat(children.forEach(listHelper)); + console.log('array ', array); + return array; + */ + }); + } + + // Search through items for items which have the search term + // in the title + function search(term) { + // modify searchResults + + return searchResults; + } + + // When the search view is opened, call listify() + // When the search button is pressed, call search() + + $scope.items = listify(); + $scope.results = search(); + } + return SearchController; +}); + + + ///// Old stuff to look at later + // Get the root object /* objectService.getObjects(['root']).then(function (objects) { @@ -55,59 +124,4 @@ define(function () { */ - - // Converts the filetree into a list - // Eventually, plan to call search service - // (but do here for now) - function listify() { - // For now, we want this view to only be in the My Items folder - if ($scope.domainObject.getId() === 'mine') { - var out = listHelper($scope.domainObject); - //console.log('out', out); - return out; - } - // Fallback if we aren't in My Items - return items; - } - // Recursive helper function to go through the tree - function listHelper(current) { - //console.log('current', current); - //console.log('current.getID', current.getId()); - var composition; - if (current.hasCapability('composition')) { - composition = current.getCapability('composition'); - } else { - //console.log('does not have capability'); - return current; - } - composition.invoke().then(function (children) { - if (children === []) { - return current; - } else { - var subList = [current], - i; - for (i = 0; i < children.length; i += 1) { - subList.concat(listHelper(children[i])); - } - //console.log('subList ', subList); //////////// - return subList; - } - }); - } - - // Search through items for items which have the search term - // in the title - function search(term) { - // modify searchResults - - return searchResults; - } - - // When the search view is opened, call listify() - // When the search button is pressed, call search() - - $scope.items = listify(); - $scope.results = search(); - } - return SearchController; -}); \ No newline at end of file + \ No newline at end of file From 4e39c4f9009577f4e36b1ba3d741cd0dcd22ec61 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 10:32:58 -0700 Subject: [PATCH 006/195] [Search] Finds root folder The search controller will now search from the root folder (My Items) even when the view is initiated from a folder inside of the tree. --- .../features/search/src/SearchController.js | 112 ++++++++++++------ 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index f37b32d503..280d581e38 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -28,31 +28,10 @@ define(function () { "use strict"; function SearchController($scope, objectService) { - var items = [], - searchResults = []; - - // Converts the filetree into a list - // Eventually, plan to call search service - // (but do here for now) - function listify() { - // For now, we want this view to only be in the My Items folder - if ($scope.domainObject.getId() === 'mine') { - var list = listHelper($scope.domainObject); - //debugger; - //console.log('out ', out); - return list.then(function (c) { - //console.log('c ', c); - return c; - }); - } - // Fallback if we aren't in My Items - return items; - } // Recursive helper function to go through the tree function listHelper(current) { var composition; - if (current.hasCapability('composition')) { composition = current.getCapability('composition'); } else { @@ -62,29 +41,55 @@ define(function () { // Recursive case. Is asynchronous. return composition.invoke().then(function (children) { - - var subList = [current], - i; - for (i = 0; i < children.length; i += 1) { - subList.push(listHelper(children[i])); - //console.log('subList', subList, 'index', i); - } - //console.log('sublist ', subList); - return subList; - + console.log('children (pre) ', children); + //(children.forEach(listHelper)).then(function (subList) { + // console.log('children (post) ', children); + // return [current].concat(children); + //}); + children.forEach(listHelper); + console.log('children (post) ', children); + return [current].concat(children); /* - var array = [current].concat(children.forEach(listHelper)); - console.log('array ', array); - return array; + var subList = [current]; + console.log('children ', children); + for (var i = 0; i < children.length; i += 1) { + console.log('children[', i, ']', children[i]); + //subList.push(listHelper(children[i])); + listHelper(children[i]).then(function (c) { + subList.concat(c); + }); + console.log('subList', subList, 'index', i); + } + console.log('sublist ', subList); + return subList; */ }); } - // Search through items for items which have the search term + // Converts the filetree into a list + // Eventually, plan to call search service (but do here for now) + function listify() { + // Aquire My Items (root folder) + return objectService.getObjects(['mine']).then(function (objects) { + console.log(' '); + return listHelper(objects.mine).then(function (c) { + console.log('final result ', c); + return c; + }); + }); + } + + // Search through items for items which contain the search term // in the title function search(term) { - // modify searchResults - + var searchResults = [], + itemsLength = $scope.items.length, // Slight time optimization + i; + for (i = 0; i < itemsLength; i += 1) { + if ($scope.items[i].includes(term)) { + searchResults.push($scope.items[i]); + } + } return searchResults; } @@ -124,4 +129,37 @@ define(function () { */ + // Recursive search + /* + var subList = [current], + i; + console.log('children ', children); + for (i = 0; i < children.length; i += 1) { + console.log('children[', i, ']', children[i]); + subList.push(listHelper(children[i])); + console.log('subList', subList, 'index', i); + } + console.log('sublist ', subList); + return subList; + */ + /* + var array = [current].concat(children.forEach(listHelper)); + console.log('array ', array); + return array; + */ + + + /* + // For now, we want this view to only be in the My Items folder + if ($scope.domainObject.getId() === 'mine') { + var list = listHelper($scope.domainObject); + //debugger; + console.log(' '); + console.log('list ', list); + return list.then(function (c) { + console.log('final result ', c); + return c; + }); + } + */ \ No newline at end of file From efba0f02360f83460898dfc2741cfe83168f8a04 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 12:43:39 -0700 Subject: [PATCH 007/195] [Search] Search results by name doSearch() does search by getting each object's name. Still buggy. --- .../features/search/res/templates/search.html | 19 ++++-- .../features/search/src/SearchController.js | 66 +++++++++++++------ 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 87de36a0d2..e8125458bf 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -19,24 +19,35 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> - +
    + + Search:
    +
    - + --> + + + +
    diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 280d581e38..1281e2e765 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -41,28 +41,31 @@ define(function () { // Recursive case. Is asynchronous. return composition.invoke().then(function (children) { - console.log('children (pre) ', children); - //(children.forEach(listHelper)).then(function (subList) { - // console.log('children (post) ', children); - // return [current].concat(children); - //}); - children.forEach(listHelper); - console.log('children (post) ', children); - return [current].concat(children); - /* - var subList = [current]; + var subList = [current], + i; console.log('children ', children); - for (var i = 0; i < children.length; i += 1) { + for (i = 0; i < children.length; i += 1) { console.log('children[', i, ']', children[i]); - //subList.push(listHelper(children[i])); - listHelper(children[i]).then(function (c) { - subList.concat(c); - }); + subList.push(listHelper(children[i])); console.log('subList', subList, 'index', i); } console.log('sublist ', subList); return subList; - */ + }); + } + + // Recursive helper function to go through the tree + function listHelper2(current) { + return current.getCapability('composition').invoke().then(function (children) { + return [current].concat(children.forEach(function (child) { + if (child.hasCapability('composition')) { + return listHelper2(child);//.then(function (c) { + // return c; + //}); + } else { + return child; + } + })); }); } @@ -71,9 +74,9 @@ define(function () { function listify() { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { - console.log(' '); return listHelper(objects.mine).then(function (c) { console.log('final result ', c); + $scope.items = c; // Somewhat redundant return c; }); }); @@ -82,14 +85,23 @@ define(function () { // Search through items for items which contain the search term // in the title function search(term) { + console.log('search called'); + console.log('search term ', term); var searchResults = [], - itemsLength = $scope.items.length, // Slight time optimization + itemsLength, i; + // refresh items list + listify(); + itemsLength = $scope.items.length; // Slight time optimization + for (i = 0; i < itemsLength; i += 1) { - if ($scope.items[i].includes(term)) { + console.log('items[', i, '].getModel', $scope.items[i].getModel()); + if ($scope.items[i].getModel().name.includes(term)) { searchResults.push($scope.items[i]); } } + console.log('search results ', searchResults); + $scope.results = searchResults; // Somewhat redundant return searchResults; } @@ -98,6 +110,10 @@ define(function () { $scope.items = listify(); $scope.results = search(); + + return { + search: search + }; } return SearchController; }); @@ -147,6 +163,18 @@ define(function () { console.log('array ', array); return array; */ + /* + var subList = [];//= Promise.all([]); + subList.push(current); + for (var i = 0, len = children.length; i < len; i++) { + listHelper(children[i]).then(function (c) { + subList.concat(c); + }); + } + return subList;//.then(function (c) { + // return c; + //}); + */ /* From b5756d2b99394e7199ce04340e73b654b8bd34db Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 12:53:12 -0700 Subject: [PATCH 008/195] [Search] Items list updating The search results now updates the items list when called to make sure that it gets all of the recently added items. --- .../features/search/src/SearchController.js | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 1281e2e765..a95cf6d6b3 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -85,24 +85,23 @@ define(function () { // Search through items for items which contain the search term // in the title function search(term) { - console.log('search called'); - console.log('search term ', term); + console.log('search called, with term ', term); var searchResults = [], itemsLength, i; // refresh items list - listify(); - itemsLength = $scope.items.length; // Slight time optimization - - for (i = 0; i < itemsLength; i += 1) { - console.log('items[', i, '].getModel', $scope.items[i].getModel()); - if ($scope.items[i].getModel().name.includes(term)) { - searchResults.push($scope.items[i]); + return listify().then( function () { + itemsLength = $scope.items.length; // Slight time optimization + for (i = 0; i < itemsLength; i += 1) { + console.log('items[', i, '].getModel', $scope.items[i].getModel()); + if ($scope.items[i].getModel().name.includes(term)) { + searchResults.push($scope.items[i]); + } } - } - console.log('search results ', searchResults); - $scope.results = searchResults; // Somewhat redundant - return searchResults; + console.log('search results ', searchResults); + $scope.results = searchResults; // Somewhat redundant + return searchResults; + }); } // When the search view is opened, call listify() From 6d1cb85a072c23fb69bb7c43a2ba8270fe6dfda7 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 14:20:04 -0700 Subject: [PATCH 009/195] [Search] Not case sensitive Search is no longer case sensitive. --- platform/features/search/src/SearchController.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index a95cf6d6b3..5a8cf831e7 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -88,13 +88,20 @@ define(function () { console.log('search called, with term ', term); var searchResults = [], itemsLength, + itemName, i; + // Make not case sensitive + if (term) { + term = term.toLocaleLowerCase(); + } + // refresh items list return listify().then( function () { itemsLength = $scope.items.length; // Slight time optimization for (i = 0; i < itemsLength; i += 1) { - console.log('items[', i, '].getModel', $scope.items[i].getModel()); - if ($scope.items[i].getModel().name.includes(term)) { + itemName = $scope.items[i].getModel().name; + console.log('items[', i, '] name', itemName); + if (itemName.toLocaleLowerCase().includes(term)) { searchResults.push($scope.items[i]); } } From 2e7f23a7660312f47d9be4f584b4c38bf618e35c Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 14:46:55 -0700 Subject: [PATCH 010/195] [Search] Results list displayed After searching, a results list is displayed. The list is composed of grid-items. --- .../search/res/templates/search-item.html | 10 +++---- .../features/search/res/templates/search.html | 29 ++++++++----------- .../features/search/src/SearchController.js | 8 ++++- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/platform/features/search/res/templates/search-item.html b/platform/features/search/res/templates/search-item.html index 765a64c813..b2c9ba40ed 100644 --- a/platform/features/search/res/templates/search-item.html +++ b/platform/features/search/res/templates/search-item.html @@ -19,11 +19,9 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> - - -
    - ITEM - +
    +
    @@ -45,5 +43,5 @@
    - +
    \ No newline at end of file diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index e8125458bf..8cf10ff989 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -32,10 +32,11 @@
    --> - Search:
    +
    Search:
    + name="searchform" + value="input search term here"/> + ng-click="controller.search('')">Go
    -
    +
    -
      -
    • - -
    • -
    • - -
    • -
    - +
    + Results: +
    +
    \ No newline at end of file diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 5a8cf831e7..bcd278ac6e 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -118,7 +118,13 @@ define(function () { $scope.results = search(); return { - search: search + search: search, + /** + * Check to see if there are any search results to display. + */ + areResults: function () { + return $scope.results.length !== 0; + } }; } return SearchController; From a337e04fae5f0fb78b99e59ead0f0b1f92fbf1c4 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 14:50:57 -0700 Subject: [PATCH 011/195] [Search] Removed unnecessary file Removed search-item.html, as it was the same as grid-item.html. Now search.html uses grid-item.html. --- .../search/res/templates/search-item.html | 47 ------------------- .../features/search/res/templates/search.html | 2 +- 2 files changed, 1 insertion(+), 48 deletions(-) delete mode 100644 platform/features/search/res/templates/search-item.html diff --git a/platform/features/search/res/templates/search-item.html b/platform/features/search/res/templates/search-item.html deleted file mode 100644 index b2c9ba40ed..0000000000 --- a/platform/features/search/res/templates/search-item.html +++ /dev/null @@ -1,47 +0,0 @@ - - -
    -
    -
    -
    - -
    -
    - -
    P
    -
    -
    -
    -
    {{type.getGlyph()}}
    -
    }
    -
    -
    -
    {{model.name}}
    -
    - - {{model.composition.length}} Items - -
    -
    -
    -
    \ No newline at end of file diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 8cf10ff989..35dc647784 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -60,7 +60,7 @@ style="height: 30px"> Results:
    -
    \ No newline at end of file From 8eda495aa7551c7e47731244659f8934231c8b24 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 15:06:19 -0700 Subject: [PATCH 012/195] [Search] Results without folders Folders are now no longer included in the results list. --- .../features/search/src/SearchController.js | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index bcd278ac6e..9dce798660 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -82,30 +82,35 @@ define(function () { }); } - // Search through items for items which contain the search term - // in the title + // Search through items for items which contain the search term in the name function search(term) { console.log('search called, with term ', term); var searchResults = [], itemsLength, + itemModel, itemName, i; + // Make not case sensitive if (term) { term = term.toLocaleLowerCase(); } - // refresh items list + // Refresh items list return listify().then( function () { - itemsLength = $scope.items.length; // Slight time optimization + // Slight time optimization + itemsLength = $scope.items.length; + for (i = 0; i < itemsLength; i += 1) { - itemName = $scope.items[i].getModel().name; - console.log('items[', i, '] name', itemName); - if (itemName.toLocaleLowerCase().includes(term)) { + itemModel = $scope.items[i].getModel(); + itemName = itemModel.name.toLocaleLowerCase(); + + // Include any matching items, except folders + if (itemName.includes(term) && itemModel.type !== 'folder') { searchResults.push($scope.items[i]); } } - console.log('search results ', searchResults); + $scope.results = searchResults; // Somewhat redundant return searchResults; }); From 33b30f75838468b4278ee88932a906193f83559c Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 15:16:28 -0700 Subject: [PATCH 013/195] [Search] Removed unnecissary variable Removed $scope.items, because it was unnecissary. --- .../features/search/src/SearchController.js | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 9dce798660..a425124bf6 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -76,7 +76,6 @@ define(function () { return objectService.getObjects(['mine']).then(function (objects) { return listHelper(objects.mine).then(function (c) { console.log('final result ', c); - $scope.items = c; // Somewhat redundant return c; }); }); @@ -96,37 +95,33 @@ define(function () { term = term.toLocaleLowerCase(); } - // Refresh items list - return listify().then( function () { - // Slight time optimization - itemsLength = $scope.items.length; + // Get items list + return listify().then(function (items) { + // (slight time optimization) + itemsLength = items.length; + // Then filter through the items list for (i = 0; i < itemsLength; i += 1) { - itemModel = $scope.items[i].getModel(); + itemModel = items[i].getModel(); itemName = itemModel.name.toLocaleLowerCase(); // Include any matching items, except folders if (itemName.includes(term) && itemModel.type !== 'folder') { - searchResults.push($scope.items[i]); + searchResults.push(items[i]); } } - $scope.results = searchResults; // Somewhat redundant + $scope.results = searchResults; // Some redundancy return searchResults; }); } - // When the search view is opened, call listify() - // When the search button is pressed, call search() - - $scope.items = listify(); $scope.results = search(); return { search: search, - /** - * Check to see if there are any search results to display. - */ + + // Check to see if there are any search results to display. areResults: function () { return $scope.results.length !== 0; } From 04257aedae28ebb9197d7d225aa7665dfb7b5587 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 16:41:43 -0700 Subject: [PATCH 014/195] [Search] Gets user input Now sucessfully gets user input for the search term. --- .../features/search/res/templates/search.html | 38 ++++------- .../features/search/src/SearchController.js | 63 ++++--------------- 2 files changed, 23 insertions(+), 78 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 35dc647784..dd780aa3a2 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -24,32 +24,15 @@ ng-controller="SearchController as controller"> -
    -
    - -
    Search:
    - - - - - - -
    +
    +
    Search:
    + + + +
    @@ -62,5 +45,6 @@
    + mct-object="result"> +
    \ No newline at end of file diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index a425124bf6..36da922625 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -43,13 +43,13 @@ define(function () { return composition.invoke().then(function (children) { var subList = [current], i; - console.log('children ', children); + //console.log('children ', children); for (i = 0; i < children.length; i += 1) { - console.log('children[', i, ']', children[i]); + //console.log('children[', i, ']', children[i]); subList.push(listHelper(children[i])); - console.log('subList', subList, 'index', i); + //console.log('subList', subList, 'index', i); } - console.log('sublist ', subList); + //console.log('sublist ', subList); return subList; }); } @@ -75,25 +75,26 @@ define(function () { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { return listHelper(objects.mine).then(function (c) { - console.log('final result ', c); + //console.log('final result ', c); return c; }); }); } // Search through items for items which contain the search term in the name - function search(term) { - console.log('search called, with term ', term); - var searchResults = [], + function search() { + var term, + searchResults = [], itemsLength, itemModel, itemName, i; + // Search for user input by element id + term = document.getElementById("searchinput").value; + // Make not case sensitive - if (term) { - term = term.toLocaleLowerCase(); - } + term = term.toLocaleLowerCase(); // Get items list return listify().then(function (items) { @@ -133,30 +134,6 @@ define(function () { ///// Old stuff to look at later - // Get the root object - /* - objectService.getObjects(['root']).then(function (objects) { - console.log('rootObject 1', rootObject); - rootObject = objects.root; - console.log('rootObject 2', rootObject); - - - - console.log('hasCapability("editor") ', rootObject.hasCapability('editor')); - console.log('getModel() ', rootObject.getModel()); - console.log('getId() ', rootObject.getId()); - - // Get the children of the root object - console.log('hasCapability("composition") ', rootObject.hasCapability('composition')); - if (rootObject.hasCapability('composition')) { - rootComposition = rootObject.getCapability('composition').invoke(); - console.log('rootComposition ', rootComposition); - } - }); - console.log('rootObject 3', rootObject); - */ - - // Recursive search /* var subList = [current], @@ -187,19 +164,3 @@ define(function () { // return c; //}); */ - - - /* - // For now, we want this view to only be in the My Items folder - if ($scope.domainObject.getId() === 'mine') { - var list = listHelper($scope.domainObject); - //debugger; - console.log(' '); - console.log('list ', list); - return list.then(function (c) { - console.log('final result ', c); - return c; - }); - } - */ - \ No newline at end of file From 03c0678cbeeb7404aa73de3e13506fa22632f990 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 10 Jul 2015 16:54:42 -0700 Subject: [PATCH 015/195] [Search] Syle modifications Changed 'i += 1' in for loops to 'i++' --- platform/features/search/src/SearchController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 36da922625..0d378de220 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -44,7 +44,7 @@ define(function () { var subList = [current], i; //console.log('children ', children); - for (i = 0; i < children.length; i += 1) { + for (i = 0; i < children.length; i++) { //console.log('children[', i, ']', children[i]); subList.push(listHelper(children[i])); //console.log('subList', subList, 'index', i); @@ -102,7 +102,7 @@ define(function () { itemsLength = items.length; // Then filter through the items list - for (i = 0; i < itemsLength; i += 1) { + for (i = 0; i < itemsLength; i++) { itemModel = items[i].getModel(); itemName = itemModel.name.toLocaleLowerCase(); From 2432e9c2aaa7348e20ab1d94569f23696432e948 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 13 Jul 2015 10:13:46 -0700 Subject: [PATCH 016/195] [Search] Using ElasticSearch --- bundles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles.json b/bundles.json index 3ded09421b..2c7ea10b99 100644 --- a/bundles.json +++ b/bundles.json @@ -19,11 +19,11 @@ "platform/features/search", "platform/features/events", "platform/forms", + "platform/persistence/elastic", "platform/persistence/queue", "platform/policy", "example/imagery", - "example/persistence", "example/eventGenerator", "example/generator" ] From 409d12aa758a7b2fbcee1bc9131d120c3625d3bc Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 13 Jul 2015 10:34:06 -0700 Subject: [PATCH 017/195] [Search] Created QueryService Created a query service which handles the creation of the searchable list of items. This has partially broken the search view. --- platform/features/search/bundle.json | 9 +- platform/features/search/src/QueryService.js | 96 +++++++++++++++++++ .../features/search/src/SearchController.js | 56 +---------- 3 files changed, 106 insertions(+), 55 deletions(-) create mode 100644 platform/features/search/src/QueryService.js diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index e391934114..a989ce4de1 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -15,7 +15,7 @@ { "key": "SearchController", "implementation": "SearchController.js", - "depends": [ "$scope", "objectService" ] + "depends": [ "$scope", "queryService" ] } ], "representations": [ @@ -25,6 +25,13 @@ "uses": [ "type", "action", "composition" ], "gestures": [ "info", "menu" ] } + ], + "services": [ + { + "key": "queryService", + "implementation": "QueryService.js", + "depends": [ "objectService" ] + } ] } } \ No newline at end of file diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js new file mode 100644 index 0000000000..30ce096a40 --- /dev/null +++ b/platform/features/search/src/QueryService.js @@ -0,0 +1,96 @@ +/***************************************************************************** + * 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*/ + +/** + * Module defining QueryService. Created by shale on 07/13/2015. + */ +define( + [], + function () { + "use strict"; + /** + * The query service is responsible for creating an index + * of objects in the filetree which is searchable. + * @constructor + */ + function QueryService(objectService) { + // Recursive helper function to go through the tree + function listHelper(current) { + var composition; + if (current.hasCapability('composition')) { + composition = current.getCapability('composition'); + } else { + // Base case. + return current; + } + + // Recursive case. Is asynchronous. + return composition.invoke().then(function (children) { + var subList = [current], + i; + //console.log('children ', children); + for (i = 0; i < children.length; i++) { + //console.log('children[', i, ']', children[i]); + subList.push(listHelper(children[i])); + //console.log('subList', subList, 'index', i); + } + //console.log('sublist ', subList); + return subList; + }); + } + + // Recursive helper function to go through the tree + function listHelper2(current) { + return current.getCapability('composition').invoke().then(function (children) { + return [current].concat(children.forEach(function (child) { + if (child.hasCapability('composition')) { + return listHelper2(child);//.then(function (c) { + // return c; + //}); + } else { + return child; + } + })); + }); + } + + // Converts the filetree into a list + // Eventually, plan to call search service (but do here for now) + function listify() { + // Aquire My Items (root folder) + return objectService.getObjects(['mine']).then(function (objects) { + return listHelper(objects.mine).then(function (c) { + //console.log('final result ', c); + return c; + }); + }); + } + + return { + listify: listify + }; + } + + return QueryService; + } +); \ No newline at end of file diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 0d378de220..bdd68baa97 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -27,59 +27,7 @@ define(function () { "use strict"; - function SearchController($scope, objectService) { - - // Recursive helper function to go through the tree - function listHelper(current) { - var composition; - if (current.hasCapability('composition')) { - composition = current.getCapability('composition'); - } else { - // Base case. - return current; - } - - // Recursive case. Is asynchronous. - return composition.invoke().then(function (children) { - var subList = [current], - i; - //console.log('children ', children); - for (i = 0; i < children.length; i++) { - //console.log('children[', i, ']', children[i]); - subList.push(listHelper(children[i])); - //console.log('subList', subList, 'index', i); - } - //console.log('sublist ', subList); - return subList; - }); - } - - // Recursive helper function to go through the tree - function listHelper2(current) { - return current.getCapability('composition').invoke().then(function (children) { - return [current].concat(children.forEach(function (child) { - if (child.hasCapability('composition')) { - return listHelper2(child);//.then(function (c) { - // return c; - //}); - } else { - return child; - } - })); - }); - } - - // Converts the filetree into a list - // Eventually, plan to call search service (but do here for now) - function listify() { - // Aquire My Items (root folder) - return objectService.getObjects(['mine']).then(function (objects) { - return listHelper(objects.mine).then(function (c) { - //console.log('final result ', c); - return c; - }); - }); - } + function SearchController($scope, queryService) { // Search through items for items which contain the search term in the name function search() { @@ -97,7 +45,7 @@ define(function () { term = term.toLocaleLowerCase(); // Get items list - return listify().then(function (items) { + return queryService.listify().then(function (items) { // (slight time optimization) itemsLength = items.length; From 598057591890781369796f117274744b3ca14e98 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 13 Jul 2015 11:11:55 -0700 Subject: [PATCH 018/195] [Search] Fixed results display problem Fixed problem with search results not properly being displayed in the search view. (Checked that things were defined before calling them.) --- .../features/search/src/SearchController.js | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index bdd68baa97..bb38837723 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -51,12 +51,16 @@ define(function () { // Then filter through the items list for (i = 0; i < itemsLength; i++) { - itemModel = items[i].getModel(); - itemName = itemModel.name.toLocaleLowerCase(); - - // Include any matching items, except folders - if (itemName.includes(term) && itemModel.type !== 'folder') { - searchResults.push(items[i]); + // Prevent errors from getModel not being defined + if (items[i].getModel) { + itemModel = items[i].getModel(); + itemName = itemModel.name.toLocaleLowerCase(); + + // Include any matching items, except folders + // TODO: Should have a policy for this + if (itemName.includes(term) && itemModel.type !== 'folder') { + searchResults.push(items[i]); + } } } @@ -65,14 +69,16 @@ define(function () { }); } - $scope.results = search(); - return { search: search, // Check to see if there are any search results to display. areResults: function () { - return $scope.results.length !== 0; + if ($scope.results) { + return $scope.results.length > 0; + } else { + return false; + } } }; } From 3cb0b41b22a2f4792ef8bafc8bdf598c86f44b0b Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 13 Jul 2015 16:49:06 -0700 Subject: [PATCH 019/195] [Search] Poking around EasticSearch Sucessfully queries elasticsearch, but displaying the results poses problems because of asych things. --- platform/features/search/bundle.json | 7 +- platform/features/search/src/QueryService.js | 115 ++++++++++++++---- .../features/search/src/SearchController.js | 62 +++++++++- 3 files changed, 152 insertions(+), 32 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index a989ce4de1..b1847bcc95 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -15,22 +15,21 @@ { "key": "SearchController", "implementation": "SearchController.js", - "depends": [ "$scope", "queryService" ] + "depends": [ "$scope", "$http", "objectService", "queryService", "ELASTIC_ROOT" ] } ], "representations": [ { "key": "search-item", "templateUrl": "templates/search-item.html", - "uses": [ "type", "action", "composition" ], - "gestures": [ "info", "menu" ] + "uses": [ "grid-item" ] } ], "services": [ { "key": "queryService", "implementation": "QueryService.js", - "depends": [ "objectService" ] + "depends": [ "objectService", "ELASTIC_ROOT" ] } ] } diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 30ce096a40..a46c6829f8 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -33,7 +33,7 @@ define( * of objects in the filetree which is searchable. * @constructor */ - function QueryService(objectService) { + function QueryService(objectService, ROOT) { // Recursive helper function to go through the tree function listHelper(current) { var composition; @@ -43,51 +43,116 @@ define( // Base case. return current; } - + // Recursive case. Is asynchronous. return composition.invoke().then(function (children) { var subList = [current], i; - //console.log('children ', children); for (i = 0; i < children.length; i++) { - //console.log('children[', i, ']', children[i]); subList.push(listHelper(children[i])); - //console.log('subList', subList, 'index', i); } - //console.log('sublist ', subList); return subList; }); } - - // Recursive helper function to go through the tree - function listHelper2(current) { - return current.getCapability('composition').invoke().then(function (children) { - return [current].concat(children.forEach(function (child) { - if (child.hasCapability('composition')) { - return listHelper2(child);//.then(function (c) { - // return c; - //}); - } else { - return child; - } - })); - }); - } - + // Converts the filetree into a list // Eventually, plan to call search service (but do here for now) - function listify() { + function getItems() { + console.log('in getItems()'); + debugger; + /* + var elasticsearch = require(['platform/persistence/elastic'], function (elasticsearch) { + debugger; + + console.log('elasticsearch (inside) ', elasticsearch); + + var client = new elasticsearch.Client({ + host: ROOT + }); + console.log('client', client); + + var testsearch = client.search({q: 'name=test123'});//[params, [callback]]); + console.log('search', testsearch); + }); + */ + var elasticsearch = require('elasticsearch'); + + debugger; + + console.log('elasticsearch (outside) ', elasticsearch); + + var client = new elasticsearch.Client({ + host: ROOT + }); + console.log('client', client); + + var testsearch = client.search({q: 'name=test123'});//[params, [callback]]); + console.log('search', testsearch); + + + /* + console.log('elasticsearch', elasticsearch); + var client = new elasticsearch.Client({ + host: 'localhost:9200' + }); + console.log('client', client); + var test = client.search();//[params, [callback]]); + console.log('search', test); + */ + + /* + var elasticApp = angular.module('elasticApp', ['elasticsearch']); + console.log('elasticApp', elasticApp); + + var client = elasticApp.service('client', function (esFactory) { + return esFactory({ + host: 'localhost:8080' + }); + }); + console.log('client', client); + */ + /* + var controller = elasticApp.controller('ElasticController', function ($scope, client, esFactory) { + client.cluster.state({ + metric: [ + 'cluster_name', + 'nodes', + 'master_node', + 'version' + ] + }).then(function (resp) { + $scope.clusterState = resp; + $scope.error = null; + }).catch(function (err) { + $scope.clusterState = null; + $scope.error = err; + // if the err is a NoConnections error, then the client was not able to + // connect to elasticsearch. In that case, create a more detailed error + // message + if (err instanceof esFactory.errors.NoConnections) { + $scope.error = new Error('Unable to connect to elasticsearch. ' + + 'Make sure that it is running and listening ' + + 'at http://localhost:9200'); + } + }); + }); + console.log('controller', controller); + */ + /* + var testSearch = client.search();//[params, [callback]]); + console.log('search', testSearch); + */ + // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { return listHelper(objects.mine).then(function (c) { - //console.log('final result ', c); return c; }); }); } return { - listify: listify + getItems: getItems }; } diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index bb38837723..ccb9553af1 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -27,7 +27,11 @@ define(function () { "use strict"; - function SearchController($scope, queryService) { + // JSLint doesn't like underscore-prefixed properties, + // so hide them here. + var ID = "_id"; + + function SearchController($scope, $http, objectService, queryService, ROOT) { // Search through items for items which contain the search term in the name function search() { @@ -45,7 +49,7 @@ define(function () { term = term.toLocaleLowerCase(); // Get items list - return queryService.listify().then(function (items) { + return queryService.getItems().then(function (items) { // (slight time optimization) itemsLength = items.length; @@ -69,8 +73,52 @@ define(function () { }); } + function search2() { + var term = document.getElementById("searchinput").value; + + $http({ + method: "GET", + url: ROOT + "/_search", + data: { + query: { + term: { + name: term + } + } + } + }).then(function (raw) { + var id; + var output = raw.data.hits.hits; + var outputLength = output.length; + console.log('raw', raw); + console.log('output, pre', output); + + var i; + for (i = 0; i < output.length; i++) { + output[i] = output[i][ID]; + console.log('output [', i, ']', output[i]); + + objectService.getObjects([ output[i] ]).then(function (obj) { + output[i] = obj; + // Manually get the member name to get to the actual object + for (var prop in output[i]) { + console.log('prop [', i, ']', output[i][prop]); + output[i] = output[i][prop]; + debugger; + } + }); + console.log('output [', i, ']', output[i]); + + } + console.log('output, post', output); + + $scope.results = output; + //return output; + }); + } + return { - search: search, + search: search2, // Check to see if there are any search results to display. areResults: function () { @@ -79,6 +127,14 @@ define(function () { } else { return false; } + }, + + getObjectByID: function (id) { + console.log('getObjectByID called'); + objectService.getObjects([id]).then(function (out) { + console.log('object gotten by id', out[id]); + return out[id]; + }); } }; } From b994b2a862315970053808d246c0c47f492ae6b3 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 13 Jul 2015 16:57:27 -0700 Subject: [PATCH 020/195] [Search] Style --- .../features/search/src/SearchController.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index ccb9553af1..a54b9b37a8 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -76,6 +76,7 @@ define(function () { function search2() { var term = document.getElementById("searchinput").value; + // Get the data... $http({ method: "GET", url: ROOT + "/_search", @@ -87,17 +88,21 @@ define(function () { } } }).then(function (raw) { - var id; - var output = raw.data.hits.hits; - var outputLength = output.length; + // ...then process the data + var output = raw.data.hits.hits, + outputLength = output.length, + id, + i; + console.log('raw', raw); console.log('output, pre', output); - var i; - for (i = 0; i < output.length; i++) { + for (i = 0; i < outputLength; i++) { + // Get the object's ID output[i] = output[i][ID]; console.log('output [', i, ']', output[i]); + // Get the object itself from its ID objectService.getObjects([ output[i] ]).then(function (obj) { output[i] = obj; // Manually get the member name to get to the actual object @@ -112,8 +117,8 @@ define(function () { } console.log('output, post', output); + // Don't need to return, just set scope's version $scope.results = output; - //return output; }); } From 75ce5cd0e93f33c22c82a09b80370c45847aacb9 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 13 Jul 2015 17:05:23 -0700 Subject: [PATCH 021/195] [Search] Changed variable names Because of the async funtion, changed variable names in serach2 to make more clear. --- .../features/search/src/SearchController.js | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index a54b9b37a8..814aba5c76 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -29,7 +29,8 @@ define(function () { // JSLint doesn't like underscore-prefixed properties, // so hide them here. - var ID = "_id"; + var ID = "_id", + SOURCE = "_source"; function SearchController($scope, $http, objectService, queryService, ROOT) { @@ -77,7 +78,7 @@ define(function () { var term = document.getElementById("searchinput").value; // Get the data... - $http({ + $scope.results = $http({ method: "GET", url: ROOT + "/_search", data: { @@ -87,38 +88,38 @@ define(function () { } } } - }).then(function (raw) { + }).then(function (rawResults) { // ...then process the data - var output = raw.data.hits.hits, - outputLength = output.length, + var results = rawResults.data.hits.hits, + resultsLength = results.length, + output, id, i; - console.log('raw', raw); - console.log('output, pre', output); + console.log('raw', rawResults); + console.log('results, pre', results); - for (i = 0; i < outputLength; i++) { + for (i = 0; i < resultsLength; i++) { // Get the object's ID - output[i] = output[i][ID]; + results[i] = results[i][ID]; console.log('output [', i, ']', output[i]); // Get the object itself from its ID - objectService.getObjects([ output[i] ]).then(function (obj) { - output[i] = obj; + objectService.getObjects([ results[i] ]).then(function (obj) { // Manually get the member name to get to the actual object - for (var prop in output[i]) { - console.log('prop [', i, ']', output[i][prop]); - output[i] = output[i][prop]; + for (var prop in obj) { + console.log('prop [', i, ']', obj[prop]); + output.push(obj[prop]); debugger; } }); + console.log('results [', i, ']', results[i]); console.log('output [', i, ']', output[i]); - } + console.log('results, post', results); console.log('output, post', output); - // Don't need to return, just set scope's version - $scope.results = output; + return output; }); } From 89d0ea6506484ea0c030d503d2004b24e2dd84de Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 09:17:14 -0700 Subject: [PATCH 022/195] [Search] Fixed uninitialized array bug --- platform/features/search/src/SearchController.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 814aba5c76..44e40158d5 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -92,7 +92,7 @@ define(function () { // ...then process the data var results = rawResults.data.hits.hits, resultsLength = results.length, - output, + output = [], id, i; @@ -102,7 +102,7 @@ define(function () { for (i = 0; i < resultsLength; i++) { // Get the object's ID results[i] = results[i][ID]; - console.log('output [', i, ']', output[i]); + console.log('results [', i, '] (id)', results[i]); // Get the object itself from its ID objectService.getObjects([ results[i] ]).then(function (obj) { @@ -113,8 +113,8 @@ define(function () { debugger; } }); - console.log('results [', i, ']', results[i]); - console.log('output [', i, ']', output[i]); + console.log('results [', i, '] (id)', results[i]); + console.log('output [', i, '] (obj)', output[i]); } console.log('results, post', results); console.log('output, post', output); From 07e08c283a2be50739c276d54ddeb66736ce80e0 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 09:36:58 -0700 Subject: [PATCH 023/195] [Search] Partway works The search function now returns actual objects are results. They may not be the correct results though. --- .../features/search/src/SearchController.js | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 44e40158d5..c622de301f 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -34,6 +34,7 @@ define(function () { function SearchController($scope, $http, objectService, queryService, ROOT) { + /* // Search through items for items which contain the search term in the name function search() { var term, @@ -63,7 +64,7 @@ define(function () { // Include any matching items, except folders // TODO: Should have a policy for this - if (itemName.includes(term) && itemModel.type !== 'folder') { + if (itemName.includes(term) && itemModel.type !== "folder") { searchResults.push(items[i]); } } @@ -73,12 +74,13 @@ define(function () { return searchResults; }); } + */ function search2() { var term = document.getElementById("searchinput").value; // Get the data... - $scope.results = $http({ + return $http({ method: "GET", url: ROOT + "/_search", data: { @@ -92,39 +94,37 @@ define(function () { // ...then process the data var results = rawResults.data.hits.hits, resultsLength = results.length, - output = [], - id, + ids = [], i; - console.log('raw', rawResults); - console.log('results, pre', results); - + // Get the result objects' IDs for (i = 0; i < resultsLength; i++) { - // Get the object's ID - results[i] = results[i][ID]; - console.log('results [', i, '] (id)', results[i]); - - // Get the object itself from its ID - objectService.getObjects([ results[i] ]).then(function (obj) { - // Manually get the member name to get to the actual object - for (var prop in obj) { - console.log('prop [', i, ']', obj[prop]); - output.push(obj[prop]); - debugger; - } - }); - console.log('results [', i, '] (id)', results[i]); - console.log('output [', i, '] (obj)', output[i]); + ids.push(results[i][ID]); } - console.log('results, post', results); - console.log('output, post', output); - return output; + // Get the objects themselves from their IDs + return objectService.getObjects(ids).then(function (objects) { + var output = [], + id, + j; + + for (j = 0; j < resultsLength; j++) { + id = ids[j]; + output.push(objects[id]); + } + + console.log('final output', output); + return output; + }); }); } return { - search: search2, + search: function () { + search2().then( function (c) { + $scope.results = c; + }); + }, // Check to see if there are any search results to display. areResults: function () { From b35fddefc06d8268057b5dd43fe35d3f90d59c49 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 09:38:44 -0700 Subject: [PATCH 024/195] [Search] Removed getObjectByID Was no longer necissary with the current method of search() getting objects. --- platform/features/search/src/SearchController.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index c622de301f..bfb5cf0b68 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -120,6 +120,7 @@ define(function () { } return { + // Search the database using the user input from id "searchinput" search: function () { search2().then( function (c) { $scope.results = c; @@ -133,14 +134,6 @@ define(function () { } else { return false; } - }, - - getObjectByID: function (id) { - console.log('getObjectByID called'); - objectService.getObjects([id]).then(function (out) { - console.log('object gotten by id', out[id]); - return out[id]; - }); } }; } From d7dd53c2da1dd47e58f1795b96777410d00ec5f9 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 09:45:31 -0700 Subject: [PATCH 025/195] [Search] Checks for folders Search now (again) checks to not add folders to the results list. This later should be made into a policy. --- platform/features/search/src/SearchController.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index bfb5cf0b68..a3ed138a81 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -110,7 +110,14 @@ define(function () { for (j = 0; j < resultsLength; j++) { id = ids[j]; - output.push(objects[id]); + + // Include any item except folders + // TODO: Should have a policy for this + if (objects[id].getModel) { + if (objects[id].getModel().type !== "folder") { + output.push(objects[id]); + } + } } console.log('final output', output); From c92d15ba4244e98d31d2fa3a497b8427d83a153e Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 09:55:26 -0700 Subject: [PATCH 026/195] [Search] Cleanup Added and removed some comments, for clarity --- .../features/search/src/SearchController.js | 63 +++++-------------- 1 file changed, 16 insertions(+), 47 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index a3ed138a81..1446a40b61 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -30,13 +30,14 @@ define(function () { // JSLint doesn't like underscore-prefixed properties, // so hide them here. var ID = "_id", - SOURCE = "_source"; + SOURCE = "_source"; // TODO: Do we need this one? function SearchController($scope, $http, objectService, queryService, ROOT) { - /* - // Search through items for items which contain the search term in the name - function search() { + // Search through items for items manually + // This is a fallback if other search services aren't avaliable + // ... currently only searches 1 layer down (TODO) + function searchFallback() { var term, searchResults = [], itemsLength, @@ -70,14 +71,14 @@ define(function () { } } - $scope.results = searchResults; // Some redundancy + //$scope.results = searchResults; // Some redundancy return searchResults; }); } - */ - function search2() { - var term = document.getElementById("searchinput").value; + // Use elasticsearch's search to search through all the objects + function searchElastic() { + var searchTerm = document.getElementById("searchinput").value; // Get the data... return $http({ @@ -86,7 +87,7 @@ define(function () { data: { query: { term: { - name: term + name: searchTerm } } } @@ -97,12 +98,14 @@ define(function () { ids = [], i; + //console.log('raw results', rawResults); + // Get the result objects' IDs for (i = 0; i < resultsLength; i++) { ids.push(results[i][ID]); } - // Get the objects themselves from their IDs + // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { var output = [], id, @@ -120,16 +123,16 @@ define(function () { } } - console.log('final output', output); + //console.log('final output', output); return output; }); }); } return { - // Search the database using the user input from id "searchinput" + // Search the database using the user input of id "searchinput" search: function () { - search2().then( function (c) { + searchElastic().then( function (c) { $scope.results = c; }); }, @@ -146,37 +149,3 @@ define(function () { } return SearchController; }); - - - ///// Old stuff to look at later - - // Recursive search - /* - var subList = [current], - i; - console.log('children ', children); - for (i = 0; i < children.length; i += 1) { - console.log('children[', i, ']', children[i]); - subList.push(listHelper(children[i])); - console.log('subList', subList, 'index', i); - } - console.log('sublist ', subList); - return subList; - */ - /* - var array = [current].concat(children.forEach(listHelper)); - console.log('array ', array); - return array; - */ - /* - var subList = [];//= Promise.all([]); - subList.push(current); - for (var i = 0, len = children.length; i < len; i++) { - listHelper(children[i]).then(function (c) { - subList.concat(c); - }); - } - return subList;//.then(function (c) { - // return c; - //}); - */ From 457193657f6d0073261ccce0c475d2fa6925afba Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 09:59:48 -0700 Subject: [PATCH 027/195] [Search] Added input ID parameter Added a parameter to the controller's search function so that the html side can clearly see/choose which input ID is being used as the search input. --- .../features/search/res/templates/search.html | 2 +- .../features/search/src/SearchController.js | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index dd780aa3a2..19f6dd6bfa 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -31,7 +31,7 @@ value=""/> + ng-click="controller.search('searchinput')">Go
    diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 1446a40b61..6133ed87b8 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -77,8 +77,17 @@ define(function () { } // Use elasticsearch's search to search through all the objects - function searchElastic() { - var searchTerm = document.getElementById("searchinput").value; + function searchElastic(inputID) { + var searchTerm; + + // Get the user input + if (inputID) { + searchTerm = document.getElementById(inputID).value; + } else { + // Backward compatibility? + // TODO: May be unnecsisary + searchTerm = document.getElementById("searchinput").value; + } // Get the data... return $http({ @@ -131,8 +140,8 @@ define(function () { return { // Search the database using the user input of id "searchinput" - search: function () { - searchElastic().then( function (c) { + search: function (inputID) { + searchElastic(inputID).then( function (c) { $scope.results = c; }); }, From b9f8f6e33dbf6183e15c9b2674b1352eb672df6f Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 10:02:27 -0700 Subject: [PATCH 028/195] [Search] Code style --- platform/features/search/src/SearchController.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 6133ed87b8..eaa87c8747 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -57,7 +57,7 @@ define(function () { itemsLength = items.length; // Then filter through the items list - for (i = 0; i < itemsLength; i++) { + for (i = 0; i < itemsLength; i += 1) { // Prevent errors from getModel not being defined if (items[i].getModel) { itemModel = items[i].getModel(); @@ -110,17 +110,17 @@ define(function () { //console.log('raw results', rawResults); // Get the result objects' IDs - for (i = 0; i < resultsLength; i++) { + for (i = 0; i < resultsLength; i += 1) { ids.push(results[i][ID]); } // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { var output = [], - id, + id, j; - for (j = 0; j < resultsLength; j++) { + for (j = 0; j < resultsLength; j += 1) { id = ids[j]; // Include any item except folders @@ -141,7 +141,7 @@ define(function () { return { // Search the database using the user input of id "searchinput" search: function (inputID) { - searchElastic(inputID).then( function (c) { + searchElastic(inputID).then(function (c) { $scope.results = c; }); }, From 58925946685f8e5e46a6a16f83208013cce8cdef Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 10:30:47 -0700 Subject: [PATCH 029/195] [Search] More robust search Seach now searches using terms, which are the domain objects' names split at the spaces. Still does not work with any substring, must be space separated. Not case sensitive. --- platform/features/search/src/SearchController.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index eaa87c8747..303c6eac07 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -92,14 +92,16 @@ define(function () { // Get the data... return $http({ method: "GET", - url: ROOT + "/_search", + url: ROOT + "/_search/?q=name:'" + searchTerm + "'" + /*, data: { query: { - term: { - name: searchTerm + term : { + _source: { name : "test123" } } } } + */ }).then(function (rawResults) { // ...then process the data var results = rawResults.data.hits.hits, @@ -107,7 +109,7 @@ define(function () { ids = [], i; - //console.log('raw results', rawResults); + console.log('raw results', rawResults); // Get the result objects' IDs for (i = 0; i < resultsLength; i += 1) { @@ -132,7 +134,7 @@ define(function () { } } - //console.log('final output', output); + console.log('final output', output); return output; }); }); From 503811f69c0f802ebbf4e2c37073aec49196bde0 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 10:45:51 -0700 Subject: [PATCH 030/195] [Search] Search behaves as expected Seaching any substring of a domain object title now will give the domian object as a search result. Still not case sensitive. Empty string will return all results. Special characters do not search correctly. Still has result number cap. --- platform/features/search/src/SearchController.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index 303c6eac07..b1988a1b18 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -89,19 +89,14 @@ define(function () { searchTerm = document.getElementById("searchinput").value; } + // Process search term + // Put wildcards on front and end to allow substring behavior + searchTerm = '*' + searchTerm + '*'; + // Get the data... return $http({ method: "GET", - url: ROOT + "/_search/?q=name:'" + searchTerm + "'" - /*, - data: { - query: { - term : { - _source: { name : "test123" } - } - } - } - */ + url: ROOT + "/_search/?q=name:" + searchTerm }).then(function (rawResults) { // ...then process the data var results = rawResults.data.hits.hits, From 1a8fd3843042acf1a979b85470408e16f90fd96a Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 10:56:52 -0700 Subject: [PATCH 031/195] [Search] Max results Changed the default number of results to be a max of 25, and added a parameter to allow the user to set this. (May be used in an advaned search later?) Because folders are filtered out, the number displayed is not necissarily exact. --- platform/features/search/src/SearchController.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index b1988a1b18..d38062ebdc 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -77,9 +77,16 @@ define(function () { } // Use elasticsearch's search to search through all the objects - function searchElastic(inputID) { + function searchElastic(inputID, maxResults) { var searchTerm; + // Check to see if the user provided a maximum + // number of results to display + if (!maxResults) { + // Else, we provide a default value + maxResults = 25; + } + // Get the user input if (inputID) { searchTerm = document.getElementById(inputID).value; @@ -96,7 +103,8 @@ define(function () { // Get the data... return $http({ method: "GET", - url: ROOT + "/_search/?q=name:" + searchTerm + url: ROOT + "/_search/?q=name:" + searchTerm + + "&size=" + maxResults }).then(function (rawResults) { // ...then process the data var results = rawResults.data.hits.hits, From 1d0d2302d899d29b67b4a86e2d9c6f60824e2115 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 11:28:47 -0700 Subject: [PATCH 032/195] [Search] Moved functionality into QueryService Moved the actual searching implementation into the query service. The search view controller now just calls the query service. --- platform/features/search/bundle.json | 4 +- platform/features/search/src/QueryService.js | 224 +++++++++++------- .../features/search/src/SearchController.js | 118 +-------- 3 files changed, 138 insertions(+), 208 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index b1847bcc95..69bc277806 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -15,7 +15,7 @@ { "key": "SearchController", "implementation": "SearchController.js", - "depends": [ "$scope", "$http", "objectService", "queryService", "ELASTIC_ROOT" ] + "depends": [ "$scope", "queryService" ] } ], "representations": [ @@ -29,7 +29,7 @@ { "key": "queryService", "implementation": "QueryService.js", - "depends": [ "objectService", "ELASTIC_ROOT" ] + "depends": [ "$http", "objectService", "ELASTIC_ROOT" ] } ] } diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index a46c6829f8..fdeea76f74 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -28,13 +28,19 @@ define( [], function () { "use strict"; + + // JSLint doesn't like underscore-prefixed properties, + // so hide them here. + var ID = "_id"; + /** * The query service is responsible for creating an index * of objects in the filetree which is searchable. * @constructor */ - function QueryService(objectService, ROOT) { - // Recursive helper function to go through the tree + function QueryService($http, objectService, ROOT) { + + // Recursive helper function for getItems function listHelper(current) { var composition; if (current.hasCapability('composition')) { @@ -48,7 +54,7 @@ define( return composition.invoke().then(function (children) { var subList = [current], i; - for (i = 0; i < children.length; i++) { + for (i = 0; i < children.length; i += 1) { subList.push(listHelper(children[i])); } return subList; @@ -56,93 +62,8 @@ define( } // Converts the filetree into a list - // Eventually, plan to call search service (but do here for now) + // Used for the fallback function getItems() { - console.log('in getItems()'); - debugger; - /* - var elasticsearch = require(['platform/persistence/elastic'], function (elasticsearch) { - debugger; - - console.log('elasticsearch (inside) ', elasticsearch); - - var client = new elasticsearch.Client({ - host: ROOT - }); - console.log('client', client); - - var testsearch = client.search({q: 'name=test123'});//[params, [callback]]); - console.log('search', testsearch); - }); - */ - var elasticsearch = require('elasticsearch'); - - debugger; - - console.log('elasticsearch (outside) ', elasticsearch); - - var client = new elasticsearch.Client({ - host: ROOT - }); - console.log('client', client); - - var testsearch = client.search({q: 'name=test123'});//[params, [callback]]); - console.log('search', testsearch); - - - /* - console.log('elasticsearch', elasticsearch); - var client = new elasticsearch.Client({ - host: 'localhost:9200' - }); - console.log('client', client); - var test = client.search();//[params, [callback]]); - console.log('search', test); - */ - - /* - var elasticApp = angular.module('elasticApp', ['elasticsearch']); - console.log('elasticApp', elasticApp); - - var client = elasticApp.service('client', function (esFactory) { - return esFactory({ - host: 'localhost:8080' - }); - }); - console.log('client', client); - */ - /* - var controller = elasticApp.controller('ElasticController', function ($scope, client, esFactory) { - client.cluster.state({ - metric: [ - 'cluster_name', - 'nodes', - 'master_node', - 'version' - ] - }).then(function (resp) { - $scope.clusterState = resp; - $scope.error = null; - }).catch(function (err) { - $scope.clusterState = null; - $scope.error = err; - // if the err is a NoConnections error, then the client was not able to - // connect to elasticsearch. In that case, create a more detailed error - // message - if (err instanceof esFactory.errors.NoConnections) { - $scope.error = new Error('Unable to connect to elasticsearch. ' + - 'Make sure that it is running and listening ' + - 'at http://localhost:9200'); - } - }); - }); - console.log('controller', controller); - */ - /* - var testSearch = client.search();//[params, [callback]]); - console.log('search', testSearch); - */ - // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { return listHelper(objects.mine).then(function (c) { @@ -151,8 +72,131 @@ define( }); } + // Search through items for items manually + // This is a fallback if other search services aren't avaliable + // ... currently only searches 1 layer down (TODO) + function queryFallback(inputID) { + var term, + searchResults = [], + itemsLength, + itemModel, + itemName, + i; + + // Get the user input + if (inputID) { + term = document.getElementById(inputID).value; + } else { + // Backward compatibility? + // TODO: May be unnecsisary + term = document.getElementById("searchinput").value; + } + + // Make not case sensitive + term = term.toLocaleLowerCase(); + + // Get items list + return getItems().then(function (items) { + // (slight time optimization) + itemsLength = items.length; + + // Then filter through the items list + for (i = 0; i < itemsLength; i += 1) { + // Prevent errors from getModel not being defined + if (items[i].getModel) { + itemModel = items[i].getModel(); + itemName = itemModel.name.toLocaleLowerCase(); + + // Include any matching items, except folders + // TODO: Should have a policy for this + if (itemName.includes(term) && itemModel.type !== "folder") { + searchResults.push(items[i]); + } + } + } + + //$scope.results = searchResults; // Some redundancy + return searchResults; + }); + } + + // Use elasticsearch's search to search through all the objects + function queryElasticsearch(inputID, maxResults) { + var searchTerm; + + // Check to see if the user provided a maximum + // number of results to display + if (!maxResults) { + // Else, we provide a default value + maxResults = 25; + } + + // Get the user input + if (inputID) { + searchTerm = document.getElementById(inputID).value; + } else { + // Backward compatibility? + // TODO: May be unnecsisary + searchTerm = document.getElementById("searchinput").value; + } + + // Process search term + // Put wildcards on front and end to allow substring behavior + searchTerm = '*' + searchTerm + '*'; + + // Get the data... + return $http({ + method: "GET", + url: ROOT + "/_search/?q=name:" + searchTerm + + "&size=" + maxResults + }).then(function (rawResults) { + // ...then process the data + var results = rawResults.data.hits.hits, + resultsLength = results.length, + ids = [], + i; + + if (rawResults.data.hits.total > resultsLength) { + // TODO: Somehow communicate this to the user + console.log('Total number of results greater than displayed results'); + } + + // Get the result objects' IDs + for (i = 0; i < resultsLength; i += 1) { + ids.push(results[i][ID]); + } + + // Get the domain objects from their IDs + return objectService.getObjects(ids).then(function (objects) { + var output = [], + id, + j; + + for (j = 0; j < resultsLength; j += 1) { + id = ids[j]; + + // Include any item except folders + // TODO: Should have a policy for this + if (objects[id].getModel) { + if (objects[id].getModel().type !== "folder") { + output.push(objects[id]); + } + } + } + + return output; + }); + }); + } + return { - getItems: getItems + // Only used in the fallback case of not having elasticsearch + // or equivalent. Returns a list of all of the domain objects + // in the tree. + getItems: getItems, + + // Takes a serach term and (optionally) the max number of results. + query: queryElasticsearch }; } diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/SearchController.js index d38062ebdc..ec3cb7e8c7 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/SearchController.js @@ -27,126 +27,12 @@ define(function () { "use strict"; - // JSLint doesn't like underscore-prefixed properties, - // so hide them here. - var ID = "_id", - SOURCE = "_source"; // TODO: Do we need this one? - - function SearchController($scope, $http, objectService, queryService, ROOT) { + function SearchController($scope, queryService) { - // Search through items for items manually - // This is a fallback if other search services aren't avaliable - // ... currently only searches 1 layer down (TODO) - function searchFallback() { - var term, - searchResults = [], - itemsLength, - itemModel, - itemName, - i; - - // Search for user input by element id - term = document.getElementById("searchinput").value; - - // Make not case sensitive - term = term.toLocaleLowerCase(); - - // Get items list - return queryService.getItems().then(function (items) { - // (slight time optimization) - itemsLength = items.length; - - // Then filter through the items list - for (i = 0; i < itemsLength; i += 1) { - // Prevent errors from getModel not being defined - if (items[i].getModel) { - itemModel = items[i].getModel(); - itemName = itemModel.name.toLocaleLowerCase(); - - // Include any matching items, except folders - // TODO: Should have a policy for this - if (itemName.includes(term) && itemModel.type !== "folder") { - searchResults.push(items[i]); - } - } - } - - //$scope.results = searchResults; // Some redundancy - return searchResults; - }); - } - - // Use elasticsearch's search to search through all the objects - function searchElastic(inputID, maxResults) { - var searchTerm; - - // Check to see if the user provided a maximum - // number of results to display - if (!maxResults) { - // Else, we provide a default value - maxResults = 25; - } - - // Get the user input - if (inputID) { - searchTerm = document.getElementById(inputID).value; - } else { - // Backward compatibility? - // TODO: May be unnecsisary - searchTerm = document.getElementById("searchinput").value; - } - - // Process search term - // Put wildcards on front and end to allow substring behavior - searchTerm = '*' + searchTerm + '*'; - - // Get the data... - return $http({ - method: "GET", - url: ROOT + "/_search/?q=name:" + searchTerm + - "&size=" + maxResults - }).then(function (rawResults) { - // ...then process the data - var results = rawResults.data.hits.hits, - resultsLength = results.length, - ids = [], - i; - - console.log('raw results', rawResults); - - // Get the result objects' IDs - for (i = 0; i < resultsLength; i += 1) { - ids.push(results[i][ID]); - } - - // Get the domain objects from their IDs - return objectService.getObjects(ids).then(function (objects) { - var output = [], - id, - j; - - for (j = 0; j < resultsLength; j += 1) { - id = ids[j]; - - // Include any item except folders - // TODO: Should have a policy for this - if (objects[id].getModel) { - if (objects[id].getModel().type !== "folder") { - output.push(objects[id]); - } - } - } - - console.log('final output', output); - return output; - }); - }); - } - return { // Search the database using the user input of id "searchinput" search: function (inputID) { - searchElastic(inputID).then(function (c) { + queryService.query(inputID).then(function (c) { $scope.results = c; }); }, From bf0e6692f5d4e04b5596aaa90222aaa89496f68b Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 11:41:23 -0700 Subject: [PATCH 033/195] [Search] Comments Added comments to better explain how input processing works. --- platform/features/search/src/QueryService.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index fdeea76f74..4704529d4c 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -140,8 +140,13 @@ define( searchTerm = document.getElementById("searchinput").value; } - // Process search term - // Put wildcards on front and end to allow substring behavior + // Process search term. + // Put wildcards on front and end to allow substring behavior. + // This works when options like AND and OR are not used, which is + // the case most of the time. + // e.g. The input 'sine' become '*sine*', but the input + // 'sine OR telemetry' becomes '*sine OR telemetry*' instead of + // '*sine* OR *telemetry*' searchTerm = '*' + searchTerm + '*'; // Get the data... From 7c627fae8fbb83b65a6de82e243fdf74e32e14ab Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 12:32:52 -0700 Subject: [PATCH 034/195] [Search] More search options If the user searches with quotes (" or ') around the search term, then the term processor will not put wildcards around the search term. --- platform/features/search/src/QueryService.js | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 4704529d4c..f3df7200b1 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -139,16 +139,26 @@ define( // TODO: May be unnecsisary searchTerm = document.getElementById("searchinput").value; } - + // Process search term. - // Put wildcards on front and end to allow substring behavior. - // This works when options like AND and OR are not used, which is - // the case most of the time. - // e.g. The input 'sine' become '*sine*', but the input - // 'sine OR telemetry' becomes '*sine OR telemetry*' instead of - // '*sine* OR *telemetry*' - searchTerm = '*' + searchTerm + '*'; - + // Allow exact searches by checking to see if the first and last + // chars are quotes. + if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || + (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { + // Remove the quotes, because of how elasticsearch processses. + // This will mean that elasticsearch will return any object that has + // that searchTerm as a part of the name _separated by spaces_. + searchTerm = searchTerm.substring(1, searchTerm.length - 1); + } else { + // Put wildcards on front and end to allow substring behavior. + // This works when options like AND and OR are not used, which is + // the case most of the time. + // e.g. The input 'sine' become '*sine*', but the input + // 'sine OR telemetry' becomes '*sine OR telemetry*' instead of + // '*sine* OR *telemetry*' + searchTerm = '*' + searchTerm + '*'; + } + // Get the data... return $http({ method: "GET", From 27c74103182d85e0ac3101b10c511f15e07723ac Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 12:39:00 -0700 Subject: [PATCH 035/195] [Search] Moved hard coding Moved where the search type is prepended to the search term, to allow future changes to it. --- platform/features/search/src/QueryService.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index f3df7200b1..a24c5f5292 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -144,7 +144,7 @@ define( // Allow exact searches by checking to see if the first and last // chars are quotes. if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || - (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { + (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { // Remove the quotes, because of how elasticsearch processses. // This will mean that elasticsearch will return any object that has // that searchTerm as a part of the name _separated by spaces_. @@ -158,11 +158,13 @@ define( // '*sine* OR *telemetry*' searchTerm = '*' + searchTerm + '*'; } + // Assume that the search term is for the name by default + searchTerm = "name:" + searchTerm; // Get the data... return $http({ method: "GET", - url: ROOT + "/_search/?q=name:" + searchTerm + + url: ROOT + "/_search/?q=" + searchTerm + "&size=" + maxResults }).then(function (rawResults) { // ...then process the data From 35d038e8260792435fa55a738255bbea5d418dc1 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 12:55:00 -0700 Subject: [PATCH 036/195] [Search] Processing as separate function Moved the search term processing to be its own separate function. --- platform/features/search/src/QueryService.js | 57 +++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index a24c5f5292..655ff6cf95 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -120,6 +120,39 @@ define( }); } + // Currently specific to elasticsearch + function processSearchTerm(searchTerm) { + // Allow exact searches by checking to see if the first and last + // chars are quotes. + if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || + (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { + // Remove the quotes, because of how elasticsearch processses. + // This will mean that elasticsearch will return any object that has + // that searchTerm as a part of the name _separated by spaces_. + searchTerm = searchTerm.substring(1, searchTerm.length - 1); + } + // If the search starts with 'type:', then search for domain object type, rather + // than the domain object name. + else if (searchTerm.includes('type:')) { + // Do nothing for now + } else if (searchTerm.includes('name:')) { + // Do nothing for now + } else { + // Put wildcards on front and end to allow substring behavior. + // This works when options like AND and OR are not used, which is + // the case most of the time. + // e.g. The input 'sine' become '*sine*', but the input + // 'sine OR telemetry' becomes '*sine OR telemetry*' instead of + // '*sine* OR *telemetry*' + searchTerm = '*' + searchTerm + '*'; + + // Assume that the search term is for the name by default + searchTerm = "name:" + searchTerm; + } + + return searchTerm; + } + // Use elasticsearch's search to search through all the objects function queryElasticsearch(inputID, maxResults) { var searchTerm; @@ -140,26 +173,10 @@ define( searchTerm = document.getElementById("searchinput").value; } - // Process search term. - // Allow exact searches by checking to see if the first and last - // chars are quotes. - if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || - (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { - // Remove the quotes, because of how elasticsearch processses. - // This will mean that elasticsearch will return any object that has - // that searchTerm as a part of the name _separated by spaces_. - searchTerm = searchTerm.substring(1, searchTerm.length - 1); - } else { - // Put wildcards on front and end to allow substring behavior. - // This works when options like AND and OR are not used, which is - // the case most of the time. - // e.g. The input 'sine' become '*sine*', but the input - // 'sine OR telemetry' becomes '*sine OR telemetry*' instead of - // '*sine* OR *telemetry*' - searchTerm = '*' + searchTerm + '*'; - } - // Assume that the search term is for the name by default - searchTerm = "name:" + searchTerm; + // Process search term + searchTerm = processSearchTerm(searchTerm); + + console.log(searchTerm); // Get the data... return $http({ From dcb5af87a7ae1d22027880f79918dde80d96b176 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 13:09:06 -0700 Subject: [PATCH 037/195] [Search] Moved result processing Moved result processing to its own function. --- platform/features/search/src/QueryService.js | 91 +++++++++----------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 655ff6cf95..5022a4cbc1 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -153,6 +153,46 @@ define( return searchTerm; } + // Processes results from the format that elasticsearch resturns to + // a list of objects in the format that mct-representation can use. + function processResults(rawResults) { + var results = rawResults.data.hits.hits, + resultsLength = results.length, + ids = [], + i; + + if (rawResults.data.hits.total > resultsLength) { + // TODO: Somehow communicate this to the user + console.log('Total number of results greater than displayed results'); + } + + // Get the result objects' IDs + for (i = 0; i < resultsLength; i += 1) { + ids.push(results[i][ID]); + } + + // Get the domain objects from their IDs + return objectService.getObjects(ids).then(function (objects) { + var output = [], + id, + j; + + for (j = 0; j < resultsLength; j += 1) { + id = ids[j]; + + // Include any item except folders + // TODO: Should have a policy for this + if (objects[id].getModel) { + if (objects[id].getModel().type !== "folder") { + output.push(objects[id]); + } + } + } + + return output; + }); + } + // Use elasticsearch's search to search through all the objects function queryElasticsearch(inputID, maxResults) { var searchTerm; @@ -165,19 +205,11 @@ define( } // Get the user input - if (inputID) { - searchTerm = document.getElementById(inputID).value; - } else { - // Backward compatibility? - // TODO: May be unnecsisary - searchTerm = document.getElementById("searchinput").value; - } + searchTerm = document.getElementById(inputID).value; // Process search term searchTerm = processSearchTerm(searchTerm); - console.log(searchTerm); - // Get the data... return $http({ method: "GET", @@ -185,50 +217,11 @@ define( "&size=" + maxResults }).then(function (rawResults) { // ...then process the data - var results = rawResults.data.hits.hits, - resultsLength = results.length, - ids = [], - i; - - if (rawResults.data.hits.total > resultsLength) { - // TODO: Somehow communicate this to the user - console.log('Total number of results greater than displayed results'); - } - - // Get the result objects' IDs - for (i = 0; i < resultsLength; i += 1) { - ids.push(results[i][ID]); - } - - // Get the domain objects from their IDs - return objectService.getObjects(ids).then(function (objects) { - var output = [], - id, - j; - - for (j = 0; j < resultsLength; j += 1) { - id = ids[j]; - - // Include any item except folders - // TODO: Should have a policy for this - if (objects[id].getModel) { - if (objects[id].getModel().type !== "folder") { - output.push(objects[id]); - } - } - } - - return output; - }); + return processResults(rawResults); }); } return { - // Only used in the fallback case of not having elasticsearch - // or equivalent. Returns a list of all of the domain objects - // in the tree. - getItems: getItems, - // Takes a serach term and (optionally) the max number of results. query: queryElasticsearch }; From 0371e2e3145b7b1ab9d329ed2ba83ad713e77875 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 14:26:45 -0700 Subject: [PATCH 038/195] [Search] Made maxResults bigger Made it so that the default maximum number of results is a larger number. --- platform/features/search/src/QueryService.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 5022a4cbc1..660782ff95 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -108,7 +108,6 @@ define( itemName = itemModel.name.toLocaleLowerCase(); // Include any matching items, except folders - // TODO: Should have a policy for this if (itemName.includes(term) && itemModel.type !== "folder") { searchResults.push(items[i]); } @@ -153,7 +152,7 @@ define( return searchTerm; } - // Processes results from the format that elasticsearch resturns to + // Processes results from the format that elasticsearch returns to // a list of objects in the format that mct-representation can use. function processResults(rawResults) { var results = rawResults.data.hits.hits, @@ -181,7 +180,6 @@ define( id = ids[j]; // Include any item except folders - // TODO: Should have a policy for this if (objects[id].getModel) { if (objects[id].getModel().type !== "folder") { output.push(objects[id]); @@ -200,8 +198,9 @@ define( // Check to see if the user provided a maximum // number of results to display if (!maxResults) { - // Else, we provide a default value - maxResults = 25; + // Else, we provide a default value. This is an + // arbitrary big number. + maxResults = 2048; } // Get the user input From 5e6f1214fbc9e14c93f0895a6aae010da4b9dd54 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 15:07:27 -0700 Subject: [PATCH 039/195] [Search] Live search As the user types, search happens with each new keypress, so the user does not need to press enter. (But can press enter as well.) --- platform/features/search/res/templates/search.html | 10 ++++------ platform/features/search/src/QueryService.js | 14 +++++++++++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 19f6dd6bfa..f1e7a8fb5d 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -19,7 +19,7 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> - +
    @@ -28,11 +28,9 @@
    Search:
    - - - + value="" + ng-keyup="controller.search('searchinput')" + style="width: 66%"/>
    diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 660782ff95..30e1ed6dd1 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -41,7 +41,7 @@ define( function QueryService($http, objectService, ROOT) { // Recursive helper function for getItems - function listHelper(current) { + function itemsHelper(current) { var composition; if (current.hasCapability('composition')) { composition = current.getCapability('composition'); @@ -55,7 +55,7 @@ define( var subList = [current], i; for (i = 0; i < children.length; i += 1) { - subList.push(listHelper(children[i])); + subList.push(itemsHelper(children[i])); } return subList; }); @@ -66,7 +66,7 @@ define( function getItems() { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { - return listHelper(objects.mine).then(function (c) { + return itemsHelper(objects.mine).then(function (c) { return c; }); }); @@ -121,6 +121,14 @@ define( // Currently specific to elasticsearch function processSearchTerm(searchTerm) { + // Shave any spaces off of the ends of the input + while (searchTerm.substr(0, 1) === ' ') { + searchTerm = searchTerm.substring(1, searchTerm.length); + } + while (searchTerm.substr(searchTerm.length - 1, 1) === ' ') { + searchTerm = searchTerm.substring(0, searchTerm.length - 1); + } + // Allow exact searches by checking to see if the first and last // chars are quotes. if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || From f8e028a5d1645af5ce80dc0a3b7e689889575f2f Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 14 Jul 2015 17:06:55 -0700 Subject: [PATCH 040/195] [Search] Outlined new function Started a new search function which manually indexes all of the items in the tree. Still not fully functional. --- platform/features/search/src/QueryService.js | 79 +++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 30e1ed6dd1..1b1db71923 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -40,6 +40,51 @@ define( */ function QueryService($http, objectService, ROOT) { + /////////////// The following is for non-Elastic Search ///////////////// + /* + function foo (children, i) { + if children [i] does not have composition, + return children + if children [i] does have composition, + return merge([children before i], foo(children[i], i++), [children after i]); + } + */ + + // Recursive helper function for getItems + function itemsHelper2(children, i) { + + console.log('itemshelpher2 called..... children', children); + + var composition; + if (i >= children.length) { + + console.log('base case..... children', children); + + // Base case. + return children; + } else if (children[i].hasCapability('composition')) { + composition = children[i].getCapability('composition'); + + console.log('composition..... child[', i, ']', children[i]); + console.log('................ children', children); + + return composition.invoke().then(function (grandchildren) { + + console.log('grandchildren', grandchildren); + + return itemsHelper2( + children.splice(0, i).concat(grandchildren, children.splice(i + 1, children.length)), + i); + }); + } else { + + console.log('not composition..... child[', i, ']', children[i]); + + return itemsHelper2(children, i + 1); + } + + } + // Recursive helper function for getItems function itemsHelper(current) { var composition; @@ -52,21 +97,49 @@ define( // Recursive case. Is asynchronous. return composition.invoke().then(function (children) { + + + // Second attempt + /* + // "global" variables + var children; + + // Helper function for itemsHelper to help with loops asynchronously + var looper = function (children, childIndex) { + return itemsHelper(children[childIndex]).then(function (c) { + childIndex++; + if (childIndex >= children.length) { + return children; + } else { + return looper(children, childIndex); + } + //return remainingChildren.concat(c); + }); + } + + // Kickoff the helper-helper + return itemsHelperHelper(children, 0).concat(); + */ + + // First attempt + /* var subList = [current], i; for (i = 0; i < children.length; i += 1) { subList.push(itemsHelper(children[i])); } return subList; + */ }); } + // Converts the filetree into a list // Used for the fallback function getItems() { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { - return itemsHelper(objects.mine).then(function (c) { + return itemsHelper2([objects.mine], 0).then(function (c) { return c; }); }); @@ -119,6 +192,8 @@ define( }); } + /////////////// The following is for Elastic Search ///////////////// + // Currently specific to elasticsearch function processSearchTerm(searchTerm) { // Shave any spaces off of the ends of the input @@ -230,7 +305,7 @@ define( return { // Takes a serach term and (optionally) the max number of results. - query: queryElasticsearch + query: queryFallback }; } From fdcc6432f1b4ca120a9feeb9fe3ea80a2f93f0a5 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 09:25:10 -0700 Subject: [PATCH 041/195] [Search] Reduced term processing Term processing may be unnecissary. Now it is limited to removed spcaes from the front and end. --- platform/features/search/src/QueryService.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 1b1db71923..bd54927cc5 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -31,7 +31,8 @@ define( // JSLint doesn't like underscore-prefixed properties, // so hide them here. - var ID = "_id"; + var ID = "_id", + SCORE = "_score"; /** * The query service is responsible for creating an index @@ -204,6 +205,7 @@ define( searchTerm = searchTerm.substring(0, searchTerm.length - 1); } + /* // Allow exact searches by checking to see if the first and last // chars are quotes. if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || @@ -231,7 +233,9 @@ define( // Assume that the search term is for the name by default searchTerm = "name:" + searchTerm; } + */ + //console.log('processed serach term ', searchTerm); return searchTerm; } @@ -241,6 +245,7 @@ define( var results = rawResults.data.hits.hits, resultsLength = results.length, ids = [], + scores = [], i; if (rawResults.data.hits.total > resultsLength) { @@ -253,6 +258,13 @@ define( ids.push(results[i][ID]); } + // Get the result objects' scores + for (i = 0; i < resultsLength; i += 1) { + scores.push(results[i][SCORE]); + } + + //console.log('scores', scores); + // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { var output = [], @@ -305,7 +317,7 @@ define( return { // Takes a serach term and (optionally) the max number of results. - query: queryFallback + query: queryElasticsearch }; } From 6b3088f241ace4be4ee689658a3820c754ea8fba Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 10:10:29 -0700 Subject: [PATCH 042/195] [Search] Manual search works Manual search which does not use elasticsearch implemented. It matches based on if the name contains the search term as a substring. --- platform/features/search/src/QueryService.js | 110 +++---------------- 1 file changed, 15 insertions(+), 95 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index bd54927cc5..602fa1656b 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -41,106 +41,33 @@ define( */ function QueryService($http, objectService, ROOT) { - /////////////// The following is for non-Elastic Search ///////////////// - /* - function foo (children, i) { - if children [i] does not have composition, - return children - if children [i] does have composition, - return merge([children before i], foo(children[i], i++), [children after i]); - } - */ + /////////////// The following is for non-Elastic Search ///////////////// // Recursive helper function for getItems - function itemsHelper2(children, i) { - - console.log('itemshelpher2 called..... children', children); - + function itemsHelper(children, i) { var composition; if (i >= children.length) { - - console.log('base case..... children', children); - - // Base case. + // Base case, is a leaf return children; } else if (children[i].hasCapability('composition')) { + // Handle this child's children composition = children[i].getCapability('composition'); - - console.log('composition..... child[', i, ']', children[i]); - console.log('................ children', children); - return composition.invoke().then(function (grandchildren) { - - console.log('grandchildren', grandchildren); - - return itemsHelper2( - children.splice(0, i).concat(grandchildren, children.splice(i + 1, children.length)), - i); + // Add grandchildren to the end of the list + // They will also be checked for composition + return itemsHelper(children.concat(grandchildren), i + 1); }); } else { - - console.log('not composition..... child[', i, ']', children[i]); - - return itemsHelper2(children, i + 1); + return itemsHelper(children, i + 1); } - } - // Recursive helper function for getItems - function itemsHelper(current) { - var composition; - if (current.hasCapability('composition')) { - composition = current.getCapability('composition'); - } else { - // Base case. - return current; - } - - // Recursive case. Is asynchronous. - return composition.invoke().then(function (children) { - - - // Second attempt - /* - // "global" variables - var children; - - // Helper function for itemsHelper to help with loops asynchronously - var looper = function (children, childIndex) { - return itemsHelper(children[childIndex]).then(function (c) { - childIndex++; - if (childIndex >= children.length) { - return children; - } else { - return looper(children, childIndex); - } - //return remainingChildren.concat(c); - }); - } - - // Kickoff the helper-helper - return itemsHelperHelper(children, 0).concat(); - */ - - // First attempt - /* - var subList = [current], - i; - for (i = 0; i < children.length; i += 1) { - subList.push(itemsHelper(children[i])); - } - return subList; - */ - }); - } - - // Converts the filetree into a list - // Used for the fallback + // Used for queryManual function getItems() { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { - return itemsHelper2([objects.mine], 0).then(function (c) { + return itemsHelper([objects.mine], 0).then(function (c) { return c; }); }); @@ -148,8 +75,7 @@ define( // Search through items for items manually // This is a fallback if other search services aren't avaliable - // ... currently only searches 1 layer down (TODO) - function queryFallback(inputID) { + function queryManual(inputID) { var term, searchResults = [], itemsLength, @@ -157,21 +83,14 @@ define( itemName, i; - // Get the user input - if (inputID) { - term = document.getElementById(inputID).value; - } else { - // Backward compatibility? - // TODO: May be unnecsisary - term = document.getElementById("searchinput").value; - } + // Get the user input + term = document.getElementById(inputID).value; // Make not case sensitive term = term.toLocaleLowerCase(); // Get items list return getItems().then(function (items) { - // (slight time optimization) itemsLength = items.length; // Then filter through the items list @@ -317,7 +236,8 @@ define( return { // Takes a serach term and (optionally) the max number of results. - query: queryElasticsearch + // Currently queryElasticsearch and queryManual are valid implementations. + query: queryManual }; } From 3420eb69d3da8c0ad40e66d8d7474b75fa271122 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 10:17:59 -0700 Subject: [PATCH 043/195] [Search] Manual max results option Manual search now takes a max number of results option, just like the elasticsearch version. --- platform/features/search/src/QueryService.js | 29 ++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 602fa1656b..febbfe05a3 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -40,6 +40,7 @@ define( * @constructor */ function QueryService($http, objectService, ROOT) { + var DEFAULT_MAX_RESULTS = 2048; /////////////// The following is for non-Elastic Search ///////////////// @@ -75,14 +76,22 @@ define( // Search through items for items manually // This is a fallback if other search services aren't avaliable - function queryManual(inputID) { + function queryManual(inputID, maxResults) { var term, searchResults = [], - itemsLength, + resultsLength, itemModel, itemName, i; - + + // Check to see if the user provided a maximum + // number of results to display + if (!maxResults) { + // Else, we provide a default value. This is an + // arbitrary big number. + maxResults = DEFAULT_MAX_RESULTS; + } + // Get the user input term = document.getElementById(inputID).value; @@ -91,10 +100,15 @@ define( // Get items list return getItems().then(function (items) { - itemsLength = items.length; + // Keep track of the number of results to display + if (items.length < maxResults) { + resultsLength = items.length; + } else { + resultsLength = maxResults; + } // Then filter through the items list - for (i = 0; i < itemsLength; i += 1) { + for (i = 0; i < resultsLength; i += 1) { // Prevent errors from getModel not being defined if (items[i].getModel) { itemModel = items[i].getModel(); @@ -106,8 +120,7 @@ define( } } } - - //$scope.results = searchResults; // Some redundancy + return searchResults; }); } @@ -214,7 +227,7 @@ define( if (!maxResults) { // Else, we provide a default value. This is an // arbitrary big number. - maxResults = 2048; + maxResults = DEFAULT_MAX_RESULTS; } // Get the user input From 227cb42ba7949348f75031f123c3af1be6244e96 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 10:22:03 -0700 Subject: [PATCH 044/195] [Search] Comments --- platform/features/search/src/QueryService.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index febbfe05a3..96a4b2cf43 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -48,10 +48,10 @@ define( function itemsHelper(children, i) { var composition; if (i >= children.length) { - // Base case, is a leaf + // Done! return children; } else if (children[i].hasCapability('composition')) { - // Handle this child's children + // This child has children composition = children[i].getCapability('composition'); return composition.invoke().then(function (grandchildren) { // Add grandchildren to the end of the list @@ -59,6 +59,7 @@ define( return itemsHelper(children.concat(grandchildren), i + 1); }); } else { + // This child is a leaf return itemsHelper(children, i + 1); } } @@ -68,13 +69,14 @@ define( function getItems() { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { + // Get all of its descendents return itemsHelper([objects.mine], 0).then(function (c) { return c; }); }); } - // Search through items for items manually + // Search through filetree for items manually // This is a fallback if other search services aren't avaliable function queryManual(inputID, maxResults) { var term, @@ -87,8 +89,7 @@ define( // Check to see if the user provided a maximum // number of results to display if (!maxResults) { - // Else, we provide a default value. This is an - // arbitrary big number. + // Else, we provide a default value. maxResults = DEFAULT_MAX_RESULTS; } From eb5946c1c152f06f2dfe110ee0157db784c5e89a Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 10:45:09 -0700 Subject: [PATCH 045/195] [Search] Documentation Gave more verbose descriptions of queryManual and queryElasticsearch. --- platform/features/search/src/QueryService.js | 60 ++++++++++++++------ 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 96a4b2cf43..3892e48389 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -35,8 +35,12 @@ define( SCORE = "_score"; /** - * The query service is responsible for creating an index - * of objects in the filetree which is searchable. + * The query service is responsible for searching through + * objects in the filetree. There are multiple possible + * implementations for querying. Currently there is + * queryManual (which manually steps through the filetree) + * and queryElasticsearch (which passes the work on to + * elasticsearch). * @constructor */ function QueryService($http, objectService, ROOT) { @@ -46,14 +50,12 @@ define( // Recursive helper function for getItems function itemsHelper(children, i) { - var composition; if (i >= children.length) { // Done! return children; } else if (children[i].hasCapability('composition')) { // This child has children - composition = children[i].getCapability('composition'); - return composition.invoke().then(function (grandchildren) { + 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); @@ -76,8 +78,23 @@ define( }); } - // Search through filetree for items manually - // This is a fallback if other search services aren't avaliable + /** + * 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 search term as a + * substring. + * * Folders are not included in the results. + * * 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 + * @param maxResults (optional) the maximum number of results + * that this function should return + */ function queryManual(inputID, maxResults) { var term, searchResults = [], @@ -178,7 +195,7 @@ define( var results = rawResults.data.hits.hits, resultsLength = results.length, ids = [], - scores = [], + //scores = [], i; if (rawResults.data.hits.total > resultsLength) { @@ -191,12 +208,13 @@ define( ids.push(results[i][ID]); } + /* // Get the result objects' scores for (i = 0; i < resultsLength; i += 1) { scores.push(results[i][SCORE]); } - - //console.log('scores', scores); + console.log('scores', scores); + */ // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { @@ -219,15 +237,27 @@ define( }); } - // Use elasticsearch's search to search through all the objects + /** + * Searches through the filetree for domain objects using a search + * term. This is done through querying elasticsearch. + * Notes: + * * The order of the results is from highest to lowest score, + * as elsaticsearch determines them to be. + * * Folders are not included in the results. + * * Wildcards are supported. + * + * @param inputID the name of the ID property of the html text + * input where this funcion should find the search term + * @param maxResults (optional) the maximum number of results + * that this function should return + */ function queryElasticsearch(inputID, maxResults) { var searchTerm; // Check to see if the user provided a maximum // number of results to display if (!maxResults) { - // Else, we provide a default value. This is an - // arbitrary big number. + // Else, we provide a default value. maxResults = DEFAULT_MAX_RESULTS; } @@ -249,9 +279,7 @@ define( } return { - // Takes a serach term and (optionally) the max number of results. - // Currently queryElasticsearch and queryManual are valid implementations. - query: queryManual + query: queryElasticsearch }; } From d6720884f180eca3d3da813cab16ef064cc5ced3 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 10:52:27 -0700 Subject: [PATCH 046/195] [Search] Elasticsearch search options Changed the search term processor to allow the name and type options again (for elasticsearch). --- platform/features/search/src/QueryService.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 3892e48389..c045a19621 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -167,7 +167,9 @@ define( } // If the search starts with 'type:', then search for domain object type, rather // than the domain object name. - else if (searchTerm.includes('type:')) { + else + */ + if (searchTerm.includes('type:')) { // Do nothing for now } else if (searchTerm.includes('name:')) { // Do nothing for now @@ -178,12 +180,11 @@ define( // e.g. The input 'sine' become '*sine*', but the input // 'sine OR telemetry' becomes '*sine OR telemetry*' instead of // '*sine* OR *telemetry*' - searchTerm = '*' + searchTerm + '*'; + //searchTerm = '*' + searchTerm + '*'; // Assume that the search term is for the name by default searchTerm = "name:" + searchTerm; } - */ //console.log('processed serach term ', searchTerm); return searchTerm; From 06b26b799e87f668f32ef8a0fb40c6aac9ff0b23 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 11:10:04 -0700 Subject: [PATCH 047/195] [Search] Comments --- platform/features/search/src/QueryService.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index c045a19621..800a147443 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -246,6 +246,8 @@ define( * as elsaticsearch determines them to be. * * Folders are not included in the results. * * Wildcards are supported. + * * More search details at + * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term @@ -280,7 +282,7 @@ define( } return { - query: queryElasticsearch + query: queryManual }; } From e634d77a8e063aca95bbc6b6624f10c7ebc99446 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 11:39:02 -0700 Subject: [PATCH 048/195] [Search] Add wildcards Added wildcards to most searches at the front and end of each word that is separated by spaces. --- platform/features/search/src/QueryService.js | 54 +++++++++----------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 800a147443..fb38baf49d 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -145,6 +145,22 @@ define( /////////////// The following is for Elastic Search ///////////////// + // Check to see if the input has any special options + function isDefaultInput(searchTerm) { + // If the input has quotes, not default + if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || + (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { + return false; + } + + // If the input has a property option, not default + if (searchTerm.includes('name:') || searchTerm.includes('type:')) { + return false; + } + + return true; + } + // Currently specific to elasticsearch function processSearchTerm(searchTerm) { // Shave any spaces off of the ends of the input @@ -155,35 +171,15 @@ define( searchTerm = searchTerm.substring(0, searchTerm.length - 1); } - /* - // Allow exact searches by checking to see if the first and last - // chars are quotes. - if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || - (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { - // Remove the quotes, because of how elasticsearch processses. - // This will mean that elasticsearch will return any object that has - // that searchTerm as a part of the name _separated by spaces_. - searchTerm = searchTerm.substring(1, searchTerm.length - 1); - } - // If the search starts with 'type:', then search for domain object type, rather - // than the domain object name. - else - */ - if (searchTerm.includes('type:')) { - // Do nothing for now - } else if (searchTerm.includes('name:')) { - // Do nothing for now - } else { - // Put wildcards on front and end to allow substring behavior. - // This works when options like AND and OR are not used, which is - // the case most of the time. - // e.g. The input 'sine' become '*sine*', but the input - // 'sine OR telemetry' becomes '*sine OR telemetry*' instead of - // '*sine* OR *telemetry*' - //searchTerm = '*' + searchTerm + '*'; + if (isDefaultInput(searchTerm)) { + // Elasticsearch splits terms up by spaces + // Add wildcards to the font and end of each subterm + searchTerm = searchTerm.split(' ').map(function (s) { + return '*' + s + '*'; + }).join(' '); - // Assume that the search term is for the name by default - searchTerm = "name:" + searchTerm; + // Searching 'name' by default + searchTerm = 'name:' + searchTerm; } //console.log('processed serach term ', searchTerm); @@ -282,7 +278,7 @@ define( } return { - query: queryManual + query: queryElasticsearch }; } From eee930965041ef466ffcec3a272715d8ef1837f2 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 12:14:30 -0700 Subject: [PATCH 049/195] [Search] Fuzziness operator Insead of wildcards, adding the fuzziness operator to searches to ensure completeness of the search results. --- platform/features/search/src/QueryService.js | 29 ++++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index fb38baf49d..d6ea8c4a37 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -161,6 +161,26 @@ define( return true; } + // Add wildcards to the font and end of each subterm + function addWildcards(searchTerm) { + return searchTerm.split(' ').map(function (s) { + return '*' + s + '*'; + }).join(' '); + } + + // Add the fuzziness operator to the search term + function addFuzziness(searchTerm, editDistance) { + if (!editDistance) { + editDistance = ''; + } + + return searchTerm.split(' ').map(function (s) { + return s + '~' + editDistance; + }).join(' '); + //searchTerm + '~' + editDistance; + + } + // Currently specific to elasticsearch function processSearchTerm(searchTerm) { // Shave any spaces off of the ends of the input @@ -172,17 +192,14 @@ define( } if (isDefaultInput(searchTerm)) { - // Elasticsearch splits terms up by spaces - // Add wildcards to the font and end of each subterm - searchTerm = searchTerm.split(' ').map(function (s) { - return '*' + s + '*'; - }).join(' '); + // Add fuzziness for completeness + searchTerm = addFuzziness(searchTerm); // Searching 'name' by default searchTerm = 'name:' + searchTerm; } - //console.log('processed serach term ', searchTerm); + console.log('processed search term ', searchTerm); return searchTerm; } From 759eaa3b3596680f31f40397f688c965bd395b92 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 12:37:12 -0700 Subject: [PATCH 050/195] [Search] Comments --- platform/features/search/src/QueryService.js | 33 +++++++++----------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index d6ea8c4a37..e7be704f69 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -48,7 +48,7 @@ define( /////////////// The following is for non-Elastic Search ///////////////// - // Recursive helper function for getItems + // Recursive helper function for getItems() function itemsHelper(children, i) { if (i >= children.length) { // Done! @@ -67,7 +67,7 @@ define( } // Converts the filetree into a list - // Used for queryManual + // Used for queryManual() function getItems() { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { @@ -85,8 +85,8 @@ define( * 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 search term as a - * substring. + * the object's name property contains the exact search term + * as a substring. * * Folders are not included in the results. * * Wildcards are not supported. * @@ -146,6 +146,7 @@ define( /////////////// The following is for Elastic Search ///////////////// // Check to see if the input has any special options + // Used by queryElasticsearch() function isDefaultInput(searchTerm) { // If the input has quotes, not default if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || @@ -162,6 +163,7 @@ define( } // Add wildcards to the font and end of each subterm + // Used by queryElasticsearch() function addWildcards(searchTerm) { return searchTerm.split(' ').map(function (s) { return '*' + s + '*'; @@ -169,6 +171,7 @@ define( } // Add the fuzziness operator to the search term + // Used by queryElasticsearch() function addFuzziness(searchTerm, editDistance) { if (!editDistance) { editDistance = ''; @@ -178,10 +181,10 @@ define( return s + '~' + editDistance; }).join(' '); //searchTerm + '~' + editDistance; - } // Currently specific to elasticsearch + // Used by queryElasticsearch() function processSearchTerm(searchTerm) { // Shave any spaces off of the ends of the input while (searchTerm.substr(0, 1) === ' ') { @@ -193,23 +196,23 @@ define( if (isDefaultInput(searchTerm)) { // Add fuzziness for completeness - searchTerm = addFuzziness(searchTerm); + searchTerm = addFuzziness(searchTerm, 1); // Searching 'name' by default searchTerm = 'name:' + searchTerm; } - console.log('processed search term ', searchTerm); + //console.log('processed search term ', searchTerm); return searchTerm; } // Processes results from the format that elasticsearch returns to // a list of objects in the format that mct-representation can use. + // Used by queryElasticsearch() function processResults(rawResults) { var results = rawResults.data.hits.hits, resultsLength = results.length, ids = [], - //scores = [], i; if (rawResults.data.hits.total > resultsLength) { @@ -222,14 +225,6 @@ define( ids.push(results[i][ID]); } - /* - // Get the result objects' scores - for (i = 0; i < resultsLength; i += 1) { - scores.push(results[i][SCORE]); - } - console.log('scores', scores); - */ - // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { var output = [], @@ -256,11 +251,13 @@ define( * term. This is done through querying elasticsearch. * Notes: * * The order of the results is from highest to lowest score, - * as elsaticsearch determines them to be. + * as elsaticsearch determines them to be. * * Folders are not included in the results. * * Wildcards are supported. * * More search details at - * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html + * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html + * * Fuzziness is used to produce more results that are still + * relevant. (All results within a certain edit distance.) * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term From b94ef695e2215b83177513c028e56937c348ee19 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 13:29:45 -0700 Subject: [PATCH 051/195] [Search] Creating searchbar Starting to create a search bar which lives in the same side of the divder as the file tree does. --- .../commonUI/browse/res/templates/browse.html | 5 ++ platform/features/search/bundle.json | 18 +++++- .../search/res/templates/searchbar-item.html | 55 +++++++++++++++++++ .../search/res/templates/searchbar.html | 42 ++++++++++++++ .../search/src/SearchbarController.js | 51 +++++++++++++++++ 5 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 platform/features/search/res/templates/searchbar-item.html create mode 100644 platform/features/search/res/templates/searchbar.html create mode 100644 platform/features/search/src/SearchbarController.js diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index 0a7698e8bd..1a4cfc646b 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -27,6 +27,11 @@ style="min-width: 150px; max-width: 800px; width: 25%;"> +
    + + +
    + +
    + + + + +
    \ No newline at end of file diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html new file mode 100644 index 0000000000..f93fd1cd84 --- /dev/null +++ b/platform/features/search/res/templates/searchbar.html @@ -0,0 +1,42 @@ + + + +
    + + Search: + + +
    + + +
    + + +
    +
    \ No newline at end of file diff --git a/platform/features/search/src/SearchbarController.js b/platform/features/search/src/SearchbarController.js new file mode 100644 index 0000000000..f1166d51ea --- /dev/null +++ b/platform/features/search/src/SearchbarController.js @@ -0,0 +1,51 @@ +/***************************************************************************** + * 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*/ + +/** + * Module defining SearchbarController. Created by shale on 07/15/2015. + */ +define(function () { + "use strict"; + + function SearchbarController($scope, queryService) { + + return { + // Search the database using the user input of id "searchinput" + search: function (inputID) { + queryService.query(inputID).then(function (c) { + $scope.results = c; + }); + }, + + // Check to see if there are any search results to display. + areResults: function () { + if ($scope.results) { + return $scope.results.length > 0; + } else { + return false; + } + } + }; + } + return SearchbarController; +}); From 672fa74321a096a055a05e32a83a408d7a4be9e6 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 16:46:33 -0700 Subject: [PATCH 052/195] [Search] Changed default max results Changed the default number of max results to be 100 results. --- .../search/res/templates/searchbar.html | 6 +----- platform/features/search/src/QueryService.js | 18 ++++-------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html index f93fd1cd84..c218ae7ea0 100644 --- a/platform/features/search/res/templates/searchbar.html +++ b/platform/features/search/res/templates/searchbar.html @@ -22,14 +22,10 @@
    - - Search: - + ng-keyup="controller.search('searchbarinput')" />
    diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index e7be704f69..67ef80be9d 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -44,7 +44,7 @@ define( * @constructor */ function QueryService($http, objectService, ROOT) { - var DEFAULT_MAX_RESULTS = 2048; + var DEFAULT_MAX_RESULTS = 100; /////////////// The following is for non-Elastic Search ///////////////// @@ -162,14 +162,6 @@ define( return true; } - // Add wildcards to the font and end of each subterm - // Used by queryElasticsearch() - function addWildcards(searchTerm) { - return searchTerm.split(' ').map(function (s) { - return '*' + s + '*'; - }).join(' '); - } - // Add the fuzziness operator to the search term // Used by queryElasticsearch() function addFuzziness(searchTerm, editDistance) { @@ -180,7 +172,6 @@ define( return searchTerm.split(' ').map(function (s) { return s + '~' + editDistance; }).join(' '); - //searchTerm + '~' + editDistance; } // Currently specific to elasticsearch @@ -196,13 +187,12 @@ define( if (isDefaultInput(searchTerm)) { // Add fuzziness for completeness - searchTerm = addFuzziness(searchTerm, 1); + searchTerm = addFuzziness(searchTerm, 2); // Searching 'name' by default searchTerm = 'name:' + searchTerm; } - //console.log('processed search term ', searchTerm); return searchTerm; } @@ -250,7 +240,7 @@ define( * Searches through the filetree for domain objects using a search * term. This is done through querying elasticsearch. * Notes: - * * The order of the results is from highest to lowest score, + * * The order of the results is from highest to lowest score, * as elsaticsearch determines them to be. * * Folders are not included in the results. * * Wildcards are supported. @@ -266,7 +256,7 @@ define( */ function queryElasticsearch(inputID, maxResults) { var searchTerm; - + // Check to see if the user provided a maximum // number of results to display if (!maxResults) { From c5c3546b927d17ff85a0402906ac64bfc08d7a87 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 15 Jul 2015 17:02:35 -0700 Subject: [PATCH 053/195] [Search] Relaxed quote rules Allowed quotes more often in search terms. When there are quotes, that space-separated term will not get the fuzzy identifier. --- platform/features/search/src/QueryService.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 67ef80be9d..04d01c519c 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -149,10 +149,12 @@ define( // Used by queryElasticsearch() function isDefaultInput(searchTerm) { // If the input has quotes, not default + /* if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { return false; } + */ // If the input has a property option, not default if (searchTerm.includes('name:') || searchTerm.includes('type:')) { @@ -170,7 +172,12 @@ define( } return searchTerm.split(' ').map(function (s) { - return s + '~' + editDistance; + if (s.includes('"')) { + console.log('true'); + return s; + } else { + return s + '~' + editDistance; + } }).join(' '); } @@ -187,12 +194,13 @@ define( if (isDefaultInput(searchTerm)) { // Add fuzziness for completeness - searchTerm = addFuzziness(searchTerm, 2); + searchTerm = addFuzziness(searchTerm); // Searching 'name' by default searchTerm = 'name:' + searchTerm; } + console.log('search term ', searchTerm); return searchTerm; } From 1e05ebbfd716090a81f5036662c926ab6668dddc Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 09:56:47 -0700 Subject: [PATCH 054/195] [Search] Modified default input funct Renamed isDefaultInput() to isDefaultFormat(). It currently just checks for 'name' or 'type' tags, but it may be completely unneeded. --- platform/features/search/src/QueryService.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/QueryService.js index 04d01c519c..93cfe94e5b 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/QueryService.js @@ -147,15 +147,7 @@ define( // Check to see if the input has any special options // Used by queryElasticsearch() - function isDefaultInput(searchTerm) { - // If the input has quotes, not default - /* - if ((searchTerm.substr(0, 1) === '"' && searchTerm.substr(searchTerm.length - 1, 1) === '"') || - (searchTerm.substr(0, 1) === "'" && searchTerm.substr(searchTerm.length - 1, 1) === "'")) { - return false; - } - */ - + function isDefaultFormat(searchTerm) { // If the input has a property option, not default if (searchTerm.includes('name:') || searchTerm.includes('type:')) { return false; @@ -192,7 +184,7 @@ define( searchTerm = searchTerm.substring(0, searchTerm.length - 1); } - if (isDefaultInput(searchTerm)) { + if (isDefaultFormat(searchTerm)) { // Add fuzziness for completeness searchTerm = addFuzziness(searchTerm); @@ -252,10 +244,10 @@ define( * as elsaticsearch determines them to be. * * Folders are not included in the results. * * Wildcards are supported. - * * More search details at - * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html * * Fuzziness is used to produce more results that are still * relevant. (All results within a certain edit distance.) + * * More search details at + * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term From 6f2ad0dadcb9e07ef99161b22a1148ed2619bf38 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 10:10:07 -0700 Subject: [PATCH 055/195] [Search] Renaming and adding files Renamed QueryService as SearchService and changed the corresponding references to it. Added a SearchAggregator file and related files. Not yet begun with the implementation. --- .../commonUI/browse/res/templates/browse.html | 4 +- platform/features/search/bundle.json | 12 +-- .../features/search/src/SearchAggregator.js | 93 +++++++++++++++++++ .../src/{QueryService.js => SearchService.js} | 4 +- .../src/{ => controllers}/SearchController.js | 4 +- .../{ => controllers}/SearchbarController.js | 4 +- .../providers/ElasticsearchSearchProvider.js | 0 .../src/providers/EverythingSearchProvider.js | 0 .../providers/WARPTaxonomySearchProvider.js | 0 9 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 platform/features/search/src/SearchAggregator.js rename platform/features/search/src/{QueryService.js => SearchService.js} (99%) rename platform/features/search/src/{ => controllers}/SearchController.js (94%) rename platform/features/search/src/{ => controllers}/SearchbarController.js (93%) create mode 100644 platform/features/search/src/providers/ElasticsearchSearchProvider.js create mode 100644 platform/features/search/src/providers/EverythingSearchProvider.js create mode 100644 platform/features/search/src/providers/WARPTaxonomySearchProvider.js diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index aa4816a882..f2f0d4baa5 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -28,11 +28,11 @@ > -
    +
    bModified) ? a : (b || a); + } + + // Merge results from multiple providers into one + // large result object. + function mergeModels(provided, ids) { + var result = {}; + ids.forEach(function (id) { + provided.forEach(function (models) { + if (models[id]) { + result[id] = pick(result[id], models[id]); + } + }); + }); + return result; + } + + return { + /** + * Get models with the specified identifiers. + * + * This will invoke the `getModels()` method of all providers + * given at constructor-time, and aggregate the result into + * one object. + * + * Note that the returned object may contain a subset or a + * superset of the models requested. + * + * @param {string[]} ids an array of domain object identifiers + * @returns {Promise.} a promise for an object + * containing key-value pairs, + * where keys are object identifiers and values + * are object models. + */ + getModels: function (ids) { + return $q.all(providers.map(function (provider) { + return provider.getModels(ids); + })).then(function (provided) { + return mergeModels(provided, ids); + }); + } + }; + } + + return ModelAggregator; + } +); \ No newline at end of file diff --git a/platform/features/search/src/QueryService.js b/platform/features/search/src/SearchService.js similarity index 99% rename from platform/features/search/src/QueryService.js rename to platform/features/search/src/SearchService.js index 93cfe94e5b..16fb061cff 100644 --- a/platform/features/search/src/QueryService.js +++ b/platform/features/search/src/SearchService.js @@ -43,7 +43,7 @@ define( * elasticsearch). * @constructor */ - function QueryService($http, objectService, ROOT) { + function SearchService($http, objectService, ROOT) { var DEFAULT_MAX_RESULTS = 100; /////////////// The following is for non-Elastic Search ///////////////// @@ -286,6 +286,6 @@ define( }; } - return QueryService; + return SearchService; } ); \ No newline at end of file diff --git a/platform/features/search/src/SearchController.js b/platform/features/search/src/controllers/SearchController.js similarity index 94% rename from platform/features/search/src/SearchController.js rename to platform/features/search/src/controllers/SearchController.js index ec3cb7e8c7..423e6253bb 100644 --- a/platform/features/search/src/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -27,12 +27,12 @@ define(function () { "use strict"; - function SearchController($scope, queryService) { + function SearchController($scope, searchService) { return { // Search the database using the user input of id "searchinput" search: function (inputID) { - queryService.query(inputID).then(function (c) { + searchService.query(inputID).then(function (c) { $scope.results = c; }); }, diff --git a/platform/features/search/src/SearchbarController.js b/platform/features/search/src/controllers/SearchbarController.js similarity index 93% rename from platform/features/search/src/SearchbarController.js rename to platform/features/search/src/controllers/SearchbarController.js index f1166d51ea..1a48a9c793 100644 --- a/platform/features/search/src/SearchbarController.js +++ b/platform/features/search/src/controllers/SearchbarController.js @@ -27,12 +27,12 @@ define(function () { "use strict"; - function SearchbarController($scope, queryService) { + function SearchbarController($scope, searchService) { return { // Search the database using the user input of id "searchinput" search: function (inputID) { - queryService.query(inputID).then(function (c) { + searchService.query(inputID).then(function (c) { $scope.results = c; }); }, diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/EverythingSearchProvider.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/platform/features/search/src/providers/WARPTaxonomySearchProvider.js b/platform/features/search/src/providers/WARPTaxonomySearchProvider.js new file mode 100644 index 0000000000..e69de29bb2 From cd3c2312a59bc2abbe58d249a86eaab07f57513c Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 10:35:26 -0700 Subject: [PATCH 056/195] [Search] Basic aggregator works The search view now behaves as it previously did. The search aggregator is set to just use ElasticSearch, but it works. --- platform/features/search/bundle.json | 19 +- .../features/search/src/SearchAggregator.js | 18 +- .../providers/ElasticsearchSearchProvider.js | 191 ++++++++++++++++++ .../src/providers/EverythingSearchProvider.js | 147 ++++++++++++++ 4 files changed, 366 insertions(+), 9 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index ef90b63dfa..095abaab28 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -37,11 +37,24 @@ "uses": [ "composition" ] } ], - "services": [ + "components": [ { - "key": "searchService", - "implementation": "SearchService.js", + "provides": "searchService", + "type": "provider", + "implementation": "providers/ElasticsearchSearchProvider.js", "depends": [ "$http", "objectService", "ELASTIC_ROOT" ] + }, + { + "provides": "searchService", + "type": "provider", + "implementation": "providers/EverythingSearchProvider.js", + "depends": [ "objectService" ] + }, + { + "provides": "searchService", + "type": "aggregator", + "implementation": "SearchAggregator.js", + "depends": [ "$q" ] } ] } diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 30b645ff86..2b1fa32d3b 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -22,7 +22,7 @@ /*global define*/ /** - * Module defining ModelAggregator. Created by vwoeltje on 11/7/14. + * Module defining SearchAggregator. Created by shale on 07/16/2015. */ define( [], @@ -30,15 +30,19 @@ define( "use strict"; /** - * Allows multiple services which provide models for domain objects + * Allows multiple services which provide search functionality * to be treated as one. * * @constructor - * @param {ModelProvider[]} providers the model providers to be + * @param {SearchProvider[]} providers the search providers to be * aggregated */ - function ModelAggregator($q, providers) { - + function SearchAggregator($q, providers) { + return { + query: providers[0].query + }; + +/* // Pick a domain object model to use, favoring the one // with the most recent timestamp function pick(a, b) { @@ -78,6 +82,7 @@ define( * where keys are object identifiers and values * are object models. */ +/* getModels: function (ids) { return $q.all(providers.map(function (provider) { return provider.getModels(ids); @@ -86,8 +91,9 @@ define( }); } }; +*/ } - return ModelAggregator; + return SearchAggregator; } ); \ No newline at end of file diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index e69de29bb2..fefbd64be1 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -0,0 +1,191 @@ +/***************************************************************************** + * 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*/ + +/** + * Module defining ElasticsearchSearchProvider. Created by shale on 07/16/2015. + */ +define( + [], + function () { + "use strict"; + + // JSLint doesn't like underscore-prefixed properties, + // so hide them here. + var ID = "_id", + SCORE = "_score", + DEFAULT_MAX_RESULTS = 100; + + /** + * A model service which reads domain object models from an external + * persistence service. + * + * @constructor + * @param {PersistenceService} persistenceService the service in which + * domain object models are persisted. + * @param $q Angular's $q service, for working with promises + * @param {string} SPACE the name of the persistence space from which + * models should be retrieved. + */ + function ElasticsearchSearchProvider($http, objectService, ROOT) { + + // Check to see if the input has any special options + function isDefaultFormat(searchTerm) { + // If the input has a property option, not default + if (searchTerm.includes('name:') || searchTerm.includes('type:')) { + return false; + } + + return true; + } + + // Add the fuzziness operator to the search term + function addFuzziness(searchTerm, editDistance) { + if (!editDistance) { + editDistance = ''; + } + + return searchTerm.split(' ').map(function (s) { + if (s.includes('"')) { + console.log('true'); + return s; + } else { + return s + '~' + editDistance; + } + }).join(' '); + } + + // Currently specific to elasticsearch + function processSearchTerm(searchTerm) { + // Shave any spaces off of the ends of the input + while (searchTerm.substr(0, 1) === ' ') { + searchTerm = searchTerm.substring(1, searchTerm.length); + } + while (searchTerm.substr(searchTerm.length - 1, 1) === ' ') { + searchTerm = searchTerm.substring(0, searchTerm.length - 1); + } + + if (isDefaultFormat(searchTerm)) { + // Add fuzziness for completeness + searchTerm = addFuzziness(searchTerm); + + // Searching 'name' by default + searchTerm = 'name:' + searchTerm; + } + + console.log('search term ', searchTerm); + return searchTerm; + } + + // Processes results from the format that elasticsearch returns to + // a list of objects in the format that mct-representation can use + function processResults(rawResults) { + var results = rawResults.data.hits.hits, + resultsLength = results.length, + ids = [], + i; + + if (rawResults.data.hits.total > resultsLength) { + // TODO: Somehow communicate this to the user + console.log('Total number of results greater than displayed results'); + } + + // Get the result objects' IDs + for (i = 0; i < resultsLength; i += 1) { + ids.push(results[i][ID]); + } + + // Get the domain objects from their IDs + return objectService.getObjects(ids).then(function (objects) { + var output = [], + id, + j; + + for (j = 0; j < resultsLength; j += 1) { + id = ids[j]; + + // Include any item except folders + if (objects[id].getModel) { + if (objects[id].getModel().type !== "folder") { + output.push(objects[id]); + } + } + } + + return output; + }); + } + + /** + * Searches through the filetree for domain objects using a search + * term. This is done through querying elasticsearch. + * Notes: + * * The order of the results is from highest to lowest score, + * as elsaticsearch determines them to be. + * * Folders are not included in the results. + * * Wildcards are supported. + * * Fuzziness is used to produce more results that are still + * relevant. (All results within a certain edit distance.) + * * More search details at + * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html + * + * @param inputID the name of the ID property of the html text + * input where this funcion should find the search term + * @param maxResults (optional) the maximum number of results + * that this function should return + */ + function queryElasticsearch(inputID, maxResults) { + var searchTerm; + + // 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; + } + + // Get the user input + searchTerm = document.getElementById(inputID).value; + + // Process search term + searchTerm = processSearchTerm(searchTerm); + + // Get the data... + return $http({ + method: "GET", + url: ROOT + "/_search/?q=" + searchTerm + + "&size=" + maxResults + }).then(function (rawResults) { + // ...then process the data + return processResults(rawResults); + }); + } + + return { + query: queryElasticsearch + }; + } + + + return ElasticsearchSearchProvider; + } +); \ No newline at end of file diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/EverythingSearchProvider.js index e69de29bb2..8979d3e322 100644 --- a/platform/features/search/src/providers/EverythingSearchProvider.js +++ b/platform/features/search/src/providers/EverythingSearchProvider.js @@ -0,0 +1,147 @@ +/***************************************************************************** + * 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*/ + +/** + * Module defining EverythingSearchProvider. Created by shale on 07/16/2015. + */ +define( + [], + function () { + "use strict"; + + /** + * A model service which reads domain object models from an external + * persistence service. + * + * @constructor + * @param {PersistenceService} persistenceService the service in which + * domain object models are persisted. + * @param $q Angular's $q service, for working with promises + * @param {string} SPACE the name of the persistence space from which + * models should be retrieved. + */ + function EverythingSearchProvider(objectService) { + + // Recursive helper function for getItems() + function itemsHelper(children, i) { + if (i >= children.length) { + // 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 + function getItems() { + // Aquire My Items (root folder) + return objectService.getObjects(['mine']).then(function (objects) { + // Get all of its descendents + return itemsHelper([objects.mine], 0).then(function (c) { + return c; + }); + }); + } + + /** + * 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. + * * Folders are not included in the results. + * * 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 + * @param maxResults (optional) the maximum number of results + * that this function should return + */ + function queryManual(inputID, maxResults) { + var term, + searchResults = [], + resultsLength, + itemModel, + itemName, + i; + + // 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; + } + + // Get the user input + term = document.getElementById(inputID).value; + + // Make not case sensitive + term = term.toLocaleLowerCase(); + + // Get items list + return getItems().then(function (items) { + // Keep track of the number of results to display + if (items.length < maxResults) { + resultsLength = items.length; + } else { + resultsLength = maxResults; + } + + // Then filter through the items list + for (i = 0; i < resultsLength; i += 1) { + // Prevent errors from getModel not being defined + if (items[i].getModel) { + itemModel = items[i].getModel(); + itemName = itemModel.name.toLocaleLowerCase(); + + // Include any matching items, except folders + if (itemName.includes(term) && itemModel.type !== "folder") { + searchResults.push(items[i]); + } + } + } + + return searchResults; + }); + } + + return { + query: queryManual + }; + } + + + return EverythingSearchProvider; + } +); \ No newline at end of file From 25208a90743e2a65652d77647ea3b8c06c89a1b5 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 11:31:11 -0700 Subject: [PATCH 057/195] [Search] Aggregator aggregates The search aggregator now combines the search results from each search provider and returns that. Objects may appear in the list more than once. --- .../features/search/src/SearchAggregator.js | 81 +++++++------------ .../src/providers/EverythingSearchProvider.js | 4 +- 2 files changed, 34 insertions(+), 51 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 2b1fa32d3b..312416d184 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -38,60 +38,41 @@ define( * aggregated */ function SearchAggregator($q, providers) { - return { - query: providers[0].query - }; -/* - // Pick a domain object model to use, favoring the one - // with the most recent timestamp - function pick(a, b) { - var aModified = (a || {}).modified || Number.NEGATIVE_INFINITY, - bModified = (b || {}).modified || Number.NEGATIVE_INFINITY; - return (aModified > bModified) ? a : (b || a); - } - - // Merge results from multiple providers into one - // large result object. - function mergeModels(provided, ids) { - var result = {}; - ids.forEach(function (id) { - provided.forEach(function (models) { - if (models[id]) { - result[id] = pick(result[id], models[id]); - } - }); - }); - return result; - } - - return { - /** - * Get models with the specified identifiers. - * - * This will invoke the `getModels()` method of all providers - * given at constructor-time, and aggregate the result into - * one object. - * - * Note that the returned object may contain a subset or a - * superset of the models requested. - * - * @param {string[]} ids an array of domain object identifiers - * @returns {Promise.} a promise for an object - * containing key-value pairs, - * where keys are object identifiers and values - * are object models. - */ -/* - getModels: function (ids) { - return $q.all(providers.map(function (provider) { - return provider.getModels(ids); - })).then(function (provided) { - return mergeModels(provided, ids); + function getPromisedResults(resultsPromises, promiseIndex, finalResults) { + if (promiseIndex >= resultsPromises.length) { + return finalResults; + } else { + return resultsPromises[promiseIndex].then(function (results) { + finalResults = finalResults.concat(results); + return getPromisedResults(resultsPromises, promiseIndex + 1, finalResults); }); } + } + + // Calls the searches of each of the providers, then + // merges the results lists so that there are not redundant + // results + function mergeResults(inputID) { + var resultsPromises = [], + mergedResults = []; + + for (var i = 0; i < providers.length; i += 1) { + resultsPromises.push(providers[i].query(inputID)); + } + + mergedResults = getPromisedResults(resultsPromises, 0, []); + + //return mergedResults; + return mergedResults.then(function (c) { + //console.log('returning ', c); + return c; + }); + } + + return { + query: mergeResults }; -*/ } return SearchAggregator; diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/EverythingSearchProvider.js index 8979d3e322..2b204c3f17 100644 --- a/platform/features/search/src/providers/EverythingSearchProvider.js +++ b/platform/features/search/src/providers/EverythingSearchProvider.js @@ -28,7 +28,9 @@ define( [], function () { "use strict"; - + + var DEFAULT_MAX_RESULTS = 100; + /** * A model service which reads domain object models from an external * persistence service. From bc2072b8c6886691512a436fd8e2ee75b7902b27 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 11:33:36 -0700 Subject: [PATCH 058/195] [Search] Removed unused search provider WARP search provider should not be implemented here. And was not yet implemented or used at all anyway. --- .../features/search/src/providers/WARPTaxonomySearchProvider.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 platform/features/search/src/providers/WARPTaxonomySearchProvider.js diff --git a/platform/features/search/src/providers/WARPTaxonomySearchProvider.js b/platform/features/search/src/providers/WARPTaxonomySearchProvider.js deleted file mode 100644 index e69de29bb2..0000000000 From 80e0bd875a89007c15617c33a74457363ed1f9f7 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 13:08:05 -0700 Subject: [PATCH 059/195] [Search] Aggregator merges results The search aggregator now merges search results from different providers better. It removed duplicate results, and orders the list of results from highest to lowest score. --- platform/features/search/bundle.json | 2 +- .../features/search/res/templates/search.html | 2 +- .../features/search/src/SearchAggregator.js | 43 +++++++++++++++++-- .../src/controllers/SearchController.js | 30 ++++++++++--- .../providers/ElasticsearchSearchProvider.js | 24 ++++++++--- .../src/providers/EverythingSearchProvider.js | 29 +++++++++---- 6 files changed, 105 insertions(+), 25 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 095abaab28..0ba248ebc0 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -15,7 +15,7 @@ { "key": "SearchController", "implementation": "controllers/SearchController.js", - "depends": [ "$scope", "searchService" ] + "depends": [ "$scope", "searchService", "objectService" ] }, { "key": "SearchbarController", diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index f1e7a8fb5d..b44005f163 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -43,6 +43,6 @@ + mct-object="result.object"> \ No newline at end of file diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 312416d184..d509eeee16 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -50,12 +50,48 @@ define( } } + // Remove extra objects that have the same ID + function filterRepeats(results) { + var ids = []; + + for (var i = 0; i < results.length; i += 1) { + //if (ids.includes(results[i].id)) { + if (ids.indexOf(results[i].id) !== -1) { + // If this result's ID is already there, remove the object + results.splice(i, 1); + // Reduce loop index because we shortened the array + i -= 1; + } else { + // Otherwise add the ID to the list of the ones we have seen + ids.push(results[i].id); + } + } + + return results; + } + + // Order the objects from highest to lowest score in the array + function orderByScore(results) { + + results = results.sort(function (a, b) { + if (a.score > b.score) { + return -1; + } else if (b.score < a.score) { + return 1; + } else { + return 0; + } + }); + + return results; + } + // Calls the searches of each of the providers, then // merges the results lists so that there are not redundant // results function mergeResults(inputID) { var resultsPromises = [], - mergedResults = []; + mergedResults; for (var i = 0; i < providers.length; i += 1) { resultsPromises.push(providers[i].query(inputID)); @@ -63,9 +99,10 @@ define( mergedResults = getPromisedResults(resultsPromises, 0, []); - //return mergedResults; return mergedResults.then(function (c) { - //console.log('returning ', c); + // Get rid of the repeated objects and put in correct order + c = filterRepeats(c); + c = orderByScore(c); return c; }); } diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 423e6253bb..adb32744b9 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -27,15 +27,22 @@ define(function () { "use strict"; - function SearchController($scope, searchService) { + function SearchController($scope, searchService, objectService) { + + function getResults(inputID) { + + // Later, the search result format will be different + // Will need to compile search result list (for this + // result page) here, using pseudo linkedlist searchResult + + searchService.query(inputID).then(function (c) { + $scope.results = c; + }); + } return { // Search the database using the user input of id "searchinput" - search: function (inputID) { - searchService.query(inputID).then(function (c) { - $scope.results = c; - }); - }, + search: getResults, // Check to see if there are any search results to display. areResults: function () { @@ -44,7 +51,16 @@ define(function () { } else { return false; } - } + }/*, + + // Get a domain object from its ID + getObjectByID: function (id) { + return objectService.getObjects([id]).then(function (objects) { + var obj = objects[id]; + console.log('get object', obj); + return obj; + }); + }*/ }; } return SearchController; diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index fefbd64be1..f039e2bbff 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -92,7 +92,7 @@ define( searchTerm = 'name:' + searchTerm; } - console.log('search term ', searchTerm); + //console.log('search term ', searchTerm); return searchTerm; } @@ -102,6 +102,8 @@ define( var results = rawResults.data.hits.hits, resultsLength = results.length, ids = [], + scores = {}, + searchResults = [], i; if (rawResults.data.hits.total > resultsLength) { @@ -114,24 +116,36 @@ define( ids.push(results[i][ID]); } + // Get the result objects' scores + for (i = 0; i < resultsLength; i += 1) { + //scores.push(results[i][SCORE]); + scores[ ids[i] ] = results[i][SCORE]; + } + // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { - var output = [], - id, + var id, j; + // Filter by search term for (j = 0; j < resultsLength; j += 1) { id = ids[j]; // Include any item except folders if (objects[id].getModel) { if (objects[id].getModel().type !== "folder") { - output.push(objects[id]); + // Format the results as searchResult objects + searchResults.push({ + id: id, + object: objects[id], + score: scores[id] + }); } } } - return output; + //console.log('searchResults (in ES provider)', searchResults); + return searchResults; }); } diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/EverythingSearchProvider.js index 2b204c3f17..927e676055 100644 --- a/platform/features/search/src/providers/EverythingSearchProvider.js +++ b/platform/features/search/src/providers/EverythingSearchProvider.js @@ -67,8 +67,20 @@ define( // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { // Get all of its descendents - return itemsHelper([objects.mine], 0).then(function (c) { - return c; + 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) { + searchResultItems.push({ + id: items[i].getId(), + object: items[i], + score: 1 // TODO: Find how to score these properly + }); + } + + //console.log('searchResultItems (in Everything)', searchResultItems); + return searchResultItems; }); }); } @@ -112,10 +124,10 @@ define( term = term.toLocaleLowerCase(); // Get items list - return getItems().then(function (items) { + return getItems().then(function (searchResultItems) { // Keep track of the number of results to display - if (items.length < maxResults) { - resultsLength = items.length; + if (searchResultItems.length < maxResults) { + resultsLength = searchResultItems.length; } else { resultsLength = maxResults; } @@ -123,17 +135,18 @@ define( // Then filter through the items list for (i = 0; i < resultsLength; i += 1) { // Prevent errors from getModel not being defined - if (items[i].getModel) { - itemModel = items[i].getModel(); + if (searchResultItems[i].object.getModel) { + itemModel = searchResultItems[i].object.getModel(); itemName = itemModel.name.toLocaleLowerCase(); // Include any matching items, except folders if (itemName.includes(term) && itemModel.type !== "folder") { - searchResults.push(items[i]); + searchResults.push(searchResultItems[i]); } } } + //console.log('filtered searchResults (in Everything)', searchResults); return searchResults; }); } From 15a9d2380c5616b1955c75fc701a77b25b867e0b Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 13:10:04 -0700 Subject: [PATCH 060/195] [Search] Removed unnecissary dependency Removed an unnecissary parameter from the search aggregator ($q). --- platform/features/search/bundle.json | 3 +-- platform/features/search/src/SearchAggregator.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 0ba248ebc0..01b49a4f07 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -53,8 +53,7 @@ { "provides": "searchService", "type": "aggregator", - "implementation": "SearchAggregator.js", - "depends": [ "$q" ] + "implementation": "SearchAggregator.js" } ] } diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index d509eeee16..d0b2e8e9bf 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -37,7 +37,7 @@ define( * @param {SearchProvider[]} providers the search providers to be * aggregated */ - function SearchAggregator($q, providers) { + function SearchAggregator(providers) { function getPromisedResults(resultsPromises, promiseIndex, finalResults) { if (promiseIndex >= resultsPromises.length) { From 922a724e36e11a9ab3853a6568977dba1967667d Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 13:26:23 -0700 Subject: [PATCH 061/195] [Search] Removed unused file Removed SearchService.js, as now the searchService is implemented using the aggregator and providers. --- .../features/search/src/SearchAggregator.js | 9 +- platform/features/search/src/SearchService.js | 291 ------------------ 2 files changed, 4 insertions(+), 296 deletions(-) delete mode 100644 platform/features/search/src/SearchService.js diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index d0b2e8e9bf..e3ab7d632b 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -90,16 +90,15 @@ define( // merges the results lists so that there are not redundant // results function mergeResults(inputID) { - var resultsPromises = [], - mergedResults; + var resultsPromises = []; + // Get result list promises for (var i = 0; i < providers.length; i += 1) { resultsPromises.push(providers[i].query(inputID)); } - mergedResults = getPromisedResults(resultsPromises, 0, []); - - return mergedResults.then(function (c) { + // Wait for the promises to fufill + return getPromisedResults(resultsPromises, 0, []).then(function (c) { // Get rid of the repeated objects and put in correct order c = filterRepeats(c); c = orderByScore(c); diff --git a/platform/features/search/src/SearchService.js b/platform/features/search/src/SearchService.js deleted file mode 100644 index 16fb061cff..0000000000 --- a/platform/features/search/src/SearchService.js +++ /dev/null @@ -1,291 +0,0 @@ -/***************************************************************************** - * 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*/ - -/** - * Module defining QueryService. Created by shale on 07/13/2015. - */ -define( - [], - function () { - "use strict"; - - // JSLint doesn't like underscore-prefixed properties, - // so hide them here. - var ID = "_id", - SCORE = "_score"; - - /** - * The query service is responsible for searching through - * objects in the filetree. There are multiple possible - * implementations for querying. Currently there is - * queryManual (which manually steps through the filetree) - * and queryElasticsearch (which passes the work on to - * elasticsearch). - * @constructor - */ - function SearchService($http, objectService, ROOT) { - var DEFAULT_MAX_RESULTS = 100; - - /////////////// The following is for non-Elastic Search ///////////////// - - // Recursive helper function for getItems() - function itemsHelper(children, i) { - if (i >= children.length) { - // 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 - // Used for queryManual() - function getItems() { - // Aquire My Items (root folder) - return objectService.getObjects(['mine']).then(function (objects) { - // Get all of its descendents - return itemsHelper([objects.mine], 0).then(function (c) { - return c; - }); - }); - } - - /** - * 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. - * * Folders are not included in the results. - * * 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 - * @param maxResults (optional) the maximum number of results - * that this function should return - */ - function queryManual(inputID, maxResults) { - var term, - searchResults = [], - resultsLength, - itemModel, - itemName, - i; - - // 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; - } - - // Get the user input - term = document.getElementById(inputID).value; - - // Make not case sensitive - term = term.toLocaleLowerCase(); - - // Get items list - return getItems().then(function (items) { - // Keep track of the number of results to display - if (items.length < maxResults) { - resultsLength = items.length; - } else { - resultsLength = maxResults; - } - - // Then filter through the items list - for (i = 0; i < resultsLength; i += 1) { - // Prevent errors from getModel not being defined - if (items[i].getModel) { - itemModel = items[i].getModel(); - itemName = itemModel.name.toLocaleLowerCase(); - - // Include any matching items, except folders - if (itemName.includes(term) && itemModel.type !== "folder") { - searchResults.push(items[i]); - } - } - } - - return searchResults; - }); - } - - /////////////// The following is for Elastic Search ///////////////// - - // Check to see if the input has any special options - // Used by queryElasticsearch() - function isDefaultFormat(searchTerm) { - // If the input has a property option, not default - if (searchTerm.includes('name:') || searchTerm.includes('type:')) { - return false; - } - - return true; - } - - // Add the fuzziness operator to the search term - // Used by queryElasticsearch() - function addFuzziness(searchTerm, editDistance) { - if (!editDistance) { - editDistance = ''; - } - - return searchTerm.split(' ').map(function (s) { - if (s.includes('"')) { - console.log('true'); - return s; - } else { - return s + '~' + editDistance; - } - }).join(' '); - } - - // Currently specific to elasticsearch - // Used by queryElasticsearch() - function processSearchTerm(searchTerm) { - // Shave any spaces off of the ends of the input - while (searchTerm.substr(0, 1) === ' ') { - searchTerm = searchTerm.substring(1, searchTerm.length); - } - while (searchTerm.substr(searchTerm.length - 1, 1) === ' ') { - searchTerm = searchTerm.substring(0, searchTerm.length - 1); - } - - if (isDefaultFormat(searchTerm)) { - // Add fuzziness for completeness - searchTerm = addFuzziness(searchTerm); - - // Searching 'name' by default - searchTerm = 'name:' + searchTerm; - } - - console.log('search term ', searchTerm); - return searchTerm; - } - - // Processes results from the format that elasticsearch returns to - // a list of objects in the format that mct-representation can use. - // Used by queryElasticsearch() - function processResults(rawResults) { - var results = rawResults.data.hits.hits, - resultsLength = results.length, - ids = [], - i; - - if (rawResults.data.hits.total > resultsLength) { - // TODO: Somehow communicate this to the user - console.log('Total number of results greater than displayed results'); - } - - // Get the result objects' IDs - for (i = 0; i < resultsLength; i += 1) { - ids.push(results[i][ID]); - } - - // Get the domain objects from their IDs - return objectService.getObjects(ids).then(function (objects) { - var output = [], - id, - j; - - for (j = 0; j < resultsLength; j += 1) { - id = ids[j]; - - // Include any item except folders - if (objects[id].getModel) { - if (objects[id].getModel().type !== "folder") { - output.push(objects[id]); - } - } - } - - return output; - }); - } - - /** - * Searches through the filetree for domain objects using a search - * term. This is done through querying elasticsearch. - * Notes: - * * The order of the results is from highest to lowest score, - * as elsaticsearch determines them to be. - * * Folders are not included in the results. - * * Wildcards are supported. - * * Fuzziness is used to produce more results that are still - * relevant. (All results within a certain edit distance.) - * * More search details at - * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html - * - * @param inputID the name of the ID property of the html text - * input where this funcion should find the search term - * @param maxResults (optional) the maximum number of results - * that this function should return - */ - function queryElasticsearch(inputID, maxResults) { - var searchTerm; - - // 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; - } - - // Get the user input - searchTerm = document.getElementById(inputID).value; - - // Process search term - searchTerm = processSearchTerm(searchTerm); - - // Get the data... - return $http({ - method: "GET", - url: ROOT + "/_search/?q=" + searchTerm + - "&size=" + maxResults - }).then(function (rawResults) { - // ...then process the data - return processResults(rawResults); - }); - } - - return { - query: queryElasticsearch - }; - } - - return SearchService; - } -); \ No newline at end of file From 442a1979e7d96669b1c4d9684bb3363f9df5ca2e Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 14:36:02 -0700 Subject: [PATCH 062/195] [Search] Rudimentary scroing for manual Created a rudimentary scoring function for the EverythingSearchProvider. Also corrected the sorting by score function. --- .../features/search/src/SearchAggregator.js | 2 +- .../src/providers/EverythingSearchProvider.js | 57 +++++++++++++------ 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index e3ab7d632b..4a479a9669 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -76,7 +76,7 @@ define( results = results.sort(function (a, b) { if (a.score > b.score) { return -1; - } else if (b.score < a.score) { + } else if (b.score > a.score) { return 1; } else { return 0; diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/EverythingSearchProvider.js index 927e676055..221e4820a2 100644 --- a/platform/features/search/src/providers/EverythingSearchProvider.js +++ b/platform/features/search/src/providers/EverythingSearchProvider.js @@ -75,7 +75,7 @@ define( searchResultItems.push({ id: items[i].getId(), object: items[i], - score: 1 // TODO: Find how to score these properly + score: 0 // Assign actual score when filtering for term }); } @@ -85,6 +85,43 @@ define( }); } + // Generate a score for an item based on its similarity to a search term + // Very rudimentary + function score(item, term) { + var name = item.object.getModel().name, + numWordsinName = name.split(' ').length, + numWordsinTerm = term.split(' ').length, + weight = 1.5, + score = (term.length / name.length)/*(numWordsinTerm / numWordsinName)*/ * weight; + + return score; + } + + // Filter through a list of searchResults based on a search term + function filterResults(results, term, resultsLength) { + var searchResults = [], + itemModel, + itemName; + + for (var i = 0; i < resultsLength; i += 1) { + // Prevent errors from getModel not being defined + if (results[i].object.getModel) { + itemModel = results[i].object.getModel(); + itemName = itemModel.name.toLocaleLowerCase(); + + // Include any matching items, except folders + if (itemName.includes(term) && itemModel.type !== "folder") { + // Score the result + score(results[i], term); + // Add the result to the result list + searchResults.push(results[i]); + } + } + } + + return searchResults; + } + /** * Searches through the filetree for domain objects which match * the search term. This function is to be used as a fallback @@ -105,10 +142,7 @@ define( function queryManual(inputID, maxResults) { var term, searchResults = [], - resultsLength, - itemModel, - itemName, - i; + resultsLength; // Check to see if the user provided a maximum // number of results to display @@ -133,18 +167,7 @@ define( } // Then filter through the items list - for (i = 0; i < resultsLength; i += 1) { - // Prevent errors from getModel not being defined - if (searchResultItems[i].object.getModel) { - itemModel = searchResultItems[i].object.getModel(); - itemName = itemModel.name.toLocaleLowerCase(); - - // Include any matching items, except folders - if (itemName.includes(term) && itemModel.type !== "folder") { - searchResults.push(searchResultItems[i]); - } - } - } + searchResults = filterResults(searchResultItems, term, resultsLength); //console.log('filtered searchResults (in Everything)', searchResults); return searchResults; From c1ebd50e4cf937fa1d405c9a8884f4f1300ddbcb Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 16:22:49 -0700 Subject: [PATCH 063/195] [Search] Result paging The search view now can page the results when there are many. --- .../features/search/res/templates/search.html | 26 +++++++-- .../search/res/templates/searchbar.html | 3 +- .../features/search/src/SearchAggregator.js | 1 - .../src/controllers/SearchController.js | 53 +++++++++++++++---- .../src/providers/EverythingSearchProvider.js | 6 +-- 5 files changed, 70 insertions(+), 19 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index b44005f163..d213422787 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -38,11 +38,27 @@
    + style="height: 60px"> +

    Results: +

    +
    + + showing results {{ index+1 }} - {{ index + pageLength }} + of {{ results.length }} + +
    +
    +
    + +
    - - \ No newline at end of file diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html index c218ae7ea0..1416992fc2 100644 --- a/platform/features/search/res/templates/searchbar.html +++ b/platform/features/search/res/templates/searchbar.html @@ -25,6 +25,7 @@ @@ -32,7 +33,7 @@
    + mct-object="result.object">
    \ No newline at end of file diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 4a479a9669..5a2e08f803 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -55,7 +55,6 @@ define( var ids = []; for (var i = 0; i < results.length; i += 1) { - //if (ids.includes(results[i].id)) { if (ids.indexOf(results[i].id) !== -1) { // If this result's ID is already there, remove the object results.splice(i, 1); diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index adb32744b9..1cb3909243 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -27,7 +27,18 @@ define(function () { "use strict"; + function SearchController($scope, searchService, objectService) { + $scope.pageLength = 4; + + function page(start, howMany) { + if (!howMany) { + howMany = $scope.pageLength; + } + + $scope.index = start; + $scope.page = $scope.results.slice(start, start + howMany); + } function getResults(inputID) { @@ -37,6 +48,8 @@ define(function () { searchService.query(inputID).then(function (c) { $scope.results = c; + $scope.index = 0; + page($scope.index, $scope.pageLength); }); } @@ -51,16 +64,38 @@ define(function () { } else { return false; } - }/*, + }, - // Get a domain object from its ID - getObjectByID: function (id) { - return objectService.getObjects([id]).then(function (objects) { - var obj = objects[id]; - console.log('get object', obj); - return obj; - }); - }*/ + // Check to see if there are enough results to be paging them + arePaging: function () { + return $scope.results.length > $scope.page.length; + }, + + canGoBack: function () { + return $scope.index > 0; + }, + + canGoForward: function () { + return ($scope.index + $scope.pageLength) < $scope.results.length; + }, + + nextPage: function(howMany) { + if (!howMany) { + howMany = $scope.pageLength; + } + + $scope.index = $scope.index + howMany; + $scope.page = $scope.results.slice($scope.index, $scope.index + howMany); + }, + + previousPage: function(howMany) { + if (!howMany) { + howMany = $scope.pageLength; + } + + $scope.index = $scope.index - howMany; + $scope.page = $scope.results.slice($scope.index, $scope.index + howMany); + } }; } return SearchController; diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/EverythingSearchProvider.js index 221e4820a2..ef8e1bb679 100644 --- a/platform/features/search/src/providers/EverythingSearchProvider.js +++ b/platform/features/search/src/providers/EverythingSearchProvider.js @@ -89,10 +89,10 @@ define( // Very rudimentary function score(item, term) { var name = item.object.getModel().name, - numWordsinName = name.split(' ').length, - numWordsinTerm = term.split(' ').length, + //numWordsinName = name.split(' ').length, + //numWordsinTerm = term.split(' ').length, weight = 1.5, - score = (term.length / name.length)/*(numWordsinTerm / numWordsinName)*/ * weight; + score = (term.length / name.length) * weight; return score; } From cf3169dd68f765829b2735c700413b8727a2721f Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 16:50:07 -0700 Subject: [PATCH 064/195] [Search] More generalized restrictions Moved the EverythingSearchProvider's term to item matching to new functions, so that they can be more easily modified later. --- .../src/controllers/SearchController.js | 2 +- .../src/providers/EverythingSearchProvider.js | 27 ++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 1cb3909243..f24cce58f2 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -29,7 +29,7 @@ define(function () { function SearchController($scope, searchService, objectService) { - $scope.pageLength = 4; + $scope.pageLength = 16; function page(start, howMany) { if (!howMany) { diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/EverythingSearchProvider.js index ef8e1bb679..93194a2c88 100644 --- a/platform/features/search/src/providers/EverythingSearchProvider.js +++ b/platform/features/search/src/providers/EverythingSearchProvider.js @@ -97,20 +97,33 @@ define( return score; } + // Determines if this item can be a valid result for this search term + function validResult(item, term) { + var itemModel = item.object.getModel(), + itemName = itemModel.name.toLocaleLowerCase(), + itemType = itemModel.type.toLocaleLowerCase(); + + return itemName.includes(term) || itemType.includes(term); + } + + // Determines if this item is a valid type for a search result + function validType(item) { + var itemModel = item.object.getModel(); + + // Only folders are disallowed + return itemModel.type !== "folder"; + } + // Filter through a list of searchResults based on a search term function filterResults(results, term, resultsLength) { var searchResults = [], - itemModel, - itemName; + itemModel; for (var i = 0; i < resultsLength; i += 1) { // Prevent errors from getModel not being defined if (results[i].object.getModel) { - itemModel = results[i].object.getModel(); - itemName = itemModel.name.toLocaleLowerCase(); - - // Include any matching items, except folders - if (itemName.includes(term) && itemModel.type !== "folder") { + // Include any items that match the term and are of valid type + if (validResult(results[i], term) && validType(results[i])) { // Score the result score(results[i], term); // Add the result to the result list From c82163fa7bbccfba140c7df1a961538e9aa6703f Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 16 Jul 2015 16:54:53 -0700 Subject: [PATCH 065/195] [Search] Comments and style --- .../search/src/controllers/SearchController.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index f24cce58f2..01e9708c19 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -40,7 +40,7 @@ define(function () { $scope.page = $scope.results.slice(start, start + howMany); } - function getResults(inputID) { + function search(inputID) { // Later, the search result format will be different // Will need to compile search result list (for this @@ -55,7 +55,7 @@ define(function () { return { // Search the database using the user input of id "searchinput" - search: getResults, + search: search, // Check to see if there are any search results to display. areResults: function () { @@ -71,15 +71,18 @@ define(function () { return $scope.results.length > $scope.page.length; }, + // Check to see if are items such that we can go back a page canGoBack: function () { return $scope.index > 0; }, + // Check to see if are items such that we can go forward a page canGoForward: function () { return ($scope.index + $scope.pageLength) < $scope.results.length; }, - nextPage: function(howMany) { + // Change the items in scope to be the ones in the next page + nextPage: function (howMany) { if (!howMany) { howMany = $scope.pageLength; } @@ -88,7 +91,8 @@ define(function () { $scope.page = $scope.results.slice($scope.index, $scope.index + howMany); }, - previousPage: function(howMany) { + // Change the items in scope to be the ones in the previous page + previousPage: function (howMany) { if (!howMany) { howMany = $scope.pageLength; } From 492dbcbc5171824f5f00193abff178b1b8f22d03 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 17 Jul 2015 09:33:07 -0700 Subject: [PATCH 066/195] [Search] Comments and keypress Changed the controller for the search input to respond on keypress rather than keyup. Added comments better explaining searchResult objects to the search aggregator. --- platform/features/search/res/templates/search.html | 2 +- platform/features/search/src/SearchAggregator.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index d213422787..0e8a6eb320 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -29,7 +29,7 @@ diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 5a2e08f803..eba8c04acf 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -85,6 +85,11 @@ define( return results; } + // Recieves results in the format of a serachResult object. It + // has the members id, object, and score. It has a function + // next() which returns the next highest score search result + // for that search. + // Calls the searches of each of the providers, then // merges the results lists so that there are not redundant // results From c75d94289b10d69c4bd6d1471362a6646913f4b9 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 17 Jul 2015 11:24:33 -0700 Subject: [PATCH 067/195] [Serach] Callbacks and renaming Added validType() as a callback parameter to the search providers. It is defined in the search aggregator, and is used to put any restrictions on object type in the displayed search results. Renamed EverythingSearchProvider to GenericSearchProvider. --- platform/features/search/bundle.json | 2 +- .../features/search/src/SearchAggregator.js | 28 ++++++++++++------- .../providers/ElasticsearchSearchProvider.js | 15 ++++++---- ...chProvider.js => GenericSearchProvider.js} | 28 ++++++++----------- 4 files changed, 39 insertions(+), 34 deletions(-) rename platform/features/search/src/providers/{EverythingSearchProvider.js => GenericSearchProvider.js} (90%) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 01b49a4f07..4ef6b36ff7 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -47,7 +47,7 @@ { "provides": "searchService", "type": "provider", - "implementation": "providers/EverythingSearchProvider.js", + "implementation": "providers/GenericSearchProvider.js", "depends": [ "objectService" ] }, { diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index eba8c04acf..def32b1999 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -39,15 +39,12 @@ define( */ function SearchAggregator(providers) { - function getPromisedResults(resultsPromises, promiseIndex, finalResults) { - if (promiseIndex >= resultsPromises.length) { - return finalResults; - } else { - return resultsPromises[promiseIndex].then(function (results) { - finalResults = finalResults.concat(results); - return getPromisedResults(resultsPromises, promiseIndex + 1, finalResults); - }); - } + // Determines if a searchResult object is a valid type + // to be displayed as a final result. Is passed to the + // search providers as an argument. + function validType(model) { + // Nothing is currently disallowed + return true; } // Remove extra objects that have the same ID @@ -85,6 +82,17 @@ define( return results; } + function getPromisedResults(resultsPromises, promiseIndex, finalResults) { + if (promiseIndex >= resultsPromises.length) { + return finalResults; + } else { + return resultsPromises[promiseIndex].then(function (results) { + finalResults = finalResults.concat(results); + return getPromisedResults(resultsPromises, promiseIndex + 1, finalResults); + }); + } + } + // Recieves results in the format of a serachResult object. It // has the members id, object, and score. It has a function // next() which returns the next highest score search result @@ -98,7 +106,7 @@ define( // Get result list promises for (var i = 0; i < providers.length; i += 1) { - resultsPromises.push(providers[i].query(inputID)); + resultsPromises.push(providers[i].query(inputID, validType)); } // Wait for the promises to fufill diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index f039e2bbff..1e1e94199e 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -98,7 +98,7 @@ define( // Processes results from the format that elasticsearch returns to // a list of objects in the format that mct-representation can use - function processResults(rawResults) { + function processResults(rawResults, validType) { var results = rawResults.data.hits.hits, resultsLength = results.length, ids = [], @@ -131,9 +131,10 @@ define( for (j = 0; j < resultsLength; j += 1) { id = ids[j]; - // Include any item except folders + // Include items we can get models for if (objects[id].getModel) { - if (objects[id].getModel().type !== "folder") { + // Check to see if they are allowed to be included + if (validType(objects[id].getModel())) { // Format the results as searchResult objects searchResults.push({ id: id, @@ -155,7 +156,6 @@ define( * Notes: * * The order of the results is from highest to lowest score, * as elsaticsearch determines them to be. - * * Folders are not included in the results. * * Wildcards are supported. * * Fuzziness is used to produce more results that are still * relevant. (All results within a certain edit distance.) @@ -164,10 +164,13 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term + * @param validType a function which takes a model for an object + * and determines if it is of a valid type to include in the + * final list of results * @param maxResults (optional) the maximum number of results * that this function should return */ - function queryElasticsearch(inputID, maxResults) { + function queryElasticsearch(inputID, validType, maxResults) { var searchTerm; // Check to see if the user provided a maximum @@ -190,7 +193,7 @@ define( "&size=" + maxResults }).then(function (rawResults) { // ...then process the data - return processResults(rawResults); + return processResults(rawResults, validType); }); } diff --git a/platform/features/search/src/providers/EverythingSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js similarity index 90% rename from platform/features/search/src/providers/EverythingSearchProvider.js rename to platform/features/search/src/providers/GenericSearchProvider.js index 93194a2c88..b5e98e7b3b 100644 --- a/platform/features/search/src/providers/EverythingSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -22,7 +22,7 @@ /*global define*/ /** - * Module defining EverythingSearchProvider. Created by shale on 07/16/2015. + * Module defining GenericSearchProvider. Created by shale on 07/16/2015. */ define( [], @@ -42,7 +42,7 @@ define( * @param {string} SPACE the name of the persistence space from which * models should be retrieved. */ - function EverythingSearchProvider(objectService) { + function GenericSearchProvider(objectService) { // Recursive helper function for getItems() function itemsHelper(children, i) { @@ -98,7 +98,7 @@ define( } // Determines if this item can be a valid result for this search term - function validResult(item, term) { + function match(item, term) { var itemModel = item.object.getModel(), itemName = itemModel.name.toLocaleLowerCase(), itemType = itemModel.type.toLocaleLowerCase(); @@ -106,16 +106,8 @@ define( return itemName.includes(term) || itemType.includes(term); } - // Determines if this item is a valid type for a search result - function validType(item) { - var itemModel = item.object.getModel(); - - // Only folders are disallowed - return itemModel.type !== "folder"; - } - // Filter through a list of searchResults based on a search term - function filterResults(results, term, resultsLength) { + function filterResults(results, term, resultsLength, validType) { var searchResults = [], itemModel; @@ -123,7 +115,7 @@ define( // Prevent errors from getModel not being defined if (results[i].object.getModel) { // Include any items that match the term and are of valid type - if (validResult(results[i], term) && validType(results[i])) { + if (match(results[i], term) && validType(results[i].object.getModel())) { // Score the result score(results[i], term); // Add the result to the result list @@ -144,15 +136,17 @@ define( * * 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. - * * Folders are not included in the results. * * 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 + * @param validType a function which takes a model for an object + * and determines if it is of a valid type to include in the + * final list of results * @param maxResults (optional) the maximum number of results * that this function should return */ - function queryManual(inputID, maxResults) { + function queryManual(inputID, validType, maxResults) { var term, searchResults = [], resultsLength; @@ -180,7 +174,7 @@ define( } // Then filter through the items list - searchResults = filterResults(searchResultItems, term, resultsLength); + searchResults = filterResults(searchResultItems, term, resultsLength, validType); //console.log('filtered searchResults (in Everything)', searchResults); return searchResults; @@ -193,6 +187,6 @@ define( } - return EverythingSearchProvider; + return GenericSearchProvider; } ); \ No newline at end of file From 9f5f14826bcb0bb3b56060117e4ee4eede152c28 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 17 Jul 2015 13:49:09 -0700 Subject: [PATCH 068/195] [Search] Changed generic's matching implementation Changed how the generic search provider determines search matches. It now splits the search input into search terms by spliting at spaces, and then scores the results by how many of the terms appear as substrings in the result. --- platform/features/search/bundle.json | 8 +-- .../features/search/src/SearchAggregator.js | 6 ++ .../src/providers/GenericSearchProvider.js | 70 +++++++++++-------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 4ef6b36ff7..264dd5f68a 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -41,14 +41,14 @@ { "provides": "searchService", "type": "provider", - "implementation": "providers/ElasticsearchSearchProvider.js", - "depends": [ "$http", "objectService", "ELASTIC_ROOT" ] + "implementation": "providers/GenericSearchProvider.js", + "depends": [ "objectService" ] }, { "provides": "searchService", "type": "provider", - "implementation": "providers/GenericSearchProvider.js", - "depends": [ "objectService" ] + "implementation": "providers/ElasticsearchSearchProvider.js", + "depends": [ "$http", "objectService", "ELASTIC_ROOT" ] }, { "provides": "searchService", diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index def32b1999..263d7dff29 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -79,6 +79,12 @@ define( } }); + /* + for (var i = 0; i < results.length; i++) { + console.log('score', results[i].score, 'for', results[i].object.getModel().name); + } + */ + return results; } diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index b5e98e7b3b..585e188ce7 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -85,39 +85,51 @@ define( }); } - // Generate a score for an item based on its similarity to a search term - // Very rudimentary - function score(item, term) { - var name = item.object.getModel().name, - //numWordsinName = name.split(' ').length, - //numWordsinTerm = term.split(' ').length, - weight = 1.5, - score = (term.length / name.length) * weight; - - return score; + // Process the search input. Makes an array of search terms + // by splitting up the input at spaces. + function process(input) { + return input.split(' '); } - // Determines if this item can be a valid result for this search term - function match(item, term) { - var itemModel = item.object.getModel(), - itemName = itemModel.name.toLocaleLowerCase(), - itemType = itemModel.type.toLocaleLowerCase(); + // 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(), + weight = 1.5, + score = 0;// = (term.length / name.length) * weight; - return itemName.includes(term) || itemType.includes(term); + 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++; + } + + // Make the score really big if the item name and + // the original search input are the same + if (name === originalInput.toLocaleLowerCase()) { + score += 50; + } + } + + return score / weight; } // Filter through a list of searchResults based on a search term - function filterResults(results, term, resultsLength, validType) { - var searchResults = [], + function filterResults(results, originalInput, resultsLength, validType) { + var terms, + searchResults = [], itemModel; + // Split the original search input into search terms + terms = process(originalInput); + for (var i = 0; i < resultsLength; i += 1) { // Prevent errors from getModel not being defined if (results[i].object.getModel) { - // Include any items that match the term and are of valid type - if (match(results[i], term) && validType(results[i].object.getModel())) { - // Score the result - score(results[i], term); + 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())) { // Add the result to the result list searchResults.push(results[i]); } @@ -146,8 +158,9 @@ define( * @param maxResults (optional) the maximum number of results * that this function should return */ - function queryManual(inputID, validType, maxResults) { - var term, + function queryGeneric(inputID, validType, maxResults) { + var input, + terms = [], searchResults = [], resultsLength; @@ -159,11 +172,8 @@ define( } // Get the user input - term = document.getElementById(inputID).value; + input = document.getElementById(inputID).value; - // Make not case sensitive - term = term.toLocaleLowerCase(); - // Get items list return getItems().then(function (searchResultItems) { // Keep track of the number of results to display @@ -174,7 +184,7 @@ define( } // Then filter through the items list - searchResults = filterResults(searchResultItems, term, resultsLength, validType); + searchResults = filterResults(searchResultItems, input, resultsLength, validType); //console.log('filtered searchResults (in Everything)', searchResults); return searchResults; @@ -182,7 +192,7 @@ define( } return { - query: queryManual + query: queryGeneric }; } From e8b662571b0960396af9fd0b7dcd5430e3d39258 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 17 Jul 2015 14:06:14 -0700 Subject: [PATCH 069/195] [Search] Not case sensitive Made sure that generic search's matching is not case sensitive. --- .../src/providers/GenericSearchProvider.js | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 585e188ce7..d12d205868 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -88,7 +88,7 @@ define( // Process the search input. Makes an array of search terms // by splitting up the input at spaces. function process(input) { - return input.split(' '); + return input.toLocaleLowerCase().split(' '); } // Generate a score for an item based on its similarity to a search term. @@ -96,23 +96,29 @@ define( // object name. function score(item, terms, originalInput) { var name = item.object.getModel().name.toLocaleLowerCase(), - weight = 1.5, - score = 0;// = (term.length / name.length) * weight; + 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; + } 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++; - } - - // Make the score really big if the item name and - // the original search input are the same - if (name === originalInput.toLocaleLowerCase()) { - score += 50; + + // 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; + } } } - return score / weight; + return score * weight; } // Filter through a list of searchResults based on a search term From e9e9ca146bca0a25f5804deff24a7677d9680fd1 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 20 Jul 2015 10:58:59 -0700 Subject: [PATCH 070/195] [Search] Generic search timeout Added a time limit for generic search's indexing of the filetree, at which point it will just return the portion of the filetree it has indexed. Additioanlly attempted to move this part of the functionality to a webworker, but is not working because of unclonability of the objects. (Commented out) Also updated some documentation comments. --- .../providers/ElasticsearchSearchProvider.js | 1 + .../src/providers/GenericSearchProvider.js | 75 ++++++++++++++++--- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 1e1e94199e..f22362b974 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -47,6 +47,7 @@ define( * models should be retrieved. */ function ElasticsearchSearchProvider($http, objectService, ROOT) { + // TODO: Fix the above docstring // Check to see if the input has any special options function isDefaultFormat(searchTerm) { diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index d12d205868..bd73128a31 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -29,24 +29,71 @@ define( function () { "use strict"; - var DEFAULT_MAX_RESULTS = 100; + var DEFAULT_MAX_RESULTS = 100, + DEFAULT_TIMEOUT = 1000, + stopTime; /** - * A model service which reads domain object models from an external - * persistence service. + * A search service which searches through domain objects in + * the filetree without using external search implementations. * * @constructor - * @param {PersistenceService} persistenceService the service in which - * domain object models are persisted. - * @param $q Angular's $q service, for working with promises - * @param {string} SPACE the name of the persistence space from which - * models should be retrieved. + * @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. */ - function GenericSearchProvider(objectService) { + function GenericSearchProvider(/*$rootScope, */objectService, /*workerService*/) { + /* + var worker = workerService.run('genericSearchWorker'), + lastestItems; + + 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; + } + */ + + function handleResponse(event) { + latest = event.data; + $rootScope.$apply(); + //requestNext(); + } // Recursive helper function for getItems() function itemsHelper(children, i) { - if (i >= children.length) { + var date = new Date; + if (date.getTime() >= stopTime) { + // This indexing of items has timed out + console.log('timed out'); + console.log('returning', children); + return children; + } else if (i >= children.length) { // Done! return children; } else if (children[i].hasCapability('composition')) { @@ -67,6 +114,11 @@ define( // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { // Get all of its descendents + + // Set a timeout for itemsHelper + var date = new Date; + stopTime = date.getTime() + DEFAULT_TIMEOUT; + return itemsHelper([objects.mine], 0).then(function (items) { // Turn them into searchResult objects (object, id, and score) var searchResultItems = []; @@ -85,6 +137,8 @@ define( }); } + + // Process the search input. Makes an array of search terms // by splitting up the input at spaces. function process(input) { @@ -181,6 +235,7 @@ define( input = document.getElementById(inputID).value; // Get items list + //requestItems(); // Test out the worker return getItems().then(function (searchResultItems) { // Keep track of the number of results to display if (searchResultItems.length < maxResults) { From ed956d351d5783f2eb01560fff7b4b99262818e8 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 20 Jul 2015 11:08:43 -0700 Subject: [PATCH 071/195] [Search] Elasticsearch timeout Added a term to the elasticsearch query that should make it time out. Apparently this only works sometimes, as ES uses a 'best effort' timeout. --- .../search/src/providers/ElasticsearchSearchProvider.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index f22362b974..d2a7a6bd84 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -33,7 +33,8 @@ define( // so hide them here. var ID = "_id", SCORE = "_score", - DEFAULT_MAX_RESULTS = 100; + DEFAULT_MAX_RESULTS = 100, + DEFAULT_TIMEOUT = 1000; /** * A model service which reads domain object models from an external @@ -191,7 +192,8 @@ define( return $http({ method: "GET", url: ROOT + "/_search/?q=" + searchTerm + - "&size=" + maxResults + "&size=" + maxResults + + "&timeout=" + DEFAULT_TIMEOUT }).then(function (rawResults) { // ...then process the data return processResults(rawResults, validType); From c0c03714512f2eaf123a51bbc2a26049d10373f3 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 20 Jul 2015 11:21:55 -0700 Subject: [PATCH 072/195] [Search] Timeout passed from SearchAggregator The timeout value is now an optional parameter of the providers, and the search aggregator now passes a common default value to all of them. --- .../features/search/src/SearchAggregator.js | 9 +++++++- .../providers/ElasticsearchSearchProvider.js | 21 +++++++++++------ .../src/providers/GenericSearchProvider.js | 23 ++++++++++++------- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 263d7dff29..30be3720dd 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -29,6 +29,9 @@ define( function () { "use strict"; + var DEFUALT_TIMEOUT = 1000, + DEFAULT_MAX_RESULTS = 100; + /** * Allows multiple services which provide search functionality * to be treated as one. @@ -112,7 +115,11 @@ define( // Get result list promises for (var i = 0; i < providers.length; i += 1) { - resultsPromises.push(providers[i].query(inputID, validType)); + resultsPromises.push( + providers[i].query( + inputID, validType, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT + ) + ); } // Wait for the promises to fufill diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index d2a7a6bd84..4d8f62bdac 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -33,8 +33,7 @@ define( // so hide them here. var ID = "_id", SCORE = "_score", - DEFAULT_MAX_RESULTS = 100, - DEFAULT_TIMEOUT = 1000; + DEFAULT_MAX_RESULTS = 100; /** * A model service which reads domain object models from an external @@ -171,9 +170,12 @@ define( * final list of 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 */ - function queryElasticsearch(inputID, validType, maxResults) { - var searchTerm; + function queryElasticsearch(inputID, validType, maxResults, timeout) { + var searchTerm, + esQuery; // Check to see if the user provided a maximum // number of results to display @@ -188,12 +190,17 @@ define( // Process search term searchTerm = processSearchTerm(searchTerm); + // Create the query to elasticsearch + esQuery = ROOT + "/_search/?q=" + searchTerm + + "&size=" + maxResults; + if (timeout) { + esQuery += "&timeout=" + timeout; + } + // Get the data... return $http({ method: "GET", - url: ROOT + "/_search/?q=" + searchTerm + - "&size=" + maxResults + - "&timeout=" + DEFAULT_TIMEOUT + url: esQuery }).then(function (rawResults) { // ...then process the data return processResults(rawResults, validType); diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index bd73128a31..62e6639cd2 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -43,7 +43,7 @@ define( * @param {WorkerService} workerService the service which allows * more easy creation of web workers. */ - function GenericSearchProvider(/*$rootScope, */objectService, /*workerService*/) { + function GenericSearchProvider($rootScope, objectService, workerService) { /* var worker = workerService.run('genericSearchWorker'), lastestItems; @@ -88,7 +88,7 @@ define( // Recursive helper function for getItems() function itemsHelper(children, i) { var date = new Date; - if (date.getTime() >= stopTime) { + if (stopTime && date.getTime() >= stopTime) { // This indexing of items has timed out console.log('timed out'); console.log('returning', children); @@ -110,14 +110,18 @@ define( } // Converts the filetree into a list - function getItems() { + function getItems(timeout) { // Aquire My Items (root folder) return objectService.getObjects(['mine']).then(function (objects) { // Get all of its descendents - // Set a timeout for itemsHelper - var date = new Date; - stopTime = date.getTime() + DEFAULT_TIMEOUT; + 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 return itemsHelper([objects.mine], 0).then(function (items) { // Turn them into searchResult objects (object, id, and score) @@ -217,8 +221,10 @@ define( * final list of 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 */ - function queryGeneric(inputID, validType, maxResults) { + function queryGeneric(inputID, validType, maxResults, timeout) { var input, terms = [], searchResults = [], @@ -231,12 +237,13 @@ define( maxResults = DEFAULT_MAX_RESULTS; } + // Get the user input input = document.getElementById(inputID).value; // Get items list //requestItems(); // Test out the worker - return getItems().then(function (searchResultItems) { + return getItems(timeout).then(function (searchResultItems) { // Keep track of the number of results to display if (searchResultItems.length < maxResults) { resultsLength = searchResultItems.length; From 55200379084aabda59050859c6e4c31dae761a52 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 20 Jul 2015 14:30:18 -0700 Subject: [PATCH 073/195] [Search] Partial loading Changed the providers to return only the first search result. Each searchResult object has a function next() which returns the next search result. This allows the search aggregator to load more results without making a whole new search query. (Still requuires some cleaning up.) --- .../features/search/src/SearchAggregator.js | 78 +++++++++++++++-- .../providers/ElasticsearchSearchProvider.js | 54 ++++++++---- .../src/providers/GenericSearchProvider.js | 85 ++++++++++++++++--- 3 files changed, 183 insertions(+), 34 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 30be3720dd..27d1f3f629 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -41,6 +41,8 @@ define( * aggregated */ function SearchAggregator(providers) { + var compiledResults = []; + // Determines if a searchResult object is a valid type // to be displayed as a final result. Is passed to the @@ -82,15 +84,15 @@ define( } }); - /* for (var i = 0; i < results.length; i++) { console.log('score', results[i].score, 'for', results[i].object.getModel().name); } - */ return results; } + // 'Loop' over the promises using recursion so that the promises are fufilled by the + // time that we are done function getPromisedResults(resultsPromises, promiseIndex, finalResults) { if (promiseIndex >= resultsPromises.length) { return finalResults; @@ -102,6 +104,60 @@ define( } } + function getPromisedItems(promises, index, fufilledPromises) { + if (index >= promises.length) { + return fufilledPromises; + } else { + return promises[index].then(function (results) { + fufilledPromises = fufilledPromises.concat(results); + return getPromisedItems(promises, index + 1, fufilledPromises); + }); + } + } + + // Add more results to compiledResults + // (As if the user presed 'load more results') + function loadMore() { + + } + + // Add x number of items to the compiledResults as the initial number of results that + // we display + function initialLoad(firstPromises) { + return getPromisedItems(firstPromises, 0, []).then(function (current) { + // Push the firsts onto the compiledResults + for (var i = 0; i < current.length; i++) { + if (current[i]) { + compiledResults.push(current[i]); + } + } + // Look for more results n times and add them to compiledResults + var outOfResults = []; + for (var i = 0; i < DEFAULT_MAX_RESULTS; i++) { + // If all of the providers are returning undefined, there are + // no more results to load + if (current.every(function (c) { + return c === undefined; + })) { + break; + } + + // For each provider, load the next result and add it to compiledResults + for (var j = 0; j < current.length; j++) { + if (current[j]) { + var nextResult = current[j].next(); + if (nextResult) { + compiledResults.push(nextResult); + } + current[j] = nextResult; + } + } + } + + return compiledResults; + }); + } + // Recieves results in the format of a serachResult object. It // has the members id, object, and score. It has a function // next() which returns the next highest score search result @@ -111,11 +167,15 @@ define( // merges the results lists so that there are not redundant // results function mergeResults(inputID) { - var resultsPromises = []; + //var resultsPromises = []; - // Get result list promises + // The first result from each provider. Each should have a next() function. + var firstPromises = []; + + // Get the initial result promises for (var i = 0; i < providers.length; i += 1) { - resultsPromises.push( + //resultsPromises.push( + firstPromises.push( providers[i].query( inputID, validType, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT ) @@ -123,12 +183,20 @@ define( } // Wait for the promises to fufill + return initialLoad(firstPromises).then(function (c) { + // Get rid of the repeated objects and put in correct order + c = filterRepeats(c); + c = orderByScore(c); + return c; + }); + /* return getPromisedResults(resultsPromises, 0, []).then(function (c) { // Get rid of the repeated objects and put in correct order c = filterRepeats(c); c = orderByScore(c); return c; }); + */ } return { diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 4d8f62bdac..74df3f658f 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -48,6 +48,8 @@ define( */ function ElasticsearchSearchProvider($http, objectService, ROOT) { // TODO: Fix the above docstring + var latestSearchResults = [], + currentResultIndex = 0; // Check to see if the input has any special options function isDefaultFormat(searchTerm) { @@ -67,7 +69,6 @@ define( return searchTerm.split(' ').map(function (s) { if (s.includes('"')) { - console.log('true'); return s; } else { return s + '~' + editDistance; @@ -97,6 +98,28 @@ define( return searchTerm; } + // Get the next search result + function next() { + // Because elasticsearch only returns matching things, we just + // need to step through the array + + currentResultIndex++; + + if (currentResultIndex > latestSearchResults.length) { + // If we go past the end of the array, we return undefined + return undefined; + } else { + return latestSearchResults[currentResultIndex]; + } + } + + function first() { + // Since next() immeditely does 'i++', start before the start of the array + currentResultIndex = -1; + var n = next(); + return n; + } + // Processes results from the format that elasticsearch returns to // a list of objects in the format that mct-representation can use function processResults(rawResults, validType) { @@ -104,8 +127,7 @@ define( resultsLength = results.length, ids = [], scores = {}, - searchResults = [], - i; + searchResults = []; if (rawResults.data.hits.total > resultsLength) { // TODO: Somehow communicate this to the user @@ -113,24 +135,21 @@ define( } // Get the result objects' IDs - for (i = 0; i < resultsLength; i += 1) { + for (var i = 0; i < resultsLength; i += 1) { ids.push(results[i][ID]); } // Get the result objects' scores - for (i = 0; i < resultsLength; i += 1) { - //scores.push(results[i][SCORE]); + for (var i = 0; i < resultsLength; i += 1) { scores[ ids[i] ] = results[i][SCORE]; } // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { - var id, - j; // Filter by search term - for (j = 0; j < resultsLength; j += 1) { - id = ids[j]; + for (var j = 0; j < resultsLength; j += 1) { + var id = ids[j]; // Include items we can get models for if (objects[id].getModel) { @@ -140,13 +159,15 @@ define( searchResults.push({ id: id, object: objects[id], - score: scores[id] + score: scores[id], + next: next }); } } } - //console.log('searchResults (in ES provider)', searchResults); + console.log('setting latest search results with', searchResults); + latestSearchResults = searchResults; return searchResults; }); } @@ -191,8 +212,7 @@ define( searchTerm = processSearchTerm(searchTerm); // Create the query to elasticsearch - esQuery = ROOT + "/_search/?q=" + searchTerm + - "&size=" + maxResults; + esQuery = ROOT + "/_search/?q=" + searchTerm + "&size=" + maxResults; if (timeout) { esQuery += "&timeout=" + timeout; } @@ -203,7 +223,11 @@ define( url: esQuery }).then(function (rawResults) { // ...then process the data - return processResults(rawResults, validType); + processResults(rawResults, validType); + // and return the first result + var f = first(); + // console.log('ES return', f); + return f; }); } diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 62e6639cd2..e1dad4ca40 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -44,6 +44,12 @@ define( * more easy creation of web workers. */ function GenericSearchProvider($rootScope, objectService, workerService) { + var latestItems = [], + currentResultIndex = 0, + currentSeachInput = '', + curentSearchTerms = [], + validType = function () {return true;}; + /* var worker = workerService.run('genericSearchWorker'), lastestItems; @@ -77,21 +83,19 @@ define( }); //counter += 1; } - */ function handleResponse(event) { latest = event.data; $rootScope.$apply(); //requestNext(); } + */ // Recursive helper function for getItems() function itemsHelper(children, i) { var date = new Date; if (stopTime && date.getTime() >= stopTime) { // This indexing of items has timed out - console.log('timed out'); - console.log('returning', children); return children; } else if (i >= children.length) { // Done! @@ -131,7 +135,8 @@ define( searchResultItems.push({ id: items[i].getId(), object: items[i], - score: 0 // Assign actual score when filtering for term + score: 0, // Assign actual score when filtering for term + next: next }); } @@ -141,8 +146,6 @@ define( }); } - - // Process the search input. Makes an array of search terms // by splitting up the input at spaces. function process(input) { @@ -179,8 +182,9 @@ define( return score * weight; } + /* // Filter through a list of searchResults based on a search term - function filterResults(results, originalInput, resultsLength, validType) { + function filterResults(results, originalInput, resultsLength) { var terms, searchResults = [], itemModel; @@ -202,6 +206,51 @@ define( return searchResults; } + */ + + // Get the next item from latestItems + function next() { + var i = currentResultIndex, + gotNext = false, + nextResult; + + // Look for the next item that qualifies as a search result + while (!gotNext) { + i++; + if (i > latestItems.length) { + // If we go past the end of the array, we return undefined + gotNext = true; + nextResult = undefined; + //currentResultIndex = i; + } else if (latestItems[i]) { + // Prevent errors from getModel not being defined + if (latestItems[i].object.getModel) { + latestItems[i].score = score(latestItems[i], curentSearchTerms, currentSeachInput); + + // Include any items that match the terms and are of valid type + if (latestItems[i].score > 0 && validType(latestItems[i].object.getModel())) { + // Add the result to the result list + nextResult = latestItems[i]; + //nextResult.next = next; + currentResultIndex = i; + gotNext = true; + } + } + } + } + + return nextResult; + } + + // Get the first result in latestItems that is a search result + function first(input) { + // Set up the global variables + currentSeachInput = input; + curentSearchTerms = process(input); + // Since next() immeditely does 'i++', start before the start of the array + currentResultIndex = -1; + return next(); + } /** * Searches through the filetree for domain objects which match @@ -216,15 +265,15 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term - * @param validType a function which takes a model for an object - * and determines if it is of a valid type to include in the - * final list of results + * @param passedValidType (optional) a function which takes a model + * for an object and determines if it is of a valid type to include + * in the final list of results; default returns true * @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 */ - function queryGeneric(inputID, validType, maxResults, timeout) { + function queryGeneric(inputID, passedValidType, maxResults, timeout) { var input, terms = [], searchResults = [], @@ -237,6 +286,8 @@ define( maxResults = DEFAULT_MAX_RESULTS; } + // Set the global validType function with the passed one + validType = passedValidType; // Get the user input input = document.getElementById(inputID).value; @@ -244,6 +295,9 @@ define( // Get items list //requestItems(); // Test out the worker return getItems(timeout).then(function (searchResultItems) { + // Set global items variable + latestItems = searchResultItems; + // Keep track of the number of results to display if (searchResultItems.length < maxResults) { resultsLength = searchResultItems.length; @@ -252,10 +306,13 @@ define( } // Then filter through the items list - searchResults = filterResults(searchResultItems, input, resultsLength, validType); + //searchResults = filterResults(searchResultItems, input, resultsLength); - //console.log('filtered searchResults (in Everything)', searchResults); - return searchResults; + // Get the first search result + var firstResult = first(input); + console.log('generic return', firstResult); + + return firstResult; }); } From 1891b24bdea392538e45797bf3afe7a828ea7fc3 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 20 Jul 2015 16:56:39 -0700 Subject: [PATCH 074/195] [Search] Dump before revert Commtting changes so far before revering to a previous commit. Most changes to make next() have been unneccsiary. We no longer want next(). --- platform/features/search/bundle.json | 9 ++- .../features/search/res/templates/search.html | 2 +- .../features/search/src/SearchAggregator.js | 53 ++++++++++++- .../providers/ElasticsearchSearchProvider.js | 10 ++- .../src/providers/GenericSearchProvider.js | 4 +- .../search/src/workers/GenericSearchWorker.js | 74 +++++++++++++++++++ 6 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 platform/features/search/src/workers/GenericSearchWorker.js diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 264dd5f68a..1913c5e0da 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -42,7 +42,7 @@ "provides": "searchService", "type": "provider", "implementation": "providers/GenericSearchProvider.js", - "depends": [ "objectService" ] + "depends": [ "$rootScope", "objectService", "workerService" ] }, { "provides": "searchService", @@ -55,6 +55,13 @@ "type": "aggregator", "implementation": "SearchAggregator.js" } + ], + "workers": [ + { + "key": "genericSearchWorker", + "scriptUrl": "workers/GenericSearchWorker.js", + "depends": [ "objectService" ] + } ] } } \ No newline at end of file diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 0e8a6eb320..d213422787 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -29,7 +29,7 @@ diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 27d1f3f629..890d1612a9 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -54,21 +54,64 @@ define( // Remove extra objects that have the same ID function filterRepeats(results) { - var ids = []; + var ids = [], + idToIndicies = {}, // 'dictionary' mapping IDs to a list of indicies + filteredResults = []; + // Create a list of indicies of objects that correspond to any object ID + for (var i = 0; i < results.length; i++) { + var id = results[i].id; + + if (idToIndicies[id]) { + // If the ID already exists in the dictionary, push this index to + // the end of the array it points to + idToIndicies[id].push(i); + } else { + // Else make a new entry in the dictionary with this ID, pointing + // to this index + idToIndicies[id] = [i]; + // And also add this ID to the list of IDs that we have seen + ids.push(id); + } + } + + // Now for each ID in the dictionary, we want to use the version of + // the object that has a higher score + for (var i = 0; i < ids.length; i++) { + var id = ids[i], + indicies = idToIndicies[id], + highestScoringObject; + + highestScoringObject = results[ indicies[0] ]; + for (var j = 0; j < indicies.length; j++) { + // If the score of the object corresponding to this index of the results + // list has a higher score than the one we have, choose it instead + if (results[indicies[j]].score > highestScoringObject.score) { + highestScoringObject = results[indicies[j]]; + } + } + filteredResults.push(highestScoringObject); + } + + /* for (var i = 0; i < results.length; i += 1) { - if (ids.indexOf(results[i].id) !== -1) { + if (results[i] === undefined) { + // Catch any leftover undefined objects + results.splice(i, 1); + i--; + } else if (ids.indexOf(results[i].id) !== -1) { // If this result's ID is already there, remove the object results.splice(i, 1); // Reduce loop index because we shortened the array - i -= 1; + i--; } else { // Otherwise add the ID to the list of the ones we have seen ids.push(results[i].id); } } + */ - return results; + return filteredResults; } // Order the objects from highest to lowest score in the array @@ -84,9 +127,11 @@ define( } }); + /* for (var i = 0; i < results.length; i++) { console.log('score', results[i].score, 'for', results[i].object.getModel().name); } + */ return results; } diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 74df3f658f..a6fcebcc12 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -144,6 +144,8 @@ define( scores[ ids[i] ] = results[i][SCORE]; } + //console.log('scores {}', scores); + // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { @@ -166,7 +168,13 @@ define( } } - console.log('setting latest search results with', searchResults); + /* + for (var k = 0; k < searchResults.length; k++) { + console.log('ES score', searchResults[k].score, 'for', searchResults[k].object.getModel().name); + } + */ + + //console.log('setting latest search results with', searchResults); latestSearchResults = searchResults; return searchResults; }); diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index e1dad4ca40..378379013b 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -226,7 +226,7 @@ define( // Prevent errors from getModel not being defined if (latestItems[i].object.getModel) { latestItems[i].score = score(latestItems[i], curentSearchTerms, currentSeachInput); - + //console.log('item', latestItems[i].object.getModel().name, 'score', latestItems[i].score); // Include any items that match the terms and are of valid type if (latestItems[i].score > 0 && validType(latestItems[i].object.getModel())) { // Add the result to the result list @@ -310,7 +310,7 @@ define( // Get the first search result var firstResult = first(input); - console.log('generic return', firstResult); + //console.log('generic return', firstResult); return firstResult; }); diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js new file mode 100644 index 0000000000..0bd617e818 --- /dev/null +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -0,0 +1,74 @@ +/***************************************************************************** + * 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 self*/ + +(function () { + "use strict"; + + // Recursive helper function for getItems() + function itemsHelper(children, i) { + if (i >= children.length) { + // 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 + function getItems(objectService) { + // Aquire My Items (root folder) + return objectService.getObjects(['mine']).then(function (objects) { + // Get all of its descendents + 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) { + searchResultItems.push({ + id: items[i].getId(), + object: items[i], + score: 0 // Assign actual score when filtering for term + }); + } + + //console.log('searchResultItems (in Everything)', searchResultItems); + return searchResultItems; + }); + }); + } + + self.onmessage = function (event) { + //console.log('in worker .. 1'); + //console.log('event.data', event.data); + //console.log('objects 0', objects[0]); + self.postMessage(itemsHelper(event.data, 0)); + }; +}()); From f4bd7d7a442b1e9afcf450679eb20af738294bb8 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 20 Jul 2015 17:02:08 -0700 Subject: [PATCH 075/195] [Search] Revert to earlier commit Reverted to before implementing next(). May re add back some changes, such as removing validType and then adding web workers. --- platform/features/search/bundle.json | 9 +- .../features/search/src/SearchAggregator.js | 127 +----------------- .../providers/ElasticsearchSearchProvider.js | 62 +++------ .../src/providers/GenericSearchProvider.js | 85 ++---------- .../search/src/workers/GenericSearchWorker.js | 74 ---------- 5 files changed, 37 insertions(+), 320 deletions(-) delete mode 100644 platform/features/search/src/workers/GenericSearchWorker.js diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 1913c5e0da..264dd5f68a 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -42,7 +42,7 @@ "provides": "searchService", "type": "provider", "implementation": "providers/GenericSearchProvider.js", - "depends": [ "$rootScope", "objectService", "workerService" ] + "depends": [ "objectService" ] }, { "provides": "searchService", @@ -55,13 +55,6 @@ "type": "aggregator", "implementation": "SearchAggregator.js" } - ], - "workers": [ - { - "key": "genericSearchWorker", - "scriptUrl": "workers/GenericSearchWorker.js", - "depends": [ "objectService" ] - } ] } } \ No newline at end of file diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 890d1612a9..30be3720dd 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -41,8 +41,6 @@ define( * aggregated */ function SearchAggregator(providers) { - var compiledResults = []; - // Determines if a searchResult object is a valid type // to be displayed as a final result. Is passed to the @@ -54,64 +52,21 @@ define( // Remove extra objects that have the same ID function filterRepeats(results) { - var ids = [], - idToIndicies = {}, // 'dictionary' mapping IDs to a list of indicies - filteredResults = []; + var ids = []; - // Create a list of indicies of objects that correspond to any object ID - for (var i = 0; i < results.length; i++) { - var id = results[i].id; - - if (idToIndicies[id]) { - // If the ID already exists in the dictionary, push this index to - // the end of the array it points to - idToIndicies[id].push(i); - } else { - // Else make a new entry in the dictionary with this ID, pointing - // to this index - idToIndicies[id] = [i]; - // And also add this ID to the list of IDs that we have seen - ids.push(id); - } - } - - // Now for each ID in the dictionary, we want to use the version of - // the object that has a higher score - for (var i = 0; i < ids.length; i++) { - var id = ids[i], - indicies = idToIndicies[id], - highestScoringObject; - - highestScoringObject = results[ indicies[0] ]; - for (var j = 0; j < indicies.length; j++) { - // If the score of the object corresponding to this index of the results - // list has a higher score than the one we have, choose it instead - if (results[indicies[j]].score > highestScoringObject.score) { - highestScoringObject = results[indicies[j]]; - } - } - filteredResults.push(highestScoringObject); - } - - /* for (var i = 0; i < results.length; i += 1) { - if (results[i] === undefined) { - // Catch any leftover undefined objects - results.splice(i, 1); - i--; - } else if (ids.indexOf(results[i].id) !== -1) { + if (ids.indexOf(results[i].id) !== -1) { // If this result's ID is already there, remove the object results.splice(i, 1); // Reduce loop index because we shortened the array - i--; + i -= 1; } else { // Otherwise add the ID to the list of the ones we have seen ids.push(results[i].id); } } - */ - return filteredResults; + return results; } // Order the objects from highest to lowest score in the array @@ -136,8 +91,6 @@ define( return results; } - // 'Loop' over the promises using recursion so that the promises are fufilled by the - // time that we are done function getPromisedResults(resultsPromises, promiseIndex, finalResults) { if (promiseIndex >= resultsPromises.length) { return finalResults; @@ -149,60 +102,6 @@ define( } } - function getPromisedItems(promises, index, fufilledPromises) { - if (index >= promises.length) { - return fufilledPromises; - } else { - return promises[index].then(function (results) { - fufilledPromises = fufilledPromises.concat(results); - return getPromisedItems(promises, index + 1, fufilledPromises); - }); - } - } - - // Add more results to compiledResults - // (As if the user presed 'load more results') - function loadMore() { - - } - - // Add x number of items to the compiledResults as the initial number of results that - // we display - function initialLoad(firstPromises) { - return getPromisedItems(firstPromises, 0, []).then(function (current) { - // Push the firsts onto the compiledResults - for (var i = 0; i < current.length; i++) { - if (current[i]) { - compiledResults.push(current[i]); - } - } - // Look for more results n times and add them to compiledResults - var outOfResults = []; - for (var i = 0; i < DEFAULT_MAX_RESULTS; i++) { - // If all of the providers are returning undefined, there are - // no more results to load - if (current.every(function (c) { - return c === undefined; - })) { - break; - } - - // For each provider, load the next result and add it to compiledResults - for (var j = 0; j < current.length; j++) { - if (current[j]) { - var nextResult = current[j].next(); - if (nextResult) { - compiledResults.push(nextResult); - } - current[j] = nextResult; - } - } - } - - return compiledResults; - }); - } - // Recieves results in the format of a serachResult object. It // has the members id, object, and score. It has a function // next() which returns the next highest score search result @@ -212,15 +111,11 @@ define( // merges the results lists so that there are not redundant // results function mergeResults(inputID) { - //var resultsPromises = []; + var resultsPromises = []; - // The first result from each provider. Each should have a next() function. - var firstPromises = []; - - // Get the initial result promises + // Get result list promises for (var i = 0; i < providers.length; i += 1) { - //resultsPromises.push( - firstPromises.push( + resultsPromises.push( providers[i].query( inputID, validType, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT ) @@ -228,20 +123,12 @@ define( } // Wait for the promises to fufill - return initialLoad(firstPromises).then(function (c) { - // Get rid of the repeated objects and put in correct order - c = filterRepeats(c); - c = orderByScore(c); - return c; - }); - /* return getPromisedResults(resultsPromises, 0, []).then(function (c) { // Get rid of the repeated objects and put in correct order c = filterRepeats(c); c = orderByScore(c); return c; }); - */ } return { diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index a6fcebcc12..4d8f62bdac 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -48,8 +48,6 @@ define( */ function ElasticsearchSearchProvider($http, objectService, ROOT) { // TODO: Fix the above docstring - var latestSearchResults = [], - currentResultIndex = 0; // Check to see if the input has any special options function isDefaultFormat(searchTerm) { @@ -69,6 +67,7 @@ define( return searchTerm.split(' ').map(function (s) { if (s.includes('"')) { + console.log('true'); return s; } else { return s + '~' + editDistance; @@ -98,28 +97,6 @@ define( return searchTerm; } - // Get the next search result - function next() { - // Because elasticsearch only returns matching things, we just - // need to step through the array - - currentResultIndex++; - - if (currentResultIndex > latestSearchResults.length) { - // If we go past the end of the array, we return undefined - return undefined; - } else { - return latestSearchResults[currentResultIndex]; - } - } - - function first() { - // Since next() immeditely does 'i++', start before the start of the array - currentResultIndex = -1; - var n = next(); - return n; - } - // Processes results from the format that elasticsearch returns to // a list of objects in the format that mct-representation can use function processResults(rawResults, validType) { @@ -127,7 +104,8 @@ define( resultsLength = results.length, ids = [], scores = {}, - searchResults = []; + searchResults = [], + i; if (rawResults.data.hits.total > resultsLength) { // TODO: Somehow communicate this to the user @@ -135,23 +113,24 @@ define( } // Get the result objects' IDs - for (var i = 0; i < resultsLength; i += 1) { + for (i = 0; i < resultsLength; i += 1) { ids.push(results[i][ID]); } // Get the result objects' scores - for (var i = 0; i < resultsLength; i += 1) { + for (i = 0; i < resultsLength; i += 1) { + //scores.push(results[i][SCORE]); scores[ ids[i] ] = results[i][SCORE]; } - //console.log('scores {}', scores); - // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { + var id, + j; // Filter by search term - for (var j = 0; j < resultsLength; j += 1) { - var id = ids[j]; + for (j = 0; j < resultsLength; j += 1) { + id = ids[j]; // Include items we can get models for if (objects[id].getModel) { @@ -161,21 +140,13 @@ define( searchResults.push({ id: id, object: objects[id], - score: scores[id], - next: next + score: scores[id] }); } } } - /* - for (var k = 0; k < searchResults.length; k++) { - console.log('ES score', searchResults[k].score, 'for', searchResults[k].object.getModel().name); - } - */ - - //console.log('setting latest search results with', searchResults); - latestSearchResults = searchResults; + //console.log('searchResults (in ES provider)', searchResults); return searchResults; }); } @@ -220,7 +191,8 @@ define( searchTerm = processSearchTerm(searchTerm); // Create the query to elasticsearch - esQuery = ROOT + "/_search/?q=" + searchTerm + "&size=" + maxResults; + esQuery = ROOT + "/_search/?q=" + searchTerm + + "&size=" + maxResults; if (timeout) { esQuery += "&timeout=" + timeout; } @@ -231,11 +203,7 @@ define( url: esQuery }).then(function (rawResults) { // ...then process the data - processResults(rawResults, validType); - // and return the first result - var f = first(); - // console.log('ES return', f); - return f; + return processResults(rawResults, validType); }); } diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 378379013b..62e6639cd2 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -44,12 +44,6 @@ define( * more easy creation of web workers. */ function GenericSearchProvider($rootScope, objectService, workerService) { - var latestItems = [], - currentResultIndex = 0, - currentSeachInput = '', - curentSearchTerms = [], - validType = function () {return true;}; - /* var worker = workerService.run('genericSearchWorker'), lastestItems; @@ -83,19 +77,21 @@ define( }); //counter += 1; } + */ function handleResponse(event) { latest = event.data; $rootScope.$apply(); //requestNext(); } - */ // Recursive helper function for getItems() function itemsHelper(children, i) { var date = new Date; if (stopTime && date.getTime() >= stopTime) { // This indexing of items has timed out + console.log('timed out'); + console.log('returning', children); return children; } else if (i >= children.length) { // Done! @@ -135,8 +131,7 @@ define( searchResultItems.push({ id: items[i].getId(), object: items[i], - score: 0, // Assign actual score when filtering for term - next: next + score: 0 // Assign actual score when filtering for term }); } @@ -146,6 +141,8 @@ define( }); } + + // Process the search input. Makes an array of search terms // by splitting up the input at spaces. function process(input) { @@ -182,9 +179,8 @@ define( return score * weight; } - /* // Filter through a list of searchResults based on a search term - function filterResults(results, originalInput, resultsLength) { + function filterResults(results, originalInput, resultsLength, validType) { var terms, searchResults = [], itemModel; @@ -206,51 +202,6 @@ define( return searchResults; } - */ - - // Get the next item from latestItems - function next() { - var i = currentResultIndex, - gotNext = false, - nextResult; - - // Look for the next item that qualifies as a search result - while (!gotNext) { - i++; - if (i > latestItems.length) { - // If we go past the end of the array, we return undefined - gotNext = true; - nextResult = undefined; - //currentResultIndex = i; - } else if (latestItems[i]) { - // Prevent errors from getModel not being defined - if (latestItems[i].object.getModel) { - latestItems[i].score = score(latestItems[i], curentSearchTerms, currentSeachInput); - //console.log('item', latestItems[i].object.getModel().name, 'score', latestItems[i].score); - // Include any items that match the terms and are of valid type - if (latestItems[i].score > 0 && validType(latestItems[i].object.getModel())) { - // Add the result to the result list - nextResult = latestItems[i]; - //nextResult.next = next; - currentResultIndex = i; - gotNext = true; - } - } - } - } - - return nextResult; - } - - // Get the first result in latestItems that is a search result - function first(input) { - // Set up the global variables - currentSeachInput = input; - curentSearchTerms = process(input); - // Since next() immeditely does 'i++', start before the start of the array - currentResultIndex = -1; - return next(); - } /** * Searches through the filetree for domain objects which match @@ -265,15 +216,15 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term - * @param passedValidType (optional) a function which takes a model - * for an object and determines if it is of a valid type to include - * in the final list of results; default returns true + * @param validType a function which takes a model for an object + * and determines if it is of a valid type to include in the + * final list of 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 */ - function queryGeneric(inputID, passedValidType, maxResults, timeout) { + function queryGeneric(inputID, validType, maxResults, timeout) { var input, terms = [], searchResults = [], @@ -286,8 +237,6 @@ define( maxResults = DEFAULT_MAX_RESULTS; } - // Set the global validType function with the passed one - validType = passedValidType; // Get the user input input = document.getElementById(inputID).value; @@ -295,9 +244,6 @@ define( // Get items list //requestItems(); // Test out the worker return getItems(timeout).then(function (searchResultItems) { - // Set global items variable - latestItems = searchResultItems; - // Keep track of the number of results to display if (searchResultItems.length < maxResults) { resultsLength = searchResultItems.length; @@ -306,13 +252,10 @@ define( } // Then filter through the items list - //searchResults = filterResults(searchResultItems, input, resultsLength); + searchResults = filterResults(searchResultItems, input, resultsLength, validType); - // Get the first search result - var firstResult = first(input); - //console.log('generic return', firstResult); - - return firstResult; + //console.log('filtered searchResults (in Everything)', searchResults); + return searchResults; }); } diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js deleted file mode 100644 index 0bd617e818..0000000000 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - * 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 self*/ - -(function () { - "use strict"; - - // Recursive helper function for getItems() - function itemsHelper(children, i) { - if (i >= children.length) { - // 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 - function getItems(objectService) { - // Aquire My Items (root folder) - return objectService.getObjects(['mine']).then(function (objects) { - // Get all of its descendents - 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) { - searchResultItems.push({ - id: items[i].getId(), - object: items[i], - score: 0 // Assign actual score when filtering for term - }); - } - - //console.log('searchResultItems (in Everything)', searchResultItems); - return searchResultItems; - }); - }); - } - - self.onmessage = function (event) { - //console.log('in worker .. 1'); - //console.log('event.data', event.data); - //console.log('objects 0', objects[0]); - self.postMessage(itemsHelper(event.data, 0)); - }; -}()); From c79d1f26481a62538e0e2a1e16d7182d6a91d279 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 09:41:08 -0700 Subject: [PATCH 076/195] [Search] Choose higher score & optional parameters Changed the search aggregator's filterRepeats function to choose the version of the searchResult object that has the higher score, when it encounters multiple searchResult objects corresponding to a domain object ID. Also changed the search providers and aggregator such that the validType parameter is now optional, with a function that always returns true as the defualt. --- .../features/search/src/SearchAggregator.js | 44 +++++++++++++++++++ .../providers/ElasticsearchSearchProvider.js | 29 ++++++------ .../src/providers/GenericSearchProvider.js | 21 +++++---- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 30be3720dd..f00c62fb01 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -52,6 +52,47 @@ define( // Remove extra objects that have the same ID function filterRepeats(results) { + var ids = [], + idToIndicies = {}, // 'dictionary' mapping IDs to a list of indicies + filteredResults = []; + + // Create a list of indicies of objects that correspond to any object ID + for (var i = 0; i < results.length; i++) { + var id = results[i].id; + + if (idToIndicies[id]) { + // If the ID already exists in the dictionary, push this index to + // the end of the array it points to + idToIndicies[id].push(i); + } else { + // Else make a new entry in the dictionary with this ID, pointing + // to this index + idToIndicies[id] = [i]; + // And also add this ID to the list of IDs that we have seen + ids.push(id); + } + } + + // Now for each ID in the dictionary, we want to use the version of + // the object that has a higher score + for (var i = 0; i < ids.length; i++) { + var id = ids[i], + indicies = idToIndicies[id], + highestScoringObject; + + highestScoringObject = results[ indicies[0] ]; + for (var j = 0; j < indicies.length; j++) { + // If the score of the object corresponding to this index of the results + // list has a higher score than the one we have, choose it instead + if (results[indicies[j]].score > highestScoringObject.score) { + highestScoringObject = results[indicies[j]]; + } + } + filteredResults.push(highestScoringObject); + } + + return filteredResults; + /* var ids = []; for (var i = 0; i < results.length; i += 1) { @@ -67,6 +108,7 @@ define( } return results; + */ } // Order the objects from highest to lowest score in the array @@ -91,6 +133,8 @@ define( return results; } + // 'Loop' over the promises using recursion so that the promises are fufilled by the + // time that we are done function getPromisedResults(resultsPromises, promiseIndex, finalResults) { if (promiseIndex >= resultsPromises.length) { return finalResults; diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 4d8f62bdac..c8eade24bb 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -48,6 +48,7 @@ define( */ function ElasticsearchSearchProvider($http, objectService, ROOT) { // TODO: Fix the above docstring + var validType = function () {return true;}; // Check to see if the input has any special options function isDefaultFormat(searchTerm) { @@ -67,7 +68,6 @@ define( return searchTerm.split(' ').map(function (s) { if (s.includes('"')) { - console.log('true'); return s; } else { return s + '~' + editDistance; @@ -104,8 +104,7 @@ define( resultsLength = results.length, ids = [], scores = {}, - searchResults = [], - i; + searchResults = []; if (rawResults.data.hits.total > resultsLength) { // TODO: Somehow communicate this to the user @@ -113,24 +112,21 @@ define( } // Get the result objects' IDs - for (i = 0; i < resultsLength; i += 1) { + for (var i = 0; i < resultsLength; i += 1) { ids.push(results[i][ID]); } // Get the result objects' scores - for (i = 0; i < resultsLength; i += 1) { + for (var i = 0; i < resultsLength; i += 1) { //scores.push(results[i][SCORE]); scores[ ids[i] ] = results[i][SCORE]; } // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { - var id, - j; - // Filter by search term - for (j = 0; j < resultsLength; j += 1) { - id = ids[j]; + for (var j = 0; j < resultsLength; j += 1) { + var id = ids[j]; // Include items we can get models for if (objects[id].getModel) { @@ -165,15 +161,15 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term - * @param validType a function which takes a model for an object - * and determines if it is of a valid type to include in the - * final list of results + * @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 * @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 */ - function queryElasticsearch(inputID, validType, maxResults, timeout) { + function queryElasticsearch(inputID, passedValidType, maxResults, timeout) { var searchTerm, esQuery; @@ -184,6 +180,11 @@ define( maxResults = DEFAULT_MAX_RESULTS; } + // Check to see if a valid type function was provided + if (passedValidType) { + validType = passedValidType; + } + // Get the user input searchTerm = document.getElementById(inputID).value; diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 62e6639cd2..5e5c2738f1 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -44,6 +44,8 @@ define( * more easy creation of web workers. */ function GenericSearchProvider($rootScope, objectService, workerService) { + var validType = function () {return true;}; + /* var worker = workerService.run('genericSearchWorker'), lastestItems; @@ -90,8 +92,6 @@ define( var date = new Date; if (stopTime && date.getTime() >= stopTime) { // This indexing of items has timed out - console.log('timed out'); - console.log('returning', children); return children; } else if (i >= children.length) { // Done! @@ -180,7 +180,7 @@ define( } // Filter through a list of searchResults based on a search term - function filterResults(results, originalInput, resultsLength, validType) { + function filterResults(results, originalInput, resultsLength) { var terms, searchResults = [], itemModel; @@ -216,15 +216,15 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term - * @param validType a function which takes a model for an object - * and determines if it is of a valid type to include in the - * final list of results + * @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 * @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 */ - function queryGeneric(inputID, validType, maxResults, timeout) { + function queryGeneric(inputID, passedValidType, maxResults, timeout) { var input, terms = [], searchResults = [], @@ -237,6 +237,11 @@ define( maxResults = DEFAULT_MAX_RESULTS; } + // Check to see if a valid type function was provided + if (passedValidType) { + validType = passedValidType; + } + // Get the user input input = document.getElementById(inputID).value; @@ -252,7 +257,7 @@ define( } // Then filter through the items list - searchResults = filterResults(searchResultItems, input, resultsLength, validType); + searchResults = filterResults(searchResultItems, input, resultsLength); //console.log('filtered searchResults (in Everything)', searchResults); return searchResults; From 74961e1106d7a46f0f032b5361cf627cfe0dc247 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 09:44:14 -0700 Subject: [PATCH 077/195] [Search] Starting on workers Starting to work on using web workers to do some of the work of GenericSearch. Changed bundle.json accordingly. --- platform/features/search/bundle.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 264dd5f68a..1913c5e0da 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -42,7 +42,7 @@ "provides": "searchService", "type": "provider", "implementation": "providers/GenericSearchProvider.js", - "depends": [ "objectService" ] + "depends": [ "$rootScope", "objectService", "workerService" ] }, { "provides": "searchService", @@ -55,6 +55,13 @@ "type": "aggregator", "implementation": "SearchAggregator.js" } + ], + "workers": [ + { + "key": "genericSearchWorker", + "scriptUrl": "workers/GenericSearchWorker.js", + "depends": [ "objectService" ] + } ] } } \ No newline at end of file From c1dcd8ea5b397ec7c532428d569295c3114f9250 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 09:58:19 -0700 Subject: [PATCH 078/195] [Search] Framework of webworker implementation Made a basic outline of the desired web worker implementation. (Functions present, now need to implement them.) --- .../src/providers/GenericSearchProvider.js | 30 ++++++++++-- .../search/src/workers/GenericSearchWorker.js | 47 +++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 platform/features/search/src/workers/GenericSearchWorker.js diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 5e5c2738f1..1e02f55397 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -46,10 +46,10 @@ define( function GenericSearchProvider($rootScope, objectService, workerService) { var validType = function () {return true;}; - /* var worker = workerService.run('genericSearchWorker'), lastestItems; + /* function requestItems() { // Aquire My Items (root folder) // I don't think we can do this part in the webworker because of the objectService @@ -81,9 +81,33 @@ define( } */ + // Tell the web worker to add a new item's model to its list of items. + function indexItem(domainObject) { + var message = { + request: 'index', + model: domainObject.getModel() + }; + // 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, + number: numberOfResults + }; + worker.postMessage(message); + } + function handleResponse(event) { - latest = event.data; - $rootScope.$apply(); + //latest = event.data; + //console.log('handleResponse', event.data); + //$rootScope.$apply(); //requestNext(); } diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js new file mode 100644 index 0000000000..e8bb0c1d4c --- /dev/null +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -0,0 +1,47 @@ +/***************************************************************************** + * 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 self*/ + +(function () { + "use strict"; + + var indexedItems = []; + + function index(data) { + // Takes an object model + // Add to indexedItems + } + + function search(data) { + // Takes a search input and the number of items to find + // Converts it into search terms + // Gets matches from indexedItems + } + + self.onmessage = function (event) { + if (event.data.request === 'index') { + self.postMessage(index(event.data)); + } else if (event.data.request === 'search') { + self.postMessage(search(event.data)); + } + }; +}()); \ No newline at end of file From 7adcfc221a8e6273d4c403437f288a1e2b1ad5b5 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 10:10:34 -0700 Subject: [PATCH 079/195] [Serach] Webworker indexes items The indexItem() part of the web worker seems to be working at this point. --- .../src/providers/GenericSearchProvider.js | 13 ++++++++---- .../search/src/workers/GenericSearchWorker.js | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 1e02f55397..de2d1c6748 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -85,7 +85,8 @@ define( function indexItem(domainObject) { var message = { request: 'index', - model: domainObject.getModel() + model: domainObject.getModel(), + id: domainObject.getId() }; // Note that getModel() by definition returns a JavaScript object // that can be losslesly converted to a JSON object. @@ -106,7 +107,7 @@ define( function handleResponse(event) { //latest = event.data; - //console.log('handleResponse', event.data); + console.log('handleResponse', event.data); //$rootScope.$apply(); //requestNext(); } @@ -152,6 +153,9 @@ define( var searchResultItems = []; for (var i = 0; i < items.length; i += 1) { + // Test out calling worker indexItem + indexItem(items[i]); + searchResultItems.push({ id: items[i].getId(), object: items[i], @@ -165,8 +169,6 @@ define( }); } - - // Process the search input. Makes an array of search terms // by splitting up the input at spaces. function process(input) { @@ -279,6 +281,9 @@ define( } else { resultsLength = maxResults; } + + // Test out calling the web worker search + workerSearch(input, maxResults); // Then filter through the items list searchResults = filterResults(searchResultItems, input, resultsLength); diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index e8bb0c1d4c..822e5415f2 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -24,20 +24,41 @@ (function () { "use strict"; + // An array of objects composed of domain object IDs and models + // {id: domainObject's ID, model: domainObject's model} var indexedItems = []; + function conainsItem(id) { + for (var i = 0; i < indexedItems.length; i++) { + if (indexedItems[i].id === id) { + return true; + } + } + return false; + } + function index(data) { // Takes an object model // Add to indexedItems + console.log('webworker index', data); + if (!conainsItem(data.id)) { + indexedItems.push({ + id: data.id, + model: data.model + }); + } } function search(data) { // Takes a search input and the number of items to find // Converts it into search terms // Gets matches from indexedItems + console.log('webworker search', data); + console.log('webworker indexedItems', indexedItems); } self.onmessage = function (event) { + console.log('webworker onmessage'); if (event.data.request === 'index') { self.postMessage(index(event.data)); } else if (event.data.request === 'search') { From a0f4b98eed3413d735d2b21530e79748ca4b77c3 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 10:35:33 -0700 Subject: [PATCH 080/195] [Search] Webworker search The web worker's search() appears to work. Now we just need to link it in to the GenericSearch as the primary means of searching. --- .../src/providers/GenericSearchProvider.js | 2 +- .../search/src/workers/GenericSearchWorker.js | 73 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index de2d1c6748..4b84c3884b 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -100,7 +100,7 @@ define( var message = { request: 'search', input: searchInput, - number: numberOfResults + maxNumber: numberOfResults }; worker.postMessage(message); } diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index 822e5415f2..21763c5828 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -28,6 +28,7 @@ // {id: domainObject's ID, model: domainObject's model} var indexedItems = []; + // Helper function for index() function conainsItem(id) { for (var i = 0; i < indexedItems.length; i++) { if (indexedItems[i].id === id) { @@ -37,10 +38,17 @@ return false; } + /** + * + */ function index(data) { // Takes an object model // Add to indexedItems console.log('webworker index', data); + + // TODO: Since this is only within genericsearch, do + // we really need to check if the index already holds it? + // This might depend on how often/when we clear indexedItems. if (!conainsItem(data.id)) { indexedItems.push({ id: data.id, @@ -49,12 +57,77 @@ } } + // Helper function for serach() + function convertToTerms(input) { + return input.split(' '); + } + + // Helper function for search() + function scoreItem(item, input, terms) { + var name = item.model.name.toLocaleLowerCase(), + weight = 0.65, + score = 0.0; + + // Make the score really big if the item name and + // the original search input are the same + if (name === input) { + score = 42; + } + + 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++; + + // Add extra to the score if the search term exists + // as its own term within the items + // TODO: This may be undesired + if (name.split(' ').indexOf(terms[i]) !== -1) { + score += .5; + } + } + } + + return score * weight; + } + + /** + * + */ function search(data) { // Takes a search input and the number of items to find // Converts it into search terms // Gets matches from indexedItems console.log('webworker search', data); console.log('webworker indexedItems', indexedItems); + + // This results array will hold objects which are composed of + // the object's id, model, and score. (The score is wrt only this + // specific search input.) + // TODO: It may be unnecissary for results to have models in it. + var results = [], + input = data.input.toLocaleLowerCase(), + terms = convertToTerms(input), + timesToLoop = Math.min(indexedItems.length, data.maxNumber); + + for (var i = 0; i < timesToLoop; i++) { + var score = scoreItem(indexedItems[i], input, terms); + if (score > 0) { + results.push({ + id: indexedItems[i].id, + model: indexedItems[i].model, + score: score + }); + } + } + + console.log('webworker results', results); + + return results; + + // TODO: After a search is completed, do we need to + // clear out indexedItems? + // When do we need to clear out inedxedItems? } self.onmessage = function (event) { From fc123cd367c91c4c8c91946eeda72a7f59b43cbd Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 11:14:10 -0700 Subject: [PATCH 081/195] [Search] In progress webworker Connecting GenericSearch to the web worker is still in progress. The aggregator currently gets the results before the web worker is finished. In process of fixing sync issue. --- platform/features/search/bundle.json | 2 +- .../src/providers/GenericSearchProvider.js | 59 +++++++++++++++++-- .../search/src/workers/GenericSearchWorker.js | 12 +++- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 1913c5e0da..bc8497e291 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -42,7 +42,7 @@ "provides": "searchService", "type": "provider", "implementation": "providers/GenericSearchProvider.js", - "depends": [ "$rootScope", "objectService", "workerService" ] + "depends": [ "$rootScope", "$timeout", "objectService", "workerService" ] }, { "provides": "searchService", diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 4b84c3884b..e0c809cba8 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -43,11 +43,11 @@ define( * @param {WorkerService} workerService the service which allows * more easy creation of web workers. */ - function GenericSearchProvider($rootScope, objectService, workerService) { + function GenericSearchProvider($rootScope, $timeout, objectService, workerService) { var validType = function () {return true;}; var worker = workerService.run('genericSearchWorker'), - lastestItems; + latestResults = []; /* function requestItems() { @@ -96,18 +96,27 @@ define( // 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) { + function workerSearch(searchInput, maxResults) { var message = { request: 'search', input: searchInput, - maxNumber: numberOfResults + maxNumber: maxResults }; worker.postMessage(message); } + worker.onmessage = handleResponse; + function handleResponse(event) { //latest = event.data; + console.log('handleResponse', event.data); + if (event.data.request === 'search') { + latestResults = event.data.results; + console.log('updated latestResults', latestResults); + } + // If the message was from 'index', we don't need to do anything + //$rootScope.$apply(); //requestNext(); } @@ -149,6 +158,15 @@ define( // itemsHelper should just treat this as having no timeout return itemsHelper([objects.mine], 0).then(function (items) { + // Add each item that itemsHelper found to the web worker index + // TODO: Try to do this within itemsHelper. Perhaps just + // need to add this to the last two if statements? + for (var i = 0; i < items.length; i++) { + indexItem(items[i]); + } + return; // We don't need to return anything anymore + // TODO: Fix return statements. Do we need them still? + /* // Turn them into searchResult objects (object, id, and score) var searchResultItems = []; @@ -165,10 +183,12 @@ define( //console.log('searchResultItems (in Everything)', searchResultItems); return searchResultItems; + */ }); }); } + /* // Process the search input. Makes an array of search terms // by splitting up the input at spaces. function process(input) { @@ -228,6 +248,7 @@ define( return searchResults; } + */ /** * Searches through the filetree for domain objects which match @@ -274,7 +295,28 @@ define( // Get items list //requestItems(); // Test out the worker - return getItems(timeout).then(function (searchResultItems) { + return getItems(timeout).then(function (/*searchResultItems*/) { + var test = workerSearch(input, maxResults); + console.log('test', test); + + // Wait for latestResults to be not empty, then return + function wait(){ + if (latestResults.length === 0){ + console.log('waiting'); + console.log('latestResults', latestResults); + $timeout(wait, 100); + } else { + console.log('done waiting'); + //test = latestResults; + return latestResults; + } + } + console.log('about to wait'); + wait(); + + console.log('returning (not)'); + //return test; + /* // Keep track of the number of results to display if (searchResultItems.length < maxResults) { resultsLength = searchResultItems.length; @@ -290,11 +332,16 @@ define( //console.log('filtered searchResults (in Everything)', searchResults); return searchResults; + */ }); } return { - query: queryGeneric + query: queryGeneric, + + getLatest: function () { + return latestResults; + } }; } diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index 21763c5828..226780c073 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -55,6 +55,12 @@ model: data.model }); } + + var message = { + request: 'index', + results: undefined + }; + return message; } // Helper function for serach() @@ -123,7 +129,11 @@ console.log('webworker results', results); - return results; + var message = { + request: 'search', + results: results + }; + return message; // TODO: After a search is completed, do we need to // clear out indexedItems? From 1b5fbccc0649afb1725939cabb2445679c2145c6 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 11:17:45 -0700 Subject: [PATCH 082/195] [Search] Removed validType function Removed the validType function which previously was a paraemter to the search providers. It was no longer used, and is not necissary. --- .../features/search/src/SearchAggregator.js | 10 +------ .../providers/ElasticsearchSearchProvider.js | 30 ++++++------------- .../src/providers/GenericSearchProvider.js | 13 +------- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index f00c62fb01..0ac9190747 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -42,14 +42,6 @@ define( */ function SearchAggregator(providers) { - // Determines if a searchResult object is a valid type - // to be displayed as a final result. Is passed to the - // search providers as an argument. - function validType(model) { - // Nothing is currently disallowed - return true; - } - // Remove extra objects that have the same ID function filterRepeats(results) { var ids = [], @@ -161,7 +153,7 @@ define( for (var i = 0; i < providers.length; i += 1) { resultsPromises.push( providers[i].query( - inputID, validType, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT + inputID, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT ) ); } diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index c8eade24bb..da1a988c11 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -48,7 +48,6 @@ define( */ function ElasticsearchSearchProvider($http, objectService, ROOT) { // TODO: Fix the above docstring - var validType = function () {return true;}; // Check to see if the input has any special options function isDefaultFormat(searchTerm) { @@ -99,7 +98,7 @@ define( // Processes results from the format that elasticsearch returns to // a list of objects in the format that mct-representation can use - function processResults(rawResults, validType) { + function processResults(rawResults) { var results = rawResults.data.hits.hits, resultsLength = results.length, ids = [], @@ -130,15 +129,12 @@ define( // Include items we can get models for if (objects[id].getModel) { - // Check to see if they are allowed to be included - if (validType(objects[id].getModel())) { - // Format the results as searchResult objects - searchResults.push({ - id: id, - object: objects[id], - score: scores[id] - }); - } + // Format the results as searchResult objects + searchResults.push({ + id: id, + object: objects[id], + score: scores[id] + }); } } @@ -161,15 +157,12 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term - * @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 * @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 */ - function queryElasticsearch(inputID, passedValidType, maxResults, timeout) { + function queryElasticsearch(inputID, maxResults, timeout) { var searchTerm, esQuery; @@ -180,11 +173,6 @@ define( maxResults = DEFAULT_MAX_RESULTS; } - // Check to see if a valid type function was provided - if (passedValidType) { - validType = passedValidType; - } - // Get the user input searchTerm = document.getElementById(inputID).value; @@ -204,7 +192,7 @@ define( url: esQuery }).then(function (rawResults) { // ...then process the data - return processResults(rawResults, validType); + return processResults(rawResults); }); } diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index e0c809cba8..8fd0152dbe 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -44,8 +44,6 @@ define( * more easy creation of web workers. */ function GenericSearchProvider($rootScope, $timeout, objectService, workerService) { - var validType = function () {return true;}; - var worker = workerService.run('genericSearchWorker'), latestResults = []; @@ -263,15 +261,12 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term - * @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 * @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 */ - function queryGeneric(inputID, passedValidType, maxResults, timeout) { + function queryGeneric(inputID, maxResults, timeout) { var input, terms = [], searchResults = [], @@ -284,12 +279,6 @@ define( maxResults = DEFAULT_MAX_RESULTS; } - // Check to see if a valid type function was provided - if (passedValidType) { - validType = passedValidType; - } - - // Get the user input input = document.getElementById(inputID).value; From 4f4af87285efa44b8f376b9f746ecf8f73d682f1 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 12:34:08 -0700 Subject: [PATCH 083/195] [Search] Added timestamp to queries (Temporariliy removed the elasticsearch provider from bundle.json) Added a timestamp parameter to the query so that the aggregator can tell when the results were last updated. Created a separate function for getting the results list. GenericSearch now converts back from models to domain objects after the web worker does its work. --- platform/features/search/bundle.json | 6 - .../features/search/src/SearchAggregator.js | 35 +++- .../src/controllers/SearchController.js | 2 +- .../providers/ElasticsearchSearchProvider.js | 6 +- .../src/providers/GenericSearchProvider.js | 158 ++++-------------- .../search/src/workers/GenericSearchWorker.js | 3 +- 6 files changed, 64 insertions(+), 146 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index bc8497e291..47150db2c9 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -44,12 +44,6 @@ "implementation": "providers/GenericSearchProvider.js", "depends": [ "$rootScope", "$timeout", "objectService", "workerService" ] }, - { - "provides": "searchService", - "type": "provider", - "implementation": "providers/ElasticsearchSearchProvider.js", - "depends": [ "$http", "objectService", "ELASTIC_ROOT" ] - }, { "provides": "searchService", "type": "aggregator", diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 0ac9190747..42b16d7cf3 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -41,6 +41,7 @@ define( * aggregated */ function SearchAggregator(providers) { + var latestMergedResults = []; // Remove extra objects that have the same ID function filterRepeats(results) { @@ -138,37 +139,53 @@ define( } } - // Recieves results in the format of a serachResult object. It - // has the members id, object, and score. It has a function - // next() which returns the next highest score search result - // for that search. - // Calls the searches of each of the providers, then // merges the results lists so that there are not redundant // results - function mergeResults(inputID) { - var resultsPromises = []; + /** + * + */ + function queryAll(inputID) { + var resultsPromises = [], + date = new Date(), + timestamp = date.getTime(); // Get result list promises + // TODO: This is now 'Send the query to all the providers' for (var i = 0; i < providers.length; i += 1) { resultsPromises.push( providers[i].query( - inputID, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT + inputID, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT ) ); } + // TODO: Then we want to 'Get the latest results from all the providers' + // And then we might also want to check to see if the timestamp + // is correct. + + //var newerResults = []; + // Wait for the promises to fufill return getPromisedResults(resultsPromises, 0, []).then(function (c) { // Get rid of the repeated objects and put in correct order c = filterRepeats(c); c = orderByScore(c); + latestMergedResults = c; return c; }); } + // TODO: getLatestResults(start, stop) so you can choose which indicies to start and stop + // at, which will allow for 'load more' option + // may also need to include timestamp stuff in there + return { - query: mergeResults + sendQuery: queryAll, + getLatestResults: function (start, stop) { + // TODO: Make sure that slice handles out of bounds + return latestMergedResults.slice(start, stop); + } }; } diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 01e9708c19..78a1faab57 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -46,7 +46,7 @@ define(function () { // Will need to compile search result list (for this // result page) here, using pseudo linkedlist searchResult - searchService.query(inputID).then(function (c) { + searchService.sendQuery(inputID).then(function (c) { $scope.results = c; $scope.index = 0; page($scope.index, $scope.pageLength); diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index da1a988c11..599d388b9c 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -157,12 +157,16 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term + * @param timestamp the time at which this function was called, + * this timestamp will be associated with the latest results + * list, which allows the aggregator to see if it has been + * updated * @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 */ - function queryElasticsearch(inputID, maxResults, timeout) { + function queryElasticsearch(inputID, timestamp, maxResults, timeout) { var searchTerm, esQuery; diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 8fd0152dbe..d7edbec460 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -45,39 +45,8 @@ define( */ function GenericSearchProvider($rootScope, $timeout, objectService, workerService) { var worker = workerService.run('genericSearchWorker'), - latestResults = []; - - /* - 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; - } - */ + latestResults = [], + lastSearchTimestamp; // Tell the web worker to add a new item's model to its list of items. function indexItem(domainObject) { @@ -94,11 +63,12 @@ define( // 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, maxResults) { + function workerSearch(searchInput, maxResults, timestamp) { var message = { request: 'search', input: searchInput, - maxNumber: maxResults + maxNumber: maxResults, + timestamp: timestamp }; worker.postMessage(message); } @@ -106,17 +76,23 @@ define( worker.onmessage = handleResponse; function handleResponse(event) { - //latest = event.data; - console.log('handleResponse', event.data); if (event.data.request === 'search') { - latestResults = event.data.results; - console.log('updated latestResults', latestResults); + // Convert the ids given from the web worker into domain objects + var ids = []; + for (var i = 0; i < event.data.results.length; i++) { + ids.push(event.data.results[i].id); + } + objectService.getObjects(ids).then(function (objects) { + latestResults = []; + for (var i in objects) { + latestResults.push(objects[i]); + } + lastSearchTimestamp = event.data.timestamp; + console.log('updated latestResults', latestResults, 'with time', lastSearchTimestamp); + }); } // If the message was from 'index', we don't need to do anything - - //$rootScope.$apply(); - //requestNext(); } // Recursive helper function for getItems() @@ -164,90 +140,10 @@ define( } return; // We don't need to return anything anymore // TODO: Fix return statements. Do we need them still? - /* - // Turn them into searchResult objects (object, id, and score) - var searchResultItems = []; - - for (var i = 0; i < items.length; i += 1) { - // Test out calling worker indexItem - indexItem(items[i]); - - searchResultItems.push({ - id: items[i].getId(), - object: items[i], - score: 0 // Assign actual score when filtering for term - }); - } - - //console.log('searchResultItems (in Everything)', searchResultItems); - return searchResultItems; - */ }); }); } - /* - // Process the search input. Makes an array of search terms - // by splitting up the input at spaces. - function process(input) { - return input.toLocaleLowerCase().split(' '); - } - - // 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(), - 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; - } - - 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++; - - // 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; - } - } - } - - return score * weight; - } - - // Filter through a list of searchResults based on a search term - function filterResults(results, originalInput, resultsLength) { - var terms, - searchResults = [], - itemModel; - - // Split the original search input into search terms - terms = process(originalInput); - - for (var i = 0; i < resultsLength; i += 1) { - // Prevent errors from getModel not being defined - if (results[i].object.getModel) { - 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())) { - // Add the result to the result list - searchResults.push(results[i]); - } - } - } - - return searchResults; - } - */ - /** * Searches through the filetree for domain objects which match * the search term. This function is to be used as a fallback @@ -261,12 +157,16 @@ define( * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term + * @param timestamp the time at which this function was called, + * this timestamp will be associated with the latest results + * list, which allows the aggregator to see if it has been + * updated * @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 */ - function queryGeneric(inputID, maxResults, timeout) { + function queryGeneric(inputID, timestamp, maxResults, timeout) { var input, terms = [], searchResults = [], @@ -285,9 +185,11 @@ define( // Get items list //requestItems(); // Test out the worker return getItems(timeout).then(function (/*searchResultItems*/) { - var test = workerSearch(input, maxResults); - console.log('test', test); + workerSearch(input, maxResults, timestamp); + return; // There's nothing we need to return here + + /* // Wait for latestResults to be not empty, then return function wait(){ if (latestResults.length === 0){ @@ -301,10 +203,10 @@ define( } } console.log('about to wait'); - wait(); + return wait(); + */ + - console.log('returning (not)'); - //return test; /* // Keep track of the number of results to display if (searchResultItems.length < maxResults) { diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index 226780c073..334b446854 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -131,7 +131,8 @@ var message = { request: 'search', - results: results + results: results, + timestamp: data.timestamp }; return message; From a5febf8f0f88b2b42817eb488ffe3938e35a4c31 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 12:44:14 -0700 Subject: [PATCH 084/195] [Search] Removed paging Removed the paging from the search view, because later instead of paging there will be a 'view more' option. Also made the generic search provider return searchResult objects instead of raw domain objects. --- .../features/search/res/templates/search.html | 14 +---- .../src/controllers/SearchController.js | 51 ++----------------- .../src/providers/GenericSearchProvider.js | 8 ++- .../search/src/workers/GenericSearchWorker.js | 3 +- 4 files changed, 11 insertions(+), 65 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index d213422787..a9ab0bb6fc 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -42,22 +42,10 @@

    Results:

    -
    - - showing results {{ index+1 }} - {{ index + pageLength }} - of {{ results.length }} - -
    diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 78a1faab57..9f4a315716 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -29,16 +29,6 @@ define(function () { function SearchController($scope, searchService, objectService) { - $scope.pageLength = 16; - - function page(start, howMany) { - if (!howMany) { - howMany = $scope.pageLength; - } - - $scope.index = start; - $scope.page = $scope.results.slice(start, start + howMany); - } function search(inputID) { @@ -47,10 +37,10 @@ define(function () { // result page) here, using pseudo linkedlist searchResult searchService.sendQuery(inputID).then(function (c) { - $scope.results = c; - $scope.index = 0; - page($scope.index, $scope.pageLength); + //$scope.results = c; }); + $scope.results = searchService.getLatestResults(0, 5); + console.log('$scope results', $scope.results); } return { @@ -64,41 +54,6 @@ define(function () { } else { return false; } - }, - - // Check to see if there are enough results to be paging them - arePaging: function () { - return $scope.results.length > $scope.page.length; - }, - - // Check to see if are items such that we can go back a page - canGoBack: function () { - return $scope.index > 0; - }, - - // Check to see if are items such that we can go forward a page - canGoForward: function () { - return ($scope.index + $scope.pageLength) < $scope.results.length; - }, - - // Change the items in scope to be the ones in the next page - nextPage: function (howMany) { - if (!howMany) { - howMany = $scope.pageLength; - } - - $scope.index = $scope.index + howMany; - $scope.page = $scope.results.slice($scope.index, $scope.index + howMany); - }, - - // Change the items in scope to be the ones in the previous page - previousPage: function (howMany) { - if (!howMany) { - howMany = $scope.pageLength; - } - - $scope.index = $scope.index - howMany; - $scope.page = $scope.results.slice($scope.index, $scope.index + howMany); } }; } diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index d7edbec460..cb41cdf814 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -85,8 +85,12 @@ define( } objectService.getObjects(ids).then(function (objects) { latestResults = []; - for (var i in objects) { - latestResults.push(objects[i]); + for (var id in objects) { + latestResults.push({ + object: objects[id], + id: id + // TODO: Make the event.data.results able to get score from id + }); } lastSearchTimestamp = event.data.timestamp; console.log('updated latestResults', latestResults, 'with time', lastSearchTimestamp); diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index 334b446854..e74dd0a24a 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -57,8 +57,7 @@ } var message = { - request: 'index', - results: undefined + request: 'index' }; return message; } From f0f396f656297ae6c7f852ebf05ef6554b956971 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 12:59:52 -0700 Subject: [PATCH 085/195] [Search] Needs more updating The search aggregator now correctly gets from the providers, but because of not sync, the display is effectively one press behind the correct search results. Still, working to some extent. --- .../features/search/src/SearchAggregator.js | 29 +++++++++++++++---- .../src/controllers/SearchController.js | 4 +-- .../search/src/workers/GenericSearchWorker.js | 1 + 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 42b16d7cf3..6368848af8 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -126,6 +126,7 @@ define( return results; } + /* // 'Loop' over the promises using recursion so that the promises are fufilled by the // time that we are done function getPromisedResults(resultsPromises, promiseIndex, finalResults) { @@ -138,6 +139,23 @@ define( }); } } + */ + + function updateResults() { + var newerResults = []; + + // For each provider, get its most recent results + for (var i = 0; i < providers.length; i += 1) { + newerResults = newerResults.concat(providers[i].getLatest()); + } + + // Clean up + newerResults = filterRepeats(newerResults); + newerResults = orderByScore(newerResults); + + // After all that is done, now replace latestMergedResults with this + latestMergedResults = newerResults; + } // Calls the searches of each of the providers, then // merges the results lists so that there are not redundant @@ -146,14 +164,14 @@ define( * */ function queryAll(inputID) { - var resultsPromises = [], + var promises = [], date = new Date(), timestamp = date.getTime(); // Get result list promises // TODO: This is now 'Send the query to all the providers' for (var i = 0; i < providers.length; i += 1) { - resultsPromises.push( + promises.push( providers[i].query( inputID, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT ) @@ -163,17 +181,18 @@ define( // And then we might also want to check to see if the timestamp // is correct. - //var newerResults = []; - + updateResults(); + /* // Wait for the promises to fufill - return getPromisedResults(resultsPromises, 0, []).then(function (c) { + return getPromisedResults(promises, 0, []).then(function (c) { // Get rid of the repeated objects and put in correct order c = filterRepeats(c); c = orderByScore(c); latestMergedResults = c; return c; }); + */ } // TODO: getLatestResults(start, stop) so you can choose which indicies to start and stop diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 9f4a315716..cc07f05296 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -36,9 +36,9 @@ define(function () { // Will need to compile search result list (for this // result page) here, using pseudo linkedlist searchResult - searchService.sendQuery(inputID).then(function (c) { + searchService.sendQuery(inputID);/*.then(function (c) { //$scope.results = c; - }); + });*/ $scope.results = searchService.getLatestResults(0, 5); console.log('$scope results', $scope.results); } diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index e74dd0a24a..8caa9263ac 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -143,6 +143,7 @@ self.onmessage = function (event) { console.log('webworker onmessage'); if (event.data.request === 'index') { + // TODO: Don't really need to post here. self.postMessage(index(event.data)); } else if (event.data.request === 'search') { self.postMessage(search(event.data)); From 41c38f202d3ede91b16dc082438d146d6e6b054f Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 13:04:03 -0700 Subject: [PATCH 086/195] [Search] Comments Removed extra commented out code. --- .../features/search/src/SearchAggregator.js | 57 +------------------ .../src/providers/GenericSearchProvider.js | 41 +------------ 2 files changed, 4 insertions(+), 94 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 6368848af8..10b40fe408 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -85,23 +85,6 @@ define( } return filteredResults; - /* - var ids = []; - - for (var i = 0; i < results.length; i += 1) { - if (ids.indexOf(results[i].id) !== -1) { - // If this result's ID is already there, remove the object - results.splice(i, 1); - // Reduce loop index because we shortened the array - i -= 1; - } else { - // Otherwise add the ID to the list of the ones we have seen - ids.push(results[i].id); - } - } - - return results; - */ } // Order the objects from highest to lowest score in the array @@ -117,30 +100,9 @@ define( } }); - /* - for (var i = 0; i < results.length; i++) { - console.log('score', results[i].score, 'for', results[i].object.getModel().name); - } - */ - return results; } - /* - // 'Loop' over the promises using recursion so that the promises are fufilled by the - // time that we are done - function getPromisedResults(resultsPromises, promiseIndex, finalResults) { - if (promiseIndex >= resultsPromises.length) { - return finalResults; - } else { - return resultsPromises[promiseIndex].then(function (results) { - finalResults = finalResults.concat(results); - return getPromisedResults(resultsPromises, promiseIndex + 1, finalResults); - }); - } - } - */ - function updateResults() { var newerResults = []; @@ -168,8 +130,7 @@ define( date = new Date(), timestamp = date.getTime(); - // Get result list promises - // TODO: This is now 'Send the query to all the providers' + // Send the query to all the providers for (var i = 0; i < providers.length; i += 1) { promises.push( providers[i].query( @@ -181,24 +142,10 @@ define( // And then we might also want to check to see if the timestamp // is correct. + // Update the merged results list updateResults(); - - /* - // Wait for the promises to fufill - return getPromisedResults(promises, 0, []).then(function (c) { - // Get rid of the repeated objects and put in correct order - c = filterRepeats(c); - c = orderByScore(c); - latestMergedResults = c; - return c; - }); - */ } - // TODO: getLatestResults(start, stop) so you can choose which indicies to start and stop - // at, which will allow for 'load more' option - // may also need to include timestamp stuff in there - return { sendQuery: queryAll, getLatestResults: function (start, stop) { diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index cb41cdf814..f2a33f4416 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -187,47 +187,10 @@ define( input = document.getElementById(inputID).value; // Get items list - //requestItems(); // Test out the worker - return getItems(timeout).then(function (/*searchResultItems*/) { - + return getItems(timeout).then(function () { + // Then get the worker to search through it workerSearch(input, maxResults, timestamp); return; // There's nothing we need to return here - - /* - // Wait for latestResults to be not empty, then return - function wait(){ - if (latestResults.length === 0){ - console.log('waiting'); - console.log('latestResults', latestResults); - $timeout(wait, 100); - } else { - console.log('done waiting'); - //test = latestResults; - return latestResults; - } - } - console.log('about to wait'); - return wait(); - */ - - - /* - // Keep track of the number of results to display - if (searchResultItems.length < maxResults) { - resultsLength = searchResultItems.length; - } else { - resultsLength = maxResults; - } - - // Test out calling the web worker search - workerSearch(input, maxResults); - - // Then filter through the items list - searchResults = filterResults(searchResultItems, input, resultsLength); - - //console.log('filtered searchResults (in Everything)', searchResults); - return searchResults; - */ }); } From 5a93e5a2bcf0e0aa5370b45dd3fa1c67a3109828 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 14:23:44 -0700 Subject: [PATCH 087/195] [Search] Correct search updating The search controller now updates the display results list, then repeatedly asks the aggregator to update until the timestamps all are at least as new as the one that the controller originally gave for the query. Basically, the search now updates correctly without having to press enter again. --- platform/features/search/bundle.json | 2 +- .../features/search/res/templates/search.html | 2 +- .../features/search/src/SearchAggregator.js | 48 ++++++++++++------- .../src/controllers/SearchController.js | 34 +++++++++---- .../src/providers/GenericSearchProvider.js | 10 ++-- .../search/src/workers/GenericSearchWorker.js | 19 +++++--- 6 files changed, 77 insertions(+), 38 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 47150db2c9..f5df8bce26 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -15,7 +15,7 @@ { "key": "SearchController", "implementation": "controllers/SearchController.js", - "depends": [ "$scope", "searchService", "objectService" ] + "depends": [ "$scope", "$timeout", "searchService" ] }, { "key": "SearchbarController", diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index a9ab0bb6fc..f6b730a8c3 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -31,7 +31,7 @@ value="" ng-keyup="controller.search('searchinput')" style="width: 66%"/> - +
    diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 10b40fe408..76cc606093 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -41,7 +41,8 @@ define( * aggregated */ function SearchAggregator(providers) { - var latestMergedResults = []; + var latestMergedResults = [], + lastMergeTimestamps = []; // Remove extra objects that have the same ID function filterRepeats(results) { @@ -104,11 +105,13 @@ define( } function updateResults() { - var newerResults = []; + var newerResults = [], + providerTimestamps = []; // For each provider, get its most recent results for (var i = 0; i < providers.length; i += 1) { - newerResults = newerResults.concat(providers[i].getLatest()); + newerResults = newerResults.concat(providers[i].getLatestResults()); + providerTimestamps.push(providers[i].getLatestTimestamp()); } // Clean up @@ -117,27 +120,32 @@ define( // After all that is done, now replace latestMergedResults with this latestMergedResults = newerResults; + lastMergeTimestamps = providerTimestamps; } - // Calls the searches of each of the providers, then - // merges the results lists so that there are not redundant - // results /** - * + * Sends a query to each of the providers, then updates the globl + * latestMergedResults accordingly. + * + * @param inputID The name of the ID property of the html text + * input where this funcion should find the search term. + * @param timestamp (optional) The time at which this function + * was called. This timestamp will be associated with the + * latest results list, which allows us to see if it has been + * updated. If not provided, this aggregator will. */ - function queryAll(inputID) { - var promises = [], - date = new Date(), + function queryAll(inputID, timestamp) { + // If there's not a timestamp, make this time the timestamp + if (!timestamp) { + var date = new Date(); timestamp = date.getTime(); + } // Send the query to all the providers for (var i = 0; i < providers.length; i += 1) { - promises.push( - providers[i].query( - inputID, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT - ) - ); + providers[i].query(inputID, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT); } + // TODO: Then we want to 'Get the latest results from all the providers' // And then we might also want to check to see if the timestamp // is correct. @@ -148,9 +156,17 @@ define( return { sendQuery: queryAll, + updateResults: updateResults, getLatestResults: function (start, stop) { // TODO: Make sure that slice handles out of bounds - return latestMergedResults.slice(start, stop); + // By default if there are no start or stop provided, will return + // the entire thing. + var a = latestMergedResults.slice(start, stop); + return a; + }, + getLatestTimestamps: function () { + var b = lastMergeTimestamps; + return b; } }; } diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index cc07f05296..1b16bb2ce2 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -28,19 +28,35 @@ define(function () { "use strict"; - function SearchController($scope, searchService, objectService) { + function SearchController($scope, $timeout, searchService) { function search(inputID) { + var date = new Date(), + timestamp = date.getTime(), + numResults = 20; - // Later, the search result format will be different - // Will need to compile search result list (for this - // result page) here, using pseudo linkedlist searchResult + // Send the query + searchService.sendQuery(inputID, timestamp); - searchService.sendQuery(inputID);/*.then(function (c) { - //$scope.results = c; - });*/ - $scope.results = searchService.getLatestResults(0, 5); - console.log('$scope results', $scope.results); + // Get the results + $scope.results = searchService.getLatestResults(0, numResults); + + // Check to make sure that these results are the latest ones + function waitForLatest() { + var timestamps = searchService.getLatestTimestamps(), + areOld = timestamps.some(function(c) {return c < timestamp;}); + // If any of the timestamps are older than the one we made the query with + if (areOld) { + // Then wait and try to update again + searchService.updateResults(); + var latest = searchService.getLatestResults(0, numResults); + $timeout(waitForLatest, 100); + } else { + // We got the latest results now + $scope.results = searchService.getLatestResults(0, numResults); + } + } + waitForLatest(); } return { diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index f2a33f4416..95adc8e158 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -46,7 +46,7 @@ define( function GenericSearchProvider($rootScope, $timeout, objectService, workerService) { var worker = workerService.run('genericSearchWorker'), latestResults = [], - lastSearchTimestamp; + lastSearchTimestamp = 0; // Tell the web worker to add a new item's model to its list of items. function indexItem(domainObject) { @@ -76,7 +76,6 @@ define( worker.onmessage = handleResponse; function handleResponse(event) { - console.log('handleResponse', event.data); if (event.data.request === 'search') { // Convert the ids given from the web worker into domain objects var ids = []; @@ -93,7 +92,6 @@ define( }); } lastSearchTimestamp = event.data.timestamp; - console.log('updated latestResults', latestResults, 'with time', lastSearchTimestamp); }); } // If the message was from 'index', we don't need to do anything @@ -197,8 +195,12 @@ define( return { query: queryGeneric, - getLatest: function () { + getLatestResults: function () { return latestResults; + }, + + getLatestTimestamp: function () { + return lastSearchTimestamp; } }; } diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index 8caa9263ac..a1170fb74b 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -44,7 +44,6 @@ function index(data) { // Takes an object model // Add to indexedItems - console.log('webworker index', data); // TODO: Since this is only within genericsearch, do // we really need to check if the index already holds it? @@ -64,7 +63,18 @@ // Helper function for serach() function convertToTerms(input) { - return input.split(' '); + var terms = input; + // Shave any spaces off of the ends of the input + while (terms.substr(0, 1) === ' ') { + terms = terms.substring(1, terms.length); + } + while (terms.substr(terms.length - 1, 1) === ' ') { + terms = terms.substring(0, terms.length - 1); + } + // Then split it at the spaces + terms = terms.split(' '); + console.log('terms', terms); + return terms; } // Helper function for search() @@ -103,8 +113,6 @@ // Takes a search input and the number of items to find // Converts it into search terms // Gets matches from indexedItems - console.log('webworker search', data); - console.log('webworker indexedItems', indexedItems); // This results array will hold objects which are composed of // the object's id, model, and score. (The score is wrt only this @@ -126,8 +134,6 @@ } } - console.log('webworker results', results); - var message = { request: 'search', results: results, @@ -141,7 +147,6 @@ } self.onmessage = function (event) { - console.log('webworker onmessage'); if (event.data.request === 'index') { // TODO: Don't really need to post here. self.postMessage(index(event.data)); From 7934e8d42594bf60b2456e5d5b50c1b7a775db68 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 14:55:44 -0700 Subject: [PATCH 088/195] [Search] Changed worker result implementation The interface remains the same, but the web worker returns a pseudo dictionary (actually an object) after being told the search. The key value pairs for this dictionary are ids and scores. --- .../src/providers/GenericSearchProvider.js | 18 +++++----- .../search/src/workers/GenericSearchWorker.js | 35 +++++++++++-------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 95adc8e158..e1e7b1577e 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -79,16 +79,16 @@ define( if (event.data.request === 'search') { // Convert the ids given from the web worker into domain objects var ids = []; - for (var i = 0; i < event.data.results.length; i++) { - ids.push(event.data.results[i].id); + for (var id in event.data.results) { + ids.push(id); } objectService.getObjects(ids).then(function (objects) { latestResults = []; for (var id in objects) { latestResults.push({ object: objects[id], - id: id - // TODO: Make the event.data.results able to get score from id + id: id, + score: event.data.results[id].score }); } lastSearchTimestamp = event.data.timestamp; @@ -152,10 +152,12 @@ define( * 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. + * * 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). + * * Scores are higher for matches that have more than one of + * the terms as substrings. + * * Wildcards are not (yet?) supported. * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index a1170fb74b..a1d99f9f3c 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -21,6 +21,9 @@ *****************************************************************************/ /*global self*/ +/** + * Module defining GenericSearchWorker. Created by shale on 07/21/2015. + */ (function () { "use strict"; @@ -39,12 +42,13 @@ } /** + * Indexes an item to indexedItems. * + * @param data An object which contains: + * * model: The model of the domain object + * * id: The ID of the domain object */ function index(data) { - // Takes an object model - // Add to indexedItems - // TODO: Since this is only within genericsearch, do // we really need to check if the index already holds it? // This might depend on how often/when we clear indexedItems. @@ -107,18 +111,20 @@ } /** + * Gets search results from the indexedItems based on provided search + * input. Returns matching results from indexedItems, as well as the + * timestamp that was passed to it. * + * @param data An object which contains: + * * input: The original string which we are searching with + * * maxNumber: The maximum number of search results desired + * * timestamp: The time identifier from when the query was made */ function search(data) { - // Takes a search input and the number of items to find - // Converts it into search terms - // Gets matches from indexedItems - - // This results array will hold objects which are composed of - // the object's id, model, and score. (The score is wrt only this + // This results 'dictionary' will have domain object ID keys which + // point to the domain object's score. (The score is wrt only this // specific search input.) - // TODO: It may be unnecissary for results to have models in it. - var results = [], + var results = {}, input = data.input.toLocaleLowerCase(), terms = convertToTerms(input), timesToLoop = Math.min(indexedItems.length, data.maxNumber); @@ -126,11 +132,10 @@ for (var i = 0; i < timesToLoop; i++) { var score = scoreItem(indexedItems[i], input, terms); if (score > 0) { - results.push({ - id: indexedItems[i].id, - model: indexedItems[i].model, + results[indexedItems[i].id] = { score: score - }); + }; + console.log(results[indexedItems[i].id]); } } From 416bd8258929f2f6127ff6e50d65034042d41c42 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 15:04:50 -0700 Subject: [PATCH 089/195] [Search] Cleanup Removed a couple of unnecissary things, and fixed up the comments. --- platform/features/search/bundle.json | 2 +- platform/features/search/src/SearchAggregator.js | 4 ---- .../src/providers/ElasticsearchSearchProvider.js | 15 +++++++-------- .../search/src/providers/GenericSearchProvider.js | 3 +-- .../search/src/workers/GenericSearchWorker.js | 4 ++-- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index f5df8bce26..908741b183 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -42,7 +42,7 @@ "provides": "searchService", "type": "provider", "implementation": "providers/GenericSearchProvider.js", - "depends": [ "$rootScope", "$timeout", "objectService", "workerService" ] + "depends": [ "$rootScope", "objectService", "workerService" ] }, { "provides": "searchService", diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 76cc606093..501c972420 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -146,10 +146,6 @@ define( providers[i].query(inputID, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT); } - // TODO: Then we want to 'Get the latest results from all the providers' - // And then we might also want to check to see if the timestamp - // is correct. - // Update the merged results list updateResults(); } diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 599d388b9c..c6a71e240b 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -36,18 +36,17 @@ define( DEFAULT_MAX_RESULTS = 100; /** - * A model service which reads domain object models from an external - * persistence service. + * A search service which searches through domain objects in + * the filetree using ElasticSearch. * * @constructor - * @param {PersistenceService} persistenceService the service in which - * domain object models are persisted. - * @param $q Angular's $q service, for working with promises - * @param {string} SPACE the name of the persistence space from which - * models should be retrieved. + * @param $http Angular's $http service, for working with urls + * @param {ObjectService} objectService the service from which + * domain objects can be gotten. + * @param ROOT the constant ELASTIC_ROOT which allows us to + * interact with ElasticSearch. */ function ElasticsearchSearchProvider($http, objectService, ROOT) { - // TODO: Fix the above docstring // Check to see if the input has any special options function isDefaultFormat(searchTerm) { diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index e1e7b1577e..9a148c5d80 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -43,7 +43,7 @@ define( * @param {WorkerService} workerService the service which allows * more easy creation of web workers. */ - function GenericSearchProvider($rootScope, $timeout, objectService, workerService) { + function GenericSearchProvider($rootScope, objectService, workerService) { var worker = workerService.run('genericSearchWorker'), latestResults = [], lastSearchTimestamp = 0; @@ -94,7 +94,6 @@ define( lastSearchTimestamp = event.data.timestamp; }); } - // If the message was from 'index', we don't need to do anything } // Recursive helper function for getItems() diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index a1d99f9f3c..7c5c7cab12 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -75,6 +75,7 @@ while (terms.substr(terms.length - 1, 1) === ' ') { terms = terms.substring(0, terms.length - 1); } + // Then split it at the spaces terms = terms.split(' '); console.log('terms', terms); @@ -153,8 +154,7 @@ self.onmessage = function (event) { if (event.data.request === 'index') { - // TODO: Don't really need to post here. - self.postMessage(index(event.data)); + index(event.data); } else if (event.data.request === 'search') { self.postMessage(search(event.data)); } From 92df11acc194dbe1a067193fd3ff5590eb0690f7 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 15:14:07 -0700 Subject: [PATCH 090/195] [Search] Readded ElasticSearch provider Previously had removed the elasticsearch provider from bundle.json so could work on the generic search web worker. Now have modified the elasticsearch provider to match the new interface with the aggregator, and it works. At this point, search is 'working' --- platform/features/search/bundle.json | 6 +++++ .../providers/ElasticsearchSearchProvider.js | 22 ++++++++++++++----- .../search/src/workers/GenericSearchWorker.js | 2 -- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 908741b183..fd01c28a12 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -44,6 +44,12 @@ "implementation": "providers/GenericSearchProvider.js", "depends": [ "$rootScope", "objectService", "workerService" ] }, + { + "provides": "searchService", + "type": "provider", + "implementation": "providers/ElasticsearchSearchProvider.js", + "depends": [ "$http", "objectService", "ELASTIC_ROOT" ] + }, { "provides": "searchService", "type": "aggregator", diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index c6a71e240b..14da8b3029 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -40,13 +40,15 @@ define( * the filetree using ElasticSearch. * * @constructor - * @param $http Angular's $http service, for working with urls + * @param $http Angular's $http service, for working with urls. * @param {ObjectService} objectService the service from which * domain objects can be gotten. * @param ROOT the constant ELASTIC_ROOT which allows us to * interact with ElasticSearch. */ function ElasticsearchSearchProvider($http, objectService, ROOT) { + var latestResults = [], + lastSearchTimestamp = 0; // Check to see if the input has any special options function isDefaultFormat(searchTerm) { @@ -97,7 +99,7 @@ define( // Processes results from the format that elasticsearch returns to // a list of objects in the format that mct-representation can use - function processResults(rawResults) { + function processResults(rawResults, timestamp) { var results = rawResults.data.hits.hits, resultsLength = results.length, ids = [], @@ -122,7 +124,6 @@ define( // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { - // Filter by search term for (var j = 0; j < resultsLength; j += 1) { var id = ids[j]; @@ -137,7 +138,8 @@ define( } } - //console.log('searchResults (in ES provider)', searchResults); + latestResults = searchResults; + lastSearchTimestamp = timestamp; return searchResults; }); } @@ -195,12 +197,20 @@ define( url: esQuery }).then(function (rawResults) { // ...then process the data - return processResults(rawResults); + return processResults(rawResults, timestamp); }); } return { - query: queryElasticsearch + query: queryElasticsearch, + + getLatestResults: function () { + return latestResults; + }, + + getLatestTimestamp: function () { + return lastSearchTimestamp; + } }; } diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index 7c5c7cab12..336c2e1222 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -78,7 +78,6 @@ // Then split it at the spaces terms = terms.split(' '); - console.log('terms', terms); return terms; } @@ -136,7 +135,6 @@ results[indexedItems[i].id] = { score: score }; - console.log(results[indexedItems[i].id]); } } From 4191bc1ac3bb17c12aa713cd054864f767c25b33 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 15:31:23 -0700 Subject: [PATCH 091/195] [Search] Comments Updated the documentation. --- .../features/search/src/SearchAggregator.js | 53 +++++++++++------ .../src/controllers/SearchController.js | 12 +++- .../providers/ElasticsearchSearchProvider.js | 55 ++++++++++-------- .../src/providers/GenericSearchProvider.js | 57 +++++++++++-------- 4 files changed, 111 insertions(+), 66 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 501c972420..86bb8fe372 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -44,7 +44,7 @@ define( var latestMergedResults = [], lastMergeTimestamps = []; - // Remove extra objects that have the same ID + // Remove duplicate objects that have the same ID function filterRepeats(results) { var ids = [], idToIndicies = {}, // 'dictionary' mapping IDs to a list of indicies @@ -104,6 +104,7 @@ define( return results; } + // For documentation, see updateResults below. function updateResults() { var newerResults = [], providerTimestamps = []; @@ -123,17 +124,7 @@ define( lastMergeTimestamps = providerTimestamps; } - /** - * Sends a query to each of the providers, then updates the globl - * latestMergedResults accordingly. - * - * @param inputID The name of the ID property of the html text - * input where this funcion should find the search term. - * @param timestamp (optional) The time at which this function - * was called. This timestamp will be associated with the - * latest results list, which allows us to see if it has been - * updated. If not provided, this aggregator will. - */ + // For documentation, see sendQuery below. function queryAll(inputID, timestamp) { // If there's not a timestamp, make this time the timestamp if (!timestamp) { @@ -151,18 +142,48 @@ define( } return { + /** + * Sends a query to each of the providers, then updates the global + * latestMergedResults accordingly. + * + * @param inputID The name of the ID property of the html text + * input where this funcion should find the search term. + * @param timestamp (optional) The time at which this function + * was called. This timestamp will be associated with the + * latest results list, which allows us to see if it has been + * updated. If not provided, this aggregator will. + */ sendQuery: queryAll, + + /** + * Updates the global latestMergedResults and lastMergeTimestamps + * by checking the latest results of each of the providers. + */ updateResults: updateResults, + + /** + * Get the latest search results that have been calculated. The + * format of the returned objects are searchResult objects, which + * have the members id, object, and score. + * + * @param start (optional) The index of latestMergedResults at + * which to start getting results. + * @param stop (optional) The index of latestMergedResults at + * which to stop getting results. + */ getLatestResults: function (start, stop) { // TODO: Make sure that slice handles out of bounds // By default if there are no start or stop provided, will return // the entire thing. - var a = latestMergedResults.slice(start, stop); - return a; + return latestMergedResults.slice(start, stop); }, + + /** + * Get the timestamps for each of the provider's last controbutions + * to the latestMergedResults. + */ getLatestTimestamps: function () { - var b = lastMergeTimestamps; - return b; + return lastMergeTimestamps; } }; } diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 1b16bb2ce2..0892c400bc 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -49,7 +49,6 @@ define(function () { if (areOld) { // Then wait and try to update again searchService.updateResults(); - var latest = searchService.getLatestResults(0, numResults); $timeout(waitForLatest, 100); } else { // We got the latest results now @@ -60,10 +59,17 @@ define(function () { } return { - // Search the database using the user input of id "searchinput" + /** + * Search the filetree. + * + * @param inputID The name of the ID property of the html text + * input where this funcion should find the search term. + */ search: search, - // Check to see if there are any search results to display. + /** + * Checks to see if there are any search results to display. + */ areResults: function () { if ($scope.results) { return $scope.results.length > 0; diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 14da8b3029..f34941023d 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -144,29 +144,7 @@ define( }); } - /** - * Searches through the filetree for domain objects using a search - * term. This is done through querying elasticsearch. - * Notes: - * * The order of the results is from highest to lowest score, - * as elsaticsearch determines them to be. - * * Wildcards are supported. - * * Fuzziness is used to produce more results that are still - * relevant. (All results within a certain edit distance.) - * * More search details at - * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html - * - * @param inputID the name of the ID property of the html text - * input where this funcion should find the search term - * @param timestamp the time at which this function was called, - * this timestamp will be associated with the latest results - * list, which allows the aggregator to see if it has been - * updated - * @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 - */ + // For documentation, see query below. function queryElasticsearch(inputID, timestamp, maxResults, timeout) { var searchTerm, esQuery; @@ -202,12 +180,43 @@ define( } return { + /** + * Searches through the filetree for domain objects using a search + * term. This is done through querying elasticsearch. + * Notes: + * * The order of the results is from highest to lowest score, + * as elsaticsearch determines them to be. + * * Wildcards are supported. + * * Fuzziness is used to produce more results that are still + * relevant. (All results within a certain edit distance.) + * * More search details at + * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html + * + * @param inputID the name of the ID property of the html text + * input where this funcion should find the search term + * @param timestamp the time at which this function was called, + * this timestamp will be associated with the latest results + * list, which allows the aggregator to see if it has been + * updated + * @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 + */ query: queryElasticsearch, + /** + * Get the latest search results that have been calculated. The + * format of the returned objects are searchResult objects, which + * have the members id, object, and score. + */ getLatestResults: function () { return latestResults; }, + /** + * Get the timestamp for the last update of latestResults. + */ getLatestTimestamp: function () { return lastSearchTimestamp; } diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 9a148c5d80..04e2ff65b5 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -145,30 +145,7 @@ define( }); } - /** - * 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 input if - * the object's name property contains any of the search terms - * (which are generated by splitting the input at spaces). - * * Scores are higher for matches that have more than one of - * the terms as substrings. - * * Wildcards are not (yet?) supported. - * - * @param inputID the name of the ID property of the html text - * input where this funcion should find the search term - * @param timestamp the time at which this function was called, - * this timestamp will be associated with the latest results - * list, which allows the aggregator to see if it has been - * updated - * @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 - */ + // For documentation, see query below. function queryGeneric(inputID, timestamp, maxResults, timeout) { var input, terms = [], @@ -194,12 +171,44 @@ define( } return { + /** + * 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 input if + * the object's name property contains any of the search terms + * (which are generated by splitting the input at spaces). + * * Scores are higher for matches that have more than one of + * the terms as substrings. + * * Wildcards are not (yet?) supported. + * + * @param inputID the name of the ID property of the html text + * input where this funcion should find the search term + * @param timestamp the time at which this function was called, + * this timestamp will be associated with the latest results + * list, which allows the aggregator to see if it has been + * updated + * @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 + */ query: queryGeneric, + /** + * Get the latest search results that have been calculated. The + * format of the returned objects are searchResult objects, which + * have the members id, object, and score. + */ getLatestResults: function () { return latestResults; }, + /** + * Get the timestamp for the last update of latestResults. + */ getLatestTimestamp: function () { return lastSearchTimestamp; } From 5f30249065e260a11cab14e271165bbe28b8e3e4 Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 15:49:54 -0700 Subject: [PATCH 092/195] [Search] Load more option Made the search view have a 'Load more' button. Added functionalty to allow this to happen. --- .../features/search/res/templates/search.html | 5 +++ .../features/search/src/SearchAggregator.js | 8 ++++ .../src/controllers/SearchController.js | 42 +++++++++++++++---- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index f6b730a8c3..b6e5d47a27 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -42,6 +42,11 @@

    Results:

    +
    + +
    Date: Tue, 21 Jul 2015 16:10:35 -0700 Subject: [PATCH 093/195] [Search] Added wildcards to generic Added wildcard support to the generic search provider. In this case, wildcards behave just like spaces. --- .../search/src/controllers/SearchController.js | 2 +- .../src/providers/ElasticsearchSearchProvider.js | 1 - .../search/src/providers/GenericSearchProvider.js | 1 - .../features/search/src/workers/GenericSearchWorker.js | 10 ++++++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 74aad0b464..34104c5aa0 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -27,7 +27,7 @@ define(function () { "use strict"; - var INITIAL_LOAD_NUMBER = 5, + var INITIAL_LOAD_NUMBER = 20, LOAD_INCREMENT = 5; function SearchController($scope, $timeout, searchService) { diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index f34941023d..427e44ebf6 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -186,7 +186,6 @@ define( * Notes: * * The order of the results is from highest to lowest score, * as elsaticsearch determines them to be. - * * Wildcards are supported. * * Fuzziness is used to produce more results that are still * relevant. (All results within a certain edit distance.) * * More search details at diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 04e2ff65b5..c478bbaaf1 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -182,7 +182,6 @@ define( * (which are generated by splitting the input at spaces). * * Scores are higher for matches that have more than one of * the terms as substrings. - * * Wildcards are not (yet?) supported. * * @param inputID the name of the ID property of the html text * input where this funcion should find the search term diff --git a/platform/features/search/src/workers/GenericSearchWorker.js b/platform/features/search/src/workers/GenericSearchWorker.js index 336c2e1222..5674ce9ac4 100644 --- a/platform/features/search/src/workers/GenericSearchWorker.js +++ b/platform/features/search/src/workers/GenericSearchWorker.js @@ -76,8 +76,14 @@ terms = terms.substring(0, terms.length - 1); } - // Then split it at the spaces - terms = terms.split(' '); + // Then split it at spaces and asterisks + terms = terms.split(/ |\*/); + + // Remove any empty strings from the terms + while (terms.indexOf('') !== -1) { + terms.splice(terms.indexOf(''), 1); + } + return terms; } From b5f8e6d90c97a3608e041f957ade0001356c395a Mon Sep 17 00:00:00 2001 From: shale Date: Tue, 21 Jul 2015 16:21:23 -0700 Subject: [PATCH 094/195] [Search] Updating searchbar Updating the searchbar to be again more similar to the search view. It now has a 'load more' button, but it is not clickable for some reason. In progress. --- .../commonUI/browse/res/templates/browse.html | 4 +- platform/features/search/bundle.json | 2 +- .../search/res/templates/searchbar.html | 7 ++ .../src/controllers/SearchbarController.js | 74 +++++++++++++++++-- 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index f2f0d4baa5..aa4816a882 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -28,11 +28,11 @@ > - +
    + + +
    + +
    \ No newline at end of file diff --git a/platform/features/search/src/controllers/SearchbarController.js b/platform/features/search/src/controllers/SearchbarController.js index 1a48a9c793..5fa81793a5 100644 --- a/platform/features/search/src/controllers/SearchbarController.js +++ b/platform/features/search/src/controllers/SearchbarController.js @@ -27,23 +27,81 @@ define(function () { "use strict"; - function SearchbarController($scope, searchService) { + var INITIAL_LOAD_NUMBER = 20, + LOAD_INCREMENT = 5; + + function SearchbarController($scope, $timeout, searchService) { + // Starting amount of results to load. Will get increased. + var numResults = INITIAL_LOAD_NUMBER; + + function update(timestamp) { + // Get the results + $scope.results = searchService.getLatestResults(0, numResults); + + // Check to make sure that these results are the latest ones + function waitForLatest() { + var timestamps = searchService.getLatestTimestamps(), + areOld = timestamps.some(function(c) {return c < timestamp;}); + // If any of the timestamps are older than the one we made the query with + if (areOld) { + // Then wait and try to update again + searchService.updateResults(); + $timeout(waitForLatest, 100); + } else { + // We got the latest results now + $scope.results = searchService.getLatestResults(0, numResults); + } + } + waitForLatest(); + } + + function search(inputID) { + var date = new Date(), + timestamp = date.getTime(); + + // Reset 'load more' + numResults = INITIAL_LOAD_NUMBER; + + // Send the query + searchService.sendQuery(inputID, timestamp); + + update(timestamp); + } return { - // Search the database using the user input of id "searchinput" - search: function (inputID) { - searchService.query(inputID).then(function (c) { - $scope.results = c; - }); - }, + /** + * Search the filetree. + * + * @param inputID The name of the ID property of the html text + * input where this funcion should find the search term. + */ + search: search, - // Check to see if there are any search results to display. + /** + * Checks to see if there are any search results to display. + */ areResults: function () { if ($scope.results) { return $scope.results.length > 0; } else { return false; } + }, + + /** + * Checks to see if there are more search results to display. + */ + areMore: function () { + return numResults < searchService.getNumResults(); + }, + + /** + * Increases the number of search results to display, and then + * load them. + */ + loadMore: function () { + numResults += LOAD_INCREMENT; + update(); } }; } From bcc1e2e26fc19e337e981151ce49f053741ca545 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 10:38:56 -0700 Subject: [PATCH 095/195] [Search] Starting front-end Starting to modify the front-end so that the searchbar appears in the tree view area. Made the tree holder have relative position so that the searchbar is visibile for now. (Later will be different.) --- .../general/res/css/theme-espresso.css | 45 +++-- platform/commonUI/general/res/sass/_main.scss | 1 + .../general/res/sass/search/_layout.scss | 37 +++++ .../general/res/sass/search/_search.scss | 156 ++++++++++++++++++ 4 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 platform/commonUI/general/res/sass/search/_layout.scss create mode 100644 platform/commonUI/general/res/sass/search/_search.scss diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index e3bbcd7448..2ce1f1780a 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -92,7 +92,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 5, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, @@ -113,38 +113,38 @@ time, mark, audio, video { font-size: 100%; vertical-align: baseline; } -/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 22, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html { line-height: 1; } -/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 24, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ ol, ul { list-style: none; } -/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 26, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ table { border-collapse: collapse; border-spacing: 0; } -/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 28, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } -/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 30, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q, blockquote { quotes: none; } - /* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ + /* line 103, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } -/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 32, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ a img { border: none; } -/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 116, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } @@ -675,10 +675,35 @@ mct-container { .split-layout.vertical > .pane:first-child .holder { right: 3px; } -/* line 284, ../sass/user-environ/_layout.scss */ +/* line 286, ../sass/user-environ/_layout.scss */ .vscroll { overflow-y: auto; } +/***************************************************************************** + * 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. + *****************************************************************************/ +/* line 27, ../sass/search/_layout.scss */ +.split-layout.vertical > .pane:first-child .holder { + position: relative; } + /***************************************************************************** * Open MCT Web, Copyright (c) 2014-2015, United States Government * as represented by the Administrator of the National Aeronautics and Space diff --git a/platform/commonUI/general/res/sass/_main.scss b/platform/commonUI/general/res/sass/_main.scss index d56c55aca5..06eb0c2e7a 100644 --- a/platform/commonUI/general/res/sass/_main.scss +++ b/platform/commonUI/general/res/sass/_main.scss @@ -31,6 +31,7 @@ @import "global"; @import "fonts"; @import "user-environ/layout"; +@import "search/layout"; @import "fixed-position"; @import "about"; @import "text"; diff --git a/platform/commonUI/general/res/sass/search/_layout.scss b/platform/commonUI/general/res/sass/search/_layout.scss new file mode 100644 index 0000000000..795c3e6627 --- /dev/null +++ b/platform/commonUI/general/res/sass/search/_layout.scss @@ -0,0 +1,37 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +.split-layout { + &.vertical { + >.pane { + &:first-child { + .holder { + // Want tree holder to dissapear when search is activated. + // Currently though, just have the tree holder position + // relative to search. + position: relative; + } + } + } + + } +} diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss new file mode 100644 index 0000000000..b4f54ac8b6 --- /dev/null +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -0,0 +1,156 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +ul.searchbar { + @include menuUlReset(); + li { + display: block; + position: relative; + span.searchbar-item { + $runningItemW: 0; + @include border-radius($basicCr); + @include single-transition(background-color, 0.25s); + display: block; + font-size: 0.8em; + height: $menuLineH; + line-height: $menuLineH; + margin-bottom: $interiorMarginSm; + position: relative; +/* + .view-control { + display: inline-block; + margin-left: $interiorMargin; + font-size: 0.75em; + width: $treeVCW; + $runningItemW: $interiorMargin + $treeVCW; + &:hover { + color: $colorItemTreeVCHover; + } + } +*/ + + .label { + display: block; + @include absPosDefault(); + left: $runningItemW; + + .type-icon { + @include absPosDefault(0, false); + @include txtShdwSubtle(0.6); + color: $colorItemTreeIcon; + left: $interiorMargin; + right: auto; width: 1em; + + .icon { + &.l-icon-link, + &.l-icon-alert { + @include txtShdwSubtle(1); + position: absolute; + z-index: 2; + } + &.l-icon-alert { + $d: 8px; + @include ancillaryIcon($d, $colorAlert); + top: 1px; + right: -2px; + } + &.l-icon-link { + $d: 8px; + @include ancillaryIcon($d, $colorIconLink); + left: -3px; + bottom: 5px; + + } + } + } + .title-label { + @include absPosDefault(); + display: block; + left: $runningItemW + ($interiorMargin * 3); + //right: $treeContextTriggerW + $interiorMargin; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + &.loading { + pointer-events: none; + .label { + opacity: 0.5; + .title-label { + font-style: italic; + } + } + .wait-spinner { + margin-left: 14px; + } + } + + &.selected { + $c: #fff; + background: $colorKeySelectedBg; + color: $c; + .view-control { + color: $colorItemTreeIcon; + } + .label .type-icon { + color: #fff; //$colorItemTreeIconHover; + } + } + + &:not(.selected) { + &:hover { + background: lighten($colorBodyBg, 5%); + color: lighten($colorBodyFg, 20%); + .context-trigger { + display: block; + } + .icon { + color: $colorItemTreeIconHover; + } + } + } + + &:not(.loading) { + cursor: pointer; + } + + .context-trigger { + $h: 0.9rem; + //display: none; + top: -1px; + position: absolute; + right: $interiorMarginSm; + .invoke-menu { + font-size: 0.75em; + height: $h; + line-height: $h; + } + } + } + } + + ul.tree { + margin-left: $treeVCW + $interiorMargin; + } +} \ No newline at end of file From ff3770c9ee1960a953de984408208274597b5919 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 11:21:14 -0700 Subject: [PATCH 096/195] [Search] Added css classes Added classes to the HTML so that CSS and Sass could get access to style the searchbar items. The structure for styling is now mostly set up. --- .../general/res/css/theme-espresso.css | 2 +- platform/commonUI/general/res/css/tree.css | 34 +++++ .../general/res/sass/search/_search.scss | 143 ++---------------- platform/commonUI/general/res/sass/tree.scss | 3 +- .../search/res/templates/searchbar-item.html | 2 +- .../search/res/templates/searchbar.html | 5 +- 6 files changed, 54 insertions(+), 135 deletions(-) diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index 2ce1f1780a..08446c1b32 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -675,7 +675,7 @@ mct-container { .split-layout.vertical > .pane:first-child .holder { right: 3px; } -/* line 286, ../sass/user-environ/_layout.scss */ +/* line 284, ../sass/user-environ/_layout.scss */ .vscroll { overflow-y: auto; } diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index f45504233e..9c1f7cb78b 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -249,3 +249,37 @@ ul.tree { /* line 154, ../sass/tree/_tree.scss */ ul.tree ul.tree { margin-left: 15px; } + +/***************************************************************************** + * 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. + *****************************************************************************/ +/* line 23, ../sass/search/_search.scss */ +span.searchbar { + color: #ff0099; } + /* line 26, ../sass/search/_search.scss */ + span.searchbar .results { + color: #ff0000; } + /* line 31, ../sass/search/_search.scss */ + span.searchbar .results .searchbar-item { + color: #aa00ff; } + /* line 34, ../sass/search/_search.scss */ + span.searchbar .results .searchbar-item .label { + color: #00aa00; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index b4f54ac8b6..2903285ba9 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -20,137 +20,20 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -ul.searchbar { - @include menuUlReset(); - li { - display: block; - position: relative; - span.searchbar-item { - $runningItemW: 0; - @include border-radius($basicCr); - @include single-transition(background-color, 0.25s); - display: block; - font-size: 0.8em; - height: $menuLineH; - line-height: $menuLineH; - margin-bottom: $interiorMarginSm; - position: relative; -/* - .view-control { - display: inline-block; - margin-left: $interiorMargin; - font-size: 0.75em; - width: $treeVCW; - $runningItemW: $interiorMargin + $treeVCW; - &:hover { - color: $colorItemTreeVCHover; - } - } -*/ +span.searchbar { + color: #ff0099; + //@include menuUlReset(); + .results { + //display: block; + //position: relative; + color: #ff0000; + + .searchbar-item { + color: #aa00ff; - .label { - display: block; - @include absPosDefault(); - left: $runningItemW; - - .type-icon { - @include absPosDefault(0, false); - @include txtShdwSubtle(0.6); - color: $colorItemTreeIcon; - left: $interiorMargin; - right: auto; width: 1em; - - .icon { - &.l-icon-link, - &.l-icon-alert { - @include txtShdwSubtle(1); - position: absolute; - z-index: 2; - } - &.l-icon-alert { - $d: 8px; - @include ancillaryIcon($d, $colorAlert); - top: 1px; - right: -2px; - } - &.l-icon-link { - $d: 8px; - @include ancillaryIcon($d, $colorIconLink); - left: -3px; - bottom: 5px; - - } - } - } - .title-label { - @include absPosDefault(); - display: block; - left: $runningItemW + ($interiorMargin * 3); - //right: $treeContextTriggerW + $interiorMargin; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } - - &.loading { - pointer-events: none; - .label { - opacity: 0.5; - .title-label { - font-style: italic; - } - } - .wait-spinner { - margin-left: 14px; - } - } - - &.selected { - $c: #fff; - background: $colorKeySelectedBg; - color: $c; - .view-control { - color: $colorItemTreeIcon; - } - .label .type-icon { - color: #fff; //$colorItemTreeIconHover; - } - } - - &:not(.selected) { - &:hover { - background: lighten($colorBodyBg, 5%); - color: lighten($colorBodyFg, 20%); - .context-trigger { - display: block; - } - .icon { - color: $colorItemTreeIconHover; - } - } - } - - &:not(.loading) { - cursor: pointer; - } - - .context-trigger { - $h: 0.9rem; - //display: none; - top: -1px; - position: absolute; - right: $interiorMarginSm; - .invoke-menu { - font-size: 0.75em; - height: $h; - line-height: $h; - } - } + .label { + color: #00aa00; // Good up to here. + } } } - - ul.tree { - margin-left: $treeVCW + $interiorMargin; - } } \ No newline at end of file diff --git a/platform/commonUI/general/res/sass/tree.scss b/platform/commonUI/general/res/sass/tree.scss index b8b2d09124..82b2338f30 100644 --- a/platform/commonUI/general/res/sass/tree.scss +++ b/platform/commonUI/general/res/sass/tree.scss @@ -27,4 +27,5 @@ @import "constants"; @import "mixins"; -@import "tree/tree"; \ No newline at end of file +@import "tree/tree"; +@import "search/search"; \ No newline at end of file diff --git a/platform/features/search/res/templates/searchbar-item.html b/platform/features/search/res/templates/searchbar-item.html index f865a7b64d..e2d04dcc91 100644 --- a/platform/features/search/res/templates/searchbar-item.html +++ b/platform/features/search/res/templates/searchbar-item.html @@ -20,7 +20,7 @@ at runtime from the About dialog for additional information. --> -
    +
    - +
    -
    +
    From ab3d3ec45b608cae502f63bff12dc34726521825 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 11:48:13 -0700 Subject: [PATCH 097/195] [Search] Overflow text Overflow text on the search item labels is now hidden, with ellipses. New problem: Text is on a different line than the icon. --- platform/commonUI/general/res/css/tree.css | 11 +++++++++-- .../general/res/sass/search/_search.scss | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 9c1f7cb78b..21d4de5e92 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -279,7 +279,14 @@ span.searchbar { color: #ff0000; } /* line 31, ../sass/search/_search.scss */ span.searchbar .results .searchbar-item { - color: #aa00ff; } - /* line 34, ../sass/search/_search.scss */ + color: #8800ff; } + /* line 35, ../sass/search/_search.scss */ span.searchbar .results .searchbar-item .label { color: #00aa00; } + /* line 38, ../sass/search/_search.scss */ + span.searchbar .results .searchbar-item .label .title-label { + color: #aa00aa; + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index 2903285ba9..917317aaa7 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -29,10 +29,23 @@ span.searchbar { color: #ff0000; .searchbar-item { - color: #aa00ff; + $runningItemW: 0; + color: #8800ff; .label { - color: #00aa00; // Good up to here. + color: #00aa00; + + .title-label { + color: #aa00aa; + + //@include absPosDefault(); + display: block; + //left: $runningItemW + ($interiorMargin * 3); + //left: 60px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } } } From 3ae681c79c5ffeb6b63073d08c34e05b252f078e Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 12:33:16 -0700 Subject: [PATCH 098/195] [Search] Colors and positioning Corrected the colors back to the normal style. Also made the text on the same line as the icon, but this fix is a temporary one. --- platform/commonUI/general/res/css/tree.css | 36 +++++++++---------- .../general/res/sass/search/_search.scss | 36 ++++++++++++------- .../search/res/templates/searchbar.html | 9 ++--- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 21d4de5e92..a1372825a9 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -271,22 +271,20 @@ ul.tree { * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 23, ../sass/search/_search.scss */ -span.searchbar { - color: #ff0099; } - /* line 26, ../sass/search/_search.scss */ - span.searchbar .results { - color: #ff0000; } - /* line 31, ../sass/search/_search.scss */ - span.searchbar .results .searchbar-item { - color: #8800ff; } - /* line 35, ../sass/search/_search.scss */ - span.searchbar .results .searchbar-item .label { - color: #00aa00; } - /* line 38, ../sass/search/_search.scss */ - span.searchbar .results .searchbar-item .label .title-label { - color: #aa00aa; - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } +/* line 27, ../sass/search/_search.scss */ +span.search-holder .searchbar { + width: 100%; + margin-top: 20px; } +/* line 44, ../sass/search/_search.scss */ +span.search-holder .results .searchbar-item .label .title-label { + position: relative; + left: 20px; + top: -17px; + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } +/* line 58, ../sass/search/_search.scss */ +span.search-holder .load-more-button { + width: 100%; + margin-top: 20px; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index 917317aaa7..a6d0b64672 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -20,28 +20,33 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -span.searchbar { - color: #ff0099; - //@include menuUlReset(); +span.search-holder { + $iconwidth: 20px; + $iconheight: 17px; + + .searchbar { + width: 100%; + margin-top: 20px; + } + .results { - //display: block; - //position: relative; - color: #ff0000; .searchbar-item { - $runningItemW: 0; - color: #8800ff; + //margin-top: 5px; .label { - color: #00aa00; + + .type-icon { + .icon { + } + } .title-label { - color: #aa00aa; + position: relative; + left: $iconwidth; + top: -$iconheight; - //@include absPosDefault(); display: block; - //left: $runningItemW + ($interiorMargin * 3); - //left: 60px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -49,4 +54,9 @@ span.searchbar { } } } + + .load-more-button { + width: 100%; + margin-top: 20px; + } } \ No newline at end of file diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html index 0ed0a5f016..76cdaf3cae 100644 --- a/platform/features/search/res/templates/searchbar.html +++ b/platform/features/search/res/templates/searchbar.html @@ -19,14 +19,14 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> -
    -
    @@ -40,7 +40,8 @@
    -
    From dcd400601775ef3e68d2f8f71ef37d0e9435829e Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 13:38:57 -0700 Subject: [PATCH 099/195] [Search] Positioning fixed Fixed the search results so that they now display correctly, with overflow hidden, and no unusual positioning. Also changed font size to 0.8em. --- platform/commonUI/general/res/css/tree.css | 30 ++++++++++++------- .../general/res/sass/search/_search.scss | 21 ++++++++----- .../search/res/templates/searchbar-item.html | 2 +- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index a1372825a9..51a3d70880 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -275,16 +275,24 @@ ul.tree { span.search-holder .searchbar { width: 100%; margin-top: 20px; } -/* line 44, ../sass/search/_search.scss */ -span.search-holder .results .searchbar-item .label .title-label { - position: relative; - left: 20px; - top: -17px; - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } -/* line 58, ../sass/search/_search.scss */ +/* line 32, ../sass/search/_search.scss */ +span.search-holder .results { + margin-top: 10px; } + /* line 35, ../sass/search/_search.scss */ + span.search-holder .results .search-result-item { + margin-bottom: 5px; } + /* line 45, ../sass/search/_search.scss */ + span.search-holder .results .search-result-item .label .title-label { + display: inline-block; + position: absolute; + width: auto; + left: 20px; + right: 0; + font-size: .8em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } +/* line 63, ../sass/search/_search.scss */ span.search-holder .load-more-button { width: 100%; - margin-top: 20px; } + margin-top: 5px; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index a6d0b64672..9a99038395 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -22,7 +22,7 @@ span.search-holder { $iconwidth: 20px; - $iconheight: 17px; + //$iconheight: 17px; .searchbar { width: 100%; @@ -30,9 +30,10 @@ span.search-holder { } .results { + margin-top: 10px; - .searchbar-item { - //margin-top: 5px; + .search-result-item { + margin-bottom: 5px; .label { @@ -42,11 +43,15 @@ span.search-holder { } .title-label { - position: relative; - left: $iconwidth; - top: -$iconheight; + display: inline-block; + position: absolute; + + width: auto; + left: $iconwidth; + right: 0; + + font-size: .8em; - display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -57,6 +62,6 @@ span.search-holder { .load-more-button { width: 100%; - margin-top: 20px; + margin-top: 5px; } } \ No newline at end of file diff --git a/platform/features/search/res/templates/searchbar-item.html b/platform/features/search/res/templates/searchbar-item.html index e2d04dcc91..b626f8ae41 100644 --- a/platform/features/search/res/templates/searchbar-item.html +++ b/platform/features/search/res/templates/searchbar-item.html @@ -20,7 +20,7 @@ at runtime from the About dialog for additional information. --> -
    +
    Date: Wed, 22 Jul 2015 13:46:40 -0700 Subject: [PATCH 100/195] [Search] Removed Search View Removed the search view from bundle.json because the search in the left panel is the actualy UI for searching. The search view is temporary. --- platform/features/search/bundle.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index bb1ae81806..0158a3534f 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -2,21 +2,7 @@ "name": "Search View", "description": "Allows the user to search through the file tree.", "extensions": { - "views": [ - { - "key": "search", - "name": "Search", - "glyph": "5", - "description": "Search functionality.", - "templateUrl": "templates/search.html" - } - ], "controllers": [ - { - "key": "SearchController", - "implementation": "controllers/SearchController.js", - "depends": [ "$scope", "$timeout", "searchService" ] - }, { "key": "SearchbarController", "implementation": "controllers/SearchbarController.js", From d82538a799f1d6b83a05ead3a60adbfd494f6946 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 14:48:14 -0700 Subject: [PATCH 101/195] [Search] Item background highlight Each result item now has a highlighted background, with correct rounding of edges. Need to now detect when to highlight (on selection). --- platform/commonUI/general/res/css/tree.css | 49 ++++---- .../general/res/sass/search/_search.scss | 15 ++- platform/features/search/bundle.json | 10 ++ .../search/res/templates/searchbar-item.html | 64 ++++++----- .../controllers/SearchbarItemController.js | 105 ++++++++++++++++++ .../src/controllers/ToggleController.js | 66 +++++++++++ 6 files changed, 256 insertions(+), 53 deletions(-) create mode 100644 platform/features/search/src/controllers/SearchbarItemController.js create mode 100644 platform/features/search/src/controllers/ToggleController.js diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 51a3d70880..bd7d170e32 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -271,28 +271,37 @@ ul.tree { * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 27, ../sass/search/_search.scss */ -span.search-holder .searchbar { +/* line 28, ../sass/search/_search.scss */ +.search-holder .searchbar { width: 100%; margin-top: 20px; } -/* line 32, ../sass/search/_search.scss */ -span.search-holder .results { +/* line 33, ../sass/search/_search.scss */ +.search-holder .results { margin-top: 10px; } - /* line 35, ../sass/search/_search.scss */ - span.search-holder .results .search-result-item { - margin-bottom: 5px; } - /* line 45, ../sass/search/_search.scss */ - span.search-holder .results .search-result-item .label .title-label { - display: inline-block; - position: absolute; - width: auto; - left: 20px; - right: 0; - font-size: .8em; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } -/* line 63, ../sass/search/_search.scss */ -span.search-holder .load-more-button { + /* line 36, ../sass/search/_search.scss */ + .search-holder .results .search-result-item { + margin-bottom: 5px; + background: #005177; + border-radius: 2px; + padding-top: 2px; + padding-bottom: 1px; } + /* line 43, ../sass/search/_search.scss */ + .search-holder .results .search-result-item .label { + left: 15px; + margin-left: 8px; } + /* line 53, ../sass/search/_search.scss */ + .search-holder .results .search-result-item .label .title-label { + display: inline-block; + position: absolute; + width: auto; + left: 31px; + right: 0; + font-size: .8em; + line-height: 17px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } +/* line 72, ../sass/search/_search.scss */ +.search-holder .load-more-button { width: 100%; margin-top: 5px; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index 9a99038395..a4623556b5 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -20,9 +20,10 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -span.search-holder { - $iconwidth: 20px; +.search-holder { + $iconWidth: 20px; //$iconheight: 17px; + $leftMargin: 8px; .searchbar { width: 100%; @@ -34,8 +35,15 @@ span.search-holder { .search-result-item { margin-bottom: 5px; + background: $colorKeySelectedBg; // Later make this apply to only certain ones + border-radius: 2px; + padding-top: 2px; + padding-bottom: 1px; .label { + //position: absolute; + left: 15px; + margin-left: $leftMargin; .type-icon { .icon { @@ -47,10 +55,11 @@ span.search-holder { position: absolute; width: auto; - left: $iconwidth; + left: $leftMargin + 3px + $iconWidth; right: 0; font-size: .8em; + line-height: 17px; overflow: hidden; text-overflow: ellipsis; diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 0158a3534f..c7fe967012 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -7,6 +7,16 @@ "key": "SearchbarController", "implementation": "controllers/SearchbarController.js", "depends": [ "$scope", "$timeout", "searchService" ] + }, + { + "key": "SearchbarItemController", + "implementation": "controllers/SearchbarItemController.js", + "depends": [ "$scope" ] + }, + { + "key": "ToggleController", + "implementation": "controllers/ToggleController.js", + "depends": [ ] } ], "templates": [ diff --git a/platform/features/search/res/templates/searchbar-item.html b/platform/features/search/res/templates/searchbar-item.html index b626f8ae41..9ef432e35a 100644 --- a/platform/features/search/res/templates/searchbar-item.html +++ b/platform/features/search/res/templates/searchbar-item.html @@ -20,36 +20,40 @@ at runtime from the About dialog for additional information. --> -
    - - - - -
    \ No newline at end of file + +
    + \ No newline at end of file diff --git a/platform/features/search/src/controllers/SearchbarItemController.js b/platform/features/search/src/controllers/SearchbarItemController.js new file mode 100644 index 0000000000..3d47384773 --- /dev/null +++ b/platform/features/search/src/controllers/SearchbarItemController.js @@ -0,0 +1,105 @@ +/***************************************************************************** + * 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*/ + +/** + * Module defining SearchbarItemController. Based on TreeNodeController. + * Created by shale on 07/22/2015. + */ +define(function () { + "use strict"; + + function SearchbarItemController($scope) { + var selectedObject = ($scope.ngModel || {}).selectedObject, + isSelected = false; + + // Consider the currently-navigated object and update + // parameters which support display. + function checkSelection() { + var nodeObject = $scope.domainObject, + navObject = selectedObject, + nodeContext = nodeObject && + nodeObject.getCapability('context'), + navContext = navObject && + navObject.getCapability('context'), + nodePath, + navPath; + + // Deselect; we will reselect below, iff we are + // exactly at the end of the path. + isSelected = false; + + // Expand if necessary (if the navigated object will + // be in this node's subtree) + if (nodeContext && navContext) { + // Get the paths as arrays of identifiers + nodePath = nodeContext.getPath().map(getId); + navPath = navContext.getPath().map(getId); + + // Check to see if the node's path lies entirely + // within the navigation path; otherwise, navigation + // has happened in some other subtree. + if (navPath.length >= nodePath.length && + checkPath(nodePath, navPath)) { + + // nodePath is along the navPath; if it's + // at the end of the path, highlight; + // otherwise, expand. + if (nodePath.length === navPath.length) { + isSelected = true; + } else { // node path is shorter: Expand! + if ($scope.toggle) { + $scope.toggle.setState(true); + } + trackExpansion(); + } + + } + } + } + + // Callback for the selection updates; track the currently + // navigated object and update display parameters as needed. + function setSelection(object) { + selectedObject = object; + checkSelection(); + } + + // Listen for changes which will effect display parameters + $scope.$watch("ngModel.selectedObject", setSelection); + $scope.$watch("domainObject", checkSelection); + + return { + /** + * Check whether or not the domain object represented by + * this tree node should be highlighted. + * An object will be highlighted if it matches + * ngModel.selectedObject + * @returns true if this should be highlighted + */ + isSelected: function () { + return isSelected; + } + }; + } + return SearchbarItemController; +}); diff --git a/platform/features/search/src/controllers/ToggleController.js b/platform/features/search/src/controllers/ToggleController.js new file mode 100644 index 0000000000..0d3bd664ca --- /dev/null +++ b/platform/features/search/src/controllers/ToggleController.js @@ -0,0 +1,66 @@ +/***************************************************************************** + * 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,Promise*/ + +define( + [], + function () { + "use strict"; + + /** + * A ToggleController is used to activate/deactivate things. + * A common usage is for "twistie" + * + * @constructor + */ + function ToggleController() { + var state = false; + + return { + /** + * Get the current state of the toggle. + * @return {boolean} true if active + */ + isActive: function () { + return state; + }, + /** + * Set a new state for the toggle. + * @return {boolean} true to activate + */ + setState: function (newState) { + state = newState; + }, + /** + * Toggle the current state; activate if it is inactive, + * deactivate if it is active. + */ + toggle: function () { + state = !state; + } + }; + + } + + return ToggleController; + } +); \ No newline at end of file From 1dbe039be8b43f1390d0926e3d395ace39851bf7 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 15:15:50 -0700 Subject: [PATCH 102/195] [Search] Load more button style Styled the load more button to match the general theme. --- platform/commonUI/general/res/css/tree.css | 24 +++++++++++-------- .../general/res/sass/search/_search.scss | 12 ++++++---- .../search/res/templates/searchbar.html | 2 +- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index bd7d170e32..f3c5ba6fbf 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -271,37 +271,41 @@ ul.tree { * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 28, ../sass/search/_search.scss */ +/* line 27, ../sass/search/_search.scss */ .search-holder .searchbar { width: 100%; margin-top: 20px; } -/* line 33, ../sass/search/_search.scss */ +/* line 32, ../sass/search/_search.scss */ .search-holder .results { margin-top: 10px; } - /* line 36, ../sass/search/_search.scss */ + /* line 35, ../sass/search/_search.scss */ .search-holder .results .search-result-item { margin-bottom: 5px; background: #005177; border-radius: 2px; padding-top: 2px; padding-bottom: 1px; } - /* line 43, ../sass/search/_search.scss */ + /* line 42, ../sass/search/_search.scss */ .search-holder .results .search-result-item .label { left: 15px; - margin-left: 8px; } - /* line 53, ../sass/search/_search.scss */ + margin-left: 6px; } + /* line 51, ../sass/search/_search.scss */ .search-holder .results .search-result-item .label .title-label { display: inline-block; position: absolute; width: auto; - left: 31px; + left: 29px; right: 0; font-size: .8em; line-height: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -/* line 72, ../sass/search/_search.scss */ +/* line 70, ../sass/search/_search.scss */ .search-holder .load-more-button { - width: 100%; - margin-top: 5px; } + margin-top: 5px; + position: relative; + left: 25%; + height: 20px; + line-height: 11px; + font-size: 0.7em; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index a4623556b5..097b500934 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -22,8 +22,7 @@ .search-holder { $iconWidth: 20px; - //$iconheight: 17px; - $leftMargin: 8px; + $leftMargin: 6px; .searchbar { width: 100%; @@ -41,7 +40,6 @@ padding-bottom: 1px; .label { - //position: absolute; left: 15px; margin-left: $leftMargin; @@ -70,7 +68,13 @@ } .load-more-button { - width: 100%; margin-top: 5px; + + position: relative; + left: 25%; + + height: 20px; + line-height: 11px; + font-size: 0.7em; } } \ No newline at end of file diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html index 76cdaf3cae..1c432a6646 100644 --- a/platform/features/search/res/templates/searchbar.html +++ b/platform/features/search/res/templates/searchbar.html @@ -40,7 +40,7 @@
    - From b16af5fe3e2ed4fde82af26305efa84d0d9b5b46 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 15:43:28 -0700 Subject: [PATCH 103/195] [Search] Renaming search and searchbar Changed what was previously just 'search' and renamed to 'search view'. Then, took what was previously 'searchbar' and renamed to 'search'. --- .../commonUI/browse/res/templates/browse.html | 4 +- platform/commonUI/general/res/css/tree.css | 12 ++--- .../general/res/sass/search/_search.scss | 2 +- platform/features/search/bundle.json | 16 +++--- .../{searchbar-item.html => search-item.html} | 2 +- .../{searchbar.html => search-view.html} | 49 +++++++++++-------- .../features/search/res/templates/search.html | 49 ++++++++----------- .../src/controllers/SearchController.js | 2 +- ...mController.js => SearchItemController.js} | 0 ...rController.js => SearchViewController.js} | 6 +-- 10 files changed, 71 insertions(+), 71 deletions(-) rename platform/features/search/res/templates/{searchbar-item.html => search-item.html} (96%) rename platform/features/search/res/templates/{searchbar.html => search-view.html} (57%) rename platform/features/search/src/controllers/{SearchbarItemController.js => SearchItemController.js} (100%) rename platform/features/search/src/controllers/{SearchbarController.js => SearchViewController.js} (95%) diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index aa4816a882..992e851bee 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -28,8 +28,8 @@ > -
    - +
    diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index f3c5ba6fbf..35c1b1d17e 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -272,25 +272,25 @@ ul.tree { * at runtime from the About dialog for additional information. *****************************************************************************/ /* line 27, ../sass/search/_search.scss */ -.search-holder .searchbar { +.search .searchbar { width: 100%; margin-top: 20px; } /* line 32, ../sass/search/_search.scss */ -.search-holder .results { +.search .results { margin-top: 10px; } /* line 35, ../sass/search/_search.scss */ - .search-holder .results .search-result-item { + .search .results .search-result-item { margin-bottom: 5px; background: #005177; border-radius: 2px; padding-top: 2px; padding-bottom: 1px; } /* line 42, ../sass/search/_search.scss */ - .search-holder .results .search-result-item .label { + .search .results .search-result-item .label { left: 15px; margin-left: 6px; } /* line 51, ../sass/search/_search.scss */ - .search-holder .results .search-result-item .label .title-label { + .search .results .search-result-item .label .title-label { display: inline-block; position: absolute; width: auto; @@ -302,7 +302,7 @@ ul.tree { text-overflow: ellipsis; white-space: nowrap; } /* line 70, ../sass/search/_search.scss */ -.search-holder .load-more-button { +.search .load-more-button { margin-top: 5px; position: relative; left: 25%; diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index 097b500934..bee4f0fc2f 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -.search-holder { +.search { $iconWidth: 20px; $leftMargin: 6px; diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index c7fe967012..fed5f05e9d 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -4,13 +4,13 @@ "extensions": { "controllers": [ { - "key": "SearchbarController", - "implementation": "controllers/SearchbarController.js", + "key": "SearchController", + "implementation": "controllers/SearchController.js", "depends": [ "$scope", "$timeout", "searchService" ] }, { - "key": "SearchbarItemController", - "implementation": "controllers/SearchbarItemController.js", + "key": "SearchItemController", + "implementation": "controllers/SearchItemController.js", "depends": [ "$scope" ] }, { @@ -21,15 +21,15 @@ ], "templates": [ { - "key": "searchbar", - "templateUrl": "templates/searchbar.html", + "key": "search", + "templateUrl": "templates/search.html", "uses": [ "composition" ] } ], "representations": [ { - "key": "searchbar-item", - "templateUrl": "templates/searchbar-item.html", + "key": "search-item", + "templateUrl": "templates/search-item.html", "uses": [ "composition" ] } ], diff --git a/platform/features/search/res/templates/searchbar-item.html b/platform/features/search/res/templates/search-item.html similarity index 96% rename from platform/features/search/res/templates/searchbar-item.html rename to platform/features/search/res/templates/search-item.html index 9ef432e35a..9640efc19c 100644 --- a/platform/features/search/res/templates/searchbar-item.html +++ b/platform/features/search/res/templates/search-item.html @@ -22,7 +22,7 @@
    + ng-controller="SearchItemController as controller"> - - + +
    + +
    - Search:
    + + ng-keyup="controller.search('searchinput')" + style="width: 66%"/>
    + +
    + -
    - +
    +

    + Results: +

    +
    + +
    +
    +
    +
    - - -
    - -
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index b6e5d47a27..7201f2d9af 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -19,39 +19,30 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> - -
    - - + +
    -
    Search:
    - + ng-keyup="controller.search('searchbarinput')" />
    - -
    - -
    -

    - Results: -

    -
    - -
    -
    -
    - +
    +
    -
    \ No newline at end of file + + +
    + +
    +
    \ No newline at end of file diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 34104c5aa0..c84ac34143 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -22,7 +22,7 @@ /*global define*/ /** - * Module defining SearchController. Created by shale on 07/08/2015. + * Module defining SearchController. Created by shale on 07/15/2015. */ define(function () { "use strict"; diff --git a/platform/features/search/src/controllers/SearchbarItemController.js b/platform/features/search/src/controllers/SearchItemController.js similarity index 100% rename from platform/features/search/src/controllers/SearchbarItemController.js rename to platform/features/search/src/controllers/SearchItemController.js diff --git a/platform/features/search/src/controllers/SearchbarController.js b/platform/features/search/src/controllers/SearchViewController.js similarity index 95% rename from platform/features/search/src/controllers/SearchbarController.js rename to platform/features/search/src/controllers/SearchViewController.js index 5fa81793a5..e4ed78f301 100644 --- a/platform/features/search/src/controllers/SearchbarController.js +++ b/platform/features/search/src/controllers/SearchViewController.js @@ -22,7 +22,7 @@ /*global define*/ /** - * Module defining SearchbarController. Created by shale on 07/15/2015. + * Module defining SearchViewController. Created by shale on 07/08/2015. */ define(function () { "use strict"; @@ -30,7 +30,7 @@ define(function () { var INITIAL_LOAD_NUMBER = 20, LOAD_INCREMENT = 5; - function SearchbarController($scope, $timeout, searchService) { + function SearchViewController($scope, $timeout, searchService) { // Starting amount of results to load. Will get increased. var numResults = INITIAL_LOAD_NUMBER; @@ -105,5 +105,5 @@ define(function () { } }; } - return SearchbarController; + return SearchViewController; }); From b0e7dca98549c2b38e680c12c4e39510d963e802 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 16:09:14 -0700 Subject: [PATCH 104/195] [Search] Empty search resets results When there is no input into the search bar no results are displayed/displayed results are removed. This is because the search providers were changed to return empty arrays for empty search strings. --- platform/commonUI/general/res/css/tree.css | 4 +- .../general/res/sass/search/_search.scss | 4 +- .../features/search/res/templates/search.html | 2 +- .../providers/ElasticsearchSearchProvider.js | 41 +++++++++++-------- .../search/src/workers/GenericSearchWorker.js | 16 +++++--- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 35c1b1d17e..d7e6e0fc84 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -272,9 +272,9 @@ ul.tree { * at runtime from the About dialog for additional information. *****************************************************************************/ /* line 27, ../sass/search/_search.scss */ -.search .searchbar { +.search .search-input { width: 100%; - margin-top: 20px; } + margin-top: 10px; } /* line 32, ../sass/search/_search.scss */ .search .results { margin-top: 10px; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index bee4f0fc2f..c2153b54d7 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -24,9 +24,9 @@ $iconWidth: 20px; $leftMargin: 6px; - .searchbar { + .search-input { width: 100%; - margin-top: 20px; + margin-top: 10px; } .results { diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 7201f2d9af..1577730044 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -23,7 +23,7 @@ ng-controller="SearchController as controller">
    - 0) { - results[indexedItems[i].id] = { - score: score - }; + + // If the user input is empty, we want to have no search results. + if (input !== '') { + for (var i = 0; i < timesToLoop; i++) { + var score = scoreItem(indexedItems[i], input, terms); + if (score > 0) { + results[indexedItems[i].id] = { + score: score + }; + } } } From 8f1f4eb177b365398f24a7dcf8d0b10a58c2b0ad Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 16:21:34 -0700 Subject: [PATCH 105/195] [Search] Generic search gets all roots Generic search now automatically finds all the roots before searching. --- platform/features/search/bundle.json | 2 +- .../src/providers/GenericSearchProvider.js | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index fed5f05e9d..2faf40d4cb 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -38,7 +38,7 @@ "provides": "searchService", "type": "provider", "implementation": "providers/GenericSearchProvider.js", - "depends": [ "$rootScope", "objectService", "workerService" ] + "depends": [ "$rootScope", "objectService", "workerService", "roots[]" ] }, { "provides": "searchService", diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index c478bbaaf1..1b5a1ef520 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -43,7 +43,7 @@ define( * @param {WorkerService} workerService the service which allows * more easy creation of web workers. */ - function GenericSearchProvider($rootScope, objectService, workerService) { + function GenericSearchProvider($rootScope, objectService, workerService, roots) { var worker = workerService.run('genericSearchWorker'), latestResults = [], lastSearchTimestamp = 0; @@ -120,9 +120,15 @@ define( // Converts the filetree into a list function getItems(timeout) { - // Aquire My Items (root folder) - return objectService.getObjects(['mine']).then(function (objects) { - // Get all of its descendents + var rootIds = []; + + for (var i = 0; i < roots.length; i++) { + rootIds.push(roots[i].id); + } + + // Aquire root objects + return objectService.getObjects(rootIds).then(function (objectsById) { + var objects = []; if (timeout) { // Set a timeout for itemsHelper @@ -132,7 +138,13 @@ define( // If there was no timeout provided, leave undefined // itemsHelper should just treat this as having no timeout - return itemsHelper([objects.mine], 0).then(function (items) { + // Convert to the format itemsHelper takes + for (var id in objectsById) { + objects.push(objectsById[id]); + } + + // Get all of its descendents + return itemsHelper(objects, 0).then(function (items) { // Add each item that itemsHelper found to the web worker index // TODO: Try to do this within itemsHelper. Perhaps just // need to add this to the last two if statements? From 501e426868c2246de997a5d60cc654fb7c20a8d9 Mon Sep 17 00:00:00 2001 From: shale Date: Wed, 22 Jul 2015 16:35:41 -0700 Subject: [PATCH 106/195] [Search] Centered load more button More correctly centered the load more button, so that when the left panel is resized, the button remains in the middle. Additionally, added more comments to the sass. --- platform/commonUI/general/res/css/tree.css | 16 ++++++++-------- .../general/res/sass/search/_search.scss | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index d7e6e0fc84..8dca5804c4 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -273,23 +273,22 @@ ul.tree { *****************************************************************************/ /* line 27, ../sass/search/_search.scss */ .search .search-input { - width: 100%; - margin-top: 10px; } -/* line 32, ../sass/search/_search.scss */ + margin-top: 10px; + width: 100%; } +/* line 33, ../sass/search/_search.scss */ .search .results { margin-top: 10px; } - /* line 35, ../sass/search/_search.scss */ + /* line 37, ../sass/search/_search.scss */ .search .results .search-result-item { margin-bottom: 5px; background: #005177; border-radius: 2px; padding-top: 2px; padding-bottom: 1px; } - /* line 42, ../sass/search/_search.scss */ + /* line 47, ../sass/search/_search.scss */ .search .results .search-result-item .label { - left: 15px; margin-left: 6px; } - /* line 51, ../sass/search/_search.scss */ + /* line 56, ../sass/search/_search.scss */ .search .results .search-result-item .label .title-label { display: inline-block; position: absolute; @@ -301,11 +300,12 @@ ul.tree { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -/* line 70, ../sass/search/_search.scss */ +/* line 79, ../sass/search/_search.scss */ .search .load-more-button { margin-top: 5px; position: relative; left: 25%; + width: 50%; height: 20px; line-height: 11px; font-size: 0.7em; } diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index c2153b54d7..9c72ec1d64 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -25,22 +25,27 @@ $leftMargin: 6px; .search-input { - width: 100%; + // Align with the top of the divider bar, below create button margin-top: 10px; + width: 100%; } .results { + // Spacing away from the search input margin-top: 10px; .search-result-item { + // Space the results from each other margin-bottom: 5px; + + // Make the highlights the right color and shape background: $colorKeySelectedBg; // Later make this apply to only certain ones border-radius: 2px; padding-top: 2px; padding-bottom: 1px; .label { - left: 15px; + // Give some padding away from the left side margin-left: $leftMargin; .type-icon { @@ -52,13 +57,17 @@ display: inline-block; position: absolute; + // Give some padding away from the left side width: auto; left: $leftMargin + 3px + $iconWidth; right: 0; + // Size and position the text font-size: .8em; line-height: 17px; + // Hide overflow text + // Only works when width is defined overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -68,11 +77,15 @@ } .load-more-button { + // Space away form the results list margin-top: 5px; + // Center it position: relative; left: 25%; + width: 50%; + // Make smallish button height: 20px; line-height: 11px; font-size: 0.7em; From 8c08f7b93e6428c82026335de7cb13cfe9868cf9 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 23 Jul 2015 09:25:10 -0700 Subject: [PATCH 107/195] [Search] Less space above tree Removed the awkward spacing between the filetree and the search bar. Now 'My Items' appears just below the search bar. Also added .search-holder to the sass, but haven't done anything with it yet. --- .../general/res/css/theme-espresso.css | 6 +- platform/commonUI/general/res/css/tree.css | 79 ++++++----- .../general/res/sass/search/_layout.scss | 12 +- .../general/res/sass/search/_search.scss | 134 +++++++++--------- .../features/search/res/templates/search.html | 2 +- 5 files changed, 127 insertions(+), 106 deletions(-) diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index 08446c1b32..afba02c116 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -700,10 +700,14 @@ mct-container { * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 27, ../sass/search/_layout.scss */ +/* line 29, ../sass/search/_layout.scss */ .split-layout.vertical > .pane:first-child .holder { position: relative; } +/* line 42, ../sass/search/_layout.scss */ +.pane.treeview.left .tree-holder { + top: 0; } + /***************************************************************************** * Open MCT Web, Copyright (c) 2014-2015, United States Government * as represented by the Administrator of the National Aeronautics and Space diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 8dca5804c4..d7e21b33b9 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -271,41 +271,44 @@ ul.tree { * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 27, ../sass/search/_search.scss */ -.search .search-input { - margin-top: 10px; - width: 100%; } -/* line 33, ../sass/search/_search.scss */ -.search .results { - margin-top: 10px; } - /* line 37, ../sass/search/_search.scss */ - .search .results .search-result-item { - margin-bottom: 5px; - background: #005177; - border-radius: 2px; - padding-top: 2px; - padding-bottom: 1px; } - /* line 47, ../sass/search/_search.scss */ - .search .results .search-result-item .label { - margin-left: 6px; } - /* line 56, ../sass/search/_search.scss */ - .search .results .search-result-item .label .title-label { - display: inline-block; - position: absolute; - width: auto; - left: 29px; - right: 0; - font-size: .8em; - line-height: 17px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } -/* line 79, ../sass/search/_search.scss */ -.search .load-more-button { - margin-top: 5px; - position: relative; - left: 25%; - width: 50%; - height: 20px; - line-height: 11px; - font-size: 0.7em; } +/* line 22, ../sass/search/_search.scss */ +.search-holder { + overflow-y: auto; } + /* line 30, ../sass/search/_search.scss */ + .search-holder .search .search-input { + margin-top: 10px; + width: 100%; } + /* line 36, ../sass/search/_search.scss */ + .search-holder .search .results { + margin-top: 10px; } + /* line 40, ../sass/search/_search.scss */ + .search-holder .search .results .search-result-item { + margin-bottom: 5px; + background: #005177; + border-radius: 2px; + padding-top: 2px; + padding-bottom: 1px; } + /* line 50, ../sass/search/_search.scss */ + .search-holder .search .results .search-result-item .label { + margin-left: 6px; } + /* line 59, ../sass/search/_search.scss */ + .search-holder .search .results .search-result-item .label .title-label { + display: inline-block; + position: absolute; + width: auto; + left: 29px; + right: 0; + font-size: .8em; + line-height: 17px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + /* line 82, ../sass/search/_search.scss */ + .search-holder .search .load-more-button { + margin-top: 5px; + position: relative; + left: 25%; + width: 50%; + height: 20px; + line-height: 11px; + font-size: 0.7em; } diff --git a/platform/commonUI/general/res/sass/search/_layout.scss b/platform/commonUI/general/res/sass/search/_layout.scss index 795c3e6627..90b4c0c28c 100644 --- a/platform/commonUI/general/res/sass/search/_layout.scss +++ b/platform/commonUI/general/res/sass/search/_layout.scss @@ -20,6 +20,8 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ +// Overrides some styling in user-environ/_layout.scss + .split-layout { &.vertical { >.pane { @@ -32,6 +34,14 @@ } } } - } } + +.pane { + &.treeview.left { + .tree-holder { + // Want tree holder to start right below the search bar + top: 0; + } + } +} \ No newline at end of file diff --git a/platform/commonUI/general/res/sass/search/_search.scss b/platform/commonUI/general/res/sass/search/_search.scss index 9c72ec1d64..fa6dab7e10 100644 --- a/platform/commonUI/general/res/sass/search/_search.scss +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -19,75 +19,79 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ - -.search { - $iconWidth: 20px; - $leftMargin: 6px; +.search-holder { + //position: relative; + overflow-y: auto; // This should make it scroll, but isn't wokring :( - .search-input { - // Align with the top of the divider bar, below create button - margin-top: 10px; - width: 100%; - } - - .results { - // Spacing away from the search input - margin-top: 10px; + .search { + $iconWidth: 20px; + $leftMargin: 6px; - .search-result-item { - // Space the results from each other - margin-bottom: 5px; - - // Make the highlights the right color and shape - background: $colorKeySelectedBg; // Later make this apply to only certain ones - border-radius: 2px; - padding-top: 2px; - padding-bottom: 1px; - - .label { - // Give some padding away from the left side - margin-left: $leftMargin; - - .type-icon { - .icon { - } - } - - .title-label { - display: inline-block; - position: absolute; - + .search-input { + // Align with the top of the divider bar, below create button + margin-top: 10px; + width: 100%; + } + + .results { + // Spacing away from the search input + margin-top: 10px; + + .search-result-item { + // Space the results from each other + margin-bottom: 5px; + + // Make the highlights the right color and shape + background: $colorKeySelectedBg; // Later make this apply to only certain ones + border-radius: 2px; + padding-top: 2px; + padding-bottom: 1px; + + .label { // Give some padding away from the left side - width: auto; - left: $leftMargin + 3px + $iconWidth; - right: 0; - - // Size and position the text - font-size: .8em; - line-height: 17px; - - // Hide overflow text - // Only works when width is defined - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + margin-left: $leftMargin; + + .type-icon { + .icon { + } + } + + .title-label { + display: inline-block; + position: absolute; + + // Give some padding away from the left side + width: auto; + left: $leftMargin + 3px + $iconWidth; + right: 0; + + // Size and position the text + font-size: .8em; + line-height: 17px; + + // Hide overflow text + // Only works when width is defined + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } } - } - } - - .load-more-button { - // Space away form the results list - margin-top: 5px; - - // Center it - position: relative; - left: 25%; - width: 50%; - - // Make smallish button - height: 20px; - line-height: 11px; - font-size: 0.7em; + } + + .load-more-button { + // Space away form the results list + margin-top: 5px; + + // Center it + position: relative; + left: 25%; + width: 50%; + + // Make smallish button + height: 20px; + line-height: 11px; + font-size: 0.7em; + } } } \ No newline at end of file diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 1577730044..932330da69 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -38,7 +38,7 @@
    - +
    - +
    +
    +
    - - -
    - - Loading... -
    - - -
    - -
    -
    \ No newline at end of file +
    \ No newline at end of file From f4d34a2a9cdeb4389501480cf041d0de8055c6b0 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 23 Jul 2015 15:29:19 -0700 Subject: [PATCH 118/195] [Search] mctControl for searchbar Attempting to generalize the searchbar using mct-control. In progress. --- platform/features/search/bundle.json | 6 +++++ .../search/res/templates/search-item.html | 1 - .../features/search/res/templates/search.html | 9 ++++--- .../search/res/templates/searchbar.html | 26 +++++++++++++++++++ 4 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 platform/features/search/res/templates/searchbar.html diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 072afdd4f1..0b54821d14 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -18,6 +18,12 @@ "implementation": "controllers/ToggleController.js", "depends": [ ] } + ], + "controls": [ + { + "key": "searchbar", + "templateUrl": "templates/searchbar.html" + } ], "templates": [ { diff --git a/platform/features/search/res/templates/search-item.html b/platform/features/search/res/templates/search-item.html index e3285baef4..d2efec7442 100644 --- a/platform/features/search/res/templates/search-item.html +++ b/platform/features/search/res/templates/search-item.html @@ -21,7 +21,6 @@ --> -
    - - + a + asdf - +
    diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html new file mode 100644 index 0000000000..42d9e9dcc4 --- /dev/null +++ b/platform/features/search/res/templates/searchbar.html @@ -0,0 +1,26 @@ + + + \ No newline at end of file From 7d495f6389146d8456b680d73dca09a1c530dbf0 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 23 Jul 2015 15:55:20 -0700 Subject: [PATCH 119/195] [Search] Hide tree The tree is hidden when there are search results. --- platform/commonUI/browse/res/templates/browse.html | 5 +++-- platform/features/search/res/templates/search.html | 9 ++++----- .../features/search/src/controllers/SearchController.js | 7 +++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index c897b4272d..d926044f7e 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -28,13 +28,14 @@ > -
    +
    -
    +
    diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index d3d7fc26d6..977a3619f8 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -23,15 +23,14 @@ ng-controller="SearchController as controller">
    - - a - +
    diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 95019b2ed7..335687add7 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -56,6 +56,13 @@ define(function () { // We got the latest results now (and done loading) loading = false; $scope.results = searchService.getLatestResults(0, numResults); + + // Update whether the file tree should be displayed + if ($scope.results.length === 0) { + $scope.ngModel.filter = false; + } else { + $scope.ngModel.filter = true; + } } } waitForLatest(); From 33e8084852a6f83e95dee87abd525ac461a4ec45 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 23 Jul 2015 16:10:03 -0700 Subject: [PATCH 120/195] [Search] Getting input text The controller now gets the input text from the DOM element ID, then passes that string along to the search service, instead of passing the raw ID. --- platform/features/search/src/SearchAggregator.js | 7 +++---- .../search/src/controllers/SearchController.js | 9 +++++++-- .../src/providers/ElasticsearchSearchProvider.js | 10 +++------- .../search/src/providers/GenericSearchProvider.js | 11 +++-------- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index bd2de34b65..21e7f65b35 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -125,7 +125,7 @@ define( } // For documentation, see sendQuery below. - function queryAll(inputID, timestamp) { + function queryAll(inputText, timestamp) { // If there's not a timestamp, make this time the timestamp if (!timestamp) { var date = new Date(); @@ -134,7 +134,7 @@ define( // Send the query to all the providers for (var i = 0; i < providers.length; i += 1) { - providers[i].query(inputID, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT); + providers[i].query(inputText, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT); } // Update the merged results list @@ -146,8 +146,7 @@ define( * Sends a query to each of the providers, then updates the global * latestMergedResults accordingly. * - * @param inputID The name of the ID property of the html text - * input where this funcion should find the search term. + * @param inputText The text input that is the query. * @param timestamp (optional) The time at which this function * was called. This timestamp will be associated with the * latest results list, which allows us to see if it has been diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 335687add7..70edf748fe 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -70,13 +70,14 @@ define(function () { function search(inputID) { var date = new Date(), - timestamp = date.getTime(); + timestamp = date.getTime(), + inputText = document.getElementById(inputID).value; // Reset 'load more' numResults = INITIAL_LOAD_NUMBER; // Send the query - searchService.sendQuery(inputID, timestamp); + searchService.sendQuery(inputText, timestamp); update(timestamp); } @@ -101,6 +102,10 @@ define(function () { } }, + /** + * Checks to see if we are still waiting for the results to be + * fully updated. + */ isLoading: function () { return loading; }, diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 88e4342893..cb4344aab8 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -145,9 +145,8 @@ define( } // For documentation, see query below. - function queryElasticsearch(inputID, timestamp, maxResults, timeout) { - var searchTerm, - esQuery; + function queryElasticsearch(searchTerm, timestamp, maxResults, timeout) { + var esQuery; // Check to see if the user provided a maximum // number of results to display @@ -156,9 +155,6 @@ define( maxResults = DEFAULT_MAX_RESULTS; } - // Get the user input - searchTerm = document.getElementById(inputID).value; - // If the user input is empty, we want to have no search results. if (searchTerm !== '') { // Process search term @@ -198,7 +194,7 @@ define( * * More search details at * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html * - * @param inputID the name of the ID property of the html text + * @param searchTerm The text input that is the query. * input where this funcion should find the search term * @param timestamp the time at which this function was called, * this timestamp will be associated with the latest results diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 1b5a1ef520..4099bbf6f3 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -158,9 +158,8 @@ define( } // For documentation, see query below. - function queryGeneric(inputID, timestamp, maxResults, timeout) { - var input, - terms = [], + function queryGeneric(input, timestamp, maxResults, timeout) { + var terms = [], searchResults = [], resultsLength; @@ -171,9 +170,6 @@ define( maxResults = DEFAULT_MAX_RESULTS; } - // Get the user input - input = document.getElementById(inputID).value; - // Get items list return getItems(timeout).then(function () { // Then get the worker to search through it @@ -195,8 +191,7 @@ define( * * Scores are higher for matches that have more than one of * the terms as substrings. * - * @param inputID the name of the ID property of the html text - * input where this funcion should find the search term + * @param input The text input that is the query. * @param timestamp the time at which this function was called, * this timestamp will be associated with the latest results * list, which allows the aggregator to see if it has been From 341218e8f60a26e0112d6db09088a54e6291b1d4 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 23 Jul 2015 16:24:38 -0700 Subject: [PATCH 121/195] [Search] Tree hide change The tree is now hidden whenever there is text in the search bar. (This allows for the case when there are no search results, but text in the search bar.) --- platform/commonUI/browse/res/templates/browse.html | 2 +- .../search/src/controllers/SearchController.js | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index d926044f7e..5af59e43e0 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -35,7 +35,7 @@
    + ng-hide="treeModel.search"> diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 70edf748fe..d0a4f0a2fb 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -56,13 +56,6 @@ define(function () { // We got the latest results now (and done loading) loading = false; $scope.results = searchService.getLatestResults(0, numResults); - - // Update whether the file tree should be displayed - if ($scope.results.length === 0) { - $scope.ngModel.filter = false; - } else { - $scope.ngModel.filter = true; - } } } waitForLatest(); @@ -73,6 +66,13 @@ define(function () { timestamp = date.getTime(), inputText = document.getElementById(inputID).value; + // Update whether the file tree should be displayed + if (inputText === '') { + $scope.ngModel.search = false; + } else { + $scope.ngModel.search = true; + } + // Reset 'load more' numResults = INITIAL_LOAD_NUMBER; From 300280e03e3fcb1becae83f5d8db8e8505111662 Mon Sep 17 00:00:00 2001 From: shale Date: Thu, 23 Jul 2015 16:58:21 -0700 Subject: [PATCH 122/195] [Search] Moving responsibility Moving the responsibility of polling for updates from the search controller to the search aggregator. In progress. Previously this prototype was what could be called semi-stable, but now it is no longer. --- .../features/search/res/templates/search.html | 2 +- platform/features/search/src/SearchAggregator.js | 15 +++++++++++++-- .../search/src/controllers/SearchController.js | 9 +++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index 977a3619f8..f1d5ca245c 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -39,7 +39,7 @@
    diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 21e7f65b35..361ddfe446 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -42,7 +42,8 @@ define( */ function SearchAggregator(providers) { var latestMergedResults = [], - lastMergeTimestamps = []; + lastMergeTimestamps = [], + returnObject; // Remove duplicate objects that have the same ID function filterRepeats(results) { @@ -122,6 +123,7 @@ define( // After all that is done, now replace latestMergedResults with this latestMergedResults = newerResults; lastMergeTimestamps = providerTimestamps; + returnObject.latestResults = latestMergedResults; } // For documentation, see sendQuery below. @@ -141,7 +143,7 @@ define( updateResults(); } - return { + returnObject = { /** * Sends a query to each of the providers, then updates the global * latestMergedResults accordingly. @@ -177,6 +179,14 @@ define( return latestMergedResults.slice(start, stop); }, + /** + * The latest search results that have been calculated. The + * format of the returned objects are searchResult objects, + * which have the members id, object, and score. This array + * is updated constantly. + */ + latestResults: latestMergedResults, + /** * Get the timestamps for each of the provider's last controbutions * to the latestMergedResults. @@ -193,6 +203,7 @@ define( return latestMergedResults.length; } }; + return returnObject; } return SearchAggregator; diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index d0a4f0a2fb..1d6764d91d 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -35,6 +35,15 @@ define(function () { var numResults = INITIAL_LOAD_NUMBER, loading = false; + //$scope.results = searchService.latestResults; + + // This allows us to directly access the search aggregator's members. + // Most important is latestResults, which is continuously updated. This + // means that this controller does not have to poll for results any more. + $scope.searchService = searchService; + // TODO: Modify search aggregator to have a search result array which + // is of a size that can be chosen and modified by this controller. + function update(timestamp) { // We are loading results loading = true; From 9143f5febd7c4fdf95c8093de771ca856695d3d3 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 24 Jul 2015 13:03:18 -0700 Subject: [PATCH 123/195] [Search] Comments and errors Changed TreeNodeController slightly to do error checking. Also updated some comments. --- .../general/src/controllers/TreeNodeController.js | 5 +++-- platform/features/search/src/SearchAggregator.js | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/platform/commonUI/general/src/controllers/TreeNodeController.js b/platform/commonUI/general/src/controllers/TreeNodeController.js index a804ddabff..64e040ee89 100644 --- a/platform/commonUI/general/src/controllers/TreeNodeController.js +++ b/platform/commonUI/general/src/controllers/TreeNodeController.js @@ -171,9 +171,10 @@ define( // If this object is the same as the model's selected object // Same being them having the same ID (this allows different // instances of the same thing to be recognized as the same) - return $scope.ngModel.selectedObject.getId() === $scope.domainObject.getId(); + return getId($scope.ngModel.selectedObject) === getId($scope.domainObject); - // TODO: Check to make sure this change doesn't break anything. + // TODO: Check to make sure this change doesn't break + // anything/find a better way to do this } }; } diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 361ddfe446..9fefb45d87 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -180,10 +180,10 @@ define( }, /** - * The latest search results that have been calculated. The - * format of the returned objects are searchResult objects, - * which have the members id, object, and score. This array - * is updated constantly. + * An array containing the latest search results that have been + * calculated. The format of the returned objects are searchResult + * objects, which have the members id, object, and score. This + * array is updated often. */ latestResults: latestMergedResults, From 05c43db6fe85b8938a25bee5c4b3e9fdc1ddecad Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 24 Jul 2015 13:04:42 -0700 Subject: [PATCH 124/195] [Search] Search input using the model Made the search bar text input go to ngModel.input, rather than getting the text manually from the DOM element. Additionally, removed the search service from the search controller's scope. --- platform/features/search/bundle.json | 2 +- .../features/search/res/templates/search.html | 25 ++++++++++++++----- .../search/res/templates/searchbar.html | 12 +++++++-- .../src/controllers/SearchController.js | 10 +++----- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 0b54821d14..7190537305 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -21,7 +21,7 @@ ], "controls": [ { - "key": "searchbar", + "key": "searchbar-control", "templateUrl": "templates/searchbar.html" } ], diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index f1d5ca245c..d24b2d5d80 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -24,13 +24,26 @@
    - + ng-model="ngModel.input" + ng-keyup="controller.search()" /> +
    @@ -39,7 +52,7 @@
    diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html index 42d9e9dcc4..1b9508e45a 100644 --- a/platform/features/search/res/templates/searchbar.html +++ b/platform/features/search/res/templates/searchbar.html @@ -20,7 +20,15 @@ at runtime from the About dialog for additional information. --> - \ No newline at end of file + value="" /--> + + + + + + + \ No newline at end of file diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index 1d6764d91d..2aa1c7bf86 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -40,7 +40,7 @@ define(function () { // This allows us to directly access the search aggregator's members. // Most important is latestResults, which is continuously updated. This // means that this controller does not have to poll for results any more. - $scope.searchService = searchService; + //$scope.searchService = searchService; // TODO: Modify search aggregator to have a search result array which // is of a size that can be chosen and modified by this controller. @@ -70,10 +70,10 @@ define(function () { waitForLatest(); } - function search(inputID) { + function search() { var date = new Date(), timestamp = date.getTime(), - inputText = document.getElementById(inputID).value; + inputText = $scope.ngModel.input;//document.getElementById(inputID).value; // Update whether the file tree should be displayed if (inputText === '') { @@ -94,9 +94,7 @@ define(function () { return { /** * Search the filetree. - * - * @param inputID The name of the ID property of the html text - * input where this funcion should find the search term. + * Assumes that there will be search text in ngModel.input */ search: search, From dca0014862652b9f00c31863e83d229972ffc80d Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 24 Jul 2015 15:08:43 -0700 Subject: [PATCH 125/195] [Search] Removed unused Removed incorrect 'uses' statements from bundle.json. Also removed unused controller ToggleController. Edited some comments. --- platform/features/search/bundle.json | 11 +--- .../features/search/res/templates/search.html | 11 ++-- .../features/search/src/SearchAggregator.js | 9 +-- .../src/controllers/ToggleController.js | 66 ------------------- 4 files changed, 12 insertions(+), 85 deletions(-) delete mode 100644 platform/features/search/src/controllers/ToggleController.js diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 7190537305..f34a00df50 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -12,11 +12,6 @@ "key": "SearchItemController", "implementation": "controllers/SearchItemController.js", "depends": [ "$scope" ] - }, - { - "key": "ToggleController", - "implementation": "controllers/ToggleController.js", - "depends": [ ] } ], "controls": [ @@ -28,15 +23,13 @@ "templates": [ { "key": "search", - "templateUrl": "templates/search.html", - "uses": [ "composition" ] + "templateUrl": "templates/search.html" } ], "representations": [ { "key": "search-item", - "templateUrl": "templates/search-item.html", - "uses": [ "composition" ] + "templateUrl": "templates/search-item.html" } ], "components": [ diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index d24b2d5d80..a1f001aaa7 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -32,18 +32,17 @@ ng-model="ngModel" structure="{cssclass: search-input, size: 50}">asdf - - + + +
    diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 9fefb45d87..80467dd686 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -43,7 +43,7 @@ define( function SearchAggregator(providers) { var latestMergedResults = [], lastMergeTimestamps = [], - returnObject; + aggregator = {}; // Remove duplicate objects that have the same ID function filterRepeats(results) { @@ -123,7 +123,7 @@ define( // After all that is done, now replace latestMergedResults with this latestMergedResults = newerResults; lastMergeTimestamps = providerTimestamps; - returnObject.latestResults = latestMergedResults; + aggregator.latestResults = latestMergedResults; } // For documentation, see sendQuery below. @@ -143,7 +143,7 @@ define( updateResults(); } - returnObject = { + aggregator = { /** * Sends a query to each of the providers, then updates the global * latestMergedResults accordingly. @@ -203,7 +203,8 @@ define( return latestMergedResults.length; } }; - return returnObject; + + return aggregator; } return SearchAggregator; diff --git a/platform/features/search/src/controllers/ToggleController.js b/platform/features/search/src/controllers/ToggleController.js deleted file mode 100644 index 0d3bd664ca..0000000000 --- a/platform/features/search/src/controllers/ToggleController.js +++ /dev/null @@ -1,66 +0,0 @@ -/***************************************************************************** - * 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,Promise*/ - -define( - [], - function () { - "use strict"; - - /** - * A ToggleController is used to activate/deactivate things. - * A common usage is for "twistie" - * - * @constructor - */ - function ToggleController() { - var state = false; - - return { - /** - * Get the current state of the toggle. - * @return {boolean} true if active - */ - isActive: function () { - return state; - }, - /** - * Set a new state for the toggle. - * @return {boolean} true to activate - */ - setState: function (newState) { - state = newState; - }, - /** - * Toggle the current state; activate if it is inactive, - * deactivate if it is active. - */ - toggle: function () { - state = !state; - } - }; - - } - - return ToggleController; - } -); \ No newline at end of file From d35a149108a1797e72e8d14e22ca8e9a43a2e938 Mon Sep 17 00:00:00 2001 From: shale Date: Fri, 24 Jul 2015 16:52:55 -0700 Subject: [PATCH 126/195] [Search] Remove unused controll Removed searchbar controll, as the control to use would be the provided textfield control. --- platform/features/search/bundle.json | 9 ++--- .../search/res/templates/searchbar.html | 34 ------------------- 2 files changed, 2 insertions(+), 41 deletions(-) delete mode 100644 platform/features/search/res/templates/searchbar.html diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index f34a00df50..4778428e11 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -13,17 +13,12 @@ "implementation": "controllers/SearchItemController.js", "depends": [ "$scope" ] } - ], - "controls": [ - { - "key": "searchbar-control", - "templateUrl": "templates/searchbar.html" - } ], "templates": [ { "key": "search", - "templateUrl": "templates/search.html" + "templateUrl": "templates/search.html", + "uses": [ "controls", "forms" ] } ], "representations": [ diff --git a/platform/features/search/res/templates/searchbar.html b/platform/features/search/res/templates/searchbar.html deleted file mode 100644 index 1b9508e45a..0000000000 --- a/platform/features/search/res/templates/searchbar.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - \ No newline at end of file From 181fb32a2aefd5bb59fcd029978d8ae3066f4c76 Mon Sep 17 00:00:00 2001 From: shale Date: Mon, 27 Jul 2015 10:04:09 -0700 Subject: [PATCH 127/195] [Search] Responsibility change (in progress) Attempting to move some responsibility from the search controller to the aggregator. (Committing for save before possible revert.) --- platform/features/search/bundle.json | 3 +- .../features/search/res/templates/search.html | 10 +++--- .../features/search/src/SearchAggregator.js | 33 +++++++++++++++++-- .../src/controllers/SearchController.js | 14 ++++++-- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index 4778428e11..0bb4d8d050 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -43,7 +43,8 @@ { "provides": "searchService", "type": "aggregator", - "implementation": "SearchAggregator.js" + "implementation": "SearchAggregator.js", + "depends": [ "$timeout" ] } ], "workers": [ diff --git a/platform/features/search/res/templates/search.html b/platform/features/search/res/templates/search.html index a1f001aaa7..e1712a8dbc 100644 --- a/platform/features/search/res/templates/search.html +++ b/platform/features/search/res/templates/search.html @@ -20,7 +20,9 @@ at runtime from the About dialog for additional information. -->