Merge branch 'open-master' into angular-1.4.4

This commit is contained in:
Victor Woeltjen 2015-09-08 19:26:46 -07:00
commit 6a917f5393
67 changed files with 3267 additions and 352 deletions

6
.gitignore vendored
View File

@ -3,9 +3,13 @@
*.gzip
*.tgz
*.DS_Store
*.idea
*.sass-cache
# Intellij project configuration files
*.idea
*.iml
# External dependencies
# Build output

View File

@ -18,6 +18,7 @@
"platform/features/scrolling",
"platform/features/events",
"platform/forms",
"platform/identity",
"platform/persistence/queue",
"platform/policy",
"platform/entanglement",

View File

@ -0,0 +1,12 @@
{
"extensions": {
"components": [
{
"implementation": "ExampleIdentityService.js",
"provides": "identityService",
"type": "provider",
"depends": [ "dialogService" ]
}
]
}
}

View File

@ -0,0 +1,75 @@
/*****************************************************************************
* 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*/
define(
function () {
"use strict";
var DEFAULT_IDENTITY = { key: "user", name: "Example User" },
DIALOG_STRUCTURE = {
name: "Identify Yourself",
sections: [{ rows: [
{
name: "User ID",
control: "textfield",
key: "key",
required: true
},
{
name: "Human name",
control: "textfield",
key: "name",
required: true
}
]}]
};
/**
* Example implementation of an identity service. This prompts the
* user to enter a name and user ID; in a more realistic
* implementation, this would be read from a server, possibly
* prompting for a user name and password (or similar) as
* appropriate.
*
* @implements {IdentityService}
* @memberof platform/identity
*/
function ExampleIdentityProvider(dialogService) {
// Handle rejected dialog messages by treating the
// current user as undefined.
function echo(v) { return v; }
function giveUndefined() { return undefined; }
this.userPromise =
dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY)
.then(echo, giveUndefined);
}
ExampleIdentityProvider.prototype.getUser = function () {
return this.userPromise;
};
return ExampleIdentityProvider;
}
);

View File

@ -88,11 +88,6 @@
{
"key": "navigationService",
"implementation": "navigation/NavigationService.js"
},
{
"key": "creationService",
"implementation": "creation/CreationService.js",
"depends": [ "persistenceService", "$q", "$log" ]
}
],
"actions": [
@ -110,7 +105,7 @@
"depends": [ "urlService", "$window" ],
"group": "windowing",
"glyph": "y",
"priority": "preferred"
"priority": "preferred"
},
{
"key": "fullscreen",
@ -118,7 +113,7 @@
"category": "view-control",
"group": "windowing",
"glyph": "z",
"priority": "default"
"priority": "default"
}
],
"views": [
@ -141,6 +136,13 @@
"type": "provider",
"implementation": "creation/CreateActionProvider.js",
"depends": [ "typeService", "dialogService", "creationService", "policyService" ]
},
{
"key": "CreationService",
"provides": "creationService",
"type": "provider",
"implementation": "creation/CreationService.js",
"depends": [ "persistenceService", "$q", "$log" ]
}
],
"runs": [

View File

@ -28,7 +28,15 @@
>
<mct-representation key="'create-button'" mct-object="navigatedObject">
</mct-representation>
<div class='holder tree-holder abs'>
<div class='holder search-holder abs'
ng-class="{active: treeModel.search}">
<mct-representation key="'search'"
mct-object="domainObject"
ng-model="treeModel">
</mct-representation>
</div>
<div class='holder tree-holder abs'
ng-hide="treeModel.search">
<mct-representation key="'tree'"
mct-object="domainObject"
ng-model="treeModel">

View File

@ -59,10 +59,10 @@ define(
var locatingType = locatingObject &&
locatingObject.getCapability('type');
return locatingType && policyService.allow(
"composition",
locatingType,
type
);
"composition",
locatingType,
type
);
}
sections.push({
@ -77,6 +77,9 @@ define(
row.key = index;
return row;
}).filter(function (row) {
// Only show rows which have defined controls
return row && row.control;
})
});

View File

@ -55,6 +55,10 @@ define(
* space an object is created within (as it is possible to
* have multiple persistence spaces attached.)
*
* Note that the model passed in for object creation may be
* modified to attach additional initial properties associated
* with domain object creation.
*
* @param {object} model the model for the newly-created
* domain object
* @param {DomainObject} parent the domain object which
@ -67,12 +71,6 @@ define(
var persistence = parent.getCapability("persistence"),
self = this;
// Store the location of an object relative to it's parent.
function addLocationToModel(modelId, model, parent) {
model.location = parent.getId();
return model;
}
// Persist the new domain object's model; it will be fully
// constituted as a domain object when loaded back, as all
// domain object models are.
@ -135,7 +133,6 @@ define(
// 2. Create a model with that ID in the persistence space
// 3. Add that ID to
return self.$q.when(uuid()).then(function (id) {
model = addLocationToModel(id, model, parent);
return doPersist(persistence.getSpace(), id, model);
}).then(function (id) {
return addToComposition(id, parent, persistence);

View File

@ -42,7 +42,9 @@ define(
"property" + name,
[ "getDefinition", "getValue", "setValue" ]
);
mockProperty.getDefinition.andReturn({});
mockProperty.getDefinition.andReturn({
control: "textfield"
});
mockProperty.getValue.andReturn(name);
return mockProperty;
}
@ -157,4 +159,4 @@ define(
});
}
);
);

View File

@ -201,16 +201,6 @@ define(
expect(mockLog.error).toHaveBeenCalled();
});
it("stores location on new domainObjects", function () {
var model = { name: "my model" },
objectPromise = creationService.createObject(
model,
mockParentObject
);
expect(model.location).toBe('parentId');
});
});
}
);

View File

@ -59,7 +59,7 @@
"glyph": "Z",
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [ "$q" ]
"depends": [ "$q", "navigationService" ]
},
{
"key": "save",

View File

@ -41,9 +41,10 @@ define(
* @constructor
* @implements {Action}
*/
function RemoveAction($q, context) {
function RemoveAction($q, navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.$q = $q;
this.navigationService = navigationService;
}
/**
@ -53,8 +54,8 @@ define(
*/
RemoveAction.prototype.perform = function () {
var $q = this.$q,
navigationService = this.navigationService,
domainObject = this.domainObject;
/*
* Check whether an object ID matches the ID of the object being
* removed (used to filter a parent's composition to handle the
@ -80,21 +81,53 @@ define(
var persistence = domainObject.getCapability('persistence');
return persistence && persistence.persist();
}
/*
* Checks current object and ascendants of current
* object with object being removed, if the current
* object or any in the current object's path is being removed,
* navigate back to parent of removed object.
*/
function checkObjectNavigation(object, parentObject) {
// Traverse object starts at current location
var traverseObject = (navigationService).getNavigation();
// Stop when object is not defined (above ROOT)
while (traverseObject) {
// If object currently traversed to is object being removed
// navigate to parent of current object and then exit loop
if (traverseObject.getId() === object.getId()) {
navigationService.setNavigation(parentObject);
return;
}
// Traverses to parent of current object, moving
// up the ascendant path
traverseObject = traverseObject.getCapability('context').getParent();
}
}
/*
* Remove the object from its parent, as identified by its context
* capability.
* capability. Based on object's location and selected object's location
* user may be navigated to existing parent object
*/
function removeFromContext(contextCapability) {
var parent = contextCapability.getParent();
function removeFromContext(object) {
var contextCapability = object.getCapability('context'),
parent = contextCapability.getParent();
// If currently within path of removed object(s),
// navigates to existing object up tree
checkObjectNavigation(object, parent);
return $q.when(
parent.useCapability('mutation', doMutate)
).then(function () {
return doPersist(parent);
});
parent.useCapability('mutation', doMutate)
).then(function () {
return doPersist(parent);
});
}
return $q.when(this.domainObject.getCapability('context'))
return $q.when(domainObject)
.then(removeFromContext);
};

View File

@ -28,9 +28,16 @@ define(
describe("The Remove action", function () {
var mockQ,
mockNavigationService,
mockDomainObject,
mockParent,
mockChildObject,
mockGrandchildObject,
mockRootObject,
mockContext,
mockChildContext,
mockGrandchildContext,
mockRootContext,
mockMutation,
mockPersistence,
mockType,
@ -54,6 +61,18 @@ define(
"domainObject",
[ "getId", "getCapability" ]
);
mockChildObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getCapability" ]
);
mockGrandchildObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getCapability" ]
);
mockRootObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getCapability" ]
);
mockQ = { when: mockPromise };
mockParent = {
getModel: function () {
@ -67,28 +86,41 @@ define(
}
};
mockContext = jasmine.createSpyObj("context", [ "getParent" ]);
mockChildContext = jasmine.createSpyObj("context", [ "getParent" ]);
mockGrandchildContext = jasmine.createSpyObj("context", [ "getParent" ]);
mockRootContext = jasmine.createSpyObj("context", [ "getParent" ]);
mockMutation = jasmine.createSpyObj("mutation", [ "invoke" ]);
mockPersistence = jasmine.createSpyObj("persistence", [ "persist" ]);
mockType = jasmine.createSpyObj("type", [ "hasFeature" ]);
mockNavigationService = jasmine.createSpyObj(
"navigationService",
[
"getNavigation",
"setNavigation",
"addListener",
"removeListener"
]
);
mockNavigationService.getNavigation.andReturn(mockDomainObject);
mockDomainObject.getId.andReturn("test");
mockDomainObject.getCapability.andReturn(mockContext);
mockContext.getParent.andReturn(mockParent);
mockType.hasFeature.andReturn(true);
capabilities = {
mutation: mockMutation,
persistence: mockPersistence,
type: mockType
};
model = {
composition: [ "a", "test", "b", "c" ]
composition: [ "a", "test", "b" ]
};
actionContext = { domainObject: mockDomainObject };
action = new RemoveAction(mockQ, actionContext);
action = new RemoveAction(mockQ, mockNavigationService, actionContext);
});
it("only applies to objects with parents", function () {
@ -123,11 +155,64 @@ define(
// Should have removed "test" - that was our
// mock domain object's id.
expect(result.composition).toEqual(["a", "b", "c"]);
expect(result.composition).toEqual(["a", "b"]);
// Finally, should have persisted
expect(mockPersistence.persist).toHaveBeenCalled();
});
it("removes parent of object currently navigated to", function () {
// Navigates to child object
mockNavigationService.getNavigation.andReturn(mockChildObject);
// Test is id of object being removed
// Child object has different id
mockDomainObject.getId.andReturn("test");
mockChildObject.getId.andReturn("not test");
// Sets context for the child and domainObject
mockDomainObject.getCapability.andReturn(mockContext);
mockChildObject.getCapability.andReturn(mockChildContext);
// Parents of child and domainObject are set
mockContext.getParent.andReturn(mockParent);
mockChildContext.getParent.andReturn(mockDomainObject);
mockType.hasFeature.andReturn(true);
action.perform();
// Expects navigation to parent of domainObject (removed object)
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
});
it("checks if removing object not in ascendent path (reaches ROOT)", function () {
// Navigates to grandchild of ROOT
mockNavigationService.getNavigation.andReturn(mockGrandchildObject);
// domainObject (grandparent) is set as ROOT, child and grandchild
// are set objects not being removed
mockDomainObject.getId.andReturn("test 1");
mockRootObject.getId.andReturn("ROOT");
mockChildObject.getId.andReturn("not test 2");
mockGrandchildObject.getId.andReturn("not test 3");
// Sets context for the grandchild, child, and domainObject
mockRootObject.getCapability.andReturn(mockRootContext);
mockChildObject.getCapability.andReturn(mockChildContext);
mockGrandchildObject.getCapability.andReturn(mockGrandchildContext);
// Parents of grandchild and child are set
mockChildContext.getParent.andReturn(mockRootObject);
mockGrandchildContext.getParent.andReturn(mockChildObject);
mockType.hasFeature.andReturn(true);
action.perform();
// Expects no navigation to occur
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
});
});
}

View File

@ -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
@ -92,7 +93,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 5, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
@ -113,38 +114,38 @@ time, mark, audio, video {
font-size: 100%;
vertical-align: baseline; }
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 22, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html {
line-height: 1; }
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 24, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
ol, ul {
list-style: none; }
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 26, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
table {
border-collapse: collapse;
border-spacing: 0; }
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 28, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle; }
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 30, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q, blockquote {
quotes: none; }
/* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 103, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after {
content: "";
content: none; }
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 32, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
a img {
border: none; }
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 116, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
display: block; }
@ -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;

View File

@ -250,3 +250,249 @@ 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 {
display: none;
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 299, ../sass/search/_search.scss */
.search .search-scroll .results .search-result-item:not(.selected):hover {
background: #404040;
color: #cccccc; }
/* line 302, ../sass/search/_search.scss */
.search .search-scroll .results .search-result-item:not(.selected):hover .context-trigger {
display: block; }
/* line 305, ../sass/search/_search.scss */
.search .search-scroll .results .search-result-item:not(.selected):hover .icon {
color: #33ccff; }
/* line 313, ../sass/search/_search.scss */
.search .search-scroll .load-icon {
position: relative; }
/* line 315, ../sass/search/_search.scss */
.search .search-scroll .load-icon.loading {
pointer-events: none;
margin-left: 6px; }
/* line 319, ../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 329, ../sass/search/_search.scss */
.search .search-scroll .load-icon.loading .wait-spinner {
margin-left: 6px; }
/* line 334, ../sass/search/_search.scss */
.search .search-scroll .load-icon:not(.loading) {
cursor: pointer; }
/* line 339, ../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; }

View File

@ -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

View File

@ -83,6 +83,7 @@
<glyph unicode="&#xe604;" glyph-name="icon-tabular" d="M0 896v-192h448v256h-384c-35.2 0-64-28.8-64-64zM960 960h-384v-256h448v192c0 35.2-28.8 64-64 64zM576 576h448v-256h-448v256zM0 576h448v-256h-448v256zM0 0c0-35.2 28.8-64 64-64h384v256h-448v-192zM576-64h384c35.2 0 64 28.8 64 64v192h-448v-256z" />
<glyph unicode="&#xe605;" glyph-name="icon-calendar" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM640 512h-256v192h256v-192zM384 448h256v-192h-256v192zM320 256h-256v192h256v-192zM320 704v-192h-256v192h256zM128 0c-17 0-33 6.6-45.2 18.8s-18.8 28.2-18.8 45.2v128h256v-192h-192zM384 0v192h256v-192h-256zM960 64c0-17-6.6-33-18.8-45.2s-28.2-18.8-45.2-18.8h-192v192h256v-128zM960 256h-256v192h256v-192zM960 512h-256v192h256v-192z" />
<glyph unicode="&#xe606;" glyph-name="icon-paint-bucket" d="M896 320c0 0-130-188-128-256 2-70.6 57.4-128 128-128s126 57.4 128 128c2 68-128 256-128 256zM449 831l0.2 64.8c0 35.4-28.4 64-63.8 64.2 0 0-0.2 0-0.2 0-35.2 0-63.8-28.6-64-63.8l-0.6-190.8-294-292.6c-50-50-12.4-215.2 112.4-340s290-162.4 340-112.4l417 423.6-447 447zM384 320c-70.6 0-128 57.4-128 128 0 47.4 25.8 89 64.4 111l-0.4-110.8c0-35.4 28.4-64 63.8-64.2 0 0 0.2 0 0.2 0 35.2 0 63.8 28.6 64 63.8l0.4 110.8c38-22.2 63.6-63.4 63.6-110.6 0-70.6-57.4-128-128-128z" />
<glyph unicode="&#xe607;" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
<glyph unicode="&#xe60d;" glyph-name="icon-arrows-right-left" d="M1024 448l-448-512v1024zM448 960l-448-512 448-512z" />
<glyph unicode="&#xe642;" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -100,6 +100,7 @@ $ueAppLogoW: 105px;
$ueEditToolBarH: 25px;
$ueBrowseLeftPaneW: 25%;
$ueEditLeftPaneW: 75%;
$treeSearchInputBarH: 25px;
// Overlay
$ovrTopBarH: 60px;
$ovrFooterH: 40px;

View File

@ -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";

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -0,0 +1,350 @@
/*****************************************************************************
* 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 {
// Hide links for now. See GitHub issue #84.
display: none;
@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;
}
}
}

View File

@ -27,4 +27,5 @@
@import "constants";
@import "mixins";
@import "tree/tree";
@import "tree/tree";
@import "search/search";

View File

@ -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 {

View File

@ -135,9 +135,6 @@ define(
// Listen for changes which will effect display parameters
$scope.$watch("ngModel.selectedObject", setSelection);
$scope.$watch("domainObject", checkSelection);
}
/**

View File

@ -50,8 +50,8 @@ define(
function formatTimestamp(timestamp) {
return typeof timestamp === 'number' ?
(moment.utc(timestamp).format(TIME_FORMAT) + " UTC") :
undefined;
(moment.utc(timestamp).format(TIME_FORMAT) + " UTC") :
undefined;
}
function getProperties() {

View File

@ -72,7 +72,12 @@ define(
*/
PersistenceCapability.prototype.persist = function () {
var domainObject = this.domainObject,
modified = domainObject.getModel().modified;
model = domainObject.getModel(),
modified = model.modified,
persistenceService = this.persistenceService,
persistenceFn = model.persisted !== undefined ?
this.persistenceService.updateObject :
this.persistenceService.createObject;
// Update persistence timestamp...
domainObject.useCapability("mutation", function (model) {
@ -80,11 +85,11 @@ define(
}, modified);
// ...and persist
return this.persistenceService.updateObject(
return persistenceFn.apply(persistenceService, [
this.getSpace(),
domainObject.getId(),
domainObject.getModel()
);
]);
};
/**

View File

@ -48,7 +48,7 @@ define(
beforeEach(function () {
mockPersistenceService = jasmine.createSpyObj(
"persistenceService",
[ "updateObject", "readObject" ]
[ "updateObject", "readObject", "createObject", "deleteObject" ]
);
mockDomainObject = {
getId: function () { return id; },
@ -68,10 +68,24 @@ define(
);
});
it("makes a call to the persistence service when invoked", function () {
it("creates unpersisted objects with the persistence service", function () {
// Verify precondition; no call made during constructor
expect(mockPersistenceService.createObject).not.toHaveBeenCalled();
persistence.persist();
expect(mockPersistenceService.createObject).toHaveBeenCalledWith(
SPACE,
id,
model
);
});
it("updates previously persisted objects with the persistence service", function () {
// Verify precondition; no call made during constructor
expect(mockPersistenceService.updateObject).not.toHaveBeenCalled();
model.persisted = 12321;
persistence.persist();
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
@ -112,4 +126,4 @@ define(
});
}
);
);

View File

@ -33,6 +33,11 @@
}
],
"components": [
{
"type": "decorator",
"provides": "creationService",
"implementation": "services/LocatingCreationDecorator.js"
}
],
"controllers": [
],

View File

@ -0,0 +1,49 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* Adds a `location` property to newly-created domain objects.
* @constructor
* @augments {platform/commonUI/browse.CreationService}
* @memberof platform/entanglement
*/
function LocatingCreationDecorator(creationService) {
this.creationService = creationService;
}
LocatingCreationDecorator.prototype.createObject = function (model, parent) {
if (parent && parent.getId) {
model.location = parent.getId();
}
return this.creationService.createObject(model, parent);
};
return LocatingCreationDecorator;
}
);

View File

@ -0,0 +1,79 @@
/*****************************************************************************
* 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,beforeEach,it,jasmine,expect */
define(
[
'../../src/services/LocatingCreationDecorator'
],
function (LocatingCreationDecorator) {
"use strict";
describe("LocatingCreationDecorator", function () {
var mockCreationService,
mockPromise,
mockParent,
decorator;
beforeEach(function () {
mockCreationService = jasmine.createSpyObj(
'creationService',
['createObject']
);
mockPromise = jasmine.createSpyObj(
'promise',
['then']
);
mockParent = jasmine.createSpyObj(
'domainObject',
['getCapability', 'getId', 'getModel', 'hasCapability', 'useCapability']
);
mockCreationService.createObject.andReturn(mockPromise);
mockParent.getId.andReturn('test-id');
decorator = new LocatingCreationDecorator(mockCreationService);
});
it("delegates to its decorated service", function () {
expect(decorator.createObject(
{ someKey: "some value" },
mockParent
)).toEqual(mockPromise); // promise returned by decoratee
});
it("adds a location property", function () {
decorator.createObject(
{ someKey: "some value" },
mockParent
);
expect(mockCreationService.createObject).toHaveBeenCalledWith(
{
someKey: "some value",
location: "test-id" // Parent's identifier
},
mockParent
);
});
});
}
);

View File

@ -4,5 +4,6 @@
"services/LinkService",
"services/MoveService",
"services/LocationService",
"services/LocatingCreationDecorator",
"capabilities/LocationCapability"
]

View File

@ -0,0 +1,41 @@
{
"extensions": {
"components": [
{
"implementation": "IdentityAggregator.js",
"type": "aggregator",
"provides": "identityService",
"depends": [ "$q" ]
},
{
"implementation": "IdentityProvider.js",
"type": "provider",
"provides": "identityService",
"depends": [ "$q" ],
"priority": "fallback"
},
{
"type": "decorator",
"provides": "creationService",
"implementation": "IdentityCreationDecorator.js",
"depends": [ "identityService" ]
}
],
"indicators": [
{
"implementation": "IdentityIndicator.js",
"depends": [ "identityService" ]
}
],
"types": [
{
"properties": [
{
"key": "creator",
"name": "Creator"
}
]
}
]
}
}

View File

@ -0,0 +1,93 @@
/*****************************************************************************
* 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*/
/**
* Defines interfaces and common infrastructure for establishing
* a user's identity.
* @namespace platform/identity
*/
define(
function () {
"use strict";
/**
* Provides information about the currently logged-in
* user, if available.
*
* @interface IdentityService
*/
/**
* Get information about the current user. This returns a promise
* which will resolve to metadata about the user, or undefined if
* no information about the user is available.
*
* @method IdentityService#getUser
* @returns {Promise.<IdentityMetadata>} a promise for metadata about
* the current user
*/
/**
* Metadata about a user.
*
* @typedef IdentityMetadata
* @property {string} name the user's human-readable name
* @property {string} key the user's machine-readable name
*/
/**
* Aggregator for multiple identity services. Exposes the first
* defined identity provided by any provider, according to
* priority order.
*
* @constructor
* @implements {IdentityService}
* @memberof platform/identity
*/
function IdentityAggregator($q, providers) {
this.providers = providers;
this.$q = $q;
}
function delegateGetUser(provider) {
return provider.getUser();
}
function identity(value) {
return value;
}
function giveFirst(results) {
return results.filter(identity)[0];
}
IdentityAggregator.prototype.getUser = function () {
var $q = this.$q,
promises = this.providers.map(delegateGetUser);
return $q.all(promises).then(giveFirst);
};
return IdentityAggregator;
}
);

View File

@ -0,0 +1,55 @@
/*****************************************************************************
* 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 */
define(
function () {
"use strict";
/**
* Adds a `creator` property to newly-created domain objects.
* @constructor
* @augments {platform/commonUI/browse.CreationService}
* @memberof platform/entanglement
*/
function IdentityCreationDecorator(identityService, creationService) {
this.identityService = identityService;
this.creationService = creationService;
}
IdentityCreationDecorator.prototype.createObject = function (model, parent) {
var creationService = this.creationService,
identityService = this.identityService;
return identityService.getUser().then(function (user) {
if (user && user.key) {
model.creator = user.key;
}
return creationService.createObject(model, parent);
});
};
return IdentityCreationDecorator;
}
);

View File

@ -0,0 +1,63 @@
/*****************************************************************************
* 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*/
define(
[],
function () {
"use strict";
/**
* Indicator showing the currently logged-in user.
* @constructor
* @memberof platform/identity
* @implements {Indicator}
* @param {IdentityService} identityService the identity service
*/
function IdentityIndicator(identityService) {
// Track the current connection state
var self = this;
identityService.getUser().then(function (user) {
if (user && user.key) {
self.text = user.name || user.key;
self.description = "Logged in as " + user.key;
}
});
}
IdentityIndicator.prototype.getGlyph = function () {
return this.text && "P";
};
IdentityIndicator.prototype.getGlyphClass = function () {
return undefined;
};
IdentityIndicator.prototype.getText = function () {
return this.text;
};
IdentityIndicator.prototype.getDescription = function () {
return this.description;
};
return IdentityIndicator;
}
);

View File

@ -0,0 +1,53 @@
/*****************************************************************************
* 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*/
/**
* Defines interfaces and common infrastructure for establishing
* a user's identity.
* @namespace platform/identity
*/
define(
function () {
"use strict";
/**
* Default implementation of an identity service. Provides an
* unknown user as an `undefined` value; this is present simply
* to ensure that there is always an `identityService` available
* for platform components to use.
*
* @constructor
* @implements {IdentityService}
* @memberof platform/identity
*/
function IdentityProvider($q) {
this.userPromise = $q.when(undefined);
}
IdentityProvider.prototype.getUser = function () {
return this.userPromise;
};
return IdentityProvider;
}
);

View File

@ -0,0 +1,143 @@
/*****************************************************************************
* 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,runs,jasmine*/
define(
["../src/IdentityAggregator"],
function (IdentityAggregator) {
"use strict";
describe("The identity aggregator", function () {
var mockProviders,
mockQ,
resolves,
mockPromise,
mockCallback,
testUsers,
aggregator;
function callbackCalled() {
return mockCallback.calls.length > 0;
}
function resolveProviderPromises() {
['a', 'b', 'c'].forEach(function (id, i) {
resolves[id](testUsers[i]);
});
}
beforeEach(function () {
testUsers = [
{ key: "user0", name: "User Zero" },
{ key: "user1", name: "User One" },
{ key: "user2", name: "User Two" }
];
resolves = {};
mockProviders = ['a', 'b', 'c'].map(function (id) {
var mockProvider = jasmine.createSpyObj(
'provider-' + id,
[ 'getUser' ]
);
mockProvider.getUser.andReturn(new Promise(function (r) {
resolves[id] = r;
}));
return mockProvider;
});
mockQ = jasmine.createSpyObj('$q', ['all']);
mockQ.all.andCallFake(function (promises) {
return Promise.all(promises);
});
mockCallback = jasmine.createSpy('callback');
aggregator = new IdentityAggregator(
mockQ,
mockProviders
);
});
it("delegates to the aggregated providers", function () {
// Verify precondition
mockProviders.forEach(function (p) {
expect(p.getUser).not.toHaveBeenCalled();
});
aggregator.getUser();
mockProviders.forEach(function (p) {
expect(p.getUser).toHaveBeenCalled();
});
});
it("returns the first result when it is defined", function () {
aggregator.getUser().then(mockCallback);
resolveProviderPromises();
waitsFor(callbackCalled);
runs(function () {
expect(mockCallback).toHaveBeenCalledWith(testUsers[0]);
});
});
it("returns a later result when earlier results are undefined", function () {
testUsers[0] = undefined;
aggregator.getUser().then(mockCallback);
resolveProviderPromises();
waitsFor(callbackCalled);
runs(function () {
expect(mockCallback).toHaveBeenCalledWith(testUsers[1]);
});
});
it("returns undefined when no providers expose users", function () {
testUsers = [ undefined, undefined, undefined ];
aggregator.getUser().then(mockCallback);
resolveProviderPromises();
waitsFor(callbackCalled);
runs(function () {
expect(mockCallback).toHaveBeenCalledWith(undefined);
});
});
it("returns undefined when there are no providers", function () {
new IdentityAggregator(mockQ, []).getUser().then(mockCallback);
waitsFor(callbackCalled);
runs(function () {
expect(mockCallback).toHaveBeenCalledWith(undefined);
});
});
});
}
);

View File

@ -0,0 +1,107 @@
/*****************************************************************************
* 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,beforeEach,it,jasmine,expect,Promise,waitsFor,runs */
define(
[
'../src/IdentityCreationDecorator'
],
function (IdentityCreationDecorator) {
"use strict";
describe("IdentityCreationDecorator", function () {
var mockIdentityService,
mockCreationService,
mockParent,
mockCreatedObject,
mockCallback,
decorator;
function calledBack() {
return mockCallback.calls.length > 0;
}
beforeEach(function () {
mockCallback = jasmine.createSpy('callback');
mockIdentityService = jasmine.createSpyObj(
'identityService',
['getUser']
);
mockCreationService = jasmine.createSpyObj(
'creationService',
['createObject']
);
mockParent = jasmine.createSpyObj(
'parentObject',
['getCapability', 'getId', 'getModel', 'hasCapability', 'useCapability']
);
mockCreatedObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'getId', 'getModel', 'hasCapability', 'useCapability']
);
mockCreationService.createObject
.andReturn(Promise.resolve(mockCreatedObject));
mockIdentityService.getUser
.andReturn(Promise.resolve({ key: "test-user-id" }));
mockParent.getId.andReturn('test-id');
decorator = new IdentityCreationDecorator(
mockIdentityService,
mockCreationService
);
});
it("delegates to its decorated service when identity is available", function () {
var testModel = { someKey: "some value" };
decorator.createObject(testModel, mockParent)
.then(mockCallback);
waitsFor(calledBack);
runs(function () {
expect(mockCallback)
.toHaveBeenCalledWith(mockCreatedObject);
});
});
it("adds a creator property", function () {
var testModel = { someKey: "some value" };
decorator.createObject(testModel, mockParent)
.then(mockCallback);
waitsFor(calledBack);
runs(function () {
expect(mockCallback)
.toHaveBeenCalledWith(mockCreatedObject);
// Make sure arguments were delegated appropriately
expect(mockCreationService.createObject)
.toHaveBeenCalledWith(
{ someKey: "some value", creator: "test-user-id" },
mockParent
);
});
});
});
}
);

View File

@ -0,0 +1,76 @@
/*****************************************************************************
* 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/IdentityIndicator"],
function (IdentityIndicator) {
"use strict";
describe("The identity indicator", function () {
var mockPromise,
mockIdentityService,
indicator;
beforeEach(function () {
mockPromise = jasmine.createSpyObj('promise', ['then']);
mockIdentityService = jasmine.createSpyObj(
'identityService',
['getUser']
);
mockIdentityService.getUser.andReturn(mockPromise);
indicator = new IdentityIndicator(mockIdentityService);
});
it("shows information about the current user", function () {
mockPromise.then.mostRecentCall.args[0]({
key: "testuserid",
name: "A User"
});
// Should have a single character glyph
expect(indicator.getGlyph().length).toEqual(1);
expect(indicator.getGlyphClass()).toBeUndefined();
expect(indicator.getText()).toEqual("A User");
expect(indicator.getDescription().indexOf("testuserid"))
.not.toEqual(-1);
});
it("shows nothing while no user information is available", function () {
expect(indicator.getGlyph()).toBeUndefined();
expect(indicator.getGlyphClass()).toBeUndefined();
expect(indicator.getText()).toBeUndefined();
expect(indicator.getDescription()).toBeUndefined();
});
it("shows nothing when there is no identity information", function () {
mockPromise.then.mostRecentCall.args[0](undefined);
expect(indicator.getGlyph()).toBeUndefined();
expect(indicator.getGlyphClass()).toBeUndefined();
expect(indicator.getText()).toBeUndefined();
expect(indicator.getDescription()).toBeUndefined();
});
});
}
);

View File

@ -0,0 +1,60 @@
/*****************************************************************************
* 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,beforeEach,it,jasmine,expect,Promise,waitsFor,runs */
define(
[
'../src/IdentityProvider'
],
function (IdentityProvider) {
"use strict";
describe("IdentityProvider", function () {
var mockQ, mockCallback, provider;
function calledBack() {
return mockCallback.calls.length > 0;
}
beforeEach(function () {
mockCallback = jasmine.createSpy('callback');
mockQ = jasmine.createSpyObj('$q', ['when']);
mockQ.when.andCallFake(function (v) {
return Promise.resolve(v);
});
provider = new IdentityProvider(mockQ);
});
it("provides an undefined user", function () {
provider.getUser().then(mockCallback);
waitsFor(calledBack);
runs(function () {
expect(mockCallback).toHaveBeenCalledWith(undefined);
});
});
});
}
);

View File

@ -0,0 +1,6 @@
[
"IdentityAggregator",
"IdentityCreationDecorator",
"IdentityIndicator",
"IdentityProvider"
]

View File

@ -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": [

View File

@ -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;
}
);

View File

@ -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);
});

View File

@ -1,5 +1,5 @@
[
"ElasticIndicator",
"ElasticPersistenceProvider",
"ElasticsearchSearchProvider"
"ElasticSearchProvider"
]

View File

@ -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"
}
]
}
}
}

View File

@ -0,0 +1,30 @@
<!--
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.
-->
<div class="search-result-item"
ng-class="{selected: ngModel.selectedObject.getId() === domainObject.getId()}">
<mct-representation key="'label'"
mct-object="domainObject"
ng-model="ngModel"
ng-click="ngModel.selectedObject = domainObject">
</mct-representation>
</div>

View File

@ -0,0 +1,67 @@
<!--
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.
-->
<div ng-controller="SearchMenuController as controller">
<div class="menu checkbox-menu">
<ul>
<!-- First element is special - it's a reset option -->
<li class="search-menu-item special"
title="Select all filters"
ng-click="ngModel.checkAll = !ngModel.checkAll; controller.checkAll()">
<label class="checkbox custom no-text">
<input type="checkbox"
class="checkbox"
ng-model="ngModel.checkAll"
ng-change="controller.checkAll()" />
<em></em>
</label>
<span class="ui-symbol icon type-icon">
*
</span>
All
</li>
<!-- The filter options, by type -->
<li class="search-menu-item"
ng-repeat="type in ngModel.types"
ng-click="ngModel.checked[type.key] = !ngModel.checked[type.key]; controller.updateOptions()">
<label class="checkbox custom no-text">
<input type="checkbox"
class="checkbox"
ng-model="ngModel.checked[type.key]"
ng-change="controller.updateOptions()" />
<em></em>
</label>
<span class="ui-symbol icon type-icon">
{{ type.glyph }}
</span>
{{ type.name }}
</li>
</ul>
</div>
</div>

View File

@ -0,0 +1,116 @@
<!--
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.
-->
<div class="search"
ng-controller="SearchController as controller">
<!-- Search bar -->
<div class="search-bar"
ng-controller="ClickAwayController as toggle">
<!-- Input field -->
<input class="search-input"
type="text"
ng-model="ngModel.input"
ng-keyup="controller.search()" />
<!--mct-control key="'textfield'"
class="search-input"
ng-model="ngModel.input"
ng-keyup="controller.search()">
</mct-control-->
<!-- Search icon -->
<!-- ui symbols for search are 'd' and 'M' -->
<div class="ui-symbol search-icon"
ng-class="{content: !(ngModel.input === '' || ngModel.input === undefined)}">
M
</div>
<!-- Clear icon/button 'x' -->
<a class="ui-symbol clear-icon"
ng-class="{content: !(ngModel.input === '' || ngModel.input === undefined)}"
ng-click="ngModel.input = ''; controller.search()">
&#xe607;
</a>
<!-- Menu icon/button 'v' -->
<a class="ui-symbol menu-icon"
ng-click="toggle.toggle()">
v
</a>
<!-- Menu -->
<mct-representation key="'search-menu'"
class="menu-element search-menu-holder"
ng-class="{off: !toggle.isActive()}"
ng-model="ngModel"
ng-click="toggle.setState(true)">
</mct-representation>
</div>
<!-- Active filter display -->
<div class="active-filter-display"
ng-class="{off: ngModel.filtersString === '' || ngModel.filtersString === undefined || !ngModel.search}"
ng-controller="SearchMenuController as menuController">
<a class="ui-symbol clear-filters-icon"
ng-click="ngModel.checkAll = true; menuController.checkAll()">
&#xe607;
</a>
Filtered by: {{ ngModel.filtersString }}
<!--div class="filter-options">
Filtered by: {{ ngModel.filtersString }}
</div-->
</div>
<!-- This div exists to determine scroll bar location -->
<div class="search-scroll abs">
<!-- Results list -->
<div class="results">
<mct-representation key="'search-item'"
ng-repeat="result in results"
mct-object="result.object"
ng-model="ngModel">
</mct-representation>
</div>
<!-- Loading icon -->
<div class="load-icon"
ng-class="{loading: loading}"
ng-if="loading">
<span class="icon wait-spinner"></span>
<span class="title-label">Loading...</span>
</div>
<!-- Load more button -->
<div ng-if="controller.areMore()">
<a class="load-more-button btn very-subtle vsm"
ng-click="controller.loadMore()">
More Results
</a>
</div>
</div>
</div>

View File

@ -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;
}
);

View File

@ -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;
});

View File

@ -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;
});

View File

@ -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));
}

View File

@ -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);
});
});
}
);

View File

@ -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();
});
});
}
);

View File

@ -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('');
});
});
}
);

View File

@ -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 = {

View File

@ -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 () {

View File

@ -25,7 +25,7 @@
* SearchSpec. Created by shale on 07/31/2015.
*/
define(
["../src/SearchAggregator"],
["../../src/services/SearchAggregator"],
function (SearchAggregator) {
"use strict";

View File

@ -1,5 +1,8 @@
[
"SearchAggregator",
"GenericSearchProvider",
"GenericSearchWorker"
"controllers/SearchController",
"controllers/SearchMenuController",
"controllers/ClickAwayController",
"services/SearchAggregator",
"services/GenericSearchProvider",
"services/GenericSearchWorker"
]

11
pom.xml
View File

@ -176,6 +176,17 @@
</executions>
</plugin>
<!-- To start this WAR in an embedded Tomcat Servlet Container -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<httpPort>8080</httpPort>
<path>/mct</path>
</configuration>
</plugin>
</plugins>
</build>