diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index 0e890a50bf..f4cf649842 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -39,7 +39,16 @@ ng-model="paneModel"> -
+
+ + +
+ +
diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index 2e1c961085..26d6dd254f 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -71,6 +71,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ /* CONSTANTS */ +/***************************************************************************** /***************************************************************************** * Open MCT Web, Copyright (c) 2014-2015, United States Government * as represented by the Administrator of the National Aeronautics and Space @@ -644,44 +645,46 @@ mct-container { position: absolute; bottom: 5px; } /* line 232, ../sass/user-environ/_layout.scss */ + .pane.treeview.left .search-holder { + top: 34px; } + /* line 235, ../sass/user-environ/_layout.scss */ .pane.treeview.left .tree-holder { overflow: auto; - top: 34px; - padding-right: 5px; } - /* line 240, ../sass/user-environ/_layout.scss */ + top: 64px; } + /* line 242, ../sass/user-environ/_layout.scss */ .pane.items .object-browse-bar .left.abs, .pane.items .object-browse-bar .btn-menu span.left.l-click-area, .btn-menu .pane.items .object-browse-bar span.left.l-click-area, .pane.items .object-browse-bar .right.abs, .pane.items .object-browse-bar .btn-menu span.right.l-click-area, .btn-menu .pane.items .object-browse-bar span.right.l-click-area { top: auto; } - /* line 245, ../sass/user-environ/_layout.scss */ + /* line 247, ../sass/user-environ/_layout.scss */ .pane.items .object-holder { top: 34px; } - /* line 249, ../sass/user-environ/_layout.scss */ + /* line 251, ../sass/user-environ/_layout.scss */ .pane .object-holder { overflow: auto; } -/* line 257, ../sass/user-environ/_layout.scss */ +/* line 259, ../sass/user-environ/_layout.scss */ .split-layout.horizontal > .pane { margin-top: 5px; } - /* line 260, ../sass/user-environ/_layout.scss */ + /* line 262, ../sass/user-environ/_layout.scss */ .split-layout.horizontal > .pane:first-child { margin-top: 0; } -/* line 267, ../sass/user-environ/_layout.scss */ +/* line 269, ../sass/user-environ/_layout.scss */ .split-layout.vertical > .pane { margin-left: 5px; } - /* line 269, ../sass/user-environ/_layout.scss */ + /* line 271, ../sass/user-environ/_layout.scss */ .split-layout.vertical > .pane > .holder { left: 0; right: 0; } - /* line 273, ../sass/user-environ/_layout.scss */ + /* line 275, ../sass/user-environ/_layout.scss */ .split-layout.vertical > .pane:first-child { margin-left: 0; } - /* line 275, ../sass/user-environ/_layout.scss */ + /* line 277, ../sass/user-environ/_layout.scss */ .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; } @@ -2571,22 +2574,23 @@ label.checkbox.custom { color: #d9d9d9; line-height: 1.5rem; padding: 3px 10px 3px 30px; + position: relative; white-space: nowrap; } - /* line 46, ../sass/controls/_menus.scss */ + /* line 47, ../sass/controls/_menus.scss */ .menu-element .menu ul li:first-child { border: none; } - /* line 49, ../sass/controls/_menus.scss */ + /* line 50, ../sass/controls/_menus.scss */ .menu-element .menu ul li:hover { background: #737373; color: #fff; } - /* line 55, ../sass/controls/_menus.scss */ + /* line 56, ../sass/controls/_menus.scss */ .menu-element .menu ul li:hover .icon { color: #33ccff; } - /* line 63, ../sass/controls/_menus.scss */ + /* line 64, ../sass/controls/_menus.scss */ .menu-element .menu ul li .type-icon { left: 10px; } - /* line 70, ../sass/controls/_menus.scss */ - .menu-element .context-menu, + /* line 71, ../sass/controls/_menus.scss */ + .menu-element .context-menu, .menu-element .checkbox-menu, .menu-element .super-menu { pointer-events: auto; background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzhjOGM4YyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzgwODA4MCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); @@ -2609,35 +2613,56 @@ label.checkbox.custom { color: #999; display: inline-block; } /* line 170, ../sass/_mixins.scss */ - .menu-element .context-menu.btn-menu .invoke-menu, + .menu-element .context-menu.btn-menu .invoke-menu, .menu-element .btn-menu.checkbox-menu .invoke-menu, .menu-element .super-menu.btn-menu .invoke-menu { color: #b0b0b0; } - /* line 78, ../sass/controls/_menus.scss */ - .menu-element .context-menu ul li, + /* line 79, ../sass/controls/_menus.scss */ + .menu-element .context-menu ul li, .menu-element .checkbox-menu ul li, .menu-element .super-menu ul li { padding-left: 25px; } - /* line 80, ../sass/controls/_menus.scss */ - .menu-element .context-menu ul li a, + /* line 81, ../sass/controls/_menus.scss */ + .menu-element .context-menu ul li a, .menu-element .checkbox-menu ul li a, .menu-element .super-menu ul li a { color: white; } - /* line 81, ../sass/controls/_menus.scss */ - .menu-element .context-menu ul li .icon, + /* line 84, ../sass/controls/_menus.scss */ + .menu-element .context-menu ul li .icon, .menu-element .checkbox-menu ul li .icon, .menu-element .super-menu ul li .icon { color: #24c8ff; } - /* line 84, ../sass/controls/_menus.scss */ - .menu-element .context-menu ul li .type-icon, + /* line 87, ../sass/controls/_menus.scss */ + .menu-element .context-menu ul li .type-icon, .menu-element .checkbox-menu ul li .type-icon, .menu-element .super-menu ul li .type-icon { left: 5px; } - /* line 87, ../sass/controls/_menus.scss */ - .menu-element .context-menu ul li:hover .icon, + /* line 90, ../sass/controls/_menus.scss */ + .menu-element .context-menu ul li:hover .icon, .menu-element .checkbox-menu ul li:hover .icon, .menu-element .super-menu ul li:hover .icon { color: #3dcfff; } - /* line 94, ../sass/controls/_menus.scss */ + /* line 99, ../sass/controls/_menus.scss */ + .menu-element .checkbox-menu ul li { + padding-left: 50px; } + /* line 101, ../sass/controls/_menus.scss */ + .menu-element .checkbox-menu ul li .checkbox { + position: absolute; + left: 5px; + top: 0.53333rem; } + /* line 106, ../sass/controls/_menus.scss */ + .menu-element .checkbox-menu ul li .checkbox em { + height: 0.7rem; + width: 0.7rem; } + /* line 109, ../sass/controls/_menus.scss */ + .menu-element .checkbox-menu ul li .checkbox em:before { + font-size: 7px !important; + height: 0.7rem; + width: 0.7rem; + line-height: 0.7rem; } + /* line 117, ../sass/controls/_menus.scss */ + .menu-element .checkbox-menu ul li .type-icon { + left: 25px; } + /* line 123, ../sass/controls/_menus.scss */ .menu-element .super-menu { display: block; width: 500px; height: 480px; } - /* line 104, ../sass/controls/_menus.scss */ + /* line 133, ../sass/controls/_menus.scss */ .menu-element .super-menu .contents { overflow: hidden; position: absolute; @@ -2647,12 +2672,12 @@ label.checkbox.custom { left: 5px; width: auto; height: auto; } - /* line 107, ../sass/controls/_menus.scss */ + /* line 136, ../sass/controls/_menus.scss */ .menu-element .super-menu .pane { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } - /* line 109, ../sass/controls/_menus.scss */ + /* line 138, ../sass/controls/_menus.scss */ .menu-element .super-menu .pane.left { border-right: 1px solid rgba(255, 255, 255, 0.2); left: 0; @@ -2661,23 +2686,23 @@ label.checkbox.custom { width: 50%; overflow-x: hidden; overflow-y: auto; } - /* line 119, ../sass/controls/_menus.scss */ + /* line 148, ../sass/controls/_menus.scss */ .menu-element .super-menu .pane.left ul li { -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; padding-left: 30px; border-top: none; } - /* line 126, ../sass/controls/_menus.scss */ + /* line 155, ../sass/controls/_menus.scss */ .menu-element .super-menu .pane.right { left: auto; right: 0; padding: 25px; width: 50%; } - /* line 132, ../sass/controls/_menus.scss */ + /* line 161, ../sass/controls/_menus.scss */ .menu-element .super-menu .pane.right .icon { color: #fff; } - /* line 139, ../sass/controls/_menus.scss */ + /* line 168, ../sass/controls/_menus.scss */ .menu-element .super-menu .menu-item-description .desc-area.icon { position: relative; font-size: 8em; @@ -2686,40 +2711,40 @@ label.checkbox.custom { line-height: 150px; margin-bottom: 25px; text-align: center; } - /* line 149, ../sass/controls/_menus.scss */ + /* line 178, ../sass/controls/_menus.scss */ .menu-element .super-menu .menu-item-description .desc-area.title { color: #fff; font-size: 1.2em; margin-bottom: 0.5em; } - /* line 154, ../sass/controls/_menus.scss */ + /* line 183, ../sass/controls/_menus.scss */ .menu-element .super-menu .menu-item-description .desc-area.description { color: #fff; font-size: 0.8em; line-height: 1.5em; } - /* line 163, ../sass/controls/_menus.scss */ - .menu-element .context-menu { + /* line 192, ../sass/controls/_menus.scss */ + .menu-element .context-menu, .menu-element .checkbox-menu { font-size: 0.80rem; } -/* line 168, ../sass/controls/_menus.scss */ +/* line 197, ../sass/controls/_menus.scss */ .context-menu-holder { pointer-events: none; position: absolute; height: 200px; width: 170px; z-index: 70; } - /* line 174, ../sass/controls/_menus.scss */ + /* line 203, ../sass/controls/_menus.scss */ .context-menu-holder .context-menu-wrapper { position: absolute; height: 100%; width: 100%; } - /* line 181, ../sass/controls/_menus.scss */ - .context-menu-holder.go-left .context-menu { + /* line 210, ../sass/controls/_menus.scss */ + .context-menu-holder.go-left .context-menu, .context-menu-holder.go-left .menu-element .checkbox-menu, .menu-element .context-menu-holder.go-left .checkbox-menu { right: 0; } - /* line 182, ../sass/controls/_menus.scss */ - .context-menu-holder.go-up .context-menu { + /* line 213, ../sass/controls/_menus.scss */ + .context-menu-holder.go-up .context-menu, .context-menu-holder.go-up .menu-element .checkbox-menu, .menu-element .context-menu-holder.go-up .checkbox-menu { bottom: 0; } -/* line 185, ../sass/controls/_menus.scss */ +/* line 218, ../sass/controls/_menus.scss */ .btn-bar.right .menu, .menus-to-left .menu { left: auto; diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 8f3ac4871a..93414d5dc1 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -250,3 +250,248 @@ 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 */ +.abs.search-holder { + height: 25px; + bottom: 0; + z-index: 5; } + /* line 27, ../sass/search/_search.scss */ + .abs.search-holder.active { + height: auto; + bottom: 0; } + +/* line 38, ../sass/search/_search.scss */ +.search { + display: flex; + flex-direction: column; + height: 100%; } + /* line 49, ../sass/search/_search.scss */ + .search .search-bar { + font-size: 0.8em; + position: relative; + width: 100%; } + /* line 66, ../sass/search/_search.scss */ + .search .search-bar .search-input { + height: 25px; + line-height: 25px; + padding-top: 0; + padding-bottom: 0; } + /* line 73, ../sass/search/_search.scss */ + .search .search-bar .search-icon, + .search .search-bar .clear-icon, + .search .search-bar .menu-icon { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: #737373; + height: 17px; + width: 17px; + line-height: 17px; + position: absolute; + text-align: center; + top: 4px; } + /* line 86, ../sass/search/_search.scss */ + .search .search-bar .clear-icon, + .search .search-bar .menu-icon { + cursor: pointer; + transition: color .25s; } + /* line 93, ../sass/search/_search.scss */ + .search .search-bar .search-input { + position: relative; + width: 100%; + padding-left: 22px !important; + padding-right: 44px !important; } + /* line 100, ../sass/search/_search.scss */ + .search .search-bar .search-input input { + width: 100%; } + /* line 105, ../sass/search/_search.scss */ + .search .search-bar .search-icon { + color: #737373; + left: 3px; + transition: visibility .15s, opacity .15s, color .2s; + pointer-events: none; } + /* line 125, ../sass/search/_search.scss */ + .search .search-bar .search-input:hover + div.search-icon { + color: #a6a6a6; } + /* line 129, ../sass/search/_search.scss */ + .search .search-bar .clear-icon { + right: 22px; + visibility: hidden; + opacity: 0; + transition: visibility .15s, opacity .15s, color .2s; } + /* line 138, ../sass/search/_search.scss */ + .search .search-bar .clear-icon.content { + visibility: visible; + opacity: 1; } + /* line 143, ../sass/search/_search.scss */ + .search .search-bar .clear-icon:hover { + color: #a6a6a6; } + /* line 148, ../sass/search/_search.scss */ + .search .search-bar .menu-icon { + font-size: 0.8em; + padding-right: 4px; + right: 4px; + text-align: right; } + /* line 154, ../sass/search/_search.scss */ + .search .search-bar .menu-icon:hover { + color: #a6a6a6; } + /* line 159, ../sass/search/_search.scss */ + .search .search-bar .search-menu-holder { + float: right; + left: -20px; + z-index: 1; + transition: visibility .05s, opacity .05s; } + /* line 169, ../sass/search/_search.scss */ + .search .search-bar .search-menu-holder.off { + visibility: hidden; + opacity: 0; } + /* line 176, ../sass/search/_search.scss */ + .search .search-bar .menu-icon:hover + div.search-menu-holder { + visibility: visible; } + /* line 179, ../sass/search/_search.scss */ + .search .search-bar div.search-menu-holder:hover { + visibility: visible; } + /* line 184, ../sass/search/_search.scss */ + .search .active-filter-display { + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + line-height: 130%; + padding: 5px 0; + padding-left: 1.4625em; + font-size: 0.65em; + margin-top: 3px; } + /* line 199, ../sass/search/_search.scss */ + .search .active-filter-display .clear-filters-icon { + opacity: 0.4; + font-size: 0.8em; + position: absolute; + left: 1px; + cursor: pointer; } + /* line 210, ../sass/search/_search.scss */ + .search .active-filter-display.off { + visibility: hidden; + opacity: 0; + height: 0; + margin: 0; + padding: 0; + border: 0; } + /* line 220, ../sass/search/_search.scss */ + .search .search-scroll { + order: 3; + margin-top: 4px; + overflow-y: auto; + top: auto; + height: auto; + max-height: 100%; + position: relative; } + /* line 235, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item { + -moz-transition: background-color 0.25s; + -o-transition: background-color 0.25s; + -webkit-transition: background-color 0.25s; + transition: background-color 0.25s; + margin-bottom: 2px; + border-radius: 2px; + padding-top: 4px; + padding-bottom: 2px; } + /* line 249, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item .label { + margin-left: 6px; } + /* line 253, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item .label .title-label { + display: inline-block; + position: absolute; + left: 29px; + right: 5px; + font-size: .8em; + line-height: 17px; + width: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + /* line 275, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item.selected { + background: #005177; + color: #fff; } + /* line 279, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item.selected .view-control { + color: #0099cc; } + /* line 282, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item.selected .label .type-icon { + color: #fff; } + /* line 287, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item .label .type-icon .l-icon-link { + text-shadow: black 0 1px 2px; + z-index: 2; + color: #49dedb; + font-size: 8px; + line-height: 8px; + height: 8px; + width: 8px; + margin-left: -25px; } + /* line 296, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item:not(.selected):hover { + background: #404040; + color: #cccccc; } + /* line 299, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item:not(.selected):hover .context-trigger { + display: block; } + /* line 302, ../sass/search/_search.scss */ + .search .search-scroll .results .search-result-item:not(.selected):hover .icon { + color: #33ccff; } + /* line 310, ../sass/search/_search.scss */ + .search .search-scroll .load-icon { + position: relative; } + /* line 312, ../sass/search/_search.scss */ + .search .search-scroll .load-icon.loading { + pointer-events: none; + margin-left: 6px; } + /* line 316, ../sass/search/_search.scss */ + .search .search-scroll .load-icon.loading .title-label { + font-style: italic; + font-size: .9em; + opacity: 0.5; + margin-left: 26px; + line-height: 24px; } + /* line 326, ../sass/search/_search.scss */ + .search .search-scroll .load-icon.loading .wait-spinner { + margin-left: 6px; } + /* line 331, ../sass/search/_search.scss */ + .search .search-scroll .load-icon:not(.loading) { + cursor: pointer; } + /* line 336, ../sass/search/_search.scss */ + .search .search-scroll .load-more-button { + margin-top: 5px 0; + font-size: 0.8em; + position: relative; + left: 50%; + margin-left: -45px; + text-align: center; + width: 90px; + white-space: nowrap; } diff --git a/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json b/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json index 502ce67f79..cd432472af 100644 --- a/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json +++ b/platform/commonUI/general/res/fonts/symbols/icomoon.io-WTD-symbols-project.json @@ -1,19 +1,27 @@ { "metadata": { - "name": "WTD Symbols v2.1", - "lastOpened": 1439844340068, - "created": 1439844318831 + "name": "WTD Symbols v2.2", + "lastOpened": 1439948744240, + "created": 1439948734037 }, "iconSets": [ { "selection": [ + { + "order": 82, + "id": 84, + "prevSize": 32, + "code": 58887, + "name": "icon-x-in-circle", + "tempChar": "" + }, { "order": 77, "id": 83, "prevSize": 32, "code": 58881, "name": "icon-datatable", - "tempChar": "" + "tempChar": "" }, { "order": 78, @@ -21,7 +29,7 @@ "prevSize": 32, "code": 58882, "name": "icon-tabular-scrolling", - "tempChar": "" + "tempChar": "" }, { "order": 79, @@ -29,7 +37,7 @@ "prevSize": 32, "code": 58884, "name": "icon-tabular", - "tempChar": "" + "tempChar": "" }, { "order": 80, @@ -37,7 +45,7 @@ "prevSize": 32, "code": 58885, "name": "icon-calendar", - "tempChar": "" + "tempChar": "" }, { "order": 81, @@ -45,7 +53,7 @@ "prevSize": 32, "code": 58886, "name": "icon-paint-bucket", - "tempChar": "" + "tempChar": "" }, { "order": 1, @@ -53,7 +61,7 @@ "prevSize": 32, "code": 123, "name": "icon-pointer-left", - "tempChar": "" + "tempChar": "" }, { "order": 3, @@ -61,7 +69,7 @@ "prevSize": 32, "code": 125, "name": "icon-pointer-right", - "tempChar": "" + "tempChar": "" }, { "order": 4, @@ -69,7 +77,7 @@ "prevSize": 32, "code": 80, "name": "icon-person", - "tempChar": "" + "tempChar": "" }, { "order": 5, @@ -77,7 +85,7 @@ "prevSize": 32, "code": 232, "name": "icon-chain-links", - "tempChar": "" + "tempChar": "" }, { "order": 6, @@ -85,7 +93,7 @@ "prevSize": 32, "code": 115, "name": "icon-database-in-brackets", - "tempChar": "" + "tempChar": "" }, { "order": 7, @@ -93,7 +101,7 @@ "prevSize": 32, "code": 114, "name": "icon-refresh", - "tempChar": "" + "tempChar": "" }, { "order": 8, @@ -101,7 +109,7 @@ "prevSize": 32, "code": 108, "name": "icon-lock", - "tempChar": "" + "tempChar": "" }, { "order": 9, @@ -109,7 +117,7 @@ "prevSize": 32, "code": 51, "name": "icon-box-with-dashed-lines", - "tempChar": "" + "tempChar": "" }, { "order": 10, @@ -117,7 +125,7 @@ "prevSize": 32, "code": 58880, "name": "icon-box-with-arrow-cursor", - "tempChar": "" + "tempChar": "" }, { "order": 11, @@ -125,7 +133,7 @@ "prevSize": 32, "code": 65, "name": "icon-activity-mode", - "tempChar": "" + "tempChar": "" }, { "order": 12, @@ -133,7 +141,7 @@ "prevSize": 32, "code": 97, "name": "icon-activity", - "tempChar": "" + "tempChar": "" }, { "order": 13, @@ -141,7 +149,7 @@ "prevSize": 32, "code": 33, "name": "icon-alert-rect", - "tempChar": "" + "tempChar": "" }, { "order": 14, @@ -149,7 +157,7 @@ "prevSize": 32, "code": 58883, "name": "icon-alert-triangle", - "tempChar": "" + "tempChar": "" }, { "order": 15, @@ -157,7 +165,7 @@ "prevSize": 32, "code": 238, "name": "icon-arrow-double-down", - "tempChar": "" + "tempChar": "" }, { "order": 16, @@ -165,7 +173,7 @@ "prevSize": 32, "code": 235, "name": "icon-arrow-double-up", - "tempChar": "" + "tempChar": "" }, { "order": 2, @@ -173,7 +181,7 @@ "prevSize": 32, "code": 118, "name": "icon-arrow-down", - "tempChar": "" + "tempChar": "" }, { "order": 19, @@ -181,7 +189,7 @@ "prevSize": 32, "code": 60, "name": "icon-arrow-left", - "tempChar": "" + "tempChar": "" }, { "order": 20, @@ -189,7 +197,7 @@ "prevSize": 32, "code": 62, "name": "icon-arrow-right", - "tempChar": "" + "tempChar": "" }, { "order": 21, @@ -197,7 +205,7 @@ "prevSize": 32, "code": 236, "name": "icon-arrow-tall-down", - "tempChar": "" + "tempChar": "" }, { "order": 22, @@ -205,7 +213,7 @@ "prevSize": 32, "code": 237, "name": "icon-arrow-tall-up", - "tempChar": "" + "tempChar": "" }, { "order": 23, @@ -213,7 +221,7 @@ "prevSize": 32, "code": 94, "name": "icon-arrow-up", - "tempChar": "" + "tempChar": "" }, { "order": 24, @@ -221,7 +229,7 @@ "prevSize": 32, "code": 73, "name": "icon-arrows-out", - "tempChar": "" + "tempChar": "" }, { "order": 25, @@ -229,7 +237,7 @@ "prevSize": 32, "code": 58893, "name": "icon-arrows-right-left", - "tempChar": "" + "tempChar": "" }, { "order": 33, @@ -237,7 +245,7 @@ "prevSize": 32, "code": 53, "name": "icon-arrows-up-down", - "tempChar": "" + "tempChar": "" }, { "order": 26, @@ -245,7 +253,7 @@ "prevSize": 32, "code": 42, "name": "icon-asterisk", - "tempChar": "" + "tempChar": "" }, { "order": 27, @@ -253,7 +261,7 @@ "prevSize": 32, "code": 72, "name": "icon-autoflow-tabular", - "tempChar": "" + "tempChar": "" }, { "order": 28, @@ -261,7 +269,7 @@ "prevSize": 32, "code": 224, "name": "icon-box-round-corners", - "tempChar": "" + "tempChar": "" }, { "order": 29, @@ -269,7 +277,7 @@ "prevSize": 32, "code": 50, "name": "icon-check", - "tempChar": "" + "tempChar": "" }, { "order": 30, @@ -277,7 +285,7 @@ "prevSize": 32, "code": 67, "name": "icon-clock", - "tempChar": "" + "tempChar": "" }, { "order": 31, @@ -285,7 +293,7 @@ "prevSize": 32, "code": 46, "name": "icon-connectivity", - "tempChar": "" + "tempChar": "" }, { "order": 32, @@ -293,7 +301,7 @@ "prevSize": 32, "code": 100, "name": "icon-database-query", - "tempChar": "" + "tempChar": "" }, { "order": 17, @@ -301,7 +309,7 @@ "prevSize": 32, "code": 68, "name": "icon-database", - "tempChar": "" + "tempChar": "" }, { "order": 35, @@ -309,7 +317,7 @@ "prevSize": 32, "code": 81, "name": "icon-dictionary", - "tempChar": "" + "tempChar": "" }, { "order": 36, @@ -317,7 +325,7 @@ "prevSize": 32, "code": 242, "name": "icon-duplicate", - "tempChar": "" + "tempChar": "" }, { "order": 37, @@ -325,7 +333,7 @@ "prevSize": 32, "code": 102, "name": "icon-folder-new", - "tempChar": "" + "tempChar": "" }, { "order": 38, @@ -333,7 +341,7 @@ "prevSize": 32, "code": 70, "name": "icon-folder", - "tempChar": "" + "tempChar": "" }, { "order": 39, @@ -341,7 +349,7 @@ "prevSize": 32, "code": 95, "name": "icon-fullscreen-collapse", - "tempChar": "" + "tempChar": "" }, { "order": 40, @@ -349,7 +357,7 @@ "prevSize": 32, "code": 122, "name": "icon-fullscreen-expand", - "tempChar": "" + "tempChar": "" }, { "order": 41, @@ -357,7 +365,7 @@ "prevSize": 32, "code": 71, "name": "icon-gear", - "tempChar": "" + "tempChar": "" }, { "order": 49, @@ -365,7 +373,7 @@ "prevSize": 32, "code": 227, "name": "icon-image", - "tempChar": "" + "tempChar": "" }, { "order": 42, @@ -373,7 +381,7 @@ "prevSize": 32, "code": 225, "name": "icon-layers", - "tempChar": "" + "tempChar": "" }, { "order": 43, @@ -381,7 +389,7 @@ "prevSize": 32, "code": 76, "name": "icon-layout", - "tempChar": "" + "tempChar": "" }, { "order": 44, @@ -389,7 +397,7 @@ "prevSize": 32, "code": 226, "name": "icon-line-horz", - "tempChar": "" + "tempChar": "" }, { "order": 75, @@ -397,7 +405,7 @@ "prevSize": 32, "code": 244, "name": "icon-link", - "tempChar": "" + "tempChar": "" }, { "order": 46, @@ -405,7 +413,7 @@ "prevSize": 32, "code": 88, "name": "icon-magnify-in", - "tempChar": "" + "tempChar": "" }, { "order": 47, @@ -413,7 +421,7 @@ "prevSize": 32, "code": 89, "name": "icon-magnify-out", - "tempChar": "" + "tempChar": "" }, { "order": 48, @@ -421,7 +429,7 @@ "prevSize": 32, "code": 77, "name": "icon-magnify", - "tempChar": "" + "tempChar": "" }, { "order": 34, @@ -429,7 +437,7 @@ "prevSize": 32, "code": 109, "name": "icon-menu", - "tempChar": "" + "tempChar": "" }, { "order": 50, @@ -437,7 +445,7 @@ "prevSize": 32, "code": 243, "name": "icon-move", - "tempChar": "" + "tempChar": "" }, { "order": 51, @@ -445,7 +453,7 @@ "prevSize": 32, "code": 121, "name": "icon-new-window", - "tempChar": "" + "tempChar": "" }, { "order": 52, @@ -453,7 +461,7 @@ "prevSize": 32, "code": 111, "name": "icon-object", - "tempChar": "" + "tempChar": "" }, { "order": 73, @@ -461,7 +469,7 @@ "prevSize": 32, "code": 63, "name": "icon-object-unknown", - "tempChar": "" + "tempChar": "" }, { "order": 53, @@ -469,7 +477,7 @@ "prevSize": 32, "code": 86, "name": "icon-packet", - "tempChar": "" + "tempChar": "" }, { "order": 54, @@ -477,7 +485,7 @@ "prevSize": 32, "code": 234, "name": "icon-page", - "tempChar": "" + "tempChar": "" }, { "order": 55, @@ -485,7 +493,7 @@ "prevSize": 32, "code": 241, "name": "icon-pause", - "tempChar": "" + "tempChar": "" }, { "order": 56, @@ -493,7 +501,7 @@ "prevSize": 32, "code": 112, "name": "icon-pencil", - "tempChar": "" + "tempChar": "" }, { "order": 65, @@ -501,7 +509,7 @@ "prevSize": 32, "code": 79, "name": "icon-people", - "tempChar": "" + "tempChar": "" }, { "order": 57, @@ -509,7 +517,7 @@ "prevSize": 32, "code": 239, "name": "icon-play", - "tempChar": "" + "tempChar": "" }, { "order": 58, @@ -517,7 +525,7 @@ "prevSize": 32, "code": 233, "name": "icon-plot-resource", - "tempChar": "" + "tempChar": "" }, { "order": 59, @@ -525,7 +533,7 @@ "prevSize": 32, "code": 43, "name": "icon-plus", - "tempChar": "" + "tempChar": "" }, { "order": 60, @@ -533,7 +541,7 @@ "prevSize": 32, "code": 45, "name": "icon-minus", - "tempChar": "" + "tempChar": "" }, { "order": 61, @@ -541,7 +549,7 @@ "prevSize": 32, "code": 54, "name": "icon-sine", - "tempChar": "" + "tempChar": "" }, { "order": 62, @@ -549,7 +557,7 @@ "prevSize": 32, "code": 228, "name": "icon-T", - "tempChar": "" + "tempChar": "" }, { "order": 63, @@ -557,7 +565,7 @@ "prevSize": 32, "code": 116, "name": "icon-telemetry-panel", - "tempChar": "" + "tempChar": "" }, { "order": 64, @@ -565,7 +573,7 @@ "prevSize": 32, "code": 84, "name": "icon-telemetry", - "tempChar": "" + "tempChar": "" }, { "order": 18, @@ -573,7 +581,7 @@ "prevSize": 32, "code": 246, "name": "icon-thumbs-strip", - "tempChar": "" + "tempChar": "" }, { "order": 67, @@ -581,7 +589,7 @@ "prevSize": 32, "code": 83, "name": "icon-timeline", - "tempChar": "" + "tempChar": "" }, { "order": 68, @@ -589,7 +597,7 @@ "prevSize": 32, "code": 245, "name": "icon-timer", - "tempChar": "" + "tempChar": "" }, { "order": 69, @@ -597,7 +605,7 @@ "prevSize": 32, "code": 90, "name": "icon-trash", - "tempChar": "" + "tempChar": "" }, { "order": 70, @@ -605,7 +613,7 @@ "prevSize": 32, "code": 229, "name": "icon-two-parts-both", - "tempChar": "" + "tempChar": "" }, { "order": 71, @@ -613,7 +621,7 @@ "prevSize": 32, "code": 231, "name": "icon-two-parts-one-only", - "tempChar": "" + "tempChar": "" }, { "order": 72, @@ -621,7 +629,7 @@ "prevSize": 32, "code": 120, "name": "icon-x-heavy", - "tempChar": "" + "tempChar": "" }, { "order": 66, @@ -629,7 +637,7 @@ "prevSize": 32, "code": 58946, "name": "icon-x", - "tempChar": "" + "tempChar": "" } ], "id": 2, @@ -644,6 +652,21 @@ "height": 1024, "prevSize": 32, "icons": [ + { + "id": 84, + "paths": [ + "M512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512zM832 704l-128 128-192-192-192 192-128-128 192-192-192-192 128-128 192 192 192-192 128 128-192 192 192 192z" + ], + "attrs": [], + "isMulticolor": false, + "grid": 0, + "tags": [ + "icon-x-in-circle" + ], + "colorPermutations": { + "16161751": [] + } + }, { "id": 83, "paths": [ @@ -666,6 +689,10 @@ "icon-datatable" ], "colorPermutations": { + "16161751": [ + 1, + 1 + ], "125525525516161751": [ 1, 1 @@ -709,6 +736,13 @@ "icon-tabular-scrolling" ], "colorPermutations": { + "16161751": [ + 1, + 1, + 1, + 1, + 1 + ], "125525525516161751": [ 1, 1, @@ -760,6 +794,14 @@ "icon-tabular" ], "colorPermutations": { + "16161751": [ + 0, + 0, + 0, + 0, + 0, + 0 + ], "125525525516161751": [ 0, 0, @@ -787,6 +829,9 @@ "icon-calendar" ], "colorPermutations": { + "16161751": [ + 1 + ], "125525525516161751": [ 1 ] @@ -814,6 +859,10 @@ "icon-paint-bucket" ], "colorPermutations": { + "16161751": [ + 1, + 1 + ], "125525525516161751": [ 1, 1 diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot index 2f4f938076..3087b1c7a5 100755 Binary files a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot and b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot differ diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg index d31a879fc3..6d9fbdd714 100755 --- a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg +++ b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg @@ -83,6 +83,7 @@ + \ No newline at end of file diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf index 37af03fa79..a2a5aa3bfd 100755 Binary files a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf and b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf differ diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff index c93e44215c..fba91366e9 100755 Binary files a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff and b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff differ diff --git a/platform/commonUI/general/res/sass/_constants.scss b/platform/commonUI/general/res/sass/_constants.scss index 22518172da..66a9b08626 100644 --- a/platform/commonUI/general/res/sass/_constants.scss +++ b/platform/commonUI/general/res/sass/_constants.scss @@ -100,6 +100,7 @@ $ueAppLogoW: 105px; $ueEditToolBarH: 25px; $ueBrowseLeftPaneW: 25%; $ueEditLeftPaneW: 75%; +$treeSearchInputBarH: 25px; // Overlay $ovrTopBarH: 60px; $ovrFooterH: 40px; diff --git a/platform/commonUI/general/res/sass/_main.scss b/platform/commonUI/general/res/sass/_main.scss index 21a9e4a275..33e03268e8 100644 --- a/platform/commonUI/general/res/sass/_main.scss +++ b/platform/commonUI/general/res/sass/_main.scss @@ -1,3 +1,4 @@ +/***************************************************************************** /***************************************************************************** * Open MCT Web, Copyright (c) 2014-2015, United States Government * as represented by the Administrator of the National Aeronautics and Space @@ -31,6 +32,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/controls/_menus.scss b/platform/commonUI/general/res/sass/controls/_menus.scss index 59312a46a2..14210198ab 100644 --- a/platform/commonUI/general/res/sass/controls/_menus.scss +++ b/platform/commonUI/general/res/sass/controls/_menus.scss @@ -21,15 +21,15 @@ *****************************************************************************/ /******************************************************** MENUS */ .menu-element { - $bg: lighten($colorBodyBg, 5%); + $bg: lighten($colorBodyBg, 5%); $bgHover: lighten($bg, 20%); $iconColor: $colorKey; cursor: pointer; position: relative; .menu { @include border-radius($basicCr); - @include containerSubtle($bg); - @include txtShdwSubtle(0.2); + @include containerSubtle($bg); + @include txtShdwSubtle(0.2); display: block; // set to block via jQuery padding: $interiorMarginSm 0; position: absolute; @@ -37,11 +37,12 @@ ul { @include menuUlReset(); li { - @include box-sizing(border-box); + @include box-sizing(border-box); border-top: 1px solid lighten($bg, 20%); color: lighten($bg, 60%); line-height: $menuLineH; padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW; + position: relative; white-space: nowrap; &:first-child { border: none; @@ -61,7 +62,7 @@ // display: block; //} .type-icon { - left: $interiorMargin * 2; + left: $interiorMargin * 2; } } } @@ -77,7 +78,9 @@ @include containerSubtle($bg); ul li { padding-left: 25px; - a { color: $fg; } + a { + color: $fg; + } .icon { color: $ic; } @@ -90,99 +93,131 @@ } } + .checkbox-menu { + // Used in search dropdown in tree + @extend .context-menu; + ul li { + padding-left: 50px; + .checkbox { + $d: 0.7rem; + position: absolute; + left: $interiorMargin; + top: ($menuLineH - $d) / 1.5; + em { + height: $d; + width: $d; + &:before { + font-size: 7px !important;// $d/2; + height: $d; + width: $d; + line-height: $d; + } + } + } + .type-icon { + left: 25px; + } + } + } - .super-menu { - $w: 500px; - $h: $w - 20; - $plw: 50%; //$w * 0.5; - $prw: 50%; //$w - $plw; - $fg: #fff; //lighten($colorBodyFg, 40%); - $bgHover: $colorKey; //$bg; - display: block; - width: $w; - height: $h; - .contents { - @include absPosDefault($interiorMargin); - } - .pane { - @include box-sizing(border-box); - &.left { - //@include test(); - border-right: 1px solid rgba(white, 0.2); - left: 0; - padding-right: $interiorMargin; - right: auto; - width: $plw; - overflow-x: hidden; - overflow-y: auto; - ul { - li { - @include border-radius($controlCr); - padding-left: 30px; - border-top: none; - } - } - } - &.right { - //@include test(red); - left: auto; - right: 0; - padding: $interiorMargin * 5; - width: $prw; - .icon { - color: $fg; - } - } - } - .menu-item-description { - .desc-area { - &.icon { - $h: 150px; - position: relative; - font-size: 8em; - left: 0; - height: $h; - line-height: $h; - margin-bottom: $interiorMargin * 5; - text-align: center; - } - &.title { - color: $fg; - font-size: 1.2em; - margin-bottom: 0.5em; - } - &.description { - //color: lighten($bg, 30%); - color: $fg; - font-size: 0.8em; - line-height: 1.5em; - } - } - } - } - .context-menu { - font-size: 0.80rem; - } + .super-menu { + $w: 500px; + $h: $w - 20; + $plw: 50%; //$w * 0.5; + $prw: 50%; //$w - $plw; + $fg: #fff; //lighten($colorBodyFg, 40%); + $bgHover: $colorKey; //$bg; + display: block; + width: $w; + height: $h; + .contents { + @include absPosDefault($interiorMargin); + } + .pane { + @include box-sizing(border-box); + &.left { + //@include test(); + border-right: 1px solid rgba(white, 0.2); + left: 0; + padding-right: $interiorMargin; + right: auto; + width: $plw; + overflow-x: hidden; + overflow-y: auto; + ul { + li { + @include border-radius($controlCr); + padding-left: 30px; + border-top: none; + } + } + } + &.right { + //@include test(red); + left: auto; + right: 0; + padding: $interiorMargin * 5; + width: $prw; + .icon { + color: $fg; + } + } + } + .menu-item-description { + .desc-area { + &.icon { + $h: 150px; + position: relative; + font-size: 8em; + left: 0; + height: $h; + line-height: $h; + margin-bottom: $interiorMargin * 5; + text-align: center; + } + &.title { + color: $fg; + font-size: 1.2em; + margin-bottom: 0.5em; + } + &.description { + //color: lighten($bg, 30%); + color: $fg; + font-size: 0.8em; + line-height: 1.5em; + } + } + } + } + .context-menu { + font-size: 0.80rem; + } } .context-menu-holder { - pointer-events: none; - position: absolute; - height: 200px; - width: 170px; - z-index: 70; - .context-menu-wrapper { - position: absolute; - height: 100%; - width: 100%; - .context-menu { - } - } - &.go-left .context-menu { right: 0; } - &.go-up .context-menu { bottom: 0; } + pointer-events: none; + position: absolute; + height: 200px; + width: 170px; + z-index: 70; + .context-menu-wrapper { + position: absolute; + height: 100%; + width: 100%; + .context-menu { + } + } + &.go-left .context-menu { + right: 0; + } + &.go-up .context-menu { + bottom: 0; + } } .btn-bar.right .menu, .menus-to-left .menu { - left: auto; right: 0; width: auto; + left: auto; + right: 0; + width: auto; } \ No newline at end of file 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..03612d2d3c --- /dev/null +++ b/platform/commonUI/general/res/sass/search/_layout.scss @@ -0,0 +1,31 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +// Overrides some styling in user-environ/_layout.scss +.pane { + &.treeview.left { + .tree-holder { + // Want tree holder to start right below the search bar. + top: 60px; + } + } +} \ 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 new file mode 100644 index 0000000000..ce9286e947 --- /dev/null +++ b/platform/commonUI/general/res/sass/search/_search.scss @@ -0,0 +1,347 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +.abs.search-holder { + //@include test(#990000); + height: $treeSearchInputBarH; + bottom: 0; + &.active { + height: auto; + bottom: 0; + } + //top: 23px; + + // Align with the top of the divider bar, below create button + //margin-top: 10px; // CH comment out + z-index:5; +} + +.search { + $iconWidth: 20px; + $leftMargin: 6px; + $rightPadding: 5px; + + //padding-right: $rightPadding; + //@include test(); + display: flex; //block; + flex-direction: column; + height: 100%; + + .search-bar { + //$heightAdjust: 4px; + $textInputHeight: 19px; // This is equal to the default value, 19px + $iconEdgeM: 4px; + $iconD: $treeSearchInputBarH - ($iconEdgeM*2); + font-size: 0.8em; + + //order: 1; + + position: relative; + width: 100%; + //height: $textInputHeight; + //margin-top: $heightAdjust; + .search-input, + .search-icon { + } + + .search-input { + height: $treeSearchInputBarH; + line-height: $treeSearchInputBarH; + padding-top: 0; + padding-bottom: 0; + } + + .search-icon, + .clear-icon, + .menu-icon { + //@include test(#008800); + @include box-sizing(border-box); + color: $colorItemFg; + height: $iconD; width: $iconD; + line-height: $iconD; + position: absolute; + text-align: center; + top: $iconEdgeM; + } + + .clear-icon, + .menu-icon { + cursor: pointer; + transition: color .25s; + } + + + .search-input { + position: relative; + width: 100%; + padding-left: $iconD + $interiorMargin !important; + padding-right: ($iconD * 2) + ($interiorMargin * 2) !important; + + // Make work for mct-control textfield + input { + width: 100%; + } + } + + .search-icon { + color: $colorItemFg; + left: $interiorMarginSm; + transition: visibility .15s, opacity .15s, color .2s; + pointer-events: none; + + &.content { + // Make icon invisible whenever there is text input + //visibility: hidden; + //opacity: 0; + } + } + + // Make icon invisible when the text input is focused + .search-input:focus + div.search-icon { + //visibility: hidden; + //opacity: 0; + } + + // Make icon lighten when hovering over search bar + .search-input:hover + div.search-icon { + color: lighten($colorItemFg, 20%); + } + + .clear-icon { + right: $iconD + $interiorMargin; + + // Icon is visible only when there is text input + visibility: hidden; + opacity: 0; + + transition: visibility .15s, opacity .15s, color .2s; + + &.content { + visibility: visible; + opacity: 1; + } + + &:hover { + color: lighten($colorItemFg, 20%); + } + } + + .menu-icon { + font-size: 0.8em; + padding-right: $iconEdgeM; + right: $iconEdgeM; + text-align: right; + + &:hover { + color: lighten($colorItemFg, 20%); + } + } + + .search-menu-holder { + float: right; + //margin-top: $textInputHeight - 2px; + //left: -50px; + left: -20px; + + z-index: 1; + + transition: visibility .05s, opacity .05s; + + &.off { + visibility: hidden; + opacity: 0; + } + } + + // Hovering reveals menu + .menu-icon:hover + div.search-menu-holder { + visibility: visible; + } + div.search-menu-holder:hover { + visibility: visible; + } + } + + .active-filter-display { + //order: 2; + $s: 0.65em; + $p: $interiorMargin; + @include border-radius($basicCr); + @include box-sizing(border-box); + line-height: 130%; + padding: $p 0; + padding-left: $s * 2.25; + font-size: $s; + //background-color: rgba(#000, 0.3); + //border-radius: $basicCr; + margin-top: $interiorMarginSm; + + + .clear-filters-icon { + opacity: 0.4; + font-size: 0.8em; + position: absolute; + left: 1px; + cursor: pointer; + } + + // Transition looks weird when the results list has none + //transition: visibility .2s, opacity .2s; + + &.off { + visibility: hidden; + opacity: 0; + height: 0; + margin: 0; + padding: 0; + border: 0; + } + } + + .search-scroll { + order: 3; + + //padding-right: $rightPadding; + margin-top: 4px; + + // Adjustable scrolling size + overflow-y: auto; + top: auto; + height: auto; + max-height: 100%; + position: relative; + + .results { + + .search-result-item { + // Include transitions (for the highlights) + @include single-transition(background-color, 0.25s); + + // Space the results from each other + margin-bottom: 2px; + + // Make the highlights the right color and shape. + // Attempting to match the style in the tree, but + // while having these be compact. + border-radius: 2px; + padding-top: 4px; + padding-bottom: 2px; + + .label { + // Give some padding away from the left side + margin-left: $leftMargin; + + .title-label { + display: inline-block; + position: absolute; + + // Give some padding away from the left side + left: $leftMargin + 3px + $iconWidth; + // and the right side + right: $rightPadding; + + // Size and position the text + font-size: .8em; + line-height: 17px; + + // Hide overflow text + width: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + // Change styling when it's selected + &.selected { + $c: #fff; + background: $colorKeySelectedBg; + color: $c; + .view-control { + color: $colorItemTreeIcon; + } + .label .type-icon { + color: #fff; + } + } + + .label .type-icon .l-icon-link { + @include txtShdwSubtle(1); + z-index: 2; + @include ancillaryIcon(8px, $colorIconLink); + margin-left: -25px; + } + + // Change styling when it's being hovered over + &:not(.selected) { + &:hover { + background: lighten($colorBodyBg, 5%); + color: lighten($colorBodyFg, 20%); + .context-trigger { + display: block; + } + .icon { + color: $colorItemTreeIconHover; + } + } + } + } + } + + .load-icon { + position: relative; + &.loading { + pointer-events: none; + margin-left: $leftMargin; + + .title-label { + // Text styling + font-style: italic; + font-size: .9em; + opacity: 0.5; + + // Text positioning + margin-left: $iconWidth + $leftMargin; + line-height: 24px; + } + .wait-spinner { + margin-left: $leftMargin; + } + } + + &:not(.loading) { + cursor: pointer; + } + } + + .load-more-button { + margin-top: $interiorMargin 0; + font-size: 0.8em; + position: relative; + left: 50%; + margin-left: -45px; + text-align: center; + width: 90px; + white-space: nowrap; + } + } +} \ 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/commonUI/general/res/sass/user-environ/_layout.scss b/platform/commonUI/general/res/sass/user-environ/_layout.scss index a07ed38953..ed56ec3e98 100644 --- a/platform/commonUI/general/res/sass/user-environ/_layout.scss +++ b/platform/commonUI/general/res/sass/user-environ/_layout.scss @@ -229,10 +229,12 @@ bottom: $interiorMargin; } } + .search-holder { + top: $ueTopBarH + $interiorMarginLg; + } .tree-holder { overflow: auto; - top: $ueTopBarH + $interiorMarginLg; - padding-right: $interiorMargin; + top: $ueTopBarH + $interiorMarginLg + $treeSearchInputBarH + $interiorMargin; } } &.items { diff --git a/platform/commonUI/general/src/controllers/TreeNodeController.js b/platform/commonUI/general/src/controllers/TreeNodeController.js index 3c3829700b..1ef72491d8 100644 --- a/platform/commonUI/general/src/controllers/TreeNodeController.js +++ b/platform/commonUI/general/src/controllers/TreeNodeController.js @@ -135,9 +135,6 @@ define( // Listen for changes which will effect display parameters $scope.$watch("ngModel.selectedObject", setSelection); $scope.$watch("domainObject", checkSelection); - - - } /** diff --git a/platform/persistence/elastic/bundle.json b/platform/persistence/elastic/bundle.json index 8b9ba16fd4..f78d8504f2 100644 --- a/platform/persistence/elastic/bundle.json +++ b/platform/persistence/elastic/bundle.json @@ -8,6 +8,12 @@ "type": "provider", "implementation": "ElasticPersistenceProvider.js", "depends": [ "$http", "$q", "PERSISTENCE_SPACE", "ELASTIC_ROOT", "ELASTIC_PATH" ] + }, + { + "provides": "searchService", + "type": "provider", + "implementation": "ElasticSearchProvider.js", + "depends": [ "$http", "objectService", "ELASTIC_ROOT" ] } ], "constants": [ diff --git a/platform/persistence/elastic/src/ElasticsearchSearchProvider.js b/platform/persistence/elastic/src/ElasticSearchProvider.js similarity index 93% rename from platform/persistence/elastic/src/ElasticsearchSearchProvider.js rename to platform/persistence/elastic/src/ElasticSearchProvider.js index d7dea9b1f0..604e3d0ed3 100644 --- a/platform/persistence/elastic/src/ElasticsearchSearchProvider.js +++ b/platform/persistence/elastic/src/ElasticSearchProvider.js @@ -22,8 +22,7 @@ /*global define*/ /** - * Module defining ElasticsearchSearchProvider. Created by shale on 07/16/2015. - * This is not currently included in the bundle definition. + * Module defining ElasticSearchProvider. Created by shale on 07/16/2015. */ define( [], @@ -44,13 +43,13 @@ define( * @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 + * @param ROOT the constant `ELASTIC_ROOT` which allows us to * interact with ElasticSearch. */ - function ElasticsearchSearchProvider($http, objectService, root) { + function ElasticSearchProvider($http, objectService, ROOT) { this.$http = $http; this.objectService = objectService; - this.root = root; + this.root = ROOT; } /** @@ -78,13 +77,12 @@ define( * stop calculations and return partial results. Elasticsearch * does not guarentee that this timeout will be strictly followed. */ - ElasticsearchSearchProvider.prototype.query = function query(searchTerm, timestamp, maxResults, timeout) { + ElasticSearchProvider.prototype.query = function query(searchTerm, timestamp, maxResults, timeout) { var $http = this.$http, objectService = this.objectService, root = this.root, esQuery; - - // Add the fuzziness operator to the search term + function addFuzziness(searchTerm, editDistance) { if (!editDistance) { editDistance = ''; @@ -210,6 +208,6 @@ define( }; - return ElasticsearchSearchProvider; + return ElasticSearchProvider; } ); \ No newline at end of file diff --git a/platform/persistence/elastic/test/ElasticsearchSearchProviderSpec.js b/platform/persistence/elastic/test/ElasticSearchProviderSpec.js similarity index 95% rename from platform/persistence/elastic/test/ElasticsearchSearchProviderSpec.js rename to platform/persistence/elastic/test/ElasticSearchProviderSpec.js index 1202ef77e6..decb1a5c98 100644 --- a/platform/persistence/elastic/test/ElasticsearchSearchProviderSpec.js +++ b/platform/persistence/elastic/test/ElasticSearchProviderSpec.js @@ -25,8 +25,8 @@ * SearchSpec. Created by shale on 07/31/2015. */ define( - ["../src/ElasticsearchSearchProvider"], - function (ElasticsearchSearchProvider) { + ["../src/ElasticSearchProvider"], + function (ElasticSearchProvider) { "use strict"; // JSLint doesn't like underscore-prefixed properties, @@ -68,7 +68,7 @@ define( [ "getId", "getModel" ] ); - provider = new ElasticsearchSearchProvider(mockHttp, mockObjectService, ""); + provider = new ElasticSearchProvider(mockHttp, mockObjectService, ""); provider.query(' test "query" ', 0, undefined, 1000); }); diff --git a/platform/persistence/elastic/test/suite.json b/platform/persistence/elastic/test/suite.json index 939244c089..85b407eb73 100644 --- a/platform/persistence/elastic/test/suite.json +++ b/platform/persistence/elastic/test/suite.json @@ -1,5 +1,5 @@ [ "ElasticIndicator", "ElasticPersistenceProvider", - "ElasticsearchSearchProvider" + "ElasticSearchProvider" ] diff --git a/platform/search/bundle.json b/platform/search/bundle.json index 6668022939..7ea1536556 100644 --- a/platform/search/bundle.json +++ b/platform/search/bundle.json @@ -9,25 +9,56 @@ "priority": "fallback" } ], + "controllers": [ + { + "key": "SearchController", + "implementation": "controllers/SearchController.js", + "depends": [ "$scope", "searchService" ] + }, + { + "key": "SearchMenuController", + "implementation": "controllers/SearchMenuController.js", + "depends": [ "$scope", "types[]" ] + }, + { + "key": "ClickAwayController", + "implementation": "controllers/ClickAwayController.js", + "depends": [ "$scope", "$document" ] + } + ], + "representations": [ + { + "key": "search", + "templateUrl": "templates/search.html" + }, + { + "key": "search-menu", + "templateUrl": "templates/search-menu.html" + }, + { + "key": "search-item", + "templateUrl": "templates/search-item.html" + } + ], "components": [ { "provides": "searchService", "type": "provider", - "implementation": "GenericSearchProvider.js", + "implementation": "services/GenericSearchProvider.js", "depends": [ "$q", "$timeout", "objectService", "workerService", "GENERIC_SEARCH_ROOTS" ] }, { "provides": "searchService", "type": "aggregator", - "implementation": "SearchAggregator.js", + "implementation": "services/SearchAggregator.js", "depends": [ "$q" ] } ], "workers": [ { "key": "genericSearchWorker", - "scriptUrl": "GenericSearchWorker.js" + "scriptUrl": "services/GenericSearchWorker.js" } ] } -} +} \ No newline at end of file diff --git a/platform/search/res/templates/search-item.html b/platform/search/res/templates/search-item.html new file mode 100644 index 0000000000..0cd5b60f17 --- /dev/null +++ b/platform/search/res/templates/search-item.html @@ -0,0 +1,30 @@ + + +
+ + +
\ No newline at end of file diff --git a/platform/search/res/templates/search-menu.html b/platform/search/res/templates/search-menu.html new file mode 100644 index 0000000000..8b5f275871 --- /dev/null +++ b/platform/search/res/templates/search-menu.html @@ -0,0 +1,67 @@ + + +
+ + +
\ No newline at end of file diff --git a/platform/search/res/templates/search.html b/platform/search/res/templates/search.html new file mode 100644 index 0000000000..5313cd12ed --- /dev/null +++ b/platform/search/res/templates/search.html @@ -0,0 +1,116 @@ + + \ No newline at end of file diff --git a/platform/search/src/controllers/ClickAwayController.js b/platform/search/src/controllers/ClickAwayController.js new file mode 100644 index 0000000000..9b92e89cc0 --- /dev/null +++ b/platform/search/src/controllers/ClickAwayController.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,Promise*/ + +/* + * Copied from the ClickAwayController in platform/commonUI/general + */ + +define( + [], + function () { + "use strict"; + + /** + * A ClickAwayController is used to toggle things (such as context + * menus) where clicking elsewhere in the document while the toggle + * is in an active state is intended to dismiss the toggle. + * + * @constructor + * @param $scope the scope in which this controller is active + * @param $document the document element, injected by Angular + */ + function ClickAwayController($scope, $document) { + var state = false, + clickaway; + + // Track state, but also attach and detach a listener for + // mouseup events on the document. + function deactivate() { + state = false; + $document.off("mouseup", clickaway); + } + + function activate() { + state = true; + $document.on("mouseup", clickaway); + } + + function changeState() { + if (state) { + deactivate(); + } else { + activate(); + } + } + + // Callback used by the document listener. Deactivates; + // note also $scope.$apply is invoked to indicate that + // the state of this controller has changed. + clickaway = function () { + deactivate(); + $scope.$apply(); + return 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) { + if (state !== newState) { + changeState(); + } + }, + /** + * Toggle the current state; activate if it is inactive, + * deactivate if it is active. + */ + toggle: function () { + changeState(); + } + }; + + } + + return ClickAwayController; + } +); \ No newline at end of file diff --git a/platform/search/src/controllers/SearchController.js b/platform/search/src/controllers/SearchController.js new file mode 100644 index 0000000000..10cf056b4f --- /dev/null +++ b/platform/search/src/controllers/SearchController.js @@ -0,0 +1,171 @@ +/***************************************************************************** + * 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 SearchController. Created by shale on 07/15/2015. + */ +define(function () { + "use strict"; + + var INITIAL_LOAD_NUMBER = 20, + LOAD_INCREMENT = 20; + + function SearchController($scope, searchService) { + // numResults is the amount of results to display. Will get increased. + // fullResults holds the most recent complete searchService response object + var numResults = INITIAL_LOAD_NUMBER, + fullResults = {hits: []}; + + // Scope variables are: + // Variables used only in SearchController: + // results, an array of searchResult objects + // loading, whether search() is loading + // ngModel.input, the text of the search query + // ngModel.search, a boolean of whether to display search or the tree + // Variables used also in SearchMenuController: + // ngModel.filter, the function filter defined below + // ngModel.types, an array of type objects + // ngModel.checked, a dictionary of which type filter options are checked + // ngModel.checkAll, a boolean of whether to search all types + // ngModel.filtersString, a string list of what filters on the results are active + $scope.results = []; + $scope.loading = false; + + + // Filters searchResult objects by type. Allows types that are + // checked. (ngModel.checked['typekey'] === true) + // If hits is not provided, will use fullResults.hits + function filter(hits) { + var newResults = [], + i = 0; + + if (!hits) { + hits = fullResults.hits; + } + + // If checkAll is checked, search everything no matter what the other + // checkboxes' statuses are. Otherwise filter the search by types. + if ($scope.ngModel.checkAll) { + newResults = fullResults.hits.slice(0, numResults); + } else { + while (newResults.length < numResults && i < hits.length) { + // If this is of an acceptable type, add it to the list + if ($scope.ngModel.checked[hits[i].object.getModel().type]) { + newResults.push(fullResults.hits[i]); + } + i += 1; + } + } + + $scope.results = newResults; + return newResults; + } + + // Make function accessible from SearchMenuController + $scope.ngModel.filter = filter; + + // For documentation, see search below + function search(maxResults) { + var inputText = $scope.ngModel.input; + + if (inputText !== '' && inputText !== undefined) { + // We are starting to load. + $scope.loading = true; + + // Update whether the file tree should be displayed + // Hide tree only when starting search + $scope.ngModel.search = true; + } + + if (!maxResults) { + // Reset 'load more' + numResults = INITIAL_LOAD_NUMBER; + } + + // Send the query + searchService.query(inputText, maxResults).then(function (result) { + // Store all the results before splicing off the front, so that + // we can load more to display later. + fullResults = result; + $scope.results = filter(result.hits); + + // Update whether the file tree should be displayed + // Reveal tree only when finishing search + if (inputText === '' || inputText === undefined) { + $scope.ngModel.search = false; + } + + // Now we are done loading. + $scope.loading = false; + }); + } + + return { + /** + * Search the filetree. Assumes that any search text will + * be in ngModel.input + * + * @param maxResults (optional) The maximum number of results + * that this function should return. If not provided, search + * service default will be used. + */ + search: search, + + /** + * Checks to see if there are more search results to display. If the answer is + * unclear, this function will err toward saying that there are more results. + */ + areMore: function () { + var i; + + // Check to see if any of the not displayed results are of an allowed type + for (i = numResults; i < fullResults.hits.length; i += 1) { + if ($scope.ngModel.checkAll || $scope.ngModel.checked[fullResults.hits[i].object.getModel().type]) { + return true; + } + } + + // If none of the ones at hand are correct, there still may be more if we + // re-search with a larger maxResults + return fullResults.hits.length < fullResults.total; + }, + + /** + * Increases the number of search results to display, and then + * loads them, adding to the displayed results. + */ + loadMore: function () { + numResults += LOAD_INCREMENT; + + if (numResults > fullResults.hits.length && fullResults.hits.length < fullResults.total) { + // Resend the query if we are out of items to display, but there are more to get + search(numResults); + } else { + // Otherwise just take from what we already have + $scope.results = filter(fullResults.hits); + } + } + }; + } + return SearchController; +}); diff --git a/platform/search/src/controllers/SearchMenuController.js b/platform/search/src/controllers/SearchMenuController.js new file mode 100644 index 0000000000..e0d8c342e5 --- /dev/null +++ b/platform/search/src/controllers/SearchMenuController.js @@ -0,0 +1,131 @@ +/***************************************************************************** + * 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 SearchMenuController. Created by shale on 08/17/2015. + */ +define(function () { + "use strict"; + + function SearchMenuController($scope, types) { + + // Model variables are: + // ngModel.filter, the function filter defined in SearchController + // ngModel.types, an array of type objects + // ngModel.checked, a dictionary of which type filter options are checked + // ngModel.checkAll, a boolean of whether all of the types in ngModel.checked are checked + // ngModel.filtersString, a string list of what filters on the results are active + $scope.ngModel.types = []; + $scope.ngModel.checked = {}; + $scope.ngModel.checkAll = true; + $scope.ngModel.filtersString = ''; + + // On initialization, fill the model's types with type keys + types.forEach(function (type) { + // We only want some types, the ones that are probably human readable + // Manually remove 'root', but not 'unknown' + if (type.key && type.name && type.key !== 'root') { + $scope.ngModel.types.push(type); + $scope.ngModel.checked[type.key] = false; + } + }); + + + // For documentation, see updateOptions below + function updateOptions() { + var type, + i; + + // Update all-checked status + if ($scope.ngModel.checkAll) { + for (type in $scope.ngModel.checked) { + if ($scope.ngModel.checked[type]) { + $scope.ngModel.checkAll = false; + } + } + } + + // Update the current filters string + $scope.ngModel.filtersString = ''; + if (!$scope.ngModel.checkAll) { + for (i = 0; i < $scope.ngModel.types.length; i += 1) { + // If the type key corresponds to a checked option... + if ($scope.ngModel.checked[$scope.ngModel.types[i].key]) { + // ... add it to the string list of current filter options + if ($scope.ngModel.filtersString === '') { + $scope.ngModel.filtersString += $scope.ngModel.types[i].name; + } else { + $scope.ngModel.filtersString += ', ' + $scope.ngModel.types[i].name; + } + } + } + // If there's still nothing in the filters string, there are no + // filters selected + if ($scope.ngModel.filtersString === '') { + $scope.ngModel.filtersString = 'NONE'; + } + } + + // Re-filter results + $scope.ngModel.filter(); + } + + // For documentation, see checkAll below + function checkAll() { + var type; + + // Reset all the other options to original/default position + for (type in $scope.ngModel.checked) { + $scope.ngModel.checked[type] = false; + } + + // Change the filters string depending on checkAll status + if ($scope.ngModel.checkAll) { + // This setting will make the filters display hidden + $scope.ngModel.filtersString = ''; + } else { + $scope.ngModel.filtersString = 'NONE'; + } + + // Re-filter results + $scope.ngModel.filter(); + } + + return { + /** + * Updates the status of the checked options. Updates the filtersString + * with which options are checked. Re-filters the search results after. + * Not intended to be called by checkAll when it is toggled. + */ + updateOptions: updateOptions, + + /** + * Handles the search and filter options for when checkAll has been + * toggled. This is a special case, compared to the other search + * menu options, so is intended to be called instead of updateOptions. + */ + checkAll: checkAll + }; + } + return SearchMenuController; +}); diff --git a/platform/search/src/GenericSearchProvider.js b/platform/search/src/services/GenericSearchProvider.js similarity index 100% rename from platform/search/src/GenericSearchProvider.js rename to platform/search/src/services/GenericSearchProvider.js diff --git a/platform/search/src/GenericSearchWorker.js b/platform/search/src/services/GenericSearchWorker.js similarity index 87% rename from platform/search/src/GenericSearchWorker.js rename to platform/search/src/services/GenericSearchWorker.js index 69e4104602..57be98b423 100644 --- a/platform/search/src/GenericSearchWorker.js +++ b/platform/search/src/services/GenericSearchWorker.js @@ -31,36 +31,6 @@ // {id: domainObject's ID, model: domainObject's model} var indexedItems = []; - // Helper function for index() - // Checks whether an item with this ID is already indexed - function conainsItem(id) { - var i; - for (i = 0; i < indexedItems.length; i += 1) { - if (indexedItems[i].id === id) { - return true; - } - } - return false; - } - - /** - * 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) { - var message; - - if (!conainsItem(data.id)) { - indexedItems.push({ - id: data.id, - model: data.model - }); - } - } - // Helper function for serach() function convertToTerms(input) { var terms = input; @@ -177,7 +147,10 @@ self.onmessage = function (event) { if (event.data.request === 'index') { - index(event.data); + indexedItems.push({ + id: event.data.id, + model: event.data.model + }); } else if (event.data.request === 'search') { self.postMessage(search(event.data)); } diff --git a/platform/search/src/SearchAggregator.js b/platform/search/src/services/SearchAggregator.js similarity index 100% rename from platform/search/src/SearchAggregator.js rename to platform/search/src/services/SearchAggregator.js diff --git a/platform/search/test/controllers/ClickAwayControllerSpec.js b/platform/search/test/controllers/ClickAwayControllerSpec.js new file mode 100644 index 0000000000..96e7b6c13f --- /dev/null +++ b/platform/search/test/controllers/ClickAwayControllerSpec.js @@ -0,0 +1,94 @@ +/***************************************************************************** + * 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,describe,it,expect,beforeEach,waitsFor,jasmine*/ + +define( + ["../../src/controllers/ClickAwayController"], + function (ClickAwayController) { + "use strict"; + + describe("The click-away controller", function () { + var mockScope, + mockDocument, + controller; + + beforeEach(function () { + mockScope = jasmine.createSpyObj( + "$scope", + [ "$apply" ] + ); + mockDocument = jasmine.createSpyObj( + "$document", + [ "on", "off" ] + ); + controller = new ClickAwayController(mockScope, mockDocument); + }); + + it("is initially inactive", function () { + expect(controller.isActive()).toBe(false); + }); + + it("does not listen to the document before being toggled", function () { + expect(mockDocument.on).not.toHaveBeenCalled(); + }); + + it("tracks enabled/disabled state when toggled", function () { + controller.toggle(); + expect(controller.isActive()).toBe(true); + controller.toggle(); + expect(controller.isActive()).toBe(false); + controller.toggle(); + expect(controller.isActive()).toBe(true); + controller.toggle(); + expect(controller.isActive()).toBe(false); + }); + + it("allows active state to be explictly specified", function () { + controller.setState(true); + expect(controller.isActive()).toBe(true); + controller.setState(true); + expect(controller.isActive()).toBe(true); + controller.setState(false); + expect(controller.isActive()).toBe(false); + controller.setState(false); + expect(controller.isActive()).toBe(false); + }); + + it("registers a mouse listener when activated", function () { + controller.setState(true); + expect(mockDocument.on).toHaveBeenCalled(); + }); + + it("deactivates and detaches listener on document click", function () { + var callback; + controller.setState(true); + callback = mockDocument.on.mostRecentCall.args[1]; + callback(); + expect(controller.isActive()).toEqual(false); + expect(mockDocument.off).toHaveBeenCalledWith("mouseup", callback); + }); + + + + }); + } +); \ No newline at end of file diff --git a/platform/search/test/controllers/SearchControllerSpec.js b/platform/search/test/controllers/SearchControllerSpec.js new file mode 100644 index 0000000000..720d9bd64a --- /dev/null +++ b/platform/search/test/controllers/SearchControllerSpec.js @@ -0,0 +1,208 @@ +/***************************************************************************** + * 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,describe,it,expect,beforeEach,jasmine*/ + +/** + * SearchSpec. Created by shale on 07/31/2015. + */ +define( + ["../../src/controllers/SearchController"], + function (SearchController) { + "use strict"; + + // These should be the same as the ones on the top of the search controller + var INITIAL_LOAD_NUMBER = 20, + LOAD_INCREMENT = 20; + + describe("The search controller", function () { + var mockScope, + mockSearchService, + mockPromise, + mockSearchResult, + mockDomainObject, + mockTypes, + controller; + + function bigArray(size) { + var array = [], + i; + for (i = 0; i < size; i += 1) { + array.push(mockSearchResult); + } + return array; + } + + + beforeEach(function () { + mockScope = jasmine.createSpyObj( + "$scope", + [ "$watch" ] + ); + mockScope.ngModel = {}; + mockScope.ngModel.input = "test input"; + mockScope.ngModel.checked = {}; + mockScope.ngModel.checked['mock.type'] = true; + mockScope.ngModel.checkAll = true; + + mockSearchService = jasmine.createSpyObj( + "searchService", + [ "query" ] + ); + mockPromise = jasmine.createSpyObj( + "promise", + [ "then" ] + ); + mockSearchService.query.andReturn(mockPromise); + + mockTypes = [{key: 'mock.type', name: 'Mock Type', glyph: '?'}]; + + mockSearchResult = jasmine.createSpyObj( + "searchResult", + [ "" ] + ); + mockDomainObject = jasmine.createSpyObj( + "domainObject", + [ "getModel" ] + ); + mockSearchResult.object = mockDomainObject; + mockDomainObject.getModel.andReturn({name: 'Mock Object', type: 'mock.type'}); + + controller = new SearchController(mockScope, mockSearchService, mockTypes); + controller.search(); + }); + + it("sends queries to the search service", function () { + expect(mockSearchService.query).toHaveBeenCalled(); + }); + + it("populates the results with results from the search service", function () { + expect(mockPromise.then).toHaveBeenCalledWith(jasmine.any(Function)); + mockPromise.then.mostRecentCall.args[0]({hits: []}); + + expect(mockScope.results).toBeDefined(); + }); + + it("is loading until the service's promise fufills", function () { + // Send query + controller.search(); + expect(mockScope.loading).toBeTruthy(); + + // Then resolve the promises + mockPromise.then.mostRecentCall.args[0]({hits: []}); + expect(mockScope.loading).toBeFalsy(); + }); + + + it("displays only some results when there are many", function () { + expect(mockPromise.then).toHaveBeenCalledWith(jasmine.any(Function)); + mockPromise.then.mostRecentCall.args[0]({hits: bigArray(100)}); + + expect(mockScope.results).toBeDefined(); + expect(mockScope.results.length).toBeLessThan(100); + }); + + it("detects when there are more results", function () { + mockScope.ngModel.checkAll = false; + + expect(mockPromise.then).toHaveBeenCalledWith(jasmine.any(Function)); + mockPromise.then.mostRecentCall.args[0]({ + hits: bigArray(INITIAL_LOAD_NUMBER + 5), + total: INITIAL_LOAD_NUMBER + 5 + }); + // bigArray gives searchResults of type 'mock.type' + mockScope.ngModel.checked['mock.type'] = false; + mockScope.ngModel.checked['mock.type.2'] = true; + + expect(controller.areMore()).toBeFalsy(); + + mockScope.ngModel.checked['mock.type'] = true; + + expect(controller.areMore()).toBeTruthy(); + }); + + it("can load more results", function () { + var oldSize; + + expect(mockPromise.then).toHaveBeenCalled(); + mockPromise.then.mostRecentCall.args[0]({ + hits: bigArray(INITIAL_LOAD_NUMBER + LOAD_INCREMENT + 1), + total: INITIAL_LOAD_NUMBER + LOAD_INCREMENT + 1 + }); + // These hits and total lengths are the case where the controller + // DOES NOT have to re-search to load more results + oldSize = mockScope.results.length; + + expect(controller.areMore()).toBeTruthy(); + + controller.loadMore(); + expect(mockScope.results.length).toBeGreaterThan(oldSize); + }); + + it("can re-search to load more results", function () { + var oldSize, + oldCallCount; + + expect(mockPromise.then).toHaveBeenCalled(); + mockPromise.then.mostRecentCall.args[0]({ + hits: bigArray(INITIAL_LOAD_NUMBER + LOAD_INCREMENT - 1), + total: INITIAL_LOAD_NUMBER + LOAD_INCREMENT + 1 + }); + // These hits and total lengths are the case where the controller + // DOES have to re-search to load more results + oldSize = mockScope.results.length; + oldCallCount = mockPromise.then.callCount; + expect(controller.areMore()).toBeTruthy(); + + controller.loadMore(); + expect(mockPromise.then).toHaveBeenCalled(); + // Make sure that a NEW call to search has been made + expect(oldCallCount).toBeLessThan(mockPromise.then.callCount); + mockPromise.then.mostRecentCall.args[0]({ + hits: bigArray(INITIAL_LOAD_NUMBER + LOAD_INCREMENT + 1), + total: INITIAL_LOAD_NUMBER + LOAD_INCREMENT + 1 + }); + expect(mockScope.results.length).toBeGreaterThan(oldSize); + }); + + it("sets the ngModel.search flag", function () { + // Flag should be true with nonempty input + expect(mockScope.ngModel.search).toEqual(true); + + // Flag should be flase with empty input + mockScope.ngModel.input = ""; + controller.search(); + mockPromise.then.mostRecentCall.args[0]({hits: [], total: 0}); + expect(mockScope.ngModel.search).toEqual(false); + + // Both the empty string and undefined should be 'empty input' + mockScope.ngModel.input = undefined; + controller.search(); + mockPromise.then.mostRecentCall.args[0]({hits: [], total: 0}); + expect(mockScope.ngModel.search).toEqual(false); + }); + + it("has a default results list to filter from", function () { + expect(mockScope.ngModel.filter()).toBeDefined(); + }); + }); + } +); \ No newline at end of file diff --git a/platform/search/test/controllers/SearchMenuControllerSpec.js b/platform/search/test/controllers/SearchMenuControllerSpec.js new file mode 100644 index 0000000000..9e31f461c5 --- /dev/null +++ b/platform/search/test/controllers/SearchMenuControllerSpec.js @@ -0,0 +1,133 @@ +/***************************************************************************** + * 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,describe,it,expect,beforeEach,jasmine*/ + +/** + * SearchSpec. Created by shale on 08/17/2015. + */ +define( + ["../../src/controllers/SearchMenuController"], + function (SearchMenuController) { + "use strict"; + + describe("The search menu controller", function () { + var mockScope, + mockPromise, + mockTypes, + controller; + + beforeEach(function () { + mockScope = jasmine.createSpyObj( + "$scope", + [ "" ] + ); + + mockTypes = [ + {key: 'mock.type.1', name: 'Mock Type 1', glyph: 'a'}, + {key: 'mock.type.2', name: 'Mock Type 2', glyph: 'b'} + ]; + + mockScope.ngModel = {}; + mockScope.ngModel.checked = {}; + mockScope.ngModel.checked['mock.type.1'] = false; + mockScope.ngModel.checked['mock.type.2'] = false; + mockScope.ngModel.checkAll = true; + mockScope.ngModel.filter = jasmine.createSpy('$scope.ngModel.filter'); + mockScope.ngModel.filtersString = ''; + + controller = new SearchMenuController(mockScope, mockTypes); + }); + + it("gets types on initiliztion", function () { + expect(mockScope.ngModel.types).toBeDefined(); + }); + + it("refilters results when options are updated", function () { + controller.updateOptions(); + expect(mockScope.ngModel.filter).toHaveBeenCalled(); + + controller.checkAll(); + expect(mockScope.ngModel.filter).toHaveBeenCalled(); + }); + + it("updates the filters string when options are updated", function () { + controller.updateOptions(); + expect(mockScope.ngModel.filtersString).toEqual(''); + + mockScope.ngModel.checked['mock.type.1'] = true; + + controller.updateOptions(); + expect(mockScope.ngModel.filtersString).not.toEqual(''); + }); + + it("changing checkAll status updates the filter string", function () { + controller.checkAll(); + expect(mockScope.ngModel.filtersString).toEqual(''); + + mockScope.ngModel.checkAll = false; + + controller.checkAll(); + expect(mockScope.ngModel.filtersString).toEqual('NONE'); + }); + + it("checking checkAll option resets other options", function () { + var type; + + mockScope.ngModel.checked['mock.type.1'] = true; + mockScope.ngModel.checked['mock.type.2'] = true; + + controller.checkAll(); + + for (type in mockScope.ngModel.checked) { + expect(mockScope.ngModel.checked[type]).toBeFalsy(); + } + }); + + it("tells the user when no options are checked", function () { + var type; + + for (type in mockScope.ngModel.checked) { + mockScope.ngModel.checked[type] = false; + } + mockScope.ngModel.checkAll = false; + + controller.updateOptions(); + + expect(mockScope.ngModel.filtersString).toEqual('NONE'); + }); + + it("tells the user when options are checked", function () { + var type; + + mockScope.ngModel.checkAll = false; + for (type in mockScope.ngModel.checked) { + mockScope.ngModel.checked[type] = true; + } + + controller.updateOptions(); + + expect(mockScope.ngModel.filtersString).not.toEqual('NONE'); + expect(mockScope.ngModel.filtersString).not.toEqual(''); + }); + }); + } +); \ No newline at end of file diff --git a/platform/search/test/GenericSearchProviderSpec.js b/platform/search/test/services/GenericSearchProviderSpec.js similarity index 76% rename from platform/search/test/GenericSearchProviderSpec.js rename to platform/search/test/services/GenericSearchProviderSpec.js index bec02653b8..2da7cd343b 100644 --- a/platform/search/test/GenericSearchProviderSpec.js +++ b/platform/search/test/services/GenericSearchProviderSpec.js @@ -25,7 +25,7 @@ * SearchSpec. Created by shale on 07/31/2015. */ define( - ["../src/GenericSearchProvider"], + ["../../src/services/GenericSearchProvider"], function (GenericSearchProvider) { "use strict"; @@ -81,6 +81,11 @@ define( ); mockWorkerService.run.andReturn(mockWorker); + mockCapabilityPromise = jasmine.createSpyObj( + "promise", + [ "then", "catch" ] + ); + mockDomainObjects = {}; for (i = 0; i < 4; i += 1) { mockDomainObjects[i] = ( @@ -91,6 +96,7 @@ define( ); mockDomainObjects[i].getId.andReturn(i); mockDomainObjects[i].getCapability.andReturn(mockCapability); + mockDomainObjects[i].useCapability.andReturn(mockCapabilityPromise); } // Give the first object children mockDomainObjects[0].hasCapability.andReturn(true); @@ -98,10 +104,6 @@ define( "capability", [ "invoke", "listen" ] ); - mockCapabilityPromise = jasmine.createSpyObj( - "promise", - [ "then", "catch" ] - ); mockCapability.invoke.andReturn(mockCapabilityPromise); mockDomainObjects[0].getCapability.andReturn(mockCapability); @@ -112,13 +114,34 @@ define( expect(mockObjectService.getObjects).toHaveBeenCalled(); expect(mockObjectPromise.then).toHaveBeenCalled(); + // Call through the root-getting part mockObjectPromise.then.mostRecentCall.args[0](mockDomainObjects); - //mockCapabilityPromise.then.mostRecentCall.args[0](mockDomainObjects[1]); + // Call through the children-getting part + mockTimeout.mostRecentCall.args[0](); + // Array argument indicates multiple children + mockCapabilityPromise.then.mostRecentCall.args[0]([]); + mockTimeout.mostRecentCall.args[0](); + // Call again, but for single child + mockCapabilityPromise.then.mostRecentCall.args[0]({}); + mockTimeout.mostRecentCall.args[0](); expect(mockWorker.postMessage).toHaveBeenCalled(); }); + it("when indexing, listens for composition changes", function () { + var mockListener = {composition: {}}; + + // Call indexItems + mockObjectPromise.then.mostRecentCall.args[0](mockDomainObjects); + + // Call through listening for changes + expect(mockCapability.listen).toHaveBeenCalled(); + mockCapability.listen.mostRecentCall.args[0](mockListener); + expect(mockObjectService.getObjects).toHaveBeenCalled(); + mockObjectPromise.then.mostRecentCall.args[0](mockDomainObjects); + }); + it("sends search queries to the worker", function () { var timestamp = Date.now(); provider.query(' test "query" ', timestamp, 1, 2); @@ -131,6 +154,19 @@ define( }); }); + it("gives an empty result for an empty query", function () { + var timestamp = Date.now(), + queryOutput; + + queryOutput = provider.query('', timestamp, 1, 2); + expect(queryOutput.hits).toEqual([]); + expect(queryOutput.total).toEqual(0); + + queryOutput = provider.query(); + expect(queryOutput.hits).toEqual([]); + expect(queryOutput.total).toEqual(0); + }); + it("handles responses from the worker", function () { var timestamp = Date.now(), event = { diff --git a/platform/search/test/GenericSearchWorkerSpec.js b/platform/search/test/services/GenericSearchWorkerSpec.js similarity index 99% rename from platform/search/test/GenericSearchWorkerSpec.js rename to platform/search/test/services/GenericSearchWorkerSpec.js index 2e17858400..b95ec5a1bb 100644 --- a/platform/search/test/GenericSearchWorkerSpec.js +++ b/platform/search/test/services/GenericSearchWorkerSpec.js @@ -31,7 +31,7 @@ define( describe("The generic search worker ", function () { // If this test fails, make sure this path is correct - var worker = new Worker(require.toUrl('platform/search/src/GenericSearchWorker.js')), + var worker = new Worker(require.toUrl('platform/search/src/services/GenericSearchWorker.js')), numObjects = 5; beforeEach(function () { diff --git a/platform/search/test/SearchAggregatorSpec.js b/platform/search/test/services/SearchAggregatorSpec.js similarity index 98% rename from platform/search/test/SearchAggregatorSpec.js rename to platform/search/test/services/SearchAggregatorSpec.js index cf35e2928e..3205f0f9ec 100644 --- a/platform/search/test/SearchAggregatorSpec.js +++ b/platform/search/test/services/SearchAggregatorSpec.js @@ -25,7 +25,7 @@ * SearchSpec. Created by shale on 07/31/2015. */ define( - ["../src/SearchAggregator"], + ["../../src/services/SearchAggregator"], function (SearchAggregator) { "use strict"; diff --git a/platform/search/test/suite.json b/platform/search/test/suite.json index 5097bde635..803949fb6f 100644 --- a/platform/search/test/suite.json +++ b/platform/search/test/suite.json @@ -1,5 +1,8 @@ [ - "SearchAggregator", - "GenericSearchProvider", - "GenericSearchWorker" + "controllers/SearchController", + "controllers/SearchMenuController", + "controllers/ClickAwayController", + "services/SearchAggregator", + "services/GenericSearchProvider", + "services/GenericSearchWorker" ]