Compare commits

..

82 Commits

Author SHA1 Message Date
Charles Hacskaylo
28a3ada6af [Front-end] WIP Updates to widget styles
Fixes #1644
Fixes #1668
Getting main layout in order;
Renamed *-wrapper classes to *-w;
Drag and re-order of rules is broken :(
2017-09-14 14:55:52 -07:00
Charles Hacskaylo
ce0f24c86f [Front-end] Better arg naming
Fixes #1644
Fixes #1668
2017-09-14 14:53:16 -07:00
Charles Hacskaylo
6ca2a755dc [Front-end] Generalize .section-header
Fixes #1644
Fixes #1668
2017-09-14 14:52:13 -07:00
Doubek-Kraft
f6c1488ccd [Summary Widgets] Merge with style
Merge remote-tracking branch 'origin/summary-widget-styling-2' into summary-widgets
2017-08-25 14:23:06 -07:00
Doubek-Kraft
26be1ecf37 [Summary Widgets] Merge with style
Merge remote-tracking branch 'origin/summary-widget-styling-2' into summary-widgets

Restore correct glyphs after merge with master
2017-08-25 14:19:50 -07:00
Charles Hacskaylo
38f0f072bb [Merge] Ellipsize added to l-summary-widget
Fixes #1669
2017-08-25 14:19:43 -07:00
Charles Hacskaylo
e5e969665f [Merge] Merge latest master
Fixes #1669
Merge + resolve conflicts;
2017-08-25 14:11:34 -07:00
Doubek-Kraft
ffbb662c99 [Summary Widgets] Unit tests 2017-08-25 14:09:22 -07:00
Doubek-Kraft
bd7b23f896 [Summary Widgets] Merge from style branch
Merge remote-tracking branch 'origin/summary-widget-styling-2' into summary-widgets

Resolve conflicts with divergent rule implementation
2017-08-25 12:43:29 -07:00
Doubek-Kraft
c238def902 [Summary Widgets] Unit tests 2017-08-25 11:57:29 -07:00
Charles Hacskaylo
2d430ece7f [Merge] Thumbs now show icon and label text
Fixes #1669
Updates to allow thumbs to show their associated
icon and label text;
minor CSS tweaks for icon size and ellipsizing;
New rules now don't use first icon by default;
2017-08-25 11:40:46 -07:00
Doubek-Kraft
c92644a661 [Summary Widgets] Merge from master
Merge remote-tracking branch 'origin/master' into summary-widgets

Patch error with SineWave generators after merge
2017-08-25 10:04:32 -07:00
Doubek-Kraft
41ce3c04f7 [Summary Widgets] Unit Tests 2017-08-24 16:52:44 -07:00
Doubek-Kraft
fcf77f359f [Summary Widgets] Unit tests 2017-08-24 12:06:31 -07:00
Doubek-Kraft
40a2737915 [Summary Widgets] Performance Improvements
Remove unecessary re-initialization of Rule objects on certain
user interactions, and cleanup related code
2017-08-24 10:12:55 -07:00
Doubek-Kraft
216489d67f [Summary Widgets] Tests
Add unit tests
2017-08-23 17:01:14 -07:00
Doubek-Kraft
418a393b26 [Sumamry Widgets] Destroy
Implement destroy
2017-08-23 13:09:36 -07:00
Aaron Doubek-Kraft
1f3d744494 [Summary Widgets] Event Emitters
Replace custom event handlers with EventEmitters, remove binds
assoicated with old event handlers, and update documentation and
callback functions
2017-08-22 23:31:45 -07:00
Doubek-Kraft
ff3f2dccba [Summary Widget] Tests
Add and update unit tests

Fix style in markup

Begin implementing destroy
2017-08-22 16:51:00 -07:00
Doubek-Kraft
e69973bd29 [Summary Widgets] Documentation
Finished adding JSDoc comments

Standardize usage of event handler callbacks

Fix rule persistence bug
2017-08-22 11:13:26 -07:00
Doubek-Kraft
05b352cc36 [Summary Widgets] Documentation
Add JSDoc style comments
2017-08-21 17:05:41 -07:00
Doubek-Kraft
9735548999 [Summary Widgets] Add documentation 2017-08-18 16:22:23 -07:00
Doubek-Kraft
f9529b1362 [Summary Widgets] UI for scripted conditions
Add textfield input for JavaScript condition input, and modify the
condition manager and condition evaluator to read JS conditions
correctly from the data model. Currently, custom conditions are
not actually executed and will always be evaluated as false.
2017-08-18 14:27:57 -07:00
Doubek-Kraft
c598cec702 [Summary Widgets] Unit Tests
Add and update tests for select classes

Stub specfiles for test data and DnD
2017-08-17 16:44:33 -07:00
Doubek-Kraft
e9ea1c4a0f [Summary Widgets] Edit Mode
Enable edit mode for summary widgets, and make configuration interface
visible only when the user has entered edit mode

Standardize usage of 'mutate'

Fix collision between widget palettes and other interfaces where
palettes would permanently hide other menus
2017-08-17 13:47:49 -07:00
Doubek-Kraft
e9238ff282 [Summary Widgets] Merge from View API Branch
Merge remote-tracking branch 'origin/view-api-implementation'
 into summary-widgets
2017-08-17 09:31:36 -07:00
Doubek-Kraft
4cebd72cba [Summary Widgets] Merge from style branch
Issues #1644 #1669

Merge remote-tracking branch 'origin/summary-widget-styling-2' into summary-widgets

Integrate new style for inputs
2017-08-16 14:57:29 -07:00
Doubek-Kraft
f8a44d6e71 [Summary Widget] Test Data
Issue #1644

Add user-configurable mock data to test rules. Modify evaluator to
gracefully handle uninitialzed test data points.

Fix DnD bug where drag position was not tracked correctly
2017-08-16 14:37:03 -07:00
Pete Richards
d0745b300b Allow views to be editable 2017-08-16 11:20:04 -07:00
Charles Hacskaylo
2a4e0a3081 [Frontend] Mods to custom selects
Fixes #1669
line-height, context arrow positioning and color
2017-08-16 10:50:08 -07:00
Charles Hacskaylo
1ff19f9574 [Front-end] Refinements to palette .selected
Fixes #1669
Unit tested in espresso and snow themes as well;
2017-08-15 16:04:07 -07:00
Charles Hacskaylo
7ef84cb50d [Front-end] Fix palette menu when no icon is selected
Fixes #1669
2017-08-15 15:51:32 -07:00
Charles Hacskaylo
cd05c70d64 [Front-end] Fixes to palette CSS
Fixes #1669
Changed .selected to avoid icon collision when
applying .selected to a an item in an icon palette;
Moved color defs into theme constants files;
TO-DO: fix custom select alignment issues,
fix menu when no icon is selected,
unit test in Snow theme.
2017-08-15 15:24:18 -07:00
Doubek-Kraft
568473b82f [Summary Widgets] Rule Reorders
Cleanup Widget DnD code and package it as a module
2017-08-14 16:24:38 -07:00
Doubek-Kraft
c61b074755 [Summary Widgets] Rule Reorders
Re-implement drag and drop with a 'sortable list' style interface
2017-08-14 14:21:37 -07:00
Doubek-Kraft
8ed66ab4ab [Summary Widgets] Rule Reorders
Implement drag and drop rule reorders using the native HTML5 API
2017-08-11 16:57:40 -07:00
Doubek-Kraft
b2502dd998 [Summary Widgets] Selection classes for palettes
Merge remote-tracking branch 'origin/summary-widget-styling-2' into
 summary-widgets. Issues #1669 #1644

Update palette classes to apply a visual indicator for selection
to their items.
2017-08-10 10:39:15 -07:00
Doubek-Kraft
856eedbf9d [Summary Widgets] 'Any/All Telemetry' in conditions
Add UI and implemenetion for evaluating any telemetry or all telemetry
in an individual condition. Add related unit tests.
2017-08-09 16:54:19 -07:00
Charles Hacskaylo
0c0ca6e6af [Frontend] Colors for palette defined
Fixes #1669
2017-08-09 16:00:33 -07:00
Doubek-Kraft
498b797e49 [Summary Widgets] Fix input issue
Fix a bug in the compsosition object selector where it would not display its
currently selected item on a composition add.

Update names of modules to more accurately describe their function.
2017-08-09 10:44:41 -07:00
Doubek-Kraft
02c33388ba [Summary Widgets] Generate Rule Descriptions
Dynamically update the rule description based on the current state
of the rules' conditions
2017-08-08 17:47:54 -07:00
Charles Hacskaylo
8a8e3cc055 [Front-end] WIP colors for Summary Widget palettes
Fixes #1669
2017-08-08 16:11:52 -07:00
Charles Hacskaylo
36d60b16e9 [Front-end] Updated Style Guide
Fixes #1669
Updated palette example in Style Guide to use `no-selection` and `selected` classes;
2017-08-08 15:35:41 -07:00
Charles Hacskaylo
de3114568b [Front-end] Implemented no-selection class in widgets
Fixes #1669
Added `no-selection` class to "None" selection choice in widgets palette;
2017-08-08 15:28:48 -07:00
Doubek-Kraft
eb5835faeb [Summary Widgets] Fix color palettes
Fix color palette bug where the 'none' option was not recognized as
a selectable item

Add ability to toggle 'none' option, and remove it from the text color
control

Remove 'grippy' element when only one user-defined rule exists

Fix format of requirejs headers

Add tooltips
2017-08-08 15:27:46 -07:00
Charles Hacskaylo
ff1ddb0b79 [Front-end] Added .selected class for palette items
Fixes #1669
Added `.selected` in `.s-palette-item` class;
Re-orged styles in palette.scss to place in .l-* and .s-*
classes properly;
2017-08-08 15:16:20 -07:00
Charles Hacskaylo
15b127bb2e [Front-end] Added 'no-selection' CSS class
Fixes #1669
Added to _global.scss;
implemented in color.html;
2017-08-08 15:09:56 -07:00
Doubek-Kraft
e4ed881f6d [Summary Widgets] Code Style
Fix code style issues

Update plugin syntax to more closely match existing plugins
2017-08-08 12:06:20 -07:00
Doubek-Kraft
7b62cf130c [Summary Widget] Add unit tests
Add tests for input classes

Fix code style errors
2017-08-07 17:07:21 -07:00
Doubek-Kraft
72fd2e531c [Summary Widget] Assorted Cleanup
Abstract palette behavior to superclass, and base new color and icon
palette classes on it

Add unit tests

Move private event handler methods out of object prototypes
2017-08-04 16:15:47 -07:00
Doubek-Kraft
4a5392ef78 [Summary Widgets] Minor Fixes
Update zepto in bower to enforce v1.2.0

Fix bug where summary widget conditions would modify appearance of other summary widgets

Move code to plugins directory

Stub for unit tests
2017-08-03 13:09:05 -07:00
Doubek-Kraft
0150a708ca [Evaluation] Implement condition evaluation
Issue #1644

Add telemetry subscription handling, and implement the execution of
rules.

Provide a toggle for 'any', 'all', or 'JavaScript' trigger

Add documentation
2017-08-02 14:31:26 -07:00
Doubek-Kraft
eacc181d5e [Inputs] Add value inputs for rule configuration
Dynamically add value inputs when an operation is being configured.

Cleanup code related to removed label caching feature
2017-08-01 16:03:08 -07:00
Doubek-Kraft
405bb55881 [Refactor] Cleanup old files 2017-08-01 13:51:20 -07:00
Doubek-Kraft
4a35508459 [Refactor] Overhaul of code structure
Re-implement widgets in with a module-oriented structure. Fix issues related to
asychronous loading of telemetry and composition.

Package inputs as re-usable, Zepto-based modules.
2017-08-01 13:40:04 -07:00
Doubek-Kraft
98a9d71a2e [Summary Widgets] Implementation for conditions
Support configuring and persisting multiple conditions per rule
2017-07-26 09:33:27 -07:00
Doubek-Kraft
a1596d0b06 [Summary Widgets] Make conditions persistable
Issue #1644

Add implementation and persistability for a single condition configuration
field. Baseline for adding arbitrary numbers of rules
2017-07-25 14:21:53 -07:00
Doubek-Kraft
4b3be4c483 [Inputs] Add implementation for icon palette
Issue #1644

Wire up icon palette inputs to widget, and make icon class a persistable
property of a rule
2017-07-24 12:15:39 -07:00
Doubek-Kraft
0fa8472db1 [Bug Fix] Fix text input handlers
Issue #1644

Fix merge issue related to inputs for label and message
2017-07-24 10:10:28 -07:00
Charles Hacskaylo
e1e2dca1d8 [Frontend] WIP summary widget styling
Fixes #1654
Refactor .l-color-palette to .l-palette, includes
file renaming; add icon-palette in WidgetView.js
2017-07-21 18:07:49 -07:00
Doubek-Kraft
755c013ec8 [Summary Widgets] Merge with style
Issue #1644

Merge and resolve conflicts with style branch

Fix rule indexing bug
2017-07-21 16:19:15 -07:00
Doubek-Kraft
eab702b763 [Summary Widgets] Link markup to implementation
Add additional implemenation for new markup. Rules now store label
and message, and label is applied to widget. Implementation for
duplicate.
2017-07-21 15:59:53 -07:00
Charles Hacskaylo
d15446ac91 [Frontend] WIP summary widget styling
Fixes #1654
Mod .grippy to point at new glyph class;
Stubbed in icon palette control in markup;
2017-07-21 10:32:20 -07:00
Charles Hacskaylo
500733afb2 [Frontend] Add new icon-grippy
Fixes #1654
2017-07-21 10:25:18 -07:00
Charles Hacskaylo
2aa04b0a56 Merge remote-tracking branch 'origin/summary-widgets' into summary-widgets-styling 2017-07-21 10:04:23 -07:00
Doubek-Kraft
c051f342af [Style] Merge with style branch
Merge remote-tracking branch 'origin/summary-widgets-styling' into summary-widgets

Apply new style and wire up new markup for interaction
2017-07-21 09:58:23 -07:00
Charles Hacskaylo
8aeb365f5f [Frontend] WIP summary widget styling
Fixes #1654
Add condition duplicate and delete buttons
2017-07-21 09:56:57 -07:00
Charles Hacskaylo
827a28313d [Frontend] WIP summary widget styling
Fixes #1654
Fixes and tweaks post-merge
2017-07-21 09:48:54 -07:00
Doubek-Kraft
c83de8aad2 [Summary Widgets] Minor UI implementation 2017-07-21 09:24:27 -07:00
Charles Hacskaylo
b55f43b8df [Frontend] WIP summary widget styling
Fixes #1654
Merge latest from summary-widgets branch
2017-07-21 09:15:19 -07:00
Charles Hacskaylo
8466723a90 [Frontend] WIP summary widget styling
Fixes #1654
Minor tweaks; class renaming; restructured
main containers in ruleTemplate.html;
minor updates for class names in WidgetView.js;
2017-07-20 19:01:13 -07:00
Charles Hacskaylo
a103b4dbff [Frontend] WIP summary widget styling
Fixes #1654
Significant mods to markup and SCSS;
2017-07-20 17:56:57 -07:00
Charles Hacskaylo
826ac3a947 [Frontend] WIP summary widget styling
Fixes #1654
Ported .view-control SCSS out of tree context to
allow more independent use;
2017-07-20 14:31:59 -07:00
Charles Hacskaylo
597327f138 [Frontend] WIP summary widget styling
Fixes #1654
New SCSS for widgets; markup mods in progress
2017-07-20 14:09:17 -07:00
Charles Hacskaylo
bef79402ca [Frontend] WIP summary widget styling
Fixes #1654
Ported .inspector-config SCSS from _inspector.scss
and renamed to .l-compact-form;
2017-07-20 14:08:49 -07:00
Doubek-Kraft
e68e0c381f [Summary Widgets] Make Rules Deletable
Add delete functionality and UI

Improve process for indexing and rendering rules to support deletion,
and eventually reordering

Fix bug where default style was passed by reference and overwritten
on style updates
2017-07-19 17:38:17 -07:00
Charles Hacskaylo
c73f7259c2 [Frontend] WIP summary widget styling
Fixes #1654
Markup cleanups
2017-07-19 15:38:44 -07:00
Charles Hacskaylo
4c9235ba10 [Frontend] Apply new summary-widget glyph
Fixes #1654
2017-07-19 15:01:04 -07:00
Charles Hacskaylo
55e2a77df8 [Frontend] Add new summary-widget glyph
Fixes #1654
Updated font files and icomoon json file;
2017-07-19 15:00:46 -07:00
Doubek-Kraft
cfbff02e7f [Summary Widgets] Populate rule config inputs
Add rule configuration inputs, populated with domain objects, metadata,
and appropriate operations for a given type
2017-07-18 16:19:46 -07:00
Doubek-Kraft
54980fb296 [Summary Widgets] Add summary widgets, WIP
Add a summary widget domain object type

Implement basic interface and style configuration for rules
2017-07-18 10:58:55 -07:00
Pete Richards
ba98d9315c [ViewAPI] Update view API with more support
Update view provider to allow metadata definitions and to play
nicely with old style views.

Spec out some updates to ViewProviders and ViewRegistry to
support further use of views.
2017-07-05 13:56:32 -07:00
238 changed files with 2945 additions and 8616 deletions

View File

@@ -21,6 +21,5 @@
"shadow": "outer",
"strict": "implied",
"undef": true,
"unused": "vars",
"latedef": "nofunc"
"unused": "vars"
}

17
API.md
View File

@@ -505,7 +505,7 @@ MCT, it will be pre-configured to use the UTC time system, which is installed an
The time bounds of an Open MCT application are defined as numbers, and a Time
System gives meaning and context to these numbers so that they can be correctly
interpreted. Time Systems are JavaScript objects that provide some information
interpreted. Time Systems are javscript objects that provide some information
about the current time reference frame. An example of defining and registering
a new time system is given below:
@@ -879,21 +879,6 @@ openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
themes (dark and light) available for Open MCT. Note that at least one
of these themes must be installed for Open MCT to appear correctly.
* `openmct.plugins.URLIndicatorPlugin` adds an indicator which shows the
availability of a URL with the following options:
- `url` : URL to indicate the status of
- `cssClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
- `interval`: Interval between checking the connection, defaults to `10000`
- `label` Name showing up as text in the status bar, defaults to url
```javascript
openmct.install(openmct.plugins.URLIndicatorPlugin({
url: 'http://google.com',
cssClass: 'check',
interval: 10000,
label: 'Google'
})
);
```
* `openmct.plugins.LocalStorage` provides persistence of user-created
objects in browser-local storage. This is particularly useful in
development environments.

View File

@@ -88,7 +88,7 @@ and [`gulp`](http://gulpjs.com/).
To build Open MCT for deployment:
`npm run prepare`
`npm run prepublish`
This will compile and minify JavaScript sources, as well as copy over assets.
The contents of the `dist` folder will contain a runnable Open MCT

View File

@@ -17,8 +17,8 @@
"screenfull": "^3.0.0",
"node-uuid": "^1.4.7",
"comma-separated-values": "^3.6.4",
"file-saver": "^1.3.3",
"zepto": "^1.1.6",
"FileSaver.js": "^0.0.2",
"zepto": "1.2.0",
"eventemitter3": "^1.2.0",
"lodash": "3.10.1",
"almond": "~0.3.2",

View File

@@ -1,17 +1,15 @@
machine:
node:
version: 4.7.0
dependencies:
pre:
- npm install -g npm@latest
deployment:
production:
branch: master
commands:
- npm install canvas nomnoml
- ./build-docs.sh
- git fetch --unshallow
- git push git@heroku.com:openmctweb-demo.git $CIRCLE_SHA1:refs/heads/master
openmct-demo:
branch: live_demo
heroku:
appname: openmct-demo
openmctweb-staging-deux:
branch: mobile
heroku:
@@ -24,4 +22,4 @@ test:
general:
branches:
ignore:
- gh-pages
- gh-pages

View File

@@ -2283,7 +2283,7 @@ To install build dependencies (only needs to be run once):
To build:
`npm run prepare`
`npm run prepublish`
This will compile and minify JavaScript sources, as well as copy over assets.
The contents of the `dist` folder will contain a runnable Open MCT

View File

@@ -78,8 +78,8 @@ define([
return this.workerInterface.request(workerRequest);
};
GeneratorProvider.prototype.subscribe = function (domainObject, callback) {
var workerRequest = this.makeWorkerRequest(domainObject, {});
GeneratorProvider.prototype.subscribe = function (domainObject, callback, request) {
var workerRequest = this.makeWorkerRequest(domainObject, request);
return this.workerInterface.subscribe(workerRequest, callback);
};

View File

@@ -44,7 +44,9 @@ define([
message = message.data;
var callback = this.callbacks[message.id];
if (callback) {
callback(message);
if (callback(message)) {
delete this.callbacks[message.id];
}
}
};
@@ -70,7 +72,6 @@ define([
deferred.resolve = resolve;
deferred.reject = reject;
});
var messageId;
function callback(message) {
if (message.error) {
@@ -78,27 +79,33 @@ define([
} else {
deferred.resolve(message.data);
}
delete this.callbacks[messageId];
return true;
}
messageId = this.dispatch('request', request, callback.bind(this));
this.dispatch('request', request, callback);
return promise;
};
WorkerInterface.prototype.subscribe = function (request, cb) {
function callback(message) {
var isCancelled = false;
var callback = function (message) {
if (isCancelled) {
return true;
}
cb(message.data);
};
var messageId = this.dispatch('subscribe', request, callback);
var messageId = this.dispatch('subscribe', request, callback)
return function () {
isCancelled = true;
this.dispatch('unsubscribe', {
id: messageId
});
delete this.callbacks[messageId];
}.bind(this);
};

View File

@@ -16,7 +16,6 @@ define([
{ "key": "styleguide.intro", "name": "Introduction", "cssClass": "icon-page", "description": "Introduction and overview to the style guide" },
{ "key": "styleguide.standards", "name": "Standards", "cssClass": "icon-page", "description": "" },
{ "key": "styleguide.colors", "name": "Colors", "cssClass": "icon-page", "description": "" },
{ "key": "styleguide.status", "name": "status", "cssClass": "icon-page", "description": "Limits, telemetry paused, etc." },
{ "key": "styleguide.glyphs", "name": "Glyphs", "cssClass": "icon-page", "description": "Glyphs overview" },
{ "key": "styleguide.controls", "name": "Controls", "cssClass": "icon-page", "description": "Buttons, selects, HTML controls" },
{ "key": "styleguide.input", "name": "Text Inputs", "cssClass": "icon-page", "description": "Various text inputs" },
@@ -26,7 +25,6 @@ define([
{ "key": "styleguide.intro", "type": "styleguide.intro", "templateUrl": "templates/intro.html", "editable": false },
{ "key": "styleguide.standards", "type": "styleguide.standards", "templateUrl": "templates/standards.html", "editable": false },
{ "key": "styleguide.colors", "type": "styleguide.colors", "templateUrl": "templates/colors.html", "editable": false },
{ "key": "styleguide.status", "type": "styleguide.status", "templateUrl": "templates/status.html", "editable": false },
{ "key": "styleguide.glyphs", "type": "styleguide.glyphs", "templateUrl": "templates/glyphs.html", "editable": false },
{ "key": "styleguide.controls", "type": "styleguide.controls", "templateUrl": "templates/controls.html", "editable": false },
{ "key": "styleguide.input", "type": "styleguide.input", "templateUrl": "templates/input.html", "editable": false },
@@ -49,7 +47,6 @@ define([
"intro",
"standards",
"colors",
"status",
"glyphs",
"styleguide:ui-elements"
]

View File

@@ -28,8 +28,8 @@
color: $colorKey;
}
h1, h2, strong, b {
color: pullForward($colorBodyFg, 50%);
h1, h2 {
color: pullForward($colorBodyFg, 20%);
}
h2 {
@@ -45,10 +45,6 @@
text-transform: uppercase;
}
strong, b {
font-weight: normal;
}
.w-markup {
//Wrap markup example "pre" element
background-color: $colorCode;
@@ -58,12 +54,6 @@
position: relative;
}
.w-mct-example {
div {
margin-bottom: $interiorMarginLg;
}
}
code,
pre {
font-size: 0.8rem;

View File

@@ -127,8 +127,7 @@
{ 'meaning': 'Timer object', 'cssClass': 'icon-timer', 'cssContent': 'e1127', 'htmlEntity': '&#xe1127' },
{ 'meaning': 'Data Topic', 'cssClass': 'icon-topic', 'cssContent': 'e1128', 'htmlEntity': '&#xe1128' },
{ 'meaning': 'Fixed Position object', 'cssClass': 'icon-box-with-dashed-lines', 'cssContent': 'e1129', 'htmlEntity': '&#xe1129' },
{ 'meaning': 'Summary Widget', 'cssClass': 'icon-summary-widget', 'cssContent': 'e1130', 'htmlEntity': '&#xe1130' },
{ 'meaning': 'Notebook object', 'cssClass': 'icon-notebook', 'cssContent': 'e1131', 'htmlEntity': '&#xe1131' }
{ 'meaning': 'Summary Widget', 'cssClass': 'icon-summary-widget', 'cssContent': 'e1130', 'htmlEntity': '&#xe1130' }
];
"></div>

View File

@@ -4,5 +4,5 @@
<pre></pre>
</span>
<h3>Example</h3>
<div class="w-mct-example"></div>
<div></div>
</div>

View File

@@ -1,142 +0,0 @@
<!--
Open MCT, Copyright (c) 2014-2016, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT 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 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.
-->
<style>
.w-mct-example div[class*="s-limit"],
.w-mct-example div[class*="s-status"],
.w-mct-example div[class*="s-unsynced"],
.w-mct-example span[class*="s-limit"] {
border-radius: 4px;
padding: 3px 7px;
}
.w-mct-example table {
width: 100%;
}
</style>
<div class="l-style-guide s-text">
<p class="doc-title">Open MCT Style Guide</p>
<h1>Status Indication</h1>
<div class="l-section">
<h2>Overview</h2>
<p>Many elements in Open MCT need to articulate a dynamic status; Open MCT provides the following styles and conventions to handle this:</p>
<ul>
<li><strong>Limits</strong>: when telemetry values exceed minimum or maximum values, they can be violating limits. Limit styles include both color and iconography; color is used to indicate severity while icons are used to indicate direction, upper or lower.</li>
<li><strong>Status</strong>: Open MCT also provides a number or built-in Status styles allowing telemetry or other displayed information to be visually classified by type. Common uses for these classes are to visually denote event records.</li>
<li><strong>Synchronization</strong>: When the system is displaying real-time data, it is very important that displays clearly indicate when they are not doing so, such as when a plot if frozen while panning or zooming. Open MCT provides a style for this.</li>
</ul>
</div>
<div class="l-section">
<h2>Limits</h2>
<div class="cols cols1-1">
<div class="col">
<p>Limit CSS classes can be applied to any block or inline element. Open MCT limit classes set color and optionally an icon, but don't effect other properties. Yellow and red limit classes can be used as is, or allow the application of any custom icon available in Open MCT's glyphs library. &quot;Level&quot; limit classes - upper and lower - always use an icon in addition to a color; Open MCT doesn't support level limits without color.</p>
<ul>
<li>Color only</li>
<ul>
<li><code>s-limit-yellow</code>: A yellow limit.</li>
<li><code>s-limit-red</code>: A red limit.</li>
</ul>
<li>Color and icon</li>
<ul>
<li><code>s-limit-yellow-icon</code>: A yellow limit with icon.</li>
<li><code>s-limit-red-icon</code>: A red limit with icon.</li>
</ul>
<li>Upper and lower limit indicators. Must be used with a color limit class to be visible.</li>
<ul>
<li><code>s-limit-upr</code>: Upper limit.
</li>
<li><code>s-limit-lwr</code>: Lower limit.
</li>
</ul>
</ul>
</div>
<mct-example><div class="s-limit-yellow">Yellow limit</div>
<div class="s-limit-red">Red limit</div>
<div class="s-limit-yellow-icon">Yellow limit with icon</div>
<div class="s-limit-red-icon">Red limit with icon</div>
<div class="s-limit-yellow s-limit-lwr">Lower yellow limit</div>
<div class="s-limit-red s-limit-upr">Upper red limit</div>
<div class="s-limit-red icon-bell">Red Limit with a custom icon</div>
<div>Some text with an <span class="s-limit-yellow-icon">inline element</span> showing a yellow limit.</div>
<!-- Limits applied in a table -->
<table>
<tr class='header'><td>Name</td><td>Value 1</td><td>Value 2</td></tr>
<tr><td>ENG_PWR 4991</td><td>7.023</td><td class="s-limit-yellow s-limit-upr">70.23</td></tr>
<tr><td>ENG_PWR 4992</td><td>49.784</td><td class="s-limit-red s-limit-lwr">-121.22</td></tr>
<tr><td>ENG_PWR 4993</td><td class="s-limit-yellow icon-bell">0.451</td><td>1.007</td></tr>
</table>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Status</h2>
<div class="cols cols1-1">
<div class="col">
<p>Classes here can be applied to elements as needed.</p>
<ul>
<li>Color only</li>
<ul>
<li><code>s-status-warning-hi</code></li>
<li><code>s-status-warning-lo</code></li>
<li><code>s-status-diagnostic</code></li>
<li><code>s-status-info</code></li>
<li><code>s-status-ok</code></li>
</ul>
<li>Color and icon</li>
<ul>
<li><code>s-status-warning-hi-icon</code></li>
<li><code>s-status-warning-lo-icon</code></li>
<li><code>s-status-diagnostic-icon</code></li>
<li><code>s-status-info-icon</code></li>
<li><code>s-status-ok-icon</code></li>
</ul>
</ul>
</div>
<mct-example><div class="s-status-warning-hi">WARNING HI</div>
<div class="s-status-warning-lo">WARNING LOW</div>
<div class="s-status-diagnostic">DIAGNOSTIC</div>
<div class="s-status-info">INFO</div>
<div class="s-status-ok">OK</div>
<div class="s-status-warning-hi-icon">WARNING HI with icon</div>
<div class="s-status-warning-lo-icon">WARNING LOW with icon</div>
<div class="s-status-diagnostic-icon">DIAGNOSTIC with icon</div>
<div class="s-status-info-icon">INFO with icon</div>
<div class="s-status-ok-icon">OK with icon</div>
<div class="s-status-warning-hi icon-gear">WARNING HI with custom icon</div>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Synchronization</h2>
<div class="cols cols1-1">
<div class="col">
<p>When the system is operating in real-time streaming mode, it is important for views that display real-time data to clearly articulate when they are not, such as when a user zooms or pans a plot view, freezing that view. In that case, the CSS class <code>s-unsynced</code> should be applied to that view.</p>
</div>
<mct-example><div class="s-unsynced">This element is unsynced</div>
</mct-example>
</div>
</div>
</div>

View File

@@ -34,7 +34,6 @@ define(
pages['standards'] = { name: "Standards", type: "styleguide.standards", location: "styleguide:home" };
pages['colors'] = { name: "Colors", type: "styleguide.colors", location: "styleguide:home" };
pages['glyphs'] = { name: "Glyphs", type: "styleguide.glyphs", location: "styleguide:home" };
pages['status'] = { name: "Status Indication", type: "styleguide.status", location: "styleguide:home" };
pages['controls'] = { name: "Controls", type: "styleguide.controls", location: "styleguide:ui-elements" };
pages['input'] = { name: "Text Inputs", type: "styleguide.input", location: "styleguide:ui-elements" };
pages['menus'] = { name: "Menus", type: "styleguide.menus", location: "styleguide:ui-elements" };

View File

@@ -22,8 +22,6 @@
/*global require,__dirname*/
require("v8-compile-cache");
var gulp = require('gulp'),
sourcemaps = require('gulp-sourcemaps'),
path = require('path'),
@@ -48,22 +46,9 @@ var gulp = require('gulp'),
name: 'bower_components/almond/almond.js',
include: paths.main.replace('.js', ''),
wrap: {
start: (function () {
var buildVariables = {
version: project.version,
timestamp: moment.utc(Date.now()).format(),
revision: fs.existsSync('.git') ? git.long() : 'Unknown',
branch: fs.existsSync('.git') ? git.branch() : 'Unknown'
};
return fs.readFileSync("src/start.frag", 'utf-8')
.replace(/@@(\w+)/g, function (match, key) {
return buildVariables[key];
});;
}()),
startFile: "src/start.frag",
endFile: "src/end.frag"
},
optimize: 'uglify2',
uglify2: { output: { comments: /@preserve/ } },
mainConfigFile: paths.main,
wrapShim: true
},
@@ -73,6 +58,14 @@ var gulp = require('gulp'),
},
sass: {
sourceComments: true
},
replace: {
variables: {
version: project.version,
timestamp: moment.utc(Date.now()).format(),
revision: fs.existsSync('.git') ? git.long() : 'Unknown',
branch: fs.existsSync('.git') ? git.branch() : 'Unknown'
}
}
};
@@ -83,11 +76,16 @@ if (process.env.NODE_ENV === 'development') {
gulp.task('scripts', function () {
var requirejsOptimize = require('gulp-requirejs-optimize');
var replace = require('gulp-replace-task');
var header = require('gulp-header');
var comment = fs.readFileSync('src/about.frag');
return gulp.src(paths.main)
.pipe(sourcemaps.init())
.pipe(requirejsOptimize(options.requirejsOptimize))
.pipe(sourcemaps.write('.'))
.pipe(replace(options.replace))
.pipe(header(comment, options.replace.variables))
.pipe(gulp.dest(paths.dist));
});
@@ -179,4 +177,4 @@ gulp.task('install', [ 'assets', 'scripts' ]);
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
gulp.task('build', [ 'verify', 'install' ]);
gulp.task('build', [ 'verify', 'install' ]);

View File

@@ -42,17 +42,13 @@
openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.ExampleImagery());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(openmct.plugins.ImportExport());
openmct.install(openmct.plugins.AutoflowView({
type: "telemetry.panel"
}));
openmct.install(openmct.plugins.Conductor({
menuOptions: [
{
name: "Fixed",
timeSystem: 'utc',
bounds: {
start: Date.now() - THIRTY_MINUTES,
start: Date.now() - 30 * 60 * 1000,
end: Date.now()
}
},

View File

@@ -36,7 +36,6 @@ module.exports = function(config) {
files: [
{pattern: 'bower_components/**/*.js', included: false},
{pattern: 'node_modules/d3-*/**/*.js', included: false},
{pattern: 'node_modules/vue/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'example/**/*.html', included: false},
{pattern: 'example/**/*.js', included: false},

View File

@@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global requirejs,BUILD_CONSTANTS*/
/*global requirejs*/
requirejs.config({
"paths": {
@@ -33,11 +33,10 @@ requirejs.config({
"moment": "bower_components/moment/moment",
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
"saveAs": "bower_components/file-saver/FileSaver.min",
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
"screenfull": "bower_components/screenfull/dist/screenfull.min",
"text": "bower_components/text/text",
"uuid": "bower_components/node-uuid/uuid",
"vue": "node_modules/vue/dist/vue.min",
"zepto": "bower_components/zepto/zepto.min",
"lodash": "bower_components/lodash/lodash",
"d3-selection": "node_modules/d3-selection/build/d3-selection.min",
@@ -67,9 +66,6 @@ requirejs.config({
"moment-duration-format": {
"deps": ["moment"]
},
"saveAs": {
"exports": "saveAs"
},
"screenfull": {
"exports": "screenfull"
},
@@ -95,17 +91,12 @@ requirejs.config({
define([
'./platform/framework/src/Main',
'./src/defaultRegistry',
'./src/MCT',
'./src/plugins/buildInfo/plugin'
], function (Main, defaultRegistry, MCT, buildInfo) {
'./src/MCT'
], function (Main, defaultRegistry, MCT) {
var openmct = new MCT();
openmct.legacyRegistry = defaultRegistry;
if (typeof BUILD_CONSTANTS !== 'undefined') {
openmct.install(buildInfo(BUILD_CONSTANTS));
}
openmct.on('start', function () {
return new Main().run(defaultRegistry);
});

View File

@@ -15,18 +15,19 @@
"d3-time-format": "^2.0.3",
"express": "^4.13.1",
"minimist": "^1.1.1",
"request": "^2.69.0",
"vue": "^2.5.6"
"request": "^2.69.0"
},
"devDependencies": {
"bower": "^1.7.7",
"git-rev-sync": "^1.4.0",
"glob": ">= 3.0.0",
"gulp": "^3.9.1",
"gulp-header": "^1.8.8",
"gulp-jscs": "^3.0.2",
"gulp-jshint": "^2.0.0",
"gulp-jshint-html-reporter": "^0.1.3",
"gulp-rename": "^1.2.2",
"gulp-replace-task": "^0.11.0",
"gulp-requirejs-optimize": "^0.3.1",
"gulp-sass": "^2.2.0",
"gulp-sourcemaps": "^1.6.0",
@@ -50,8 +51,7 @@
"moment": "^2.11.1",
"node-bourbon": "^4.2.3",
"requirejs": "2.1.x",
"split": "^1.0.0",
"v8-compile-cache": "^1.1.0"
"split": "^1.0.0"
},
"scripts": {
"start": "node app.js",
@@ -61,7 +61,7 @@
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
"otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
"docs": "npm run jsdoc ; npm run otherdoc",
"prepare": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
"prepublish": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
},
"repository": {
"type": "git",

View File

@@ -26,7 +26,6 @@ define([
"./src/InspectorPaneController",
"./src/BrowseObjectController",
"./src/MenuArrowController",
"./src/ObjectHeaderController",
"./src/navigation/NavigationService",
"./src/navigation/NavigateAction",
"./src/navigation/OrphanNavigationHandler",
@@ -37,7 +36,6 @@ define([
"text!./res/templates/browse-object.html",
"text!./res/templates/items/grid-item.html",
"text!./res/templates/browse/object-header.html",
"text!./res/templates/browse/object-header-frame.html",
"text!./res/templates/menu-arrow.html",
"text!./res/templates/back-arrow.html",
"text!./res/templates/items/items.html",
@@ -50,7 +48,6 @@ define([
InspectorPaneController,
BrowseObjectController,
MenuArrowController,
ObjectHeaderController,
NavigationService,
NavigateAction,
OrphanNavigationHandler,
@@ -61,7 +58,6 @@ define([
browseObjectTemplate,
gridItemTemplate,
objectHeaderTemplate,
objectHeaderFrameTemplate,
menuArrowTemplate,
backArrowTemplate,
itemsTemplate,
@@ -144,13 +140,6 @@ define([
"$location",
"$attrs"
]
},
{
"key": "ObjectHeaderController",
"implementation": ObjectHeaderController,
"depends": [
"$scope"
]
}
],
"representations": [
@@ -184,13 +173,6 @@ define([
"type"
]
},
{
"key": "object-header-frame",
"template": objectHeaderFrameTemplate,
"uses": [
"type"
]
},
{
"key": "menu-arrow",
"template": menuArrowTemplate,

View File

@@ -57,12 +57,7 @@
</div>
<mct-representation key="representation.selected.key"
mct-object="representation.selected.key && domainObject"
class="abs flex-elem grows object-holder-main scroll"
mct-selectable="{
item: domainObject.useCapability('adapter'),
oldItem: domainObject
}"
mct-init-select>
class="abs flex-elem grows object-holder-main scroll">
</mct-representation>
</div>
</div>

View File

@@ -19,21 +19,12 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div ng-controller="InspectorController as controller">
<div ng-controller="InspectorController">
<div ng-repeat="region in regions">
<mct-representation
key="'object-properties'"
mct-object="controller.selectedItem()"
key="region.content.key"
mct-object="domainObject"
ng-model="ngModel">
</mct-representation>
<div ng-if="!controller.hasProviderView()">
<mct-representation
key="inspectorKey"
mct-object="controller.selectedItem()"
ng-model="ngModel">
</mct-representation>
</div>
<div class='inspector-provider-view'>
</div>
</div>
</div>

View File

@@ -1,31 +0,0 @@
<!--
Open MCT, Copyright (c) 2014-2017, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT 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 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.
-->
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
<span class="l-elem-wrapper l-flex-row flex-elem grows" ng-controller="ObjectHeaderController as controller">
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
<span class='title-label flex-elem holder flex-can-shrink s-input-inline'>{{model.name}}</span>
<span class='t-object-alert t-alert-unsynced flex-elem holder' title='This object is not currently displaying real-time data'></span>
<mct-representation
key="'menu-arrow'"
mct-object='domainObject'
class="flex-elem context-available-w"></mct-representation>
</span>

View File

@@ -20,13 +20,9 @@
at runtime from the About dialog for additional information.
-->
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
<span class="l-elem-wrapper l-flex-row flex-elem grows" ng-controller="ObjectHeaderController as controller">
<span class="l-elem-wrapper l-flex-row flex-elem grows">
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
<span ng-attr-contenteditable="{{ controller.editable ? true : undefined }}"
class='title-label flex-elem holder flex-can-shrink s-input-inline'
ng-click="controller.edit()"
ng-blur="controller.updateName($event)"
ng-keypress="controller.updateName($event)">{{model.name}}</span>
<span class='title-label flex-elem holder flex-can-shrink'>{{model.name}}</span>
<span class='t-object-alert t-alert-unsynced flex-elem holder' title='This object is not currently displaying real-time data'></span>
<mct-representation
key="'menu-arrow'"

View File

@@ -38,6 +38,8 @@
ng-class="{ last:($index + 1) === contextualParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-model="ngModel"
ng-click="ngModel.selectedObject = parent"
class="location-item">
</mct-representation>
</span>
@@ -49,6 +51,8 @@
ng-class="{ last:($index + 1) === primaryParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-model="ngModel"
ng-click="ngModel.selectedObject = parent"
class="location-item">
</mct-representation>
</span>

View File

@@ -1,92 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
[],
function () {
/**
* Controller to provide the ability to inline edit an object name.
*
* @constructor
* @memberof platform/commonUI/browse
*/
function ObjectHeaderController($scope) {
this.$scope = $scope;
this.domainObject = $scope.domainObject;
this.editable = this.allowEdit();
}
/**
* Updates the object name on blur and enter keypress events.
*
* @param event the mouse event
*/
ObjectHeaderController.prototype.updateName = function (event) {
if (!event || !event.currentTarget) {
return;
}
if (event.type === 'blur') {
this.updateModel(event);
} else if (event.which === 13) {
this.updateModel(event);
event.currentTarget.blur();
window.getSelection().removeAllRanges();
}
};
/**
* Updates the model.
*
* @param event the mouse event
* @param private
*/
ObjectHeaderController.prototype.updateModel = function (event) {
var name = event.currentTarget.textContent.replace(/\n/g, ' ');
if (name.length === 0) {
name = "Unnamed " + this.domainObject.getCapability("type").typeDef.name;
event.currentTarget.textContent = name;
}
if (name !== this.domainObject.getModel().name) {
this.domainObject.getCapability('mutation').mutate(function (model) {
model.name = name;
});
}
};
/**
* Checks if the domain object is editable.
*
* @private
* @return true if object is editable
*/
ObjectHeaderController.prototype.allowEdit = function () {
var type = this.domainObject && this.domainObject.getCapability('type');
return !!(type && type.hasFeature('creation'));
};
return ObjectHeaderController;
}
);

View File

@@ -1,137 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
["../src/ObjectHeaderController"],
function (ObjectHeaderController) {
describe("The object header controller", function () {
var mockScope,
mockDomainObject,
mockCapabilities,
mockMutationCapability,
mockTypeCapability,
mockEvent,
mockCurrentTarget,
model,
controller;
beforeEach(function () {
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
mockTypeCapability = jasmine.createSpyObj("type", ["typeDef", "hasFeature"]);
mockTypeCapability.typeDef = { name: ""};
mockTypeCapability.hasFeature.andCallFake(function (feature) {
return feature === 'creation';
});
mockCapabilities = {
mutation: mockMutationCapability,
type: mockTypeCapability
};
model = {
name: "Test name"
};
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "getModel"]);
mockDomainObject.getModel.andReturn(model);
mockDomainObject.getCapability.andCallFake(function (key) {
return mockCapabilities[key];
});
mockScope = {
domainObject: mockDomainObject
};
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "textContent"]);
mockCurrentTarget.blur.andReturn(mockCurrentTarget);
mockEvent = {
which: {},
type: {},
currentTarget: mockCurrentTarget
};
controller = new ObjectHeaderController(mockScope);
});
it("updates the model with new name on blur", function () {
mockEvent.type = "blur";
mockCurrentTarget.textContent = "New name";
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).toHaveBeenCalled();
});
it("updates the model with a default for blank names", function () {
mockEvent.type = "blur";
mockCurrentTarget.textContent = "";
controller.updateName(mockEvent);
expect(mockCurrentTarget.textContent.length).not.toEqual(0);
expect(mockMutationCapability.mutate).toHaveBeenCalled();
});
it("does not update the model if the same name", function () {
mockEvent.type = "blur";
mockCurrentTarget.textContent = mockDomainObject.getModel().name;
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
});
it("updates the model on enter keypress event only", function () {
mockCurrentTarget.textContent = "New name";
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
mockEvent.which = 13;
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
mockMutationCapability.mutate.mostRecentCall.args[0](model);
expect(mockDomainObject.getModel().name).toBe("New name");
});
it("blurs the field on enter key press", function () {
mockCurrentTarget.textContent = "New name";
mockEvent.which = 13;
controller.updateName(mockEvent);
expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
});
it("allows editting name when object is creatable", function () {
expect(controller.allowEdit()).toBe(true);
});
it("disallows editting name when object is non-creatable", function () {
mockTypeCapability.hasFeature.andReturn(false);
expect(controller.allowEdit()).toBe(false);
});
});
}
);

View File

@@ -20,7 +20,7 @@
at runtime from the About dialog for additional information.
-->
<div class="abs top-bar">
<div class="dialog-title">{{ngModel.title}}</div>
<div class="title">{{ngModel.title}}</div>
<div class="hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
</div>
<div class='abs editor'>

View File

@@ -1,10 +1,11 @@
<div class="l-message"
ng-class="'message-severity-' + ngModel.severity">
<div class="w-message-contents">
<div class="ui-symbol type-icon message-type"></div>
<div class="message-contents">
<div class="top-bar">
<div class="title">{{ngModel.title}}</div>
<div class="hint" ng-hide="ngModel.hint === undefined">{{ngModel.hint}}</div>
</div>
<div class="hint" ng-hide="ngModel.hint === undefined">{{ngModel.hint}}</div>
<div class="message-body">
<div class="message-action">
{{ngModel.actionText}}
@@ -24,6 +25,8 @@
ng-click="ngModel.primaryOption.callback()">
{{ngModel.primaryOption.label}}
</a>
</div>
</div>
</div>

View File

@@ -1,17 +1,17 @@
<mct-container key="overlay">
<div class="t-message-list">
<div class="top-bar">
<div class="dialog-title">{{ngModel.dialog.title}}</div>
<mct-container key="overlay" class="t-message-list">
<div class="message-contents">
<div class="abs top-bar">
<div class="title">{{ngModel.dialog.title}}</div>
<div class="hint">Displaying {{ngModel.dialog.messages.length}} message<span ng-show="ngModel.dialog.messages.length > 1 ||
ngModel.dialog.messages.length == 0">s</span>
</div>
</div>
<div class="w-messages">
<div class="abs message-body">
<mct-include
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
key="'message'" ng-model="msg.model"></mct-include>
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
key="'message'" ng-model="msg.model"></mct-include>
</div>
<div class="bottom-bar">
<div class="abs bottom-bar">
<a ng-repeat="dialogAction in ngModel.dialog.actions"
class="s-button major"
ng-click="dialogAction.action()">

View File

@@ -21,7 +21,7 @@
-->
<mct-container key="overlay">
<div class="abs top-bar">
<div class="dialog-title">{{ngModel.dialog.title}}</div>
<div class="title">{{ngModel.dialog.title}}</div>
<div class="hint">{{ngModel.dialog.hint}}</div>
</div>
<div class='abs editor'>

View File

@@ -121,8 +121,7 @@ define([
"key": "ElementsController",
"implementation": ElementsController,
"depends": [
"$scope",
"openmct"
"$scope"
]
},
{
@@ -300,6 +299,9 @@ define([
{
"key": "edit-elements",
"template": elementsTemplate,
"uses": [
"composition"
],
"gestures": [
"drop"
]
@@ -383,10 +385,7 @@ define([
]
},
{
"implementation": EditToolbarRepresenter,
"depends": [
"openmct"
]
"implementation": EditToolbarRepresenter
}
],
"constants": [

View File

@@ -23,7 +23,7 @@
<div class="s-menu-button major create-button" ng-click="createController.toggle()">
<span class="title-label">Create</span>
</div>
<div class="menu super-menu l-create-menu" ng-show="createController.isActive()">
<div class="menu super-menu" ng-show="createController.isActive()">
<mct-representation mct-object="domainObject" key="'create-menu'">
</mct-representation>
</div>

View File

@@ -19,8 +19,8 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="w-menu" ng-controller="CreateMenuController">
<div class="col menu-items">
<div class="contents" ng-controller="CreateMenuController">
<div class="pane left menu-items">
<ul>
<li ng-repeat="createAction in createActions" ng-click="createAction.perform()">
<a ng-mouseover="representation.activeMetadata = createAction.getMetadata()"
@@ -31,15 +31,13 @@
</li>
</ul>
</div>
<div class="col menu-item-description">
<div class="pane right menu-item-description">
<div class="desc-area icon {{ representation.activeMetadata.cssClass }}"></div>
<div class="w-title-desc">
<div class="desc-area title">
{{representation.activeMetadata.name}}
</div>
<div class="desc-area description">
{{representation.activeMetadata.description}}
</div>
<div class="desc-area title">
{{representation.activeMetadata.name}}
</div>
<div class="desc-area description">
{{representation.activeMetadata.description}}
</div>
</div>
</div>

View File

@@ -61,12 +61,7 @@
<mct-representation key="representation.selected.key"
mct-object="representation.selected.key && domainObject"
class="abs flex-elem grows object-holder-main scroll"
toolbar="toolbar"
mct-selectable="{
item: domainObject.useCapability('adapter'),
oldItem: domainObject
}"
mct-init-select>
toolbar="toolbar">
</mct-representation>
</div><!--/ l-object-wrapper-inner -->
</div>

View File

@@ -25,7 +25,7 @@
ng-model="filterBy">
</mct-include>
<div class="flex-elem grows vscroll">
<ul class="tree" ng-if="composition.length > 0">
<ul class="tree">
<li ng-repeat="containedObject in composition | filter:searchElements">
<span class="tree-item">
<mct-representation
@@ -36,6 +36,5 @@
</span>
</li>
</ul>
<div ng-if="composition.length === 0">No contained elements</div>
</div>
</div>

View File

@@ -101,15 +101,10 @@ define(
*/
EditorCapability.prototype.finish = function () {
var domainObject = this.domainObject;
if (this.transactionService.isActive()) {
return this.transactionService.cancel().then(function () {
domainObject.getCapability("status").set("editing", false);
return domainObject;
});
} else {
return Promise.resolve(domainObject);
}
return this.transactionService.cancel().then(function () {
domainObject.getCapability("status").set("editing", false);
return domainObject;
});
};
/**

View File

@@ -28,6 +28,16 @@ define(
[],
function () {
function isDirty(domainObject) {
var navigatedObject = domainObject,
editorCapability = navigatedObject &&
navigatedObject.getCapability("editor");
return editorCapability &&
editorCapability.isEditContextRoot() &&
editorCapability.dirty();
}
function cancelEditing(domainObject) {
var navigatedObject = domainObject,
editorCapability = navigatedObject &&
@@ -49,7 +59,10 @@ define(
var removeCheck = navigationService
.checkBeforeNavigation(function () {
return "Continuing will cause the loss of any unsaved changes.";
if (isDirty(domainObject)) {
return "Continuing will cause the loss of any unsaved changes.";
}
return false;
});
$scope.$on('$destroy', function () {

View File

@@ -29,11 +29,7 @@ define(
*
* @constructor
*/
function ElementsController($scope, openmct) {
this.scope = $scope;
this.scope.composition = [];
var self = this;
function ElementsController($scope) {
function filterBy(text) {
if (typeof text === 'undefined') {
return $scope.searchText;
@@ -51,45 +47,10 @@ define(
}
}
function setSelection(selection) {
self.scope.selection = selection;
self.refreshComposition(selection);
}
$scope.filterBy = filterBy;
$scope.searchElements = searchElements;
openmct.selection.on('change', setSelection);
setSelection(openmct.selection.get());
$scope.$on("$destroy", function () {
openmct.selection.off("change", setSelection);
});
}
/**
* Gets the composition for the selected object and populates the scope with it.
*
* @param selection the selection object
* @private
*/
ElementsController.prototype.refreshComposition = function (selection) {
if (!selection[0]) {
return;
}
var selected = selection[0].context.oldItem;
var selectedObjectComposition = selected && selected.useCapability('composition');
if (selectedObjectComposition) {
selectedObjectComposition.then(function (composition) {
this.scope.composition = composition;
}.bind(this));
} else {
this.scope.composition = [];
}
};
return ElementsController;
}
);

View File

@@ -38,7 +38,7 @@ define(
* @constructor
* @implements {Representer}
*/
function EditToolbarRepresenter(openmct, scope, element, attrs) {
function EditToolbarRepresenter(scope, element, attrs) {
var self = this;
// Mark changes as ready to persist
@@ -109,7 +109,6 @@ define(
this.updateSelection = updateSelection;
this.toolbar = undefined;
this.toolbarObject = {};
this.openmct = openmct;
// If this representation exposes a toolbar, set up watches
// to synchronize with it.
@@ -147,7 +146,7 @@ define(
// Expose the toolbar object to the parent scope
initialize(definition);
// Create a selection scope
this.setSelection(new EditToolbarSelection(this.openmct));
this.setSelection(new EditToolbarSelection());
// Initialize toolbar to an empty selection
this.updateSelection([]);
};

View File

@@ -38,24 +38,10 @@ define(
* @memberof platform/commonUI/edit
* @constructor
*/
function EditToolbarSelection(openmct) {
function EditToolbarSelection() {
this.selection = [{}];
this.selecting = false;
this.selectedObj = undefined;
openmct.selection.on('change', function (selection) {
var selected = selection[0];
if (selected && selected.context.toolbar) {
this.select(selected.context.toolbar);
} else {
this.deselect();
}
if (selected && selected.context.viewProxy) {
this.proxy(selected.context.viewProxy);
}
}.bind(this));
}
/**

View File

@@ -62,7 +62,6 @@ define(
);
mockTransactionService.commit.andReturn(fastPromise());
mockTransactionService.cancel.andReturn(fastPromise());
mockTransactionService.isActive = jasmine.createSpy('isActive');
mockStatusCapability = jasmine.createSpyObj(
"statusCapability",
@@ -142,7 +141,6 @@ define(
describe("finish", function () {
beforeEach(function () {
mockTransactionService.isActive.andReturn(true);
capability.edit();
capability.finish();
});
@@ -154,23 +152,6 @@ define(
});
});
describe("finish", function () {
beforeEach(function () {
mockTransactionService.isActive.andReturn(false);
capability.edit();
});
it("does not cancel transaction when transaction is not active", function () {
capability.finish();
expect(mockTransactionService.cancel).not.toHaveBeenCalled();
});
it("returns a promise", function () {
expect(capability.finish() instanceof Promise).toBe(true);
});
});
describe("dirty", function () {
var model = {};

View File

@@ -104,10 +104,10 @@ define(
mockEditorCapability.isEditContextRoot.andReturn(false);
mockEditorCapability.dirty.andReturn(false);
expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
expect(checkFn()).toBe(false);
mockEditorCapability.isEditContextRoot.andReturn(true);
expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
expect(checkFn()).toBe(false);
mockEditorCapability.dirty.andReturn(true);
expect(checkFn())

View File

@@ -27,23 +27,11 @@ define(
describe("The Elements Pane controller", function () {
var mockScope,
mockOpenMCT,
mockSelection,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", ['$on']);
mockSelection = jasmine.createSpyObj("selection", [
'on',
'off',
'get'
]);
mockSelection.get.andReturn([]);
mockOpenMCT = {
selection: mockSelection
};
controller = new ElementsController(mockScope, mockOpenMCT);
mockScope = jasmine.createSpy("$scope");
controller = new ElementsController(mockScope);
});
function getModel(model) {

View File

@@ -29,9 +29,7 @@ define(
mockElement,
testAttrs,
mockUnwatch,
representer,
mockOpenMCT,
mockSelection;
representer;
beforeEach(function () {
mockScope = jasmine.createSpyObj(
@@ -48,18 +46,7 @@ define(
mockScope.$parent.$watchCollection.andReturn(mockUnwatch);
mockSelection = jasmine.createSpyObj("selection", [
'on',
'off',
'get'
]);
mockSelection.get.andReturn([]);
mockOpenMCT = {
selection: mockSelection
};
representer = new EditToolbarRepresenter(
mockOpenMCT,
mockScope,
mockElement,
testAttrs

View File

@@ -28,25 +28,13 @@ define(
var testProxy,
testElement,
otherElement,
selection,
mockSelection,
mockOpenMCT;
selection;
beforeEach(function () {
testProxy = { someKey: "some value" };
testElement = { someOtherKey: "some other value" };
otherElement = { yetAnotherKey: 42 };
mockSelection = jasmine.createSpyObj("selection", [
// 'select',
'on',
'off',
'get'
]);
mockSelection.get.andReturn([]);
mockOpenMCT = {
selection: mockSelection
};
selection = new EditToolbarSelection(mockOpenMCT);
selection = new EditToolbarSelection();
selection.proxy(testProxy);
});

View File

@@ -121,9 +121,6 @@ define([
};
UTCTimeFormat.prototype.parse = function (text) {
if (typeof text === 'number') {
return text;
}
return moment.utc(text, DATE_FORMATS).valueOf();
};

View File

@@ -41,7 +41,6 @@ define([
"./src/controllers/BannerController",
"./src/directives/MCTContainer",
"./src/directives/MCTDrag",
"./src/directives/MCTSelectable",
"./src/directives/MCTClickElsewhere",
"./src/directives/MCTResize",
"./src/directives/MCTPopup",
@@ -91,7 +90,6 @@ define([
BannerController,
MCTContainer,
MCTDrag,
MCTSelectable,
MCTClickElsewhere,
MCTResize,
MCTPopup,
@@ -330,13 +328,6 @@ define([
"$document"
]
},
{
"key": "mctSelectable",
"implementation": MCTSelectable,
"depends": [
"openmct"
]
},
{
"key": "mctClickElsewhere",
"implementation": MCTClickElsewhere,

View File

@@ -2,7 +2,7 @@
"metadata": {
"name": "openmct-symbols-16px",
"lastOpened": 0,
"created": 1506973656040
"created": 1502487054429
},
"iconSets": [
{
@@ -636,29 +636,13 @@
"code": 921670,
"tempChar": ""
},
{
"order": 138,
"id": 115,
"name": "icon-import",
"prevSize": 24,
"code": 921671,
"tempChar": ""
},
{
"order": 136,
"id": 116,
"name": "icon-export",
"prevSize": 24,
"code": 921672,
"tempChar": ""
},
{
"order": 37,
"prevSize": 24,
"name": "icon-activity",
"id": 32,
"code": 921856,
"tempChar": ""
"tempChar": ""
},
{
"order": 36,
@@ -666,7 +650,7 @@
"name": "icon-activity-mode",
"id": 31,
"code": 921857,
"tempChar": ""
"tempChar": ""
},
{
"order": 52,
@@ -674,7 +658,7 @@
"name": "icon-autoflow-tabular",
"id": 47,
"code": 921858,
"tempChar": ""
"tempChar": ""
},
{
"order": 55,
@@ -682,7 +666,7 @@
"name": "icon-clock",
"id": 50,
"code": 921859,
"tempChar": ""
"tempChar": ""
},
{
"order": 58,
@@ -690,7 +674,7 @@
"name": "icon-database",
"id": 53,
"code": 921860,
"tempChar": ""
"tempChar": ""
},
{
"order": 57,
@@ -698,7 +682,7 @@
"name": "icon-database-query",
"id": 52,
"code": 921861,
"tempChar": ""
"tempChar": ""
},
{
"order": 17,
@@ -706,7 +690,7 @@
"name": "icon-dataset",
"id": 12,
"code": 921862,
"tempChar": ""
"tempChar": ""
},
{
"order": 22,
@@ -714,7 +698,7 @@
"name": "icon-datatable",
"id": 17,
"code": 921863,
"tempChar": ""
"tempChar": ""
},
{
"order": 59,
@@ -722,7 +706,7 @@
"name": "icon-dictionary",
"id": 54,
"code": 921864,
"tempChar": ""
"tempChar": ""
},
{
"order": 62,
@@ -730,7 +714,7 @@
"name": "icon-folder",
"id": 57,
"code": 921865,
"tempChar": ""
"tempChar": ""
},
{
"order": 66,
@@ -738,7 +722,7 @@
"name": "icon-image",
"id": 61,
"code": 921872,
"tempChar": ""
"tempChar": ""
},
{
"order": 68,
@@ -746,7 +730,7 @@
"name": "icon-layout",
"id": 63,
"code": 921873,
"tempChar": ""
"tempChar": ""
},
{
"order": 77,
@@ -754,7 +738,7 @@
"name": "icon-object",
"id": 72,
"code": 921874,
"tempChar": ""
"tempChar": ""
},
{
"order": 78,
@@ -762,7 +746,7 @@
"name": "icon-object-unknown",
"id": 73,
"code": 921875,
"tempChar": ""
"tempChar": ""
},
{
"order": 79,
@@ -770,7 +754,7 @@
"name": "icon-packet",
"id": 74,
"code": 921876,
"tempChar": ""
"tempChar": ""
},
{
"order": 80,
@@ -778,7 +762,7 @@
"name": "icon-page",
"id": 75,
"code": 921877,
"tempChar": ""
"tempChar": ""
},
{
"order": 135,
@@ -786,7 +770,7 @@
"name": "icon-plot-overlay",
"prevSize": 24,
"code": 921878,
"tempChar": ""
"tempChar": ""
},
{
"order": 113,
@@ -794,7 +778,7 @@
"name": "icon-plot-stacked",
"prevSize": 24,
"code": 921879,
"tempChar": ""
"tempChar": ""
},
{
"order": 10,
@@ -802,7 +786,7 @@
"name": "icon-session",
"id": 5,
"code": 921880,
"tempChar": ""
"tempChar": ""
},
{
"order": 24,
@@ -810,7 +794,7 @@
"name": "icon-tabular",
"id": 19,
"code": 921881,
"tempChar": ""
"tempChar": ""
},
{
"order": 7,
@@ -818,7 +802,7 @@
"name": "icon-tabular-lad",
"id": 2,
"code": 921888,
"tempChar": ""
"tempChar": ""
},
{
"order": 6,
@@ -826,7 +810,7 @@
"name": "icon-tabular-lad-set",
"id": 1,
"code": 921889,
"tempChar": ""
"tempChar": ""
},
{
"order": 8,
@@ -834,7 +818,7 @@
"name": "icon-tabular-realtime",
"id": 3,
"code": 921890,
"tempChar": ""
"tempChar": ""
},
{
"order": 23,
@@ -842,7 +826,7 @@
"name": "icon-tabular-scrolling",
"id": 18,
"code": 921891,
"tempChar": ""
"tempChar": ""
},
{
"order": 112,
@@ -850,7 +834,7 @@
"name": "icon-telemetry",
"id": 86,
"code": 921892,
"tempChar": ""
"tempChar": ""
},
{
"order": 90,
@@ -858,7 +842,7 @@
"name": "icon-telemetry-panel",
"id": 85,
"code": 921893,
"tempChar": ""
"tempChar": ""
},
{
"order": 93,
@@ -866,7 +850,7 @@
"name": "icon-timeline",
"id": 88,
"code": 921894,
"tempChar": ""
"tempChar": ""
},
{
"order": 116,
@@ -874,7 +858,7 @@
"name": "icon-timer-v1.5",
"prevSize": 24,
"code": 921895,
"tempChar": ""
"tempChar": ""
},
{
"order": 11,
@@ -882,7 +866,7 @@
"name": "icon-topic",
"id": 6,
"code": 921896,
"tempChar": ""
"tempChar": ""
},
{
"order": 115,
@@ -890,7 +874,7 @@
"name": "icon-box-with-dashed-lines",
"id": 29,
"code": 921897,
"tempChar": ""
"tempChar": ""
},
{
"order": 126,
@@ -898,15 +882,7 @@
"name": "icon-summary-widget",
"prevSize": 24,
"code": 921904,
"tempChar": ""
},
{
"order": 139,
"id": 117,
"name": "icon-notebook",
"prevSize": 24,
"code": 921905,
"tempChar": ""
"tempChar": ""
}
],
"metadata": {
@@ -2707,52 +2683,6 @@
]
}
},
{
"id": 115,
"paths": [
"M832 192.4v639.4c0 0.2-0.2 0.2-0.4 0.4h-319.6v192h320c105.6 0 192-86.4 192-192v-640.2c0-105.6-86.4-192-192-192h-320v192h319.6c0.2 0 0.4 0.2 0.4 0.4z",
"M192 704v192l384-384-384-384v192h-192v384z"
],
"attrs": [
{},
{}
],
"grid": 16,
"tags": [
"icon-import"
],
"isMulticolor": false,
"isMulticolor2": false,
"colorPermutations": {
"1161751207457516161751": [
{},
{}
]
}
},
{
"id": 116,
"paths": [
"M192 831.66v-639.32l0.34-0.34h319.66v-192h-320c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h320v-192h-319.66z",
"M1024 512l-384-384v192h-192v384h192v192l384-384z"
],
"attrs": [
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-export"
],
"colorPermutations": {
"1161751207457516161751": [
{},
{}
]
}
},
{
"paths": [
"M576 64h-256l320 320h-290.256c-44.264-76.516-126.99-128-221.744-128h-128v512h128c94.754 0 177.48-51.484 221.744-128h290.256l-320 320h256l448-448-448-448z"
@@ -3532,29 +3462,6 @@
{}
]
}
},
{
"id": 117,
"paths": [
"M896 110.8c0-79.8-55.4-127.4-123-105.4l-773 250.6h896v-145.2z",
"M896 320h-896v576c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-448c0-70.4-57.6-128-128-128zM832 832h-384v-320h384v320z"
],
"attrs": [
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-notebook"
],
"colorPermutations": {
"1161751207457516161751": [
{},
{}
]
}
}
],
"colorThemes": [

View File

@@ -85,8 +85,6 @@
<glyph unicode="&#xe1044;" glyph-name="icon-grid-snap-no" d="M768 384h192v-64h-192v64zM256 384h192v-64h-192v64zM0 384h192v-64h-192v64zM640 448h-64v-64h-64v-64h64v-64h64v64h64v64h-64zM576 704h64v-192h-64v192zM576 960h64v-192h-64v192zM576 192h64v-192h-64v192z" />
<glyph unicode="&#xe1045;" glyph-name="icon-frame-show" d="M0 896v-896h1024v896h-1024zM896 128h-768v640h768v-640zM192 704h384v-128h-384v128z" />
<glyph unicode="&#xe1046;" glyph-name="icon-frame-hide" d="M128 770h420l104 128h-652v-802.4l128 157.4zM896 130h-420l-104-128h652v802.4l-128-157.4zM832 962l-832-1024h192l832 1024zM392 578l104 128h-304v-128z" />
<glyph unicode="&#xe1047;" glyph-name="icon-import" d="M832 767.6v-639.4c0-0.2-0.2-0.2-0.4-0.4h-319.6v-192h320c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192h-320v-192h319.6c0.2 0 0.4-0.2 0.4-0.4zM192 256v-192l384 384-384 384v-192h-192v-384z" />
<glyph unicode="&#xe1048;" glyph-name="icon-export" d="M192 128.34v639.32l0.34 0.34h319.66v192h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h320v192h-319.66zM1024 448l-384 384v-192h-192v-384h192v-192l384 384z" />
<glyph unicode="&#xe1100;" glyph-name="icon-activity" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
<glyph unicode="&#xe1101;" glyph-name="icon-activity-mode" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
<glyph unicode="&#xe1102;" glyph-name="icon-autoflow-tabular" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
@@ -118,5 +116,4 @@
<glyph unicode="&#xe1128;" glyph-name="icon-topic" d="M454.36 483.36l86.3 86.3c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c19.328-19.358 42.832-34.541 69.047-44.082l1.313 171.722-57.64 57.64c-34.407 34.33-81.9 55.558-134.35 55.558s-99.943-21.228-134.354-55.562l-86.296-86.297c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-28.674 28.654v-172.14c19.045-7.022 41.040-11.084 63.984-11.084 52.463 0 99.966 21.239 134.379 55.587zM505.64 412.64l-86.3-86.3c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-86.294 86.294c-2 2-4.2 4-6.36 6v-197.36c33.664-30.72 78.65-49.537 128.031-49.537 52.44 0 99.923 21.22 134.333 55.541l86.296 86.296c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c2-2 4.2-4 6.36-6v197.36c-33.664 30.72-78.65 49.537-128.031 49.537-52.44 0-99.923-21.22-134.333-55.541zM832 960h-128v-192h127.66l0.34-0.34v-639.32l-0.34-0.34h-127.66v-192h128c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM320 128h-127.66l-0.34 0.34v639.32l0.34 0.34h127.66v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192z" />
<glyph unicode="&#xe1129;" glyph-name="icon-box-with-dashed-lines" d="M0 576h128v-256h-128v256zM128 831.78l0.22 0.22h191.78v128h-192c-70.606-0.215-127.785-57.394-128-127.979v-192.021h128v191.78zM128 64.22v191.78h-128v-192c0.215-70.606 57.394-127.785 127.979-128h192.021v128h-191.78zM384 960h256v-128h-256v128zM896 64.22l-0.22-0.22h-191.78v-128h192c70.606 0.215 127.785 57.394 128 127.979v192.021h-128v-191.78zM896 960h-192v-128h191.78l0.22-0.22v-191.78h128v192c-0.215 70.606-57.394 127.785-127.979 128zM896 576h128v-256h-128v256zM384 64h256v-128h-256v128zM256 704h512v-512h-512v512z" />
<glyph unicode="&#xe1130;" glyph-name="icon-summary-widget" 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 128zM847.8 349.6l-82.6-143.2-189.6 131.6 19.2-230h-165.4l19.2 230-189.6-131.6-82.6 143.2 208.6 98.4-208.8 98.4 82.6 143.2 189.6-131.6-19.2 230h165.4l-19.2-230 189.6 131.6 82.6-143.2-208.6-98.4 208.8-98.4z" />
<glyph unicode="&#xe1131;" glyph-name="icon-notebook" d="M896 849.2c0 79.8-55.4 127.4-123 105.4l-773-250.6h896v145.2zM896 640h-896v-576c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v448c0 70.4-57.6 128-128 128zM832 128h-384v320h384v-320z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -21,7 +21,7 @@
*****************************************************************************/
/********************************************* COLUMN LAYOUTS STYLES */
@mixin cols($totalCols, $span) {
/*@mixin cols($totalCols, $span) {
$cw: 100% / $totalCols;
min-width: (500px / $totalCols) * $span;
@if ($totalCols != $span) {
@@ -89,7 +89,7 @@
@include clearfix;
padding: $interiorMargin 0;
}
}
}*/
/********************************************* FLEX STYLES */
.l-flex-row,
@@ -137,11 +137,6 @@
min-height: 0;
&.holder:not(:last-child) { margin-bottom: $interiorMarginLg; }
}
&.l-flex-accordion .flex-accordion-holder {
display: flex;
flex-direction: column;
//overflow: hidden !important;
}
.flex-container { @include flex-direction(column); }
}

View File

@@ -21,7 +21,7 @@
*****************************************************************************/
/************************** FEATURES */
$enableImageryThumbs: true; // Set to true if historical imagery thumbnails are supported
$enableImageryThumbs: false; // Set to true if historical imagery thumbnails are supported
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
$bodyMargin: 10px;
@@ -82,7 +82,7 @@ $tabularTdPadTB: 2px;
/*************** Imagery */
$imageMainControlBarH: 25px;
$imageThumbsD: 120px;
$imageThumbsWrapperH: 155px;
$imageThumbsWrapperH: $imageThumbsD * 1.4;
$imageThumbPad: 1px;
/*************** Ticks */
$ticksH: 25px;
@@ -111,9 +111,7 @@ $bubbleMaxW: 300px;
$reqSymbolW: 15px;
$reqSymbolM: $interiorMargin * 2;
$reqSymbolFontSize: 0.75em;
$inputTextPTopBtm: 3px;
$inputTextPLeftRight: 5px;
$inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
$inputTextP: 3px 5px;
/*************** Wait Spinner Defaults */
$waitSpinnerD: 32px;
$waitSpinnerTreeD: 20px;

View File

@@ -25,7 +25,6 @@
}
.l-fixed-position-item {
border-width: 1px;
position: absolute;
&.s-not-selected {
opacity: 0.8;
@@ -53,7 +52,6 @@
font-size: 0.8rem;
$p: 1px;
line-height: 100%;
overflow: hidden;
&.l-static-text {
padding: $p;
}

View File

@@ -1,24 +1,3 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
@mixin glyphBefore($unicode, $family: 'symbolsfont') {
&:before {
content: $unicode;
@@ -113,8 +92,6 @@ $glyph-icon-grid-snap-to: '\e1043';
$glyph-icon-grid-snap-no: '\e1044';
$glyph-icon-frame-show: '\e1045';
$glyph-icon-frame-hide: '\e1046';
$glyph-icon-import: '\e1047';
$glyph-icon-export: '\e1048';
$glyph-icon-activity: '\e1100';
$glyph-icon-activity-mode: '\e1101';
$glyph-icon-autoflow-tabular: '\e1102';
@@ -146,7 +123,6 @@ $glyph-icon-timer: '\e1127';
$glyph-icon-topic: '\e1128';
$glyph-icon-box-with-dashed-lines: '\e1129';
$glyph-icon-summary-widget: '\e1130';
$glyph-icon-notebook: '\e1131';
/************************** 16 PX CLASSES */
@@ -228,8 +204,6 @@ $glyph-icon-notebook: '\e1131';
.icon-grid-snap-no { @include glyphBefore($glyph-icon-grid-snap-no); }
.icon-frame-show { @include glyphBefore($glyph-icon-frame-show); }
.icon-frame-hide { @include glyphBefore($glyph-icon-frame-hide); }
.icon-import { @include glyphBefore($glyph-icon-import); }
.icon-export { @include glyphBefore($glyph-icon-export); }
.icon-activity { @include glyphBefore($glyph-icon-activity); }
.icon-activity-mode { @include glyphBefore($glyph-icon-activity-mode); }
.icon-autoflow-tabular { @include glyphBefore($glyph-icon-autoflow-tabular); }
@@ -261,7 +235,6 @@ $glyph-icon-notebook: '\e1131';
.icon-topic { @include glyphBefore($glyph-icon-topic); }
.icon-box-with-dashed-lines { @include glyphBefore($glyph-icon-box-with-dashed-lines); }
.icon-summary-widget { @include glyphBefore($glyph-icon-summary-widget); }
.icon-notebook { @include glyphBefore($glyph-icon-notebook); }
/************************** 12 PX CLASSES */
.icon-crosshair-12px { @include glyphBefore($glyph-icon-crosshair,'symbolsfont-12px'); }

View File

@@ -26,6 +26,5 @@
display: block;
height: 100%;
width: 100%;
border: none;
}
}

View File

@@ -0,0 +1,39 @@
@mixin limitGlyph($iconColor, $glyph: $glyph-icon-alert-triangle) {
&:before {
color: $iconColor;
content: $glyph;
font-family: symbolsfont;
font-size: 0.8em;
display: inline;
margin-right: $interiorMarginSm;
}
}
.s-limit-red { background: $colorLimitRedBg !important; }
.s-limit-yellow { background: $colorLimitYellowBg !important; }
// Handle limit when applied to a tr
tr[class*="s-limit"] {
&.s-limit-red td:first-child {
@include limitGlyph($colorLimitRedIc);
}
&.s-limit-yellow td:first-child {
@include limitGlyph($colorLimitYellowIc);
}
&.s-limit-upr td:first-child:before { content: $glyph-icon-arrow-double-up; }
&.s-limit-lwr td:first-child:before { content: $glyph-icon-arrow-double-down; }
}
// Handle limit when applied directly to a non-tr element
// Assume this is applied to the element that displays the limit value
:not(tr)[class*="s-limit"] {
&.s-limit-red {
@include limitGlyph($colorLimitRedIc);
}
&.s-limit-yellow {
@include limitGlyph($colorLimitYellowIc);
}
&.s-limit-upr:before { content: $glyph-icon-arrow-double-up; }
&.s-limit-lwr:before { content: $glyph-icon-arrow-double-down; }
}

View File

@@ -27,7 +27,7 @@
@import "about";
@import "text";
@import "icons";
@import "status";
@import "limits";
@import "data-status";
@import "helpers/bubbles";
@import "helpers/splitter";

View File

@@ -20,8 +20,8 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
@mixin absPosDefault($offset: 0px, $overflowHidden: hidden) {
overflow: $overflowHidden;
@mixin absPosDefault($offset: 0px, $overflow: hidden) {
overflow: $overflow;
position: absolute;
top: $offset;
right: $offset;
@@ -316,28 +316,23 @@
text-shadow: $shdwItemText;
}
@mixin input-base() {
@mixin input-base($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
@include appearance(none);
border-radius: $controlCr;
box-sizing: border-box;
&:focus { outline: 0; }
box-shadow: inset $shdw;
background: $bg;
border: none;
color: $fg;
outline: none;
&.error {
background-color: $colorFormFieldErrorBg;
color: $colorFormFieldErrorFg;
}
}
@mixin s-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
@include input-base();
background: $bg;
box-shadow: inset $shdw;
color: $fg;
}
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
@include s-input($bg, $fg, $shdw);
border: none;
outline: none;
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg) {
@include input-base($bg, $fg);
}
@mixin contextArrow() {
@@ -349,7 +344,7 @@
}
@mixin nice-textarea($bg: $colorBodyBg, $fg: $colorBodyFg) {
@include nice-input($bg, $fg);
@include input-base($bg, $fg);
padding: $interiorMargin;
}

View File

@@ -1,85 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
/*************************************************** MIXINS */
@mixin formulateStatusColors($c) {
// Sets bg and icon colors for elements
background: rgba($c, 0.4) !important;
&:before { color: $c !important; }
}
/*************************************************** GENERAL */
.s-limit-yellow,
.s-limit-red,
.s-limit-yellow-icon,
.s-limit-red-icon,
.s-status-warning-lo,
.s-status-warning-hi,
.s-status-diagnostic,
.s-status-command,
.s-status-info,
.s-status-ok,
.s-status-warning-lo-icon,
.s-status-warning-hi-icon,
.s-status-diagnostic-icon,
.s-status-command-icon,
.s-status-info-icon,
.s-status-ok-icon {
@include trans-prop-nice($props: background, $dur: 500ms);
&:before {
content:'';
font-family: symbolsfont;
font-size: 0.8em;
margin-right: $interiorMarginSm;
}
}
/*************************************************** LIMITS */
.s-limit-yellow, .s-limit-yellow-icon {
@include formulateStatusColors($colorWarningLo);
}
.s-limit-red, .s-limit-red-icon {
@include formulateStatusColors($colorWarningHi);
}
.s-limit-upr:before { content: $glyph-icon-arrow-double-up; }
.s-limit-lwr:before { content: $glyph-icon-arrow-double-down; }
.s-limit-yellow-icon:before,
.s-limit-red-icon:before { content: $glyph-icon-alert-triangle; }
/*************************************************** STATUS */
.s-status-warning-hi, .s-status-warning-hi-icon { @include formulateStatusColors($colorWarningHi); }
.s-status-warning-lo, .s-status-warning-lo-icon { @include formulateStatusColors($colorWarningLo); }
.s-status-diagnostic, .s-status-diagnostic-icon { @include formulateStatusColors($colorDiagnostic); }
.s-status-info, .s-status-info-icon { @include formulateStatusColors($colorInfo); }
.s-status-ok, .s-status-ok-icon { @include formulateStatusColors($colorOk); }
.s-status-warning-hi-icon:before { content: $glyph-icon-alert-triangle; }
.s-status-warning-lo-icon:before { content: $glyph-icon-alert-rect; }
.s-status-diagnostic-icon:before { content: $glyph-icon-eye-open; }
.s-status-info-icon:before { content: $glyph-icon-info; }
.s-status-ok-icon:before { content: $glyph-icon-check; }

View File

@@ -26,26 +26,22 @@
@include ellipsize();
display: inline-block;
text-align: center;
.widget-label:before {
// Widget icon
font-size: 0.9em;
margin-right: $interiorMarginSm;
}
}
.s-summary-widget {
// Widget style classes here
@include boxShdw($shdwBtns);
border-radius: $basicCr;
border-style: solid;
border-width: 1px;
box-sizing: border-box;
cursor: default;
font-size: 0.8rem;
padding: $interiorMarginLg $interiorMarginLg * 2;
&[href] {
cursor: pointer;
}
}
.l-widget-outer-w,
.widget-holder,
.widget-edit-holder {
// In browse mode, all these things should be at .abs default
@extend .abs;
}
.widget-edit-holder {
@@ -64,42 +60,19 @@
}
}
.widget-rules-wrapper,
.widget-rule-content,
.w-widget-test-data-content {
@include trans-prop-nice($props: (height, min-height, opacity), $dur: 250ms);
.widget-rule-content {
@include trans-prop-nice($props: (height, min-height), $dur: 250ms);
min-height: 0;
height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
}
.widget-rules-wrapper {
flex: 1 1 auto !important;
}
.widget-rule-content.expanded {
overflow: visible !important;
min-height: 50px;
height: auto;
opacity: 1;
pointer-events: inherit;
}
.w-widget-test-data-content {
.l-enable {
padding: $interiorMargin 0;
}
.w-widget-test-data-items {
max-height: 20vh;
overflow-y: scroll !important;
padding-right: $interiorMargin;
&.expanded {
min-height: 50px;
height: auto;
overflow: visible;
}
}
.l-widget-thumb-wrapper,
.l-widget-thumb-w,
.l-compact-form label {
$ruleLabelW: 40%;
$ruleLabelMaxW: 150px;
@@ -108,199 +81,133 @@
width: $ruleLabelW;
}
.t-message-widget-no-data {
display: none;
}
/********************************************************** EDITING A WIDGET */
.s-status-editing > mct-view > .w-summary-widget {
// Classes for editor layout while editing a widget
// This selector is ugly and brittle, but needed to prevent interface from showing when widget is in a layout
// being edited.
@include absPosDefault();
@extend .l-flex-col;
.s-status-editing .l-widget-outer-w {
$widgetHolderH: 100px;
@extend .abs;
//overflow: hidden; // Overflow scroll is handled by internal elements
> .l-summary-widget {
// Main view of the summary widget
// Give some airspace and center the widget in the area
margin: 30px auto;
.widget-holder {
bottom: auto;
height: $widgetHolderH;
.l-summary-widget {
display: inline-block;
position: absolute;
top: 50%; left: 50%;
@include transform(translateX(-50%) translateY(-50%));
}
}
.widget-edit-holder {
display: flex; // Overrides `display: none` during Browse mode
.flex-accordion-holder {
// Needed because otherwise accordion elements "creep" when contents expand and contract
display: block !important;
}
&.expanded-widget-test-data {
.w-widget-test-data-content {
min-height: 50px;
height: auto;
opacity: 1;
pointer-events: inherit;
}
&:not(.expanded-widget-rules) {
// Test data is expanded and rules are collapsed
// Make text data take up all the vertical space
.flex-accordion-holder { display: flex; }
.widget-test-data {
flex-grow: 999999;
}
.w-widget-test-data-items {
max-height: inherit;
}
}
}
&.expanded-widget-rules {
.widget-rules-wrapper {
min-height: 50px;
height: auto;
opacity: 1;
pointer-events: inherit;
}
}
}
&.s-status-no-data {
.widget-edit-holder {
opacity: 0.3;
pointer-events: none;
}
.t-message-widget-no-data {
display: flex;
}
@extend .l-flex-col;
display: block; // Needed to counteract display: none while browsing
overflow-y: scroll;
padding-right: $interiorMargin;
top: $widgetHolderH + $interiorMargin;
}
.l-compact-form {
// Overrides on .l-compact-form
ul {
&:last-child { margin: 0; }
li {
@include align-items(flex-start);
@include flex-wrap(nowrap);
line-height: 230%; // Provide enough space when controls wrap
padding: 2px 0;
&:not(.widget-rule-header) {
&:not(.connects-to-previous) {
border-top: 1px solid $colorFormLines;
}
}
&.connects-to-previous {
padding: $interiorMargin 0;
}
.widget-test-data,
.widget-rules-w {
@include test(blue, 0.1);
}
.widget-test-data {
> label {
display: block; // Needed to align text to right
text-align: right;
}
}
}
.widget-rules-w {
// Wrapper area that holds n rules
@extend .flex-elem;
box-sizing: border-box;
font-size: 0.8em;
}
.l-widget-rule {
box-sizing: border-box;
margin-bottom: $interiorMargin;
padding: $interiorMarginLg;
}
.l-widget-thumb-w {
@extend .l-flex-row;
@include align-items(center);
> span { display: block; }
.grippy-holder,
.view-control {
margin-right: $interiorMargin;
width: 1em;
height: 1em;
}
&.s-widget-test-data-item {
// Single line of ul li label span, etc.
ul {
li {
border: none !important;
> label {
display: inline-block;
width: auto;
text-align: left;
}
}
}
.widget-thumb {
@include flex(1 1 auto);
}
}
}
.widget-edit-holder {
font-size: 0.8rem;
}
.rule-title {
@include flex(0 1 auto);
color: pullForward($colorBodyFg, 50%);
}
.widget-rules-wrapper {
// Wrapper area that holds n rules
box-sizing: border-box;
overflow-y: scroll;
padding-right: $interiorMargin;
}
.rule-description {
@include flex(1 1 auto);
@include ellipsize();
color: pushBack($colorBodyFg, 20%);
}
.l-widget-rule,
.l-widget-test-data-item {
box-sizing: border-box;
margin-bottom: $interiorMarginSm;
padding: $interiorMargin $interiorMarginLg;
}
.l-widget-thumb-wrapper {
@extend .l-flex-row;
@include align-items(center);
> span { display: block; }
.grippy-holder,
.view-control {
margin-right: $interiorMargin;
width: 1em;
height: 1em;
.s-widget-rule {
background-color: rgba($colorBodyFg, 0.1);
border-radius: $basicCr;
}
.widget-thumb {
@include flex(1 1 auto);
width: 100%;
@include ellipsize();
@extend .s-summary-widget;
@extend .l-summary-widget;
padding: $interiorMarginSm $interiorMargin;
.widget-icon {
font-size: 0.8em;
}
}
}
.rule-title {
@include flex(0 1 auto);
color: pullForward($colorBodyFg, 50%);
}
.rule-description {
@include flex(1 1 auto);
@include ellipsize();
color: pushBack($colorBodyFg, 20%);
}
.s-widget-rule,
.s-widget-test-data-item {
background-color: rgba($colorBodyFg, 0.1);
border-radius: $basicCr;
}
.widget-thumb {
@include ellipsize();
@extend .s-summary-widget;
@extend .l-summary-widget;
padding: $interiorMarginSm $interiorMargin;
}
// Hide and show elements in the rule-header on hover
.l-widget-rule,
.l-widget-test-data-item {
.grippy,
.l-rule-action-buttons-wrapper,
.l-condition-action-buttons-wrapper,
.l-widget-test-data-item-action-buttons-wrapper {
@include trans-prop-nice($props: opacity, $dur: 500ms);
opacity: 0;
}
&:hover {
// Hide and show elements in the rule-header on hover
.l-widget-rule {
.grippy,
.l-rule-action-buttons-wrapper,
.l-widget-test-data-item-action-buttons-wrapper {
@include trans-prop-nice($props: opacity, $dur: 0);
opacity: 1;
.l-rule-action-buttons-w,
.l-condition-action-buttons-w {
@include trans-prop-nice($props: opacity, $dur: 500ms);
opacity: 0;
}
}
.l-rule-action-buttons-wrapper {
.t-delete {
margin-left: 10px;
}
}
.t-condition {
&:hover {
.l-condition-action-buttons-wrapper {
.grippy,
.l-rule-action-buttons-w,
.l-condition-action-buttons-w {
@include trans-prop-nice($props: opacity, $dur: 0);
opacity: 1;
}
}
}
.l-compact-form {
// Overrides
ul li {
padding: $interiorMargin 0;
&:not(.widget-rule-header) {
&:not(.connects-to-previous) {
border-top: 1px solid $colorFormLines;
}
}
&.connects-to-previous {
padding: $interiorMargin 0;
}
}
label {
display: block; // Needed to align text to right
text-align: right;
}
}
}

View File

@@ -33,6 +33,7 @@ $pad: $interiorMargin * $baseRatio;
height: $btnStdH;
line-height: $btnStdH;
padding: 0 $pad;
vertical-align: top;
&.labeled:before {
// Icon when it's included

View File

@@ -72,13 +72,11 @@
}
}
// Hyperlink objects
.s-hyperlink {
.label {
font-size: 0.8rem !important;
}
// Hyperlink objects
&:not(.s-button) {
color: $colorKey;
font-size: 0.8rem;
&:hover { color: $colorKeyHov; }
}
}
@@ -234,16 +232,12 @@ textarea {
}
/******************************************************** INPUTS */
%input-base {
@include input-base();
}
input[type="text"],
input[type="search"],
input[type="number"] {
@include nice-input();
vertical-align: baseline;
padding: $inputTextPTopBtm $inputTextPLeftRight;
padding: $inputTextP;
&.numeric {
text-align: right;
}
@@ -261,7 +255,7 @@ input[type="number"] {
input[type="text"].lg { width: 100% !important; }
.l-input-med input[type="text"],
input[type="text"].med { width: 200px !important; }
input[type="text"].sm, input[type="number"].sm { width: 50px !important; }
input[type="text"].sm { width: 50px !important; }
.l-numeric input[type="text"],
input[type="text"].numeric { text-align: right; }
@@ -287,44 +281,20 @@ textarea.lg { position: relative; height: 300px; }
}
}
*[contenteditable].s-input-inline,
input[type="text"].s-input-inline,
.s-input-inline input[type="text"] {
// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
@extend %input-base;
@include trans-prop-nice((padding, box-shadow), 250ms);
background: none;
box-shadow: none;
border: 1px solid transparent;
min-width: 20px;
padding-left: 0;
padding-right: 0;
&:hover,
&:focus {
padding-left: $inputTextPLeftRight;
padding-right: $inputTextPLeftRight;
}
&:hover {
border-color: rgba($colorBodyFg, 0.2);
}
&:focus {
@include s-input();
border-color: transparent;
}
}
/******************************************************** SELECTS */
.select {
@include btnSubtle($bg: $colorSelectBg);
@extend .icon-arrow-down; // Context arrow
//@if $shdwBtns != none { margin: 0 0 2px 0; } // Needed to avoid dropshadow from being clipped by parent containers
display: inline-block;
padding: 0 $interiorMargin;
overflow: hidden;
position: relative;
height: $btnStdH;
line-height: $btnStdH;
select {
@include appearance(none);
box-sizing: border-box;
&:focus { outline: 0; }
background: none;
color: $colorSelectFg;
cursor: pointer;
@@ -394,7 +364,8 @@ input[type="text"].s-input-inline,
.l-elem-wrapper {
mct-representation {
// Holds the context-available item
// Must have min-width to make flex work properly in Safari
// Must have min-width to make flex work properly
// in Safari
min-width: 0.7em;
}
}
@@ -560,6 +531,7 @@ input[type="text"].s-input-inline,
height: $h;
margin-top: 1 + floor($h/2) * -1;
@include btnSubtle(pullForward($colorBtnBg, 10%));
//border-radius: 50% !important;
}
@mixin sliderKnobRound() {
@@ -574,6 +546,7 @@ input[type="text"].s-input-inline,
input[type="range"] {
// HTML5 range inputs
-webkit-appearance: none; /* Hides the slider so that custom slider can be made */
background: transparent; /* Otherwise white in Chrome */
&:focus {
@@ -772,15 +745,11 @@ body.desktop {
}
.overlay ::-webkit-scrollbar-thumb {
$lr: 15%;
background: $scrollbarThumbColorOverlay;
&:hover { background: $scrollbarThumbColorOverlayHov; }
}
.menu ::-webkit-scrollbar-thumb {
background: $scrollbarThumbColorMenu;
&:hover { background: $scrollbarThumbColorMenuHov; }
}
::-webkit-scrollbar-corner {
background: $scrollbarTrackColorBg;
}

View File

@@ -21,20 +21,20 @@
*****************************************************************************/
/******************************************************** MENU BUTTONS */
.s-menu-button {
// Formerly .btn-menu
@extend .s-button;
span.l-click-area {
// In markup, this element should not enclose anything.
@extend .abs;
}
// Formerly .btn-menu
@extend .s-button;
span.l-click-area {
// In markup, this element should not enclose anything.
@extend .abs;
}
.icon {
font-size: 16px;
}
.icon {
font-size: 16px; //120%;
}
.title-label {
margin-left: $interiorMarginSm;
}
.title-label {
margin-left: $interiorMarginSm;
}
.icon-swatch,
.color-swatch {
@@ -52,60 +52,66 @@
}
}
&:after {
// Adds the downward facing 'context available / invoke menu' arrow element
@include contextArrow();
color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
}
&:after {
// Adds the downward facing 'context available / invoke menu' arrow element
@include contextArrow();
color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
}
&.create-button {
&.create-button {
@extend .icon-plus;
.title-label {
font-size: 1rem;
}
}
.title-label {
font-size: 1rem;
}
}
.menu {
left: 0;
text-align: left;
}
.menu {
left: 0;
text-align: left;
}
}
/******************************************************** MENUS THEMSELVES */
.menu-element {
cursor: pointer;
position: relative;
cursor: pointer;
position: relative;
}
.s-menu {
border-radius: $basicCr;
@include containerSubtle($colorMenuBg, $colorMenuFg);
@include boxShdw($shdwMenu);
@include txtShdw($shdwMenuText);
padding: $interiorMarginSm 0;
}
.menu {
border-radius: $basicCr;
@include containerSubtle($colorMenuBg, $colorMenuFg);
@include boxShdw($shdwMenu);
@include txtShdw($shdwMenuText);
padding: $interiorMarginSm 0;
display: block;
position: absolute;
z-index: 10;
ul {
@include menuUlReset();
li {
box-sizing: border-box;
border-top: 1px solid pullForward($colorMenuBg, 10%);
// TODO: reduce size of icons
@extend .s-menu;
display: block;
position: absolute;
z-index: 10;
ul {
@include menuUlReset();
li {
box-sizing: border-box;
border-top: 1px solid pullForward($colorMenuBg, 10%);
color: $colorMenuFg;
line-height: $menuLineH;
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
position: relative;
white-space: nowrap;
&:first-child {
border: none;
}
&:hover {
background: $colorMenuHovBg;
color: $colorMenuHovFg;
//color: pullForward($colorMenuBg, 60%);
line-height: $menuLineH;
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
position: relative;
white-space: nowrap;
&:first-child {
border: none;
}
&:hover {
background: $colorMenuHovBg;
color: $colorMenuHovFg;
&:before {
color: $colorMenuHovIc;
}
}
}
&:before {
@extend .ui-symbol;
@extend .type-icon;
@@ -113,8 +119,8 @@
display: inline-block;
left: $interiorMargin * 2;
}
}
}
}
}
}
.menu,
@@ -122,97 +128,94 @@
.context-menu,
.super-menu,
.s-menu-button .menu {
pointer-events: auto;
ul li {
a.menu-item-a {
pointer-events: auto;
ul li {
a.menu-item-a {
color: $colorMenuFg;
display: block;
}
}
&:before,
a.menu-item-a:before {
color: $colorMenuIc;
left: $interiorMargin;
}
}
}
}
.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;
height: $d;
width: $d;
line-height: $d;
}
}
}
&:before {
// 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;
height: $d;
width: $d;
line-height: $d;
}
}
}
&:before {
// Type icon
left: 25px;
}
}
}
.super-menu,
.super-menu > mct-representation,
.super-menu > .contents {
box-sizing: border-box;
display: block;
position: relative;
left: 25px;
}
}
}
.super-menu {
$plw: 50%;
$prw: 100% - $plw;
position: absolute;
.w-menu {
align-items: stretch;
display: flex;
flex-direction: row;
margin: $interiorMarginLg;
}
.col {
box-sizing: border-box;
flex: 1 1 auto;
overflow-x: hidden;
&.menu-items {
border-right: 1px solid pullForward($colorMenuBg, 10%);
overflow-y: auto;
padding-right: $interiorMargin;
width: $plw;
ul {
li {
border-radius: $controlCr;
padding-left: 30px;
border-top: none;
}
}
}
&.menu-item-description {
$p: $interiorMargin * 3;
overflow-y: hidden;
padding: $p $p 0 $p;
width: $prw;
$w: 500px;
$h: $w - 20;
$plw: 50%;
$prw: 50%;
display: block;
width: $w;
height: $h;
.contents {
@include absPosDefault($interiorMargin);
}
.pane {
box-sizing: border-box;
&.menu-items {
border-right: 1px solid pullForward($colorMenuBg, 10%);
left: 0;
padding-right: $interiorMargin;
right: auto;
width: $plw;
overflow-x: hidden;
overflow-y: auto;
ul {
li {
border-radius: $controlCr;
padding-left: 30px;
border-top: none;
}
}
}
&.menu-item-description {
left: auto;
right: 0;
padding: $interiorMargin * 5;
width: $prw;
.desc-area {
&.icon {
color: $colorCreateMenuLgIcon;
font-size: 8em;
margin-bottom: $interiorMargin * 3;
position: relative;
text-align: center;
}
&.title {
color: $colorCreateMenuText;
font-size: 1.2em;
margin-bottom: $interiorMargin * 2;
}
&.description {
color: pushBack($colorCreateMenuText, 20%);
@@ -220,104 +223,67 @@
line-height: 1.5em;
}
}
}
}
.w-title-desc {
display: flex;
flex-direction: column;
overflow: hidden; // Height set in specific menu instances
}
// Specific menu instances
&.l-create-menu {
width: 500px;
.col {
max-height: 70vh;
}
.w-title-desc {
height: 190px;
}
.desc-area {
&.icon {
font-size: 8em;
height: 135px;
margin-bottom: $interiorMargin * 3;
}
&.title {
font-size: 1.2em;
margin-bottom: $interiorMargin * 2;
}
}
}
}
}
&.mini {
width: 400px;
.col {
max-height: 50vh;
height: 300px;
.pane {
&.menu-items {
font-size: 0.8em;
}
&.menu-item-description {
$p: $interiorMargin * 2;
padding: $p $p 0 $p;
}
}
.w-title-desc {
height: 180px;
}
.desc-area {
&.icon {
font-size: 4em;
height: 70px;
margin-bottom: $interiorMargin * 3;
}
&.title {
font-size: 1em;
margin-bottom: $interiorMargin * 2;
padding: $interiorMargin * 3;
.desc-area {
&.icon {
font-size: 4em;
}
&.title {
font-size: 1em;
}
}
}
}
}
}
.context-menu {
font-size: 0.80rem;
font-size: 0.80rem;
}
.context-menu-holder,
.menu-holder {
position: absolute;
z-index: 120;
.context-menu-wrapper {
position: absolute;
height: 100%;
width: 100%;
}
&.go-left .context-menu,
&.go-left .menu {
right: 0;
}
&.go-up .context-menu,
&.go-up .menu {
bottom: 0;
}
position: absolute;
z-index: 120;
.context-menu-wrapper {
position: absolute;
height: 100%;
width: 100%;
}
&.go-left .context-menu,
&.go-left .menu {
right: 0;
}
&.go-up .context-menu,
&.go-up .menu {
bottom: 0;
}
}
.context-menu-holder {
pointer-events: none;
height: 200px;
width: 170px;
pointer-events: none;
height: 200px;
width: 170px;
}
.btn-bar.right .menu,
.menus-to-left .menu {
z-index: 79;
left: auto;
right: 0;
width: auto;
left: auto;
right: 0;
width: auto;
}
.menus-up .menu {
bottom: $btnStdH;
top: auto;
bottom: $btnStdH; top: auto;
}

View File

@@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/******************************************************************* STATUS BLOCK ELEMS */
@mixin statusBannerColors($bg, $fg: $colorStatusFg) {
$bgPb: 30%;
$bgPbD: 10%;
@@ -39,7 +39,7 @@
// Status coloring
.ok, .info {
.status-indicator {
color: $colorInfo;
color: $colorStatusInfo;
}
}
@@ -120,11 +120,7 @@
}
.status-indicator {
background: none !important;
margin-right: $interiorMarginSm;
&[class*='s-status']:before {
font-size: 1em;
}
}
.count {
@@ -140,7 +136,7 @@
}
}
/******************************************************************* MESSAGE BANNERS */
/* Styles for messages and message banners */
.message {
&.block {
border-radius: $basicCr;
@@ -196,6 +192,7 @@
padding: 0 $interiorMargin;
}
.close {
//@include test(red, 0.7);
cursor: pointer;
font-size: 7px;
width: 8px;
@@ -227,159 +224,144 @@
}
&.ok,
&.info {
@include statusBannerColors($colorInfo);
@include statusBannerColors($colorStatusInfo);
}
&.caution,
&.warning,
&.alert {
@include statusBannerColors($colorWarningLo);
@include statusBannerColors($colorStatusAlert);
}
&.error {
@include statusBannerColors($colorWarningHi);
@include statusBannerColors($colorStatusError);
}
}
/******************************************************************* MESSAGES */
/* Contexts:
In .t-message-list
In .overlay as a singleton
Inline in the view area
*/
// Archetypal message
.l-message {
$iconW: 32px;
@include display(flex);
@include flex-direction(row);
@include align-items(stretch);
padding: $interiorMarginLg;
&:before {
// Icon
@include flex(0 1 auto);
@mixin messageBlock($iconW: 32px) {
.type-icon.message-type {
@include txtShdw($shdwStatusIc);
@extend .icon-bell;
color: $colorStatusDefault;
font-size: $iconW;
padding: 1px;
width: $iconW + 2;
margin-right: $interiorMarginLg;
}
&.message-severity-info:before {
.message-severity-info .type-icon.message-type {
@extend .icon-info;
color: $colorInfo;
color: $colorStatusInfo;
}
&.message-severity-alert:before {
color: $colorWarningLo;
.message-severity-alert .type-icon.message-type {
@extend .icon-bell;
color: $colorStatusAlert;
}
&.message-severity-error:before {
.message-severity-error .type-icon.message-type {
@extend .icon-alert-rect;
color: $colorWarningHi;
color: $colorStatusError;
}
}
/* Paths:
t-dialog | t-dialog-sm > t-message-single | t-message-list > overlay > holder > contents > l-message >
message-type > (icon)
message-contents >
top-bar >
title
hint
editor >
(if displaying list of messages)
ul > li > l-message >
... same as above
bottom-bar
*/
.w-message-contents {
@include flex(1 1 auto);
.l-message {
@include display(flex);
@include flex-direction(column);
> div,
> span {
//@include test(red);
margin-bottom: $interiorMargin;
@include flex-direction(row);
@include align-items(stretch);
.type-icon.message-type {
@include flex(0 1 auto);
position: relative;
}
.message-contents {
@include flex(1 1 auto);
margin-left: $overlayMargin;
position: relative;
.message-body {
@include flex(1 1 100%);
}
}
// Singleton in an overlay dialog
.t-message-single .l-message,
.t-message-single.l-message {
$iconW: 80px;
@include absPosDefault();
padding: 0;
&:before {
font-size: $iconW;
width: $iconW + 2;
}
.title {
font-size: 1.2em;
}
}
// Singleton inline in a view
.t-message-inline .l-message,
.t-message-inline.l-message {
border-radius: $controlCr;
&.message-severity-info { background-color: rgba($colorInfo, 0.3); }
&.message-severity-alert { background-color: rgba($colorWarningLo, 0.3); }
&.message-severity-error { background-color: rgba($colorWarningHi, 0.3); }
.w-message-contents.l-message-body-only {
.top-bar,
.message-body {
margin-top: $interiorMargin;
margin-bottom: $interiorMarginLg * 2;
}
}
}
// In a list
.t-message-list {
@include absPosDefault();
@include display(flex);
@include flex-direction(column);
> div,
> span {
margin-bottom: $interiorMargin;
// Message as singleton
.t-message-single {
@include messageBlock(80px);
}
body.desktop .t-message-single {
.l-message,
.bottom-bar {
@include absPosDefault();
}
.w-messages {
@include flex(1 1 100%);
overflow-y: auto;
padding-right: $interiorMargin;
.bottom-bar {
top: auto;
height: $ovrFooterH;
}
// Each message
.l-message {
border-radius: $controlCr;
background: rgba($colorOvrFg, 0.1);
margin-bottom: $interiorMargin;
.hint,
.bottom-bar {
text-align: left;
}
}
}
@include phonePortrait {
.t-message-single .l-message,
.t-message-single.l-message {
@include flex-direction(column);
&:before {
margin-right: 0;
.t-message-single {
.l-message {
@include flex-direction(column);
.message-contents { margin-left: 0; }
}
.type-icon.message-type {
margin-bottom: $interiorMarginLg;
text-align: center;
width: 100%;
text-align: center;
}
.bottom-bar {
text-align: center;
.s-button {
display: block;
width: 100%;
text-align: center !important;
}
}
}
// Messages in list
.t-message-list {
@include messageBlock(32px);
.message-contents {
.l-message {
border-radius: $controlCr;
background: rgba($colorOvrFg, 0.1);
margin-bottom: $interiorMargin;
padding: $interiorMarginLg;
.message-contents,
.bottom-bar {
position: relative;
}
.message-contents {
font-size: 0.9em;
margin-left: $interiorMarginLg;
.message-action { color: pushBack($colorOvrFg, 20%); }
.bottom-bar { text-align: left; }
}
.top-bar,
.message-body {
margin-bottom: $interiorMarginLg;
}
}
}
}
body.desktop .t-message-list {
.w-message-contents { padding-right: $interiorMargin; }
.message-contents .l-message { margin-right: $interiorMarginLg; }
}
// Alert elements in views

View File

@@ -80,32 +80,23 @@
// Editing Grids
.l-grid-holder {
display: block;
.l-grid {
&.l-grid-x { @include bgTicks($colorGridLines, 'x'); }
&.l-grid-y { @include bgTicks($colorGridLines, 'y'); }
}
}
// Display grid when selected or selection parent.
.s-selected .l-grid-holder,
.s-selected-parent .l-grid-holder {
display: block;
// Prevent nested frames from showing their grids
.t-frame-outer .l-grid-holder { display: none !important; }
// Prevent nested elements from showing s-hover-border
.t-frame-outer .s-hover-border {
border: none !important;
}
// Display in nested frames...
.t-frame-outer {
// ...when drilled in or selection parent...
&.s-drilled-in, &.s-selected-parent {
.l-grid-holder {
display: block;
}
.t-frame-outer:not(.s-drilled-in) .l-grid-holder {
display: none;
}
}
// ...but hide otherwise.
.l-grid-holder {
display: none;
}
// Prevent nested frames from being selectable until we have proper sub-object editing
.t-frame-outer .t-frame-outer {
pointer-events: none;
}
}

View File

@@ -9,6 +9,7 @@
@if $enableImageryThumbs == true {
bottom: $interiorMargin*2 + $imageThumbsWrapperH;
}
min-height: 100px;
min-width: 150px;
.l-image-main {
background-color: $colorPlotBg;
@@ -21,9 +22,7 @@
.l-image-thumbs-wrapper {
top: auto;
min-height: $imageThumbsWrapperH;
max-height: 60%;
box-sizing: border-box;
height: $imageThumbsWrapperH;
}
.l-date,
@@ -44,16 +43,14 @@
.l-image-main-controlbar {
font-size: 0.8em;
line-height: inherit;
.l-datetime-w, .l-controls-w {
.left, .right {
direction: rtl;
overflow: hidden;
}
.l-datetime-w {
@include ellipsize();
margin-right: $interiorMarginSm;
.left {
text-align: left;
}
.l-controls-w {
.right {
z-index: 2;
}
.l-date,
@@ -85,8 +82,9 @@
/*************************************** THUMBS */
.l-image-thumbs-wrapper {
overflow-x: hidden;
overflow-y: auto;
//@include test(green);
overflow-x: auto;
overflow-y: hidden;
padding-bottom: $interiorMargin;
white-space: nowrap;
}
@@ -94,17 +92,8 @@
.l-image-thumb-item {
@include transition(background-color, 0.25s);
box-sizing: border-box;
cursor: pointer;
direction: ltr;
display: inline-block;
float: left;
font-size: 0.8em;
padding: 1px;
margin-left: $interiorMarginSm;
position: relative;
text-align: left;
width: $imageThumbsD + $imageThumbPad*2;
white-space: normal;
position: relative;
.l-thumb,
.l-date,
.l-time {
@@ -114,7 +103,14 @@
.l-time {
padding: 2px 3px;
}
cursor: pointer;
direction: ltr;
display: inline-block;
font-size: 0.8em;
margin-left: $interiorMarginSm;
text-align: left;
width: $imageThumbsD + $imageThumbPad*2;
white-space: normal;
&:hover {
background: $colorThumbHoverBg;
.l-date,
@@ -140,7 +136,6 @@
/*************************************** LOCAL CONTROLS */
.l-local-controls {
max-width: 200px;
min-width: 100px;
width: 35%;
input[type="range"] {
display: block;
@@ -189,8 +184,7 @@
/*************************************** WHEN IN FRAME */
.frame .t-imagery {
.l-image-main-wrapper {
bottom: 0 !important;
height: 100% !important;
bottom: 0;
.l-image-main-controlbar {
font-size: 0.7em;
}
@@ -200,8 +194,7 @@
}
}
}
.l-image-thumbs-wrapper,
mct-splitter {
.l-image-thumbs-wrapper {
display: none;
}
}

View File

@@ -23,16 +23,10 @@
border-radius: $basicCr;
background: $colorFormSectionHeader;
color: lighten($colorBodyFg, 20%);
font-size: inherit;
font-size: 0.8em;
margin: $interiorMargin 0;
padding: $formTBPad $formLRPad;
text-transform: uppercase;
.view-control {
display: inline-block;
margin-right: $interiorMargin;
width: 1em;
height: 1em;
}
}
.form {
@@ -60,6 +54,9 @@
margin-bottom: $interiorMarginLg * 2;
padding: $formTBPad 0;
position: relative;
//&ng-form {
// display: block;
//}
&.first {
border-top: none;
@@ -196,23 +193,16 @@
label,
.control {
@include display(flex);
//min-width: $minW;
}
label {
line-height: inherit;
padding: $interiorMarginSm 0;
width: $labelW;
}
.controls {
@include flex-grow(1);
margin-left: $interiorMargin;
input[type="text"],
input[type="search"],
input[type="number"],
.select {
height: $btnStdH;
line-height: $btnStdH;
vertical-align: middle;
}
margin-left: $interiorMargin ;
.e-control {
// Individual form controls
&:not(:first-child) {
@@ -221,6 +211,12 @@
}
}
&:not(.section-header) {
&:not(.connects-to-previous) {
//border-top: 1px solid $colorFormLines;
}
}
&.connects-to-previous {
padding-top: 0;
}

View File

@@ -129,6 +129,9 @@
}
.s-filter {
input[type="search"] {
@include input-base();
}
.clear-icon,
.menu-icon,
&:before {

View File

@@ -79,7 +79,6 @@
// Dialog boxes, size constrained and centered in desktop/tablet
&.l-dialog {
font-size: 0.8rem;
.s-button {
&:not(.major) {
@include btnSubtle($bg: $colorOvrBtnBg, $bgHov: pullForward($colorOvrBtnBg, 10%), $fg: $colorOvrBtnFg, $fgHov: $colorOvrBtnFg, $ic: $colorOvrBtnFg, $icHov: $colorOvrBtnFg);
@@ -126,9 +125,9 @@
@include containerSubtle($colorOvrBg, $colorOvrFg);
}
.dialog-title {
.title {
@include ellipsize();
font-size: 1.5em;
font-size: 1.2em;
line-height: 120%;
margin-bottom: $interiorMargin;
}
@@ -157,8 +156,6 @@
left: 0;
right: 0;
overflow: auto;
padding-right: $interiorMargin;
padding-bottom: $interiorMargin;
.field.l-input-med {
input[type='text'] {
width: 100%;

View File

@@ -26,10 +26,12 @@
z-index: 0; // Needed to prevent child-frame controls from showing through when another child-frame is above
&:not(.no-frame) {
background: $colorBodyBg;
border-color: $bc;
border: 1px solid $bc;
&:hover {
border-color: lighten($bc, 10%);
}
}
}
.object-browse-bar {
font-size: 0.75em;
height: $ohH;
@@ -42,11 +44,10 @@
&.t-object-type-timer,
&.t-object-type-clock,
&.t-object-type-hyperlink,
&.t-object-type-summary-widget {
&.t-object-type-hyperlink {
// Hide the right side buttons for objects where they don't make sense
// Note that this will hide the view Switcher button if applied
// to an object that has it.
// to an object that it.
.object-browse-bar .right { display: none; }
}
@@ -90,9 +91,9 @@
&.no-frame {
background: transparent !important;
border-color: transparent;
border: none !important;
.object-browse-bar .right {
$m: 0;
$m: 0; // $interiorMarginSm;
background: rgba(black, 0.3);
border-radius: $basicCr;
padding: $interiorMarginSm;
@@ -102,7 +103,7 @@
}
&.t-frame-outer > .t-rep-frame {
&.contents {
$m: 0px;
$m: 2px;
top: $m;
right: $m;
bottom: $m;
@@ -113,33 +114,17 @@
display: none;
}
> .object-holder.abs {
overflow: hidden;
top: 0 !important;
}
}
}
}
&.t-frame-outer .s-input-inline {
// Prevent inline inputs from being edited when nested in a Layout
pointer-events: none !important;
}
/********************************************************** OBJECT TYPES */
.t-object-type-hyperlink,
.t-object-type-summary-widget {
.object-holder {
overflow: hidden;
}
.w-summary-widget,
.l-summary-widget,
.l-hyperlink.s-button {
// Some object types expand to the full size of the object-holder.
.t-object-type-hyperlink {
.s-hyperlink.s-button {
// When a hyperlink is a button in a frame, make it expand to fill out to the object-holder
@extend .abs;
}
.l-summary-widget,
.l-hyperlink.s-button {
.label {
@include ellipsize();
@include transform(translateY(-50%));
@@ -157,7 +142,7 @@
body.desktop .frame {
// Hide local controls initially and show it them on hover when they're in an element that's in a frame context
// Frame template is used because we need to target the lowest nested frame
.object-browse-bar .btn-bar {
.right {
opacity: 0;
pointer-events: none;
}
@@ -165,7 +150,7 @@ body.desktop .frame {
// Target the first descendant so that we only show the elements in the outermost container.
// Handles the case where we have layouts in layouts.
&:hover > .object-browse-bar {
.btn-bar {
.right {
opacity: 1;
pointer-events: inherit;
}

View File

@@ -240,9 +240,7 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
.top-bar .buttons-main .s-button,
.top-bar .s-menu-button,
.tool-bar .s-button,
.tool-bar .s-menu-button,
.tool-bar .select,
.tool-bar .input-labeled {
.tool-bar .s-menu-button {
$h: $btnToolbarH;
height: $h;
line-height: $h;

View File

@@ -20,52 +20,35 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
.s-hover-border {
border: 1px solid transparent;
&:hover {
border-color: rgba($colorSelectableSelectedPrimary, 0.5) !important;
}
border: 1px dotted transparent;
}
.s-status-editing {
// Limit to editing mode
$o: 0.5;
$oHover: 0.8;
$bc: $colorSelectableSelectedPrimary;
// Limit to editing mode until we have sub-object selection
.s-hover-border {
// Show a border by default so user can see object bounds and empty objects
border-color: rgba($bc, $o) !important;
border-style: dotted !important;
border: 1px dotted rgba($colorSelectableSelectedPrimary, 0.3) !important;
&:hover {
border-color: rgba($bc, $oHover) !important;
}
&.t-object-type-layout {
border-style: dashed !important;
border-color: rgba($colorSelectableSelectedPrimary, 0.7) !important;
}
}
.s-selected {
&.s-moveable {
&:not(.s-drilled-in) {
cursor: move;
.s-selected > .s-hover-border,
.s-selected.s-hover-border {
// Styles for a selected object. Also used by legacy Fixed Position/Panel objects.
border-color: $colorSelectableSelectedPrimary !important;
@include boxShdwLarge();
// Show edit-corners if you got 'em
.edit-corner {
display: block;
&:hover {
background-color: rgba($colorKey, 1);
}
}
}
}
.s-selected > .s-hover-border,
.s-selected.s-hover-border {
// Styles for a selected object. Also used by legacy Fixed Position/Panel objects.
border-color: $colorSelectableSelectedPrimary !important;
@include boxShdwLarge();
// Show edit-corners if you got 'em
.edit-corner {
display: block;
&:hover {
background-color: rgba($colorKey, 1);
}
.s-selected > .s-moveable,
.s-selected.s-moveable {
cursor: move;
}
}
}

View File

@@ -20,7 +20,6 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
.tool-bar {
font-size: 0.7rem;
&.btn-bar {
white-space: nowrap;
}
@@ -31,7 +30,9 @@
input[type="search"],
input[type="number"] {
box-sizing: border-box;
font-size: .8em;
height: $btnToolbarH;
margin-bottom: 1px;
position: relative;
&.sm {
width: $btnToolbarH;

View File

@@ -20,7 +20,7 @@
at runtime from the About dialog for additional information.
-->
<span ng-controller="DateTimeFieldController">
<input type="text" autocorrect="off" spellcheck="false"
<input type="text"
ng-model="textValue"
ng-blur="restoreTextValue(); ngBlur()"
ng-mouseup="ngMouseup()"

View File

@@ -20,7 +20,7 @@
at runtime from the About dialog for additional information.
-->
<!-- look at action-button for example -->
<span class="t-filter l-filter"
<span class="t-filter l-filter s-filter"
ng-controller="GetterSetterController">
<input type="search"
class="t-filter-input"

View File

@@ -40,7 +40,7 @@ define(
// Gets an array of the contextual parents/ancestors of the selected object
function getContextualPath() {
var currentObj = $scope.domainObject,
var currentObj = $scope.ngModel.selectedObject,
currentParent,
parents = [];
@@ -68,7 +68,7 @@ define(
// If this the the initial call of this recursive function
if (!current) {
current = $scope.domainObject;
current = $scope.ngModel.selectedObject;
$scope.primaryParents = [];
}
@@ -87,16 +87,16 @@ define(
// Gets the metadata for the selected object
function getMetadata() {
$scope.metadata = $scope.domainObject &&
$scope.domainObject.hasCapability('metadata') &&
$scope.domainObject.useCapability('metadata');
$scope.metadata = $scope.ngModel.selectedObject &&
$scope.ngModel.selectedObject.hasCapability('metadata') &&
$scope.ngModel.selectedObject.useCapability('metadata');
}
// Set scope variables when the selected object changes
$scope.$watch('domainObject', function () {
$scope.isLink = $scope.domainObject &&
$scope.domainObject.hasCapability('location') &&
$scope.domainObject.getCapability('location').isLink();
$scope.$watch('ngModel.selectedObject', function () {
$scope.isLink = $scope.ngModel.selectedObject &&
$scope.ngModel.selectedObject.hasCapability('location') &&
$scope.ngModel.selectedObject.getCapability('location').isLink();
if ($scope.isLink) {
getPrimaryPath();
@@ -108,11 +108,8 @@ define(
getMetadata();
});
var mutation = $scope.domainObject.getCapability('mutation');
var unlisten = mutation.listen(getMetadata);
$scope.$on('$destroy', unlisten);
}
return ObjectInspectorController;
}
);

View File

@@ -1,60 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT 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 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.
*****************************************************************************/
define(
[],
function () {
/**
* The mct-selectable directive allows selection functionality
* (click) to be attached to specific elements.
*
* @memberof platform/commonUI/general
* @constructor
*/
function MCTSelectable(openmct) {
// Link; install event handlers.
function link(scope, element, attrs) {
var removeSelectable = openmct.selection.selectable(
element[0],
scope.$eval(attrs.mctSelectable),
attrs.hasOwnProperty('mctInitSelect') && scope.$eval(attrs.mctInitSelect) !== false
);
scope.$on("$destroy", function () {
removeSelectable();
});
}
return {
// mct-selectable only makes sense as an attribute
restrict: "A",
// Link function, to install event handlers
link: link
};
}
return MCTSelectable;
}
);

View File

@@ -117,8 +117,6 @@ define(
// Apply styles to child elements
function updateChildren(children) {
position = userWidthPreference || position;
// Pick out correct elements to update, flowing from
// selected anchor edge.
var first = children.eq(anchor.reversed ? 2 : 0),
@@ -128,7 +126,7 @@ define(
splitterSize = getSize(splitter[0]);
first.css(anchor.edge, "0px");
first.css(anchor.dimension, position + 'px');
first.css(anchor.dimension, (userWidthPreference || position) + 'px');
// Get actual size (to obey min-width etc.)
firstSize = getSize(first[0]);
@@ -137,8 +135,8 @@ define(
splitter.css(anchor.opposite, "auto");
last.css(anchor.edge, firstSize + splitterSize + 'px');
last.css(anchor.opposite, '0px');
position = firstSize;
last.css(anchor.opposite, "0px");
position = firstSize + splitterSize;
}
// Update positioning of contained elements
@@ -175,19 +173,17 @@ define(
positionParsed.assign($scope, position);
}
}
return position;
}
function setUserWidthPreference(value) {
if (alias) {
userWidthPreference = value;
}
userWidthPreference = value - splitterSize;
}
function persistToLocalStorage(value) {
if (alias) {
$window.localStorage.setItem(alias, value);
userWidthPreference = value - splitterSize;
$window.localStorage.setItem(alias, userWidthPreference);
}
}
@@ -229,13 +225,13 @@ define(
anchor: function () {
return anchor;
},
position: function (newPosition) {
if (arguments.length === 0) {
position: function (value) {
if (arguments.length > 0) {
setUserWidthPreference(value);
return getSetPosition(value);
} else {
return getSetPosition();
}
setUserWidthPreference(newPosition);
return getSetPosition(newPosition);
},
startResizing: function () {
toggleClass('resizing');

View File

@@ -57,10 +57,7 @@ define(
// Update the position of this splitter
newPosition = initialPosition + pixelDelta;
if (initialPosition !== newPosition) {
mctSplitPane.position(newPosition);
}
mctSplitPane.position(newPosition);
},
// Grab the event when the user is done moving
// the splitter and pass it on

View File

@@ -39,8 +39,10 @@ define(
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
["$watch", "$on"]
["$watch"]
);
mockScope.ngModel = {};
mockScope.ngModel.selectedObject = 'mock selected object';
mockObjectService = jasmine.createSpyObj(
"objectService",
@@ -67,27 +69,22 @@ define(
"location capability",
["isLink"]
);
mockDomainObject.getCapability.andCallFake(function (param) {
if (param === 'location') {
return mockLocationCapability;
} else if (param === 'context') {
return mockContextCapability;
} else if (param === 'mutation') {
return {
listen: function () {
return true;
}
};
}
});
mockScope.domainObject = mockDomainObject;
controller = new ObjectInspectorController(mockScope, mockObjectService);
// Change the selected object to trigger the watch call
mockScope.ngModel.selectedObject = mockDomainObject;
});
it("watches for changes to the selected object", function () {
expect(mockScope.$watch).toHaveBeenCalledWith('domainObject', jasmine.any(Function));
expect(mockScope.$watch).toHaveBeenCalledWith('ngModel.selectedObject', jasmine.any(Function));
});
it("looks for contextual parent objects", function () {

View File

@@ -140,7 +140,7 @@ define(
it("exposes its splitter's initial position", function () {
expect(controller.position()).toEqual(
mockFirstPane[0].offsetWidth
mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
);
});
@@ -168,7 +168,7 @@ define(
controller.position(testValue);
expect(mockFirstPane.css).toHaveBeenCalledWith(
'width',
(testValue) + 'px'
(testValue - mockSplitter[0].offsetWidth) + 'px'
);
});
@@ -200,11 +200,11 @@ define(
mockFirstPane[0].offsetWidth += 100;
// Should not reflect the change yet
expect(controller.position()).not.toEqual(
mockFirstPane[0].offsetWidth
mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
);
mockInterval.mostRecentCall.args[0]();
expect(controller.position()).toEqual(
mockFirstPane[0].offsetWidth
mockFirstPane[0].offsetWidth + mockSplitter[0].offsetWidth
);
});
@@ -216,7 +216,7 @@ define(
it("saves user preference to localStorage when user is done resizing", function () {
controller.endResizing(100);
expect(Number(mockWindow.localStorage.getItem('mctSplitPane-rightSide'))).toEqual(100);
expect(Number(mockWindow.localStorage.getItem('mctSplitPane-rightSide'))).toEqual(100 - mockSplitter[0].offsetWidth);
});
});

View File

@@ -65,10 +65,6 @@ define(
options = Object.create(OPTIONS);
options.marginX = -bubbleSpaceLR;
// prevent bubble from appearing right under pointer,
// which causes hover callback to be called multiple times
options.offsetX = 1;
// On a phone, bubble takes up more screen real estate,
// so position it differently (toward the bottom)
if (this.agentService.isPhone()) {

View File

@@ -38,8 +38,7 @@ define([
"implementation": InspectorController,
"depends": [
"$scope",
"openmct",
"$document"
"policyService"
]
}
],

View File

@@ -21,73 +21,44 @@
*****************************************************************************/
define(
[],
function () {
['../../browse/src/InspectorRegion'],
function (InspectorRegion) {
/**
* The InspectorController listens for the selection changes and adds the selection
* object to the scope.
* The InspectorController adds region data for a domain object's type
* to the scope.
*
* @constructor
*/
function InspectorController($scope, openmct, $document) {
var self = this;
self.$scope = $scope;
function InspectorController($scope, policyService) {
var domainObject = $scope.domainObject,
typeCapability = domainObject.getCapability('type'),
statusListener;
/**
* Callback handler for the selection change event.
* Adds the selection object to the scope. If the selected item has an inspector view,
* it puts the key in the scope. If provider view exists, it shows the view.
* Filters region parts to only those allowed by region policies
* @param regions
* @returns {{}}
*/
function setSelection(selection) {
if (selection[0]) {
var view = openmct.inspectorViews.get(selection);
var container = $document[0].querySelectorAll('.inspector-provider-view')[0];
container.innerHTML = "";
if (view) {
self.providerView = true;
view.show(container);
} else {
self.providerView = false;
var selectedItem = selection[0].context.oldItem;
if (selectedItem) {
$scope.inspectorKey = selectedItem.getCapability("type").typeDef.inspector;
}
}
}
self.$scope.selection = selection;
function filterRegions(inspector) {
//Dupe so we're not modifying the type definition.
return inspector.regions && inspector.regions.filter(function (region) {
return policyService.allow('region', region, domainObject);
});
}
openmct.selection.on("change", setSelection);
setSelection(openmct.selection.get());
function setRegions() {
$scope.regions = filterRegions(typeCapability.getDefinition().inspector || new InspectorRegion());
}
statusListener = domainObject.getCapability("status").listen(setRegions);
$scope.$on("$destroy", function () {
openmct.selection.off("change", setSelection);
statusListener();
});
setRegions();
}
/**
* Gets the selected item.
*
* @returns a domain object
*/
InspectorController.prototype.selectedItem = function () {
return this.$scope.selection[0].context.oldItem;
};
/**
* Checks if a provider view exists.
*
* @returns 'true' if provider view exists, 'false' otherwise
*/
InspectorController.prototype.hasProviderView = function () {
return this.providerView;
};
return InspectorController;
}
);

View File

@@ -27,93 +27,82 @@ define(
describe("The inspector controller ", function () {
var mockScope,
mockDomainObject,
mockOpenMCT,
mockSelection,
mockInspectorViews,
mockTypeDef,
controller,
container,
$document = [],
selectable = [];
mockTypeCapability,
mockTypeDefinition,
mockPolicyService,
mockStatusCapability,
capabilities = {},
controller;
beforeEach(function () {
mockTypeDef = {
typeDef: {
inspector: "some-key"
}
mockTypeDefinition = {
inspector:
{
'regions': [
{'name': 'Part One'},
{'name': 'Part Two'}
]
}
};
mockTypeCapability = jasmine.createSpyObj('typeCapability', [
'getDefinition'
]);
mockTypeCapability.getDefinition.andReturn(mockTypeDefinition);
capabilities.type = mockTypeCapability;
mockStatusCapability = jasmine.createSpyObj('statusCapability', [
'listen'
]);
capabilities.status = mockStatusCapability;
mockDomainObject = jasmine.createSpyObj('domainObject', [
'getCapability'
]);
mockDomainObject.getCapability.andReturn(mockTypeDef);
mockDomainObject.getCapability.andCallFake(function (name) {
return capabilities[name];
});
mockPolicyService = jasmine.createSpyObj('policyService', [
'allow'
]);
mockScope = jasmine.createSpyObj('$scope',
['$on', 'selection']
['$on']
);
selectable[0] = {
context: {
oldItem: mockDomainObject
}
};
mockSelection = jasmine.createSpyObj("selection", [
'on',
'off',
'get'
]);
mockSelection.get.andReturn(selectable);
mockInspectorViews = jasmine.createSpyObj('inspectorViews', ['get']);
mockOpenMCT = {
selection: mockSelection,
inspectorViews: mockInspectorViews
};
container = jasmine.createSpy('container', ['innerHTML']);
$document[0] = jasmine.createSpyObj("$document", ['querySelectorAll']);
$document[0].querySelectorAll.andReturn([container]);
controller = new InspectorController(mockScope, mockOpenMCT, $document);
mockScope.domainObject = mockDomainObject;
});
it("listens for selection change event", function () {
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
'change',
jasmine.any(Function)
);
expect(controller.selectedItem()).toEqual(mockDomainObject);
var mockItem = jasmine.createSpyObj('domainObject', [
'getCapability'
]);
mockItem.getCapability.andReturn(mockTypeDef);
selectable[0].context.oldItem = mockItem;
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
expect(controller.selectedItem()).toEqual(mockItem);
it("filters out regions disallowed by region policy", function () {
mockPolicyService.allow.andReturn(false);
controller = new InspectorController(mockScope, mockPolicyService);
expect(mockScope.regions.length).toBe(0);
});
it("cleans up on scope destroy", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
'$destroy',
jasmine.any(Function)
);
mockScope.$on.calls[0].args[1]();
expect(mockOpenMCT.selection.off).toHaveBeenCalledWith(
'change',
jasmine.any(Function)
);
it("does not filter out regions allowed by region policy", function () {
mockPolicyService.allow.andReturn(true);
controller = new InspectorController(mockScope, mockPolicyService);
expect(mockScope.regions.length).toBe(2);
});
it("adds selection object to scope", function () {
expect(mockScope.selection).toEqual(selectable);
expect(controller.selectedItem()).toEqual(mockDomainObject);
it("Responds to status changes", function () {
mockPolicyService.allow.andReturn(true);
controller = new InspectorController(mockScope, mockPolicyService);
expect(mockScope.regions.length).toBe(2);
expect(mockStatusCapability.listen).toHaveBeenCalled();
mockPolicyService.allow.andReturn(false);
mockStatusCapability.listen.mostRecentCall.args[0]();
expect(mockScope.regions.length).toBe(0);
});
it("Unregisters status listener", function () {
var mockListener = jasmine.createSpy('listener');
mockStatusCapability.listen.andReturn(mockListener);
controller = new InspectorController(mockScope, mockPolicyService);
expect(mockScope.$on).toHaveBeenCalledWith("$destroy", jasmine.any(Function));
mockScope.$on.mostRecentCall.args[1]();
expect(mockListener).toHaveBeenCalled();
});
});
}

View File

@@ -53,15 +53,9 @@ $timeControllerToiLineColor: #00c2ff;
$timeControllerToiLineColorHov: #fff;
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
// Foundation Colors
// General Colors
$colorAlt1: #ffc700;
$colorAlert: #ff3c00;
$colorWarningHi: #cc0000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
$colorIconLink: #49dedb;
$colorPausedBg: #c56f01;
$colorPausedFg: #fff;
@@ -90,8 +84,8 @@ $colorCreateMenuText: $colorMenuFg;
// Form colors
$colorCheck: $colorKey;
$colorFormRequired: $colorAlt1;
$colorFormValid: $colorOk;
$colorFormError: $colorWarningHi;
$colorFormValid: #33cc33;
$colorFormError: #990000;
$colorFormInvalid: #ff3300;
$colorFormFieldErrorBg: $colorFormError;
$colorFormFieldErrorFg: rgba(#fff, 0.6);
@@ -115,8 +109,8 @@ $colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
// Status colors, mainly used for messaging and item ancillary symbols
$colorStatusFg: #ccc;
$colorStatusDefault: #ccc;
$colorStatusInfo: $colorInfo;
$colorStatusAlert: $colorAlert;
$colorStatusInfo: #62ba72;
$colorStatusAlert: #ffa66d;
$colorStatusError: #d4585c;
$colorStatusAvailable: $colorKey;
$colorStatusBtnBg: $colorBtnBg;
@@ -131,14 +125,14 @@ $animPausedPulseDur: 500ms;
$colorSelectBg: $colorBtnBg;
$colorSelectFg: $colorBtnFg;
// Limits, status and staleness colors
// Limits and staleness colors
$colorTelemFresh: pullForward($colorBodyFg, 20%);
$colorTelemStale: pushBack($colorBodyFg, 20%);
$styleTelemStale: italic;
$colorLimitYellowBg: rgba($colorWarningLo, 0.3);
$colorLimitYellowIc: $colorWarningLo;
$colorLimitRedBg: rgba($colorWarningHi, 0.3);
$colorLimitRedIc: $colorWarningHi;
$colorLimitYellowBg: rgba(#ffaa00, 0.3);
$colorLimitYellowIc: #ffaa00;
$colorLimitRedBg: rgba(red, 0.3);
$colorLimitRedIc: red;
// Bubble colors
$colorInfoBubbleBg: #ddd;
@@ -201,15 +195,13 @@ $shdwItemTreeIcon: 0.6;
$colorThumbHoverBg: $colorItemTreeHoverBg;
// Scrollbar
$scrollbarTrackSize: 7px;
$scrollbarTrackShdw: rgba(#000, 0.5) 0 1px 5px;
$scrollbarTrackColorBg: transparent; //rgba(#000, 0.4);
$scrollbarTrackSize: 10px;
$scrollbarTrackShdw: rgba(#000, 0.7) 0 1px 5px;
$scrollbarTrackColorBg: rgba(#000, 0.4);
$scrollbarThumbColor: pullForward($colorBodyBg, 10%);
$scrollbarThumbColorHov: pullForward($scrollbarThumbColor, 2%);
$scrollbarThumbColorOverlay: pullForward($colorOvrBg, 10%);
$scrollbarThumbColorOverlayHov: pullForward($scrollbarThumbColorOverlay, 2%);
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 20%);
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
// Splitter
// All splitterD* values MUST both be either odd or even numbers

View File

@@ -13,10 +13,3 @@
// For dark interfaces, darker things move back - opposite for light interfaces
@return darken($c, $p);
}
@function bgFg($c) {
// Given a single color, return valid background and foreground versions of that color
$bg: darken($c, 20%);
$fg: lighten($c, 20%);
@return $bg, $fg;
}

View File

@@ -53,15 +53,9 @@ $timeControllerToiLineColor: $colorBodyFg;
$timeControllerToiLineColorHov: #0052b5;
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
// Foundation Colors
// General Colors
$colorAlt1: #776ba2;
$colorAlert: #ff3c00;
$colorWarningHi: #990000;
$colorWarningLo: #ff9900;
$colorDiagnostic: #a4b442;
$colorCommand: #3693bd;
$colorInfo: #2294a2;
$colorOk: #33cc33;
$colorIconLink: #49dedb;
$colorPausedBg: #ff9900;
$colorPausedFg: #fff;
@@ -90,8 +84,8 @@ $colorCreateMenuText: $colorBodyFg;
// Form colors
$colorCheck: $colorKey;
$colorFormRequired: $colorKey;
$colorFormValid: $colorOk;
$colorFormError: $colorWarningHi;
$colorFormValid: #33cc33;
$colorFormError: #990000;
$colorFormInvalid: #ff2200;
$colorFormFieldErrorBg: $colorFormError;
$colorFormFieldErrorFg: rgba(#fff, 0.6);
@@ -113,7 +107,7 @@ $colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
// Status colors, mainly used for messaging and item ancillary symbols
$colorStatusFg: #999;
$colorStatusFg: #fff;
$colorStatusDefault: #ccc;
$colorStatusInfo: #60ba7b;
$colorStatusAlert: #ffb66c;
@@ -201,15 +195,13 @@ $shdwItemTreeIcon: none;
$colorThumbHoverBg: $colorItemTreeHoverBg;
// Scrollbar
$scrollbarTrackSize: 7px;
$scrollbarTrackSize: 10px;
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
$scrollbarTrackColorBg: rgba(#000, 0.2);
$scrollbarThumbColor: darken($colorBodyBg, 50%);
$scrollbarThumbColorHov: $colorKey;
$scrollbarThumbColorOverlay: darken($colorOvrBg, 50%);
$scrollbarThumbColorOverlayHov: $scrollbarThumbColorHov;
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 10%);
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
// Splitter
// All splitterD* values MUST both be either odd or even numbers

View File

@@ -12,11 +12,3 @@
// For dark interfaces, darker things move back - opposite for light interfaces
@return lighten($c, $p);
}
@function bgFg($c) {
// Given a single color, return valid background and foreground versions of that color
$bg: darken($c, 20%);
$fg: lighten($c, 20%);
@return $bg, $fg;
}

View File

@@ -94,6 +94,31 @@ define([
}
},
"extensions": {
"versions": [
{
"name": "Version",
"value": "@@version",
"priority": 999
},
{
"name": "Built",
"value": "@@timestamp",
"description": "The date on which this version of the client was built.",
"priority": 990
},
{
"name": "Revision",
"value": "@@revision",
"description": "A unique revision identifier for the client sources.",
"priority": 995
},
{
"name": "Branch",
"value": "@@branch",
"description": "The name of the branch that was used during the build.",
"priority": 994
}
],
"components": [
{
"provides": "objectService",

View File

@@ -65,20 +65,6 @@ define(['csv'], function (CSV) {
this.saveAs(blob, filename);
};
/**
* Export an object as a JSON file. Triggers a download using the function
* provided when the ExportService was instantiated.
*
* @param {Object} obj an object to be exported as JSON
* @param {ExportOptions} [options] additional parameters for the file
* export
*/
ExportService.prototype.exportJSON = function (obj, options) {
var filename = (options && options.filename) || "test-export.json";
var jsonText = JSON.stringify(obj);
var blob = new Blob([jsonText], {type: "application/json"});
this.saveAs(blob, filename);
};
/**
* Additional parameters for file export.
* @typedef ExportOptions

View File

@@ -0,0 +1,54 @@
define([
'text!./res/templates/autoflow-tabular.html',
'./src/AutoflowTabularController',
'./src/MCTAutoflowTable'
], function (
autoflowTabularTemplate,
AutoflowTabularController,
MCTAutoflowTable
) {
return function (options) {
return function (openmct) {
openmct.legacyRegistry.register("platform/features/autoflow", {
"name": "WARP Telemetry Adapter",
"description": "Retrieves telemetry from the WARP Server and provides related types and views.",
"resources": "res",
"extensions": {
"views": [
{
"key": "autoflow",
"name": "Autoflow Tabular",
"cssClass": "icon-packet",
"description": "A tabular view of packet contents.",
"template": autoflowTabularTemplate,
"type": options && options.type,
"needs": [
"telemetry"
],
"delegation": true
}
],
"controllers": [
{
"key": "AutoflowTabularController",
"implementation": AutoflowTabularController,
"depends": [
"$scope",
"$timeout",
"telemetrySubscriber"
]
}
],
"directives": [
{
"key": "mctAutoflowTable",
"implementation": MCTAutoflowTable
}
]
}
});
openmct.legacyRegistry.enable("platform/features/autoflow");
};
};
});

View File

@@ -0,0 +1,26 @@
<div class="items-holder abs contents autoflow obj-value-format"
ng-controller="AutoflowTabularController as autoflow">
<div class="abs l-flex-row holder t-autoflow-header l-autoflow-header">
<mct-include key="'input-filter'"
ng-model="autoflow.filter"
class="flex-elem">
</mct-include>
<div class="flex-elem grows t-last-update" title="Last Update">{{autoflow.updated()}}</div>
<a title="Change column width"
class="s-button flex-elem icon-arrows-right-left change-column-width"
ng-click="autoflow.increaseColumnWidth()"></a>
</div>
<div class="abs t-autoflow-items l-autoflow-items"
mct-resize="autoflow.setBounds(bounds)"
mct-resize-interval="50">
<mct-autoflow-table values="autoflow.rangeValues()"
objects="autoflow.getTelemetryObjects()"
rows="autoflow.getRows()"
classes="autoflow.classes()"
updated="autoflow.updated()"
column-width="autoflow.columnWidth()"
counter="autoflow.counter()"
>
</mct-autoflow-table>
</div>
</div>

View File

@@ -0,0 +1,169 @@
/*global angular*/
define(
[],
function () {
/**
* The link step for the `mct-autoflow-table` directive;
* watches scope and updates the DOM appropriately.
* See documentation in `MCTAutoflowTable.js` for the rationale
* for including this directive, as well as for an explanation
* of which values are placed in scope.
*
* @constructor
* @param {Scope} scope the scope for this usage of the directive
* @param element the jqLite-wrapped element which used this directive
*/
function AutoflowTableLinker(scope, element) {
var objects, // Domain objects at last structure refresh
rows, // Number of rows from last structure refresh
priorClasses = {},
valueSpans = {}; // Span elements to put data values in
// Create a new name-value pair in the specified column
function createListItem(domainObject, ul) {
// Create a new li, and spans to go in it.
var li = angular.element('<li>'),
titleSpan = angular.element('<span>'),
valueSpan = angular.element('<span>');
// Place spans in the li, and li into the column.
// valueSpan must precede titleSpan in the DOM due to new CSS float approach
li.append(valueSpan).append(titleSpan);
ul.append(li);
// Style appropriately
li.addClass('l-autoflow-row');
titleSpan.addClass('l-autoflow-item l');
valueSpan.addClass('l-autoflow-item r l-obj-val-format');
// Set text/tooltip for the name-value row
titleSpan.text(domainObject.getModel().name);
titleSpan.attr("title", domainObject.getModel().name);
// Keep a reference to the span which will hold the
// data value, to populate in the next refreshValues call
valueSpans[domainObject.getId()] = valueSpan;
return li;
}
// Create a new column of name-value pairs in this table.
function createColumn(el) {
// Create a ul
var ul = angular.element('<ul>');
// Add it into the mct-autoflow-table
el.append(ul);
// Style appropriately
ul.addClass('l-autoflow-col');
// Get the current col width and apply at time of column creation
// Important to do this here, as new columns could be created after
// the user has changed the width.
ul.css('width', scope.columnWidth + 'px');
// Return it, so some li elements can be added
return ul;
}
// Change the width of the columns when user clicks the resize button.
function resizeColumn() {
element.find('ul').css('width', scope.columnWidth + 'px');
}
// Rebuild the DOM associated with this table.
function rebuild(domainObjects, rowCount) {
var activeColumn;
// Empty out our cached span elements
valueSpans = {};
// Start with an empty DOM beneath this directive
element.html("");
// Add DOM elements for each domain object being displayed
// in this table.
domainObjects.forEach(function (object, index) {
// Start a new column if we'd run out of room
if (index % rowCount === 0) {
activeColumn = createColumn(element);
}
// Add the DOM elements for that object to whichever
// column (a `ul` element) is current.
createListItem(object, activeColumn);
});
}
// Update spans with values, as made available via the
// `values` attribute of this directive.
function refreshValues() {
// Get the available values
var values = scope.values || {},
classes = scope.classes || {};
// Populate all spans with those values (or clear
// those spans if no value is available)
(objects || []).forEach(function (object) {
var id = object.getId(),
span = valueSpans[id],
value;
if (span) {
// Look up the value...
value = values[id];
// ...and convert to empty string if it's undefined
value = value === undefined ? "" : value;
span.attr("data-value", value);
// Update the span
span.text(value);
span.attr("title", value);
span.removeClass(priorClasses[id]);
span.addClass(classes[id]);
priorClasses[id] = classes[id];
}
// Also need stale/alert/ok class
// on span
});
}
// Refresh the DOM for this table, if necessary
function refreshStructure() {
// Only rebuild if number of rows or set of objects
// has changed; otherwise, our structure is still valid.
if (scope.objects !== objects ||
scope.rows !== rows) {
// Track those values to support future refresh checks
objects = scope.objects;
rows = scope.rows;
// Rebuild the DOM
rebuild(objects || [], rows || 1);
// Refresh all data values shown
refreshValues();
}
}
// Changing the domain objects in use or the number
// of rows should trigger a structure change (DOM rebuild)
scope.$watch("objects", refreshStructure);
scope.$watch("rows", refreshStructure);
// When the current column width has been changed, resize the column
scope.$watch('columnWidth', resizeColumn);
// When the last-updated time ticks,
scope.$watch("updated", refreshValues);
// Update displayed values when the counter changes.
scope.$watch("counter", refreshValues);
}
return AutoflowTableLinker;
}
);

View File

@@ -0,0 +1,324 @@
define(
['moment'],
function (moment) {
var ROW_HEIGHT = 16,
SLIDER_HEIGHT = 10,
INITIAL_COLUMN_WIDTH = 225,
MAX_COLUMN_WIDTH = 525,
COLUMN_WIDTH_STEP = 25,
DEBOUNCE_INTERVAL = 100,
DATE_FORMAT = "YYYY-DDD HH:mm:ss.SSS\\Z",
NOT_UPDATED = "No updates",
EMPTY_ARRAY = [];
/**
* Responsible for supporting the autoflow tabular view.
* Implements the all-over logic which drives that view,
* mediating between template-provided areas, the included
* `mct-autoflow-table` directive, and the underlying
* domain object model.
* @constructor
*/
function AutflowTabularController(
$scope,
$timeout,
telemetrySubscriber
) {
var filterValue = "",
filterValueLowercase = "",
subscription,
filteredObjects = [],
lastUpdated = {},
updateText = NOT_UPDATED,
rangeValues = {},
classes = {},
limits = {},
updatePending = false,
lastBounce = Number.NEGATIVE_INFINITY,
columnWidth = INITIAL_COLUMN_WIDTH,
rows = 1,
counter = 0;
// Trigger an update of the displayed table by incrementing
// the counter that it watches.
function triggerDisplayUpdate() {
counter += 1;
}
// Check whether or not an object's name matches the
// user-entered filter value.
function filterObject(domainObject) {
return (domainObject.getModel().name || "")
.toLowerCase()
.indexOf(filterValueLowercase) !== -1;
}
// Comparator for sorting points back into packet order
function compareObject(objectA, objectB) {
var indexA = objectA.getModel().index || 0,
indexB = objectB.getModel().index || 0;
return indexA - indexB;
}
// Update the list of currently-displayed objects; these
// will be the subset of currently subscribed-to objects
// which match a user-entered filter.
function doUpdateFilteredObjects() {
// Generate the list
filteredObjects = (
subscription ?
subscription.getTelemetryObjects() :
[]
).filter(filterObject).sort(compareObject);
// Clear the pending flag
updatePending = false;
// Track when this occurred, so that we can wait
// a whole before updating again.
lastBounce = Date.now();
triggerDisplayUpdate();
}
// Request an update to the list of current objects; this may
// run on a timeout to avoid excessive calls, e.g. while the user
// is typing a filter.
function updateFilteredObjects() {
// Don't do anything if an update is already scheduled
if (!updatePending) {
if (Date.now() > lastBounce + DEBOUNCE_INTERVAL) {
// Update immediately if it's been long enough
doUpdateFilteredObjects();
} else {
// Otherwise, update later, and track that we have
// an update pending so that subsequent calls can
// be ignored.
updatePending = true;
$timeout(doUpdateFilteredObjects, DEBOUNCE_INTERVAL);
}
}
}
// Track the latest data values for this domain object
function recordData(telemetryObject) {
// Get latest domain/range values for this object.
var id = telemetryObject.getId(),
domainValue = subscription.getDomainValue(telemetryObject),
rangeValue = subscription.getRangeValue(telemetryObject);
// Track the most recent timestamp change observed...
if (domainValue !== undefined && domainValue !== lastUpdated[id]) {
lastUpdated[id] = domainValue;
// ... and update the displayable text for that timestamp
updateText = isNaN(domainValue) ? "" :
moment.utc(domainValue).format(DATE_FORMAT);
}
// Store data values into the rangeValues structure, which
// will be used to populate the table itself.
// Note that we want full precision here.
rangeValues[id] = rangeValue;
// Update limit states as well
classes[id] = limits[id] && (limits[id].evaluate({
// This relies on external knowledge that the
// range value of a telemetry point is encoded
// in its datum as "value."
value: rangeValue
}) || {}).cssClass;
}
// Look at telemetry objects from the subscription; this is watched
// to detect changes from the subscription.
function subscribedTelemetry() {
return subscription ?
subscription.getTelemetryObjects() : EMPTY_ARRAY;
}
// Update the data values which will be used to populate the table
function updateValues() {
subscribedTelemetry().forEach(recordData);
triggerDisplayUpdate();
}
// Getter-setter function for user-entered filter text.
function filter(value) {
// If value was specified, we're a setter
if (value !== undefined) {
// Store the new value
filterValue = value;
filterValueLowercase = value.toLowerCase();
// Change which objects appear in the table
updateFilteredObjects();
}
// Always act as a getter
return filterValue;
}
// Update the bounds (width and height) of this view;
// called from the mct-resize directive. Recalculates how
// many rows should appear in the contained table.
function setBounds(bounds) {
var availableSpace = bounds.height - SLIDER_HEIGHT;
rows = Math.max(1, Math.floor(availableSpace / ROW_HEIGHT));
}
// Increment the current column width, up to the defined maximum.
// When the max is hit, roll back to the default.
function increaseColumnWidth() {
columnWidth += COLUMN_WIDTH_STEP;
// Cycle down to the initial width instead of exceeding max
columnWidth = columnWidth > MAX_COLUMN_WIDTH ?
INITIAL_COLUMN_WIDTH : columnWidth;
}
// Get displayable text for last-updated value
function updated() {
return updateText;
}
// Unsubscribe, if a subscription is active.
function releaseSubscription() {
if (subscription) {
subscription.unsubscribe();
subscription = undefined;
}
}
// Update set of telemetry objects managed by this view
function updateTelemetryObjects(telemetryObjects) {
updateFilteredObjects();
limits = {};
telemetryObjects.forEach(function (telemetryObject) {
var id = telemetryObject.getId();
limits[id] = telemetryObject.getCapability('limit');
});
}
// Create a subscription for the represented domain object.
// This will resolve capability delegation as necessary.
function makeSubscription(domainObject) {
// Unsubscribe, if there is an existing subscription
releaseSubscription();
// Clear updated timestamp
lastUpdated = {};
updateText = NOT_UPDATED;
// Create a new subscription; telemetrySubscriber gets
// to do the meaningful work here.
subscription = domainObject && telemetrySubscriber.subscribe(
domainObject,
updateValues
);
// Our set of in-view telemetry objects may have changed,
// so update the set that is being passed down to the table.
updateFilteredObjects();
}
// Watch for changes to the set of objects which have telemetry
$scope.$watch(subscribedTelemetry, updateTelemetryObjects);
// Watch for the represented domainObject (this field will
// be populated by mct-representation)
$scope.$watch("domainObject", makeSubscription);
// Make sure we unsubscribe when this view is destroyed.
$scope.$on("$destroy", releaseSubscription);
return {
/**
* Get the number of rows which should be shown in this table.
* @return {number} the number of rows to show
*/
getRows: function () {
return rows;
},
/**
* Get the objects which should currently be displayed in
* this table. This will be watched, so the return value
* should be stable when this list is unchanging. Only
* objects which match the user-entered filter value should
* be returned here.
* @return {DomainObject[]} the domain objects to include in
* this table.
*/
getTelemetryObjects: function () {
return filteredObjects;
},
/**
* Set the bounds (width/height) of this autoflow tabular view.
* The template must ensure that these bounds are tracked on
* the table area only.
* @param bounds the bounds; and object with `width` and
* `height` properties, both as numbers, in pixels.
*/
setBounds: setBounds,
/**
* Increments the width of the autoflow column.
* Setting does not yet persist.
*/
increaseColumnWidth: increaseColumnWidth,
/**
* Get-or-set the user-supplied filter value.
* @param {string} [value] the new filter value; omit to use
* as a getter
* @returns {string} the user-supplied filter value
*/
filter: filter,
/**
* Get all range values for use in this table. These will be
* returned as an object of key-value pairs, where keys are
* domain object IDs, and values are the most recently observed
* data values associated with those objects, formatted for
* display.
* @returns {object.<string,string>} most recent values
*/
rangeValues: function () {
return rangeValues;
},
/**
* Get CSS classes to apply to specific rows, representing limit
* states and/or stale states. These are returned as key-value
* pairs where keys are domain object IDs, and values are CSS
* classes to display for domain objects with those IDs.
* @returns {object.<string,string>} CSS classes
*/
classes: function () {
return classes;
},
/**
* Get the "last updated" text for this view; this will be
* the most recent timestamp observed for any telemetry-
* providing object, formatted for display.
* @returns {string} the time of the most recent update
*/
updated: updated,
/**
* Get the current column width, in pixels.
* @returns {number} column width
*/
columnWidth: function () {
return columnWidth;
},
/**
* Keep a counter and increment this whenever the display
* should be updated; this will be watched by the
* `mct-autoflow-table`.
* @returns {number} a counter value
*/
counter: function () {
return counter;
}
};
}
return AutflowTabularController;
}
);

View File

@@ -0,0 +1,60 @@
define(
["./AutoflowTableLinker"],
function (AutoflowTableLinker) {
/**
* The `mct-autoflow-table` directive specifically supports
* autoflow tabular views; it is not intended for use outside
* of that view.
*
* This directive is responsible for creating the structure
* of the table in this view, and for updating its values.
* While this is achievable using a regular Angular template,
* this is undesirable from the perspective of performance
* due to the number of watches that can be involved for large
* tables. Instead, this directive will maintain a small number
* of watches, rebuilding table structure only when necessary,
* and updating displayed values in the more common case of
* new data arriving.
*
* @constructor
*/
function MCTAutoflowTable() {
return {
// Only applicable at the element level
restrict: "E",
// The link function; handles DOM update/manipulation
link: AutoflowTableLinker,
// Parameters to pass from attributes into scope
scope: {
// Set of domain objects to show in the table
objects: "=",
// Values for those objects, by ID
values: "=",
// CSS classes to show for objects, by ID
classes: "=",
// Number of rows to show before autoflowing
rows: "=",
// Time of last update; watched to refresh values
updated: "=",
// Current width of the autoflow column
columnWidth: "=",
// A counter used to trigger display updates
counter: "="
}
};
}
return MCTAutoflowTable;
}
);

View File

@@ -0,0 +1,178 @@
define(
["../src/AutoflowTableLinker"],
function (AutoflowTableLinker) {
describe("The mct-autoflow-table linker", function () {
var cachedAngular,
mockAngular,
mockScope,
mockElement,
mockElements,
linker;
// Utility function to generate more mock elements
function createMockElement(html) {
var mockEl = jasmine.createSpyObj(
"element-" + html,
[
"append",
"addClass",
"removeClass",
"text",
"attr",
"html",
"css",
"find"
]
);
mockEl.testHtml = html;
mockEl.append.andReturn(mockEl);
mockElements.push(mockEl);
return mockEl;
}
function createMockDomainObject(id) {
var mockDomainObject = jasmine.createSpyObj(
"domainObject-" + id,
["getId", "getModel"]
);
mockDomainObject.getId.andReturn(id);
mockDomainObject.getModel.andReturn({name: id.toUpperCase()});
return mockDomainObject;
}
function fireWatch(watchExpression, value) {
mockScope.$watch.calls.forEach(function (call) {
if (call.args[0] === watchExpression) {
call.args[1](value);
}
});
}
// AutoflowTableLinker accesses Angular in the global
// scope, since it is not injectable; we simulate that
// here by adding/removing it to/from the window object.
beforeEach(function () {
mockElements = [];
mockAngular = jasmine.createSpyObj("angular", ["element"]);
mockScope = jasmine.createSpyObj("scope", ["$watch"]);
mockElement = createMockElement('<div>');
mockAngular.element.andCallFake(createMockElement);
if (window.angular !== undefined) {
cachedAngular = window.angular;
}
window.angular = mockAngular;
linker = new AutoflowTableLinker(mockScope, mockElement);
});
afterEach(function () {
if (cachedAngular !== undefined) {
window.angular = cachedAngular;
} else {
delete window.angular;
}
});
it("watches for changes in inputs", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
"objects",
jasmine.any(Function)
);
expect(mockScope.$watch).toHaveBeenCalledWith(
"rows",
jasmine.any(Function)
);
expect(mockScope.$watch).toHaveBeenCalledWith(
"counter",
jasmine.any(Function)
);
});
it("changes structure when domain objects change", function () {
// Set up scope
mockScope.rows = 4;
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
.map(createMockDomainObject);
// Fire an update to the set of objects
fireWatch("objects");
// Should have rebuilt with two columns of
// four and two rows each; first, by clearing...
expect(mockElement.html).toHaveBeenCalledWith("");
// Should have appended two columns...
expect(mockElement.append.calls.length).toEqual(2);
// ...which should have received two and four rows each
expect(mockElement.append.calls[0].args[0].append.calls.length)
.toEqual(4);
expect(mockElement.append.calls[1].args[0].append.calls.length)
.toEqual(2);
});
it("updates values", function () {
var mockSpans;
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
.map(createMockDomainObject);
mockScope.values = { a: 0 };
// Fire an update to the set of values
fireWatch("objects");
fireWatch("updated");
// Get all created spans
mockSpans = mockElements.filter(function (mockElem) {
return mockElem.testHtml === '<span>';
});
// First span should be a, should have gotten this value.
// This test detects, in particular, WTD-749
expect(mockSpans[0].text).toHaveBeenCalledWith('A');
expect(mockSpans[1].text).toHaveBeenCalledWith(0);
});
it("listens for changes in column width", function () {
var mockUL = createMockElement("<ul>");
mockElement.find.andReturn(mockUL);
mockScope.columnWidth = 200;
fireWatch("columnWidth", mockScope.columnWidth);
expect(mockUL.css).toHaveBeenCalledWith("width", "200px");
});
it("updates CSS classes", function () {
var mockSpans;
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
.map(createMockDomainObject);
mockScope.values = { a: "a value to find" };
mockScope.classes = { a: 'class-a' };
// Fire an update to the set of values
fireWatch("objects");
fireWatch("updated");
// Figure out which span holds the relevant value...
mockSpans = mockElements.filter(function (mockElem) {
return mockElem.testHtml === '<span>';
}).filter(function (mockSpan) {
var attrCalls = mockSpan.attr.calls;
return attrCalls.some(function (call) {
return call.args[0] === 'title' &&
call.args[1] === mockScope.values.a;
});
});
// ...and make sure it also has had its class applied
expect(mockSpans[0].addClass)
.toHaveBeenCalledWith(mockScope.classes.a);
});
});
}
);

Some files were not shown because too many files have changed in this diff Show More