Compare commits

..

170 Commits

Author SHA1 Message Date
9553e0c64f Tutorial packages 2017-02-27 19:28:21 -08:00
da40f4c96e [Plot] Add current conductor bounds to telemetry requests via the old API. Replaces telemetry decorator. Fixes #1458 2017-02-27 19:26:51 -08:00
6fa5a31217 Merge pull request #1433 from nasa/open1432
[Build] Installed sound suppression system for Bourbon deprecation messages.
2017-02-27 11:12:27 -08:00
5bc7a701dc Merge pull request #1455 from nasa/api-conductor-config
[Conductor] Allow configuration of conductor defaults
2017-02-24 14:58:50 -08:00
5cd0516048 Enable TC by default and hide
Set up TC so that it is always enabled and defaults to realtime mode.

This allows us to have warp-like functionality without showing
the TC interface, and simplifies a lot of tutorials.  We can still
reconfigure the TC by re-installing the plugin with different settings
2017-02-24 14:56:18 -08:00
48a603ece8 Merge branch 'api-legacy-telemetry-provider-v2' 2017-02-24 14:47:10 -08:00
abfa56464a Merge branch 'plugins-functions' 2017-02-24 14:34:54 -08:00
c1d6e21c3c Added tests. Fixes #1364 2017-02-23 13:50:14 -08:00
3bd556a406 Fixed failing tests 2017-02-23 10:21:33 -08:00
347fb6d882 Fixed style errors 2017-02-23 10:19:10 -08:00
b3cf7a5d93 Added support for new style telemetry providers from old screens. Converted SWG to new style data adapter 2017-02-23 09:58:46 -08:00
c7cffdeb3b Merge pull request #1453 from nasa/restore-search-navigation
[Search] Allow navigation from results
2017-02-22 13:21:03 -08:00
d45ae7908d [Search] Allow navigation from results
Fix search item so that navigation occurs after clicking on
a search result, while still properly preventing navigation
when required.

Related to #1366
2017-02-22 13:08:54 -08:00
b10fb4533e All builtin plugins now standardized as functions 2017-02-22 12:51:49 -08:00
c74fdb816f Merge pull request #1450 from nasa/fix-table-tests
Add hasCapability to mock
2017-02-21 18:14:18 -08:00
40985a56c8 Add hasCapability to mock 2017-02-21 18:01:43 -08:00
5c01f0be24 Merge branch 'open1077' into 1435-integration 2017-02-21 17:22:36 -08:00
f7ff5af60b Merge pull request #1448 from nasa/update-composition-policy
Update composition policy
2017-02-21 17:18:59 -08:00
2088fc52f3 Merge pull request #1446 from nasa/fix-orphan-navigation
Orphan check uses capability not model
2017-02-21 17:08:40 -08:00
db33ab143e Merge pull request #1445 from nasa/api-updates
Api updates
2017-02-21 17:04:45 -08:00
8c77d4006a Pass options to support checks 2017-02-21 17:03:16 -08:00
2fa567b98b [Table] Track by index, save the elements 2017-02-21 16:49:39 -08:00
e61f04663a Merge pull request #1444 from nasa/consistent-css-class
cssclass is now cssClass
2017-02-21 16:36:30 -08:00
4b905fa7d2 Merge pull request #1443 from nasa/remove-old-bundle-loading
Stop loading bundles.json
2017-02-21 16:32:26 -08:00
5e6e7f018a Merge pull request #1442 from nasa/dev-skip-optimize
[Build] Skip optimize in dev environment
2017-02-21 16:26:41 -08:00
53f56b430a Merge pull request #1449 from nasa/identifier-not-key
[API] Use proper key format
2017-02-21 16:24:17 -08:00
50c934820c Merge pull request #1424 from nasa/open1382
[Tables] Do not persist column configuration for non-editable objects
2017-02-21 15:18:56 -08:00
2a10a2cae2 Update specs to match composition policies 2017-02-21 15:14:35 -08:00
65325b90fd Composition policy takes child instance
The composition policy now takes a child instance instead
of the child type, as in all cases we have access to the child
object.

This allows new-style objects to be contained by old-style objects.

Updated all composition policies to use standardized argument names
instead of `context` and `candidate`; this makes it easier to
understand.

Updated AddActionProvider to hardcode the object types supported.
2017-02-21 12:32:49 -08:00
cfecc36ae6 Orphan check uses capability not model
Switch orphan checking to use capability instead of model.

This ensures that new-style composition providers work as intended.
2017-02-21 12:10:17 -08:00
d9f8622459 [Telemetry] Update TelemetryProvider API
Based on feedback from tutorial sprint, update provider API,
formatter API, and legacy adapter code.

Providers can now implement separate checks for providing realtime
and historical data, and providers are not registered with a specific
strategy.  Strategy is instead intended to be an attribute in the
request options.

Removed unused code in the telemetry API and simplify limitEvaluators.
2017-02-21 11:51:32 -08:00
8e13819e1e [API] composition providers receive new-style objects
Ensure that composition providers get new-style objects (with id
included) so that they can properly check for applicability.
2017-02-21 11:21:08 -08:00
aaedf5d576 cssclass is now cssClass
Make property name consistent with standard camelCase naming.
2017-02-21 11:14:46 -08:00
af9ffaf02d Stop loading bundles.json
Stop application from requesting bundles.json at first load.  This was
confusing to some external developers who would see an error in the
log and not know the cause.
2017-02-21 11:11:16 -08:00
970acbd56e [Build] Skip optimize in dev environment
Skip optimize in dev environment to speed up project rebuilds.  Very helpful
when integration testing openmct.js build artifact.
2017-02-21 11:05:20 -08:00
46c7399867 Merge pull request #1410 from joshbaldwin/master
adding MCT name to README
2017-02-21 09:09:51 -08:00
9a6745635d Merge pull request #1431 from dhrubomoy/master
[Documentation] Fixed filename
2017-02-15 10:18:46 -08:00
fa962b42bc [API] Use proper key format 2017-02-13 13:21:55 -08:00
34dc457aff [Tables] Restored telemetry datum field 'name'. Fixed bug with default sort not working 2017-02-10 15:39:39 -08:00
a3311e4c57 [Tables] Tests and style fixes 2017-02-10 14:22:30 -08:00
ef8efbd53d [Tables] Default UTC time system if available and none others defined 2017-02-10 14:22:28 -08:00
6cd99efbb9 [Tables] Added telemetry buffer so that subscription data is not discarded if it's beyond the end bounds 2017-02-10 14:22:28 -08:00
ae2b73a4f5 [Tables] Increase default table size 2017-02-10 14:22:28 -08:00
0c3ff82cfe [Table] Added ticking to combined historical/real-time table
Don't add duplicate telemetry data
2017-02-10 14:22:20 -08:00
50f303bbdc [Tables] limit digests to increase performance 2017-02-10 14:22:20 -08:00
2a4944d6ee [Tables] Refactoring for consolidation of historical and real-time tables
Added batch processing of large historical queries. #1077
2017-02-10 14:21:48 -08:00
3544caf4be [API] Observer path was accessing object key incorrectly 2017-02-10 14:21:47 -08:00
976333d7f7 [Tables] Support for subscriptions from new Telemetry API
Historical and real-time data flowing

Added formatting, and limits. Support telemetry objects themselves and not just composition of telemetry objects

Apply default time range if none supplied (15 minutes)
2017-02-10 14:21:26 -08:00
6d5530ba9c [Tables] Using new composition API to fetch all telemetry objects 2017-02-10 14:12:10 -08:00
77d0134e2e [Build] Added Bourbon deprecation warning suppression system. 2017-02-10 10:03:05 -08:00
d3b4ad41c2 [Documentation] Fixed filename
Fixed file name "Platform.md" to "platform.md". "Platform.md" was giving a 404 error when clicked, in github and in the official site as well.
2017-02-09 20:54:52 -05:00
b28eb049dc Merge pull request #1420 from BogdanAlexandru/tutorial-fix
[Tutorial] Replace glyph mentions with cssclass
2017-02-06 11:57:49 -08:00
3d3baddd23 [Tables] Do not persist column configuration for non-editable objects 2017-02-02 15:44:36 -08:00
e712edba4e [Tutorial] Fix icon set url 2017-01-31 21:35:42 +02:00
35d8024aaa [Tutorial] Better describe cssclass 2017-01-31 21:32:31 +02:00
17564aa489 [Tutorial] Replace glyph mentions with cssclass 2017-01-29 18:16:36 +02:00
3ae0fd7bc9 Merge pull request #1388 from nasa/open1386
[Config] Fixes for example/msl
2017-01-26 11:49:04 -08:00
df7d59bc9c [Config] Fixes for example/msl
Fixes #1386
2017-01-26 11:40:46 -08:00
4f24c46e9b Merge pull request #1406 from nasa/separate-timeline-and-plot
[Reorg] Make timeline-specific chart directive
2017-01-26 11:34:05 -08:00
d262c4428e Merge pull request #1389 from cseale/chrome-testrunner-1387
[Build] Move karma test browser from PhantomJS to Chrome
2017-01-23 10:42:15 -08:00
9f9d28deef adding MCT name to README 2017-01-21 11:27:20 -05:00
ea74385ac8 Merge pull request #1407 from nasa/fix-style-1374
[Style] Fix style bugs introduced in #1374
2017-01-19 09:33:06 -08:00
06cc95efb1 Merge pull request #1381 from ev1stensberg/master
[DOCUMENTATION] Add linting to tutorial section
2017-01-19 09:07:02 -08:00
09ebeeb8e4 Merge pull request #1376 from cseale/mct1298
[Overlay] Remove max-height and max-width from overlay CSS
2017-01-18 21:48:13 -08:00
7e8e861468 Merge pull request #1372 from nasa/api-review-followup-1122
[API] Address review followup items
2017-01-18 21:42:22 -08:00
df2ce72e39 Merge pull request #1369 from nasa/datum-fallback
Use series.getDatum when available
2017-01-18 21:37:31 -08:00
fe8398017c [Style] Fix style bugs introduced in #1374 2017-01-17 16:56:32 -08:00
c2253f5010 Merge pull request #1374 from cseale/mct1197
[Dialogs] Close dialogs by pressing the ESC key
2017-01-17 13:23:23 -08:00
290dd0abf0 Merge pull request #1400 from nasa/plugins-1398
[Plugins] Adapt legacy plugins
2017-01-17 13:22:24 -08:00
49560698f6 [Reorg] Make timeline-specific chart directive
Make a separate chart directive for drawing resource graphs in timelines.  This
is in preparation for a new plot bundle which will make a large number of
changes to the drawing API to support newly requested features.  By separating
code, there will be no impact to the timeline when the new plot features are
added.
2017-01-17 09:59:00 -08:00
1ce1d29c87 Merge branch 'master' into chrome-testrunner-1387 2017-01-14 02:08:13 +00:00
d522d105ad [Plugins] Document plugins 2017-01-13 11:57:00 -08:00
72b753c67f [Plugins] Use correct constant key for CouchDB 2017-01-13 11:46:14 -08:00
16ec65f38c [Plugins] De-camelcase Elasticsearch constructor
...since that's the way elastic does it, when they capitalize any letters.
2017-01-13 11:36:46 -08:00
ed67866f45 [Plugins] Use lodash API correctly 2017-01-13 11:34:05 -08:00
36b5197733 [Plugins] Add missing paren 2017-01-12 15:17:48 -08:00
fa28393c14 [Plugins] Add missing function keyword 2017-01-12 15:12:50 -08:00
077f076c43 [Plugins] Allow CouchDB URL to be specified 2017-01-12 15:10:14 -08:00
c7ae520d7e [Plugins] Only register elasticsearch url when provided 2017-01-12 15:08:45 -08:00
39eb7ba862 [Plugins] Allow ElasticSearch config 2017-01-12 15:07:07 -08:00
116bb2c25f [Plugins] Add persistence plugin constructors 2017-01-12 14:56:47 -08:00
6bf293f96b [Plugins] Install plugins for dev client 2017-01-12 14:51:46 -08:00
eceaa38ed8 [Plugins] Remove Espresso from defaultRegistry 2017-01-12 14:51:18 -08:00
b6aa087536 [Plugins] Expose bundle-enabling plugins
Fixes #1398
2017-01-12 14:50:55 -08:00
d94e8b10d8 Merge pull request #1385 from nasa/example-roots-1384
[Roots] Update examples
2017-01-11 15:07:05 -08:00
590a0fe080 [Build] Move karma test browser from PhantomJS to Chrome
Issue #1387
2017-01-10 18:53:56 +00:00
41d0e953f5 [Build] Specify phantomjs-prebuilt version
Attempting to resolve build failure
https://circleci.com/gh/nasa/openmct/3167
2017-01-09 15:00:32 -08:00
3436455201 [Roots] Update scratchpad bundle 2017-01-09 14:34:41 -08:00
bb63e13770 [Roots] Update taxonomy example
Fixes #1384
2017-01-09 14:32:19 -08:00
62685cb892 [DOCUMENTATION] Add linting to tutorial section
Adds code examples with linting
2017-01-07 13:49:03 +01:00
6fe0ce70eb [Overlay] Remove max-height and max-width from overlay CSS
Issue #1298
2016-12-29 23:27:10 +00:00
bee22311a7 [Dialogs] Close dialogs by pressing the ESC key
Issue #1197
2016-12-29 00:06:47 +00:00
2cde80237f [API] Inject eventEmitter 2016-12-23 16:55:18 -08:00
3b93454c53 [API] Fix EventEmitter import 2016-12-23 16:53:27 -08:00
a5a17b9502 [API] Remove singleton event emitter 2016-12-23 16:51:15 -08:00
381f3d9b69 [API] Document default composition provider
https://github.com/nasa/openmct/issues/1122#issuecomment-252115292

Fixes #1122
2016-12-23 16:40:21 -08:00
94319df69b Merge pull request #1371 from nasa/plugins-1248
[Plugins] Expose plugin functions
2016-12-23 14:20:54 -08:00
1666c42f78 [Plugins] Document plugins 2016-12-23 13:05:34 -08:00
f1870e286d [Plugins] Expose My Items plugin 2016-12-23 13:01:22 -08:00
94194ff675 [Plugins] Expose plugins on openmct project
...to allow a simple Open MCT to be configured for tutorials,
#1248
2016-12-23 12:57:52 -08:00
d37caa7665 Merge pull request #1370 from nasa/open1367
[Edit] Set key on represent
2016-12-23 11:33:54 -08:00
a768b12985 [Edit] Set key on represent
Set key on represent so that commit function can properly persist
configuration per object type.  Add tests to EditRepresenter

Fixes https://github.com/nasa/openmct/issues/1367
2016-12-23 11:22:29 -08:00
6f257593c8 Use series.getDatum when available 2016-12-22 10:02:28 -08:00
c4d47ddc26 Merge pull request #1366 from nasa/fix-navigation-warnings-1360
Fix navigation warnings, tidy editing, navigation, browse logic.
2016-12-21 12:38:54 -08:00
60d1b73160 Update tests and correct style
Update tests to reflect new functionality.

Closes https://github.com/nasa/openmct/issues/1360
2016-12-20 16:49:13 -08:00
96c054415d [Cleanup] Remove unused template in adapter 2016-12-20 16:43:23 -08:00
89be1c810a [Browse] tighter tree view integration
BrowseController uses new MCTTreeView parameters to prevent navigation
events before triggering digests.  It also no longer sets navigation
more frequently than it should.

https://github.com/nasa/openmct/issues/1360
2016-12-20 16:43:23 -08:00
6328bd9354 [Edit] Cancel action depends on promise resolution
Cancel action no longer cares about return value, simply
will not execute if navigtion promise does not resolve.

https://github.com/nasa/openmct/issues/1360
2016-12-20 16:43:23 -08:00
fcda211800 [Edit] manage editing in EditObjectController
EditObjectController now exits edit mode when it is destroyed.
It also injects a check function in the navigation service to
replace the old functionality implemented in EditNavigationPolicy.

https://github.com/nasa/openmct/issues/1360
2016-12-20 16:43:23 -08:00
daa71c4f69 [Navigation] remove mct-before-unload
Remove mct-before-unload, and move the functionality to the navigation
service.  The navigation service considers "unload" to be a navigation
event and prompts in much the same way as it would before any other
navigation event.

https://github.com/nasa/openmct/issues/1360
2016-12-20 16:43:23 -08:00
f2d61604f7 [Navigation] navigationService provides checking
Remove policy checking in navigation action and depend on navigation
service to provide those checks.

* Register checkFunctions with navigationService.checkBeforeNavigation
  which returns a function for unregistering them.
* navigationService.setNavigation will run checks before allowing
  navigation, unless a `force` argument is supplied.

https://github.com/nasa/openmct/issues/1360
2016-12-20 16:43:23 -08:00
f0b9292458 [Tree] Add additional api methods
Add methods to tree view via scope for more fine grained control.

Can supply a "allowSelection" function which should return true
if a given selection is allowed.  This is executed before a node
is selected and allows you to prevent selection.  Before this, if
you wanted to prevent the selection from changing, you had to wait
for it to change and then change it back to the original value.

Can also supply an "onSelection" function which is called when a
value is successfully selected.  This allows you to handle the
selection event without waiting for digest.  You can still $watch
"selectedObject" if you prefer.

Additionally, this changes the tree node to trigger a digest only
when the value is set via a MouseClick, instead of every time.

Tidies up directive scope bindings to clarify usage.

https://github.com/nasa/openmct/issues/1360
2016-12-20 16:43:23 -08:00
0b79ec1235 [Browse] Simplify Edit Representation
Simplify edit registration and remove extra abstractions.  No longer
attach a status listener for every representation-- just use a single watch
for the edit controller.  Simplifies logic involved in switching controllers.

https://github.com/nasa/openmct/issues/1360
2016-12-20 16:43:23 -08:00
b9601ff819 Merge pull request #1363 from BogdanAlexandru/testfix1361
[Test Fix] Mock cloned object in SaveAsActionSpec
2016-12-20 15:27:30 -08:00
6f417fc4c7 Merge pull request #1362 from nasa/open1348
[Telemetry] Added legacy provider to expose old style telemetry providers to users of the new telemetry API
2016-12-20 09:12:00 -08:00
d99b4d35ab [Failing Test] Mock cloned object in SaveAs spec 2016-12-20 12:41:58 +02:00
6936ab6100 [Telemetry] Added 'name' as a telemetry datum attribute. Fixes #1099 2016-12-19 16:14:05 -08:00
532f7a76f9 [Edit] Add notifications to Save & SaveAs (#1258)
* [Edit] Added notifications to SaveAsAction

* [Edit] Added notifications to SaveAction

* [Edit] Update SaveAsActionSpec

* [Edit] No error notif when user cancels SaveAs
2016-12-19 10:59:26 -08:00
09e79d38ff Added support for limits 2016-12-15 15:30:22 -08:00
1c40fa88ce Removed redundant methods from LegacyTelemetryProvider
Removed redundant methods from LegacyTelemetryProvider
2016-12-15 15:30:22 -08:00
a4ff5ffb43 Fix method name 2016-12-15 15:30:22 -08:00
799c418124 [Telemetry] include type telemetry metadata
Read telemetry metadata from type and include in telemetry.

Allows telemetry service to work with SWG.
2016-12-15 15:30:22 -08:00
215e9b26a8 [Telemetry] Add metadata and formatter support
Add TelemetryMetadataManager which assists developers in interrogating
telemetry metadata to find values that are useful for them.

Add TelemetryValueFormatter to simplify the parsing (retrieval of numerical
values) and formatting (retrieval of displayable string value) of datums.

https://github.com/nasa/openmct/issues/1310
2016-12-15 15:30:22 -08:00
43132ea6f8 [Telemetry] Added LegacyTelemetryProvider to make existing telemetry providers available to the new Telemetry API 2016-12-15 15:30:22 -08:00
90a7ca8ae5 [Generator] Support more config, data rates (#1353)
* [Generator] Support more config, data rates

Update sinewave generator to use webworker, have more
configuration options.  Now supports higher data rates.

Also wrote telemetry provider for new API, and updated
legacy provider as well while we flesh out the telemetry API.

Fixes https://github.com/nasa/openmct/issues/1337

* Proper Step Timing, proper value passthrough

* Remove unused value, remove non-functional plugin

Remove an unnecessary datum value, `time`, and remove the new style
plugin -- which does not actually work -- to prevent confusion.

Addresses
https://github.com/nasa/openmct/pull/1353#pullrequestreview-12571665
2016-12-14 15:02:53 -08:00
f077f4fc1b Merge pull request #1359 from nasa/open1358
[Images] Filters not working in older Chrome installs. Fixes #1358.
2016-12-14 14:15:26 -08:00
0cd849fe42 [Images] Filters not working in older Chrome installs. Fixes #1358. 2016-12-14 14:08:50 -08:00
06a24e3a7d Merge pull request #1354 from nasa/icon-assignment
Fix icon assignments
2016-12-14 13:38:57 -08:00
abd9fdec38 Merge pull request #1357 from nasa/umd-1356
[Build] Change global namespace name
2016-12-14 13:34:05 -08:00
bfdbb4dacb [Build] Change global namespace name
...to match name of module. Fixes #1356
2016-12-14 10:04:00 -08:00
b5b68e7439 Fix icon assignments
Icons had been accidentally swapped around, updated the
assignements and regenererated file.
2016-12-12 13:00:04 -08:00
a920220122 Merge pull request #1352 from nasa/open1351
[Navigation] Fix errors appearing in console on application load
2016-12-09 11:42:47 -08:00
83ed4f6b0d [Navigation] Fix errors appearing in console on initial navigation. Fixes #1351 2016-12-09 09:59:27 -08:00
6a32c53d05 Merge pull request #1350 from nasa/open1349
[Time Conductor] Fixed issue with zoom slider appearing for time systems that do not support it.
2016-12-09 09:44:29 -08:00
0785129b7f [Time Conductor] Fixed issue with zoom slider appearing for time systems that do not support it. Fixes #1349 2016-12-08 15:14:40 -08:00
45de84c183 [Time Conductor] Prevent route change when time conductor values change (#1342)
* [Time Conductor] Prevent route change on setting search parameters. fixes #1341

* [Inspector] Fixed incorrect listener deregistration which was causing errors on scope destruction

* Bare route is redirect to browse

* [Browse] handle routing without breaking $route

Manage route transitions such that route changes are properly
prevented and navigation events occur while still updating the url.

Resolves a number of issues where path and search updates had
to be supported in a very hacky manner.

https://github.com/nasa/openmct/pull/1342

* [URL] Set search without hacks

Changes in previous commit allow the search parameters to be modified
without accidentally triggering a page reload.

https://github.com/nasa/openmct/pull/1342

* [Views] Update on location changes

If the user has a bookmark or tries to change the current view of an
object by specifying view=someView as a search parameter, the change would
not previously take effect.  This resolves that bug.

https://github.com/nasa/openmct/pull/1342

* [TC] Set query params to undefined

Instead of setting params to null, which would eventually result in those
parameters equaling undefined, set them to undefined to skip the extra
step.

https://github.com/nasa/openmct/pull/1342

* [Instantiate] Instantiate objects with context

Add context to instantiate objects so that they can be navigated
to for editing.

https://github.com/nasa/openmct/pull/1342

* [Tests] Update specs

Update specs to match new expectations.

* [Style] Fix style

* [TC] Remove unused dependency

Remove $route dependency from time conductor controller as it was
not being used.  Resolves review comments.

https://github.com/nasa/openmct/pull/1342#pullrequestreview-11449260
2016-12-07 13:33:53 -08:00
b2da0cb12f Merge pull request #1335 from nasa/open1234
[Time Conductor] Remove previous time conductor. Fixes #1234
2016-12-07 13:10:45 -08:00
e121c0f8ac [Time Conductor] Remove previous time conductor. Fixes #1234 2016-12-07 12:36:52 -08:00
bf006b45e4 Merge pull request #1347 from nasa/open1278
[Edit Mode] Fix issue with navigation not triggering unsaved changes warning
2016-12-06 13:50:53 -08:00
a3f5873501 [Edit Mode] Fix issue with navigation not triggering unsaved changes message for new objects. Removed logic that prevented mutation of new objects from triggering a transactional persist call. Fixes #1278 2016-12-05 15:52:14 -08:00
86b337ec88 Revert "[Edit Mode] Fix issue with navigation not triggering unsaved changes message for new objects. Removed logic that prevented mutation of new objects from triggering a transactional persist call. Fixes #1278"
This reverts commit 7dda85cc5f.
2016-12-05 15:49:50 -08:00
7dda85cc5f [Edit Mode] Fix issue with navigation not triggering unsaved changes message for new objects. Removed logic that prevented mutation of new objects from triggering a transactional persist call. Fixes #1278 2016-12-05 15:46:56 -08:00
68d6920d38 Merge pull request #1305 from Brantron/notification-bell
Make notification icon clickable
2016-12-02 14:22:52 -08:00
f540fd08fa Merge pull request #1338 from nasa/my-items-as-model
[MyItems] Load via static model provider
2016-12-01 15:41:08 -08:00
aaf4877daa Merge pull request #1339 from nasa/open1336
[Documentation] Fixed non-functioning telemetry tutorial, updated glyphs.
2016-12-01 15:15:25 -08:00
828e5629c5 [Tutorials] Updated tutorials fixing errors preventing the Todo and Bar Graph tutorials from working. Have disabled the telemetry example for now as fixing it is more involved
[Documentation] Fixed failing telemetry tutorial

[Documentation] Fixed glyphs, fixed other minor issues

Fixes #1336. Fixes #1309. Fixes #1163
2016-12-01 15:03:24 -08:00
44ceb4e865 [Style] remove trailing comma
per https://github.com/nasa/openmct/pull/1338#discussion_r90542441
2016-12-01 14:18:55 -08:00
88f954b437 [MyItems] Load via static model provider
Define a model for my items to be used when the model
is not found in a storage provider.

Fixes https://github.com/nasa/openmct/issues/1284
2016-12-01 13:18:22 -08:00
f85595665f Merge pull request #1325 from nasa/open1231
[Time Conductor] Persist Time Conductor state in URL
2016-11-30 13:17:33 -08:00
73b3ae7264 [Composition] Composition api improvements (#1332). Fixes #1322 and Fixes #1253
* [Composition] provide ids, sync via mutation

Composition provides ids, and we sync things via mutation.  This
simplifies the composition provider interface some, and also
fixes some issues with the previous default composition provider
related to #1322
fixes #1253

* [Style] Fix style, update jsdoc

Fix style, update jsdoc, clean up composition api changes for

Fixes #1322

* [Style] Tidy and JSDoc

* [Composition] Utilize new composition API

Ensures that composition provided by new API works in old API.

Some functionality is not present in both places, but for the
time being this is sufficient.

https://github.com/nasa/openmct/pull/1332

* [Utils] add tests, fix bugs

Add tests to objectUtils to ensure correctness.  This caught a bug
where character escapes were not properly applied or removed.  As
a result, any missing object that contained a colon in it's key
would cause an infinite loop and cause the application to crash.

Bug discovered in VISTA integration.

* [Style] Fix style

* [Roots] Depend on new api for ROOT

Depend on new API for ROOT model, ensuring consistency when
fetching ROOT model.

* [Style] Remove commented code
2016-11-30 12:00:01 -08:00
eaae401d16 Added mode, timeSystem, and deltas
Fixing tests

Fixed broken tests

Added tests

Fixed style errors
2016-11-25 15:16:53 -08:00
efed5f68af [Time Conductor] Added support for loading and persisting time conductor bounds in URL. Fixes #1231 2016-11-25 15:16:31 -08:00
79b4f9a0f4 Squash-merge open1193 into master.
Closes https://github.com/nasa/openmct/pull/1287.

Squashed commit of the following:

commit af9ba3095859684cb2465f1d5222a14db231fdb7
Merge: c98286d 31308b1
Author: Pete Richards <peter.l.richards@nasa.gov>
Date:   Fri Nov 25 14:57:32 2016 -0800

    Merge branch 'open1193' into open1287-integration

    Resolve conflicts in glyph files as documented in pull request:
    https://github.com/nasa/openmct/pull/1287#issuecomment-263030180

    Closes https://github.com/nasa/openmct/pull/1287

commit 31308b1076
Author: Andrew Henry <andrew.k.henry@nasa.gov>
Date:   Tue Nov 22 17:08:10 2016 +0000

    [Time Conductor] Addressed code review comments. Fixes #1287

commit db6386e21c
Author: Henry <akhenry@gmail.com>
Date:   Wed Nov 9 11:52:39 2016 -0800

    Removed redundant ConductorService

commit a9ec8db8c6
Merge: fc36674 dfa4591
Author: Henry <akhenry@gmail.com>
Date:   Wed Nov 9 08:23:07 2016 -0800

    Merge branch 'master' into open1193

commit fc36674b5c
Author: Henry <akhenry@gmail.com>
Date:   Wed Nov 9 08:23:01 2016 -0800

    Updated wording of docs

commit d0906baccf
Author: Henry <akhenry@gmail.com>
Date:   Fri Nov 4 10:48:05 2016 -0700

    Fixed TOI not showing

commit 099c56c407
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 28 16:46:06 2016 -0700

    Fixed failing tests

commit 7cc008ed01
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 28 10:28:41 2016 -0700

    Added tests for tables, TOI controller

commit b0901e83cb
Author: Henry <akhenry@gmail.com>
Date:   Thu Oct 27 10:42:31 2016 -0700

    Added tests for ConductorAxisController and TimeConductor

commit dfed0a0783
Author: Henry <akhenry@gmail.com>
Date:   Wed Oct 26 18:07:50 2016 -0700

    Added ConductorAxisController tests

commit c3322e3847
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 25 20:54:24 2016 -0700

    Added tests for MctTableController

commit 8e76ebb5a8
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 25 15:48:15 2016 -0700

    Removed debugging code

commit 93735bc404
Author: Henry <akhenry@gmail.com>
Date:   Mon Oct 24 15:13:45 2016 -0700

    Removed bundle definition of MctAxisController
    Documenting code

commit a942541724
Author: Henry <akhenry@gmail.com>
Date:   Sun Oct 23 19:54:01 2016 -0700

    [Time Conductor] Fixed memory leak due to listeners not being deregistered

commit 49e600dcc9
Author: Henry <akhenry@gmail.com>
Date:   Sat Oct 22 16:47:11 2016 -0700

    [Time Conductor] Fixed zoom slider behavior

commit f5806613b9
Author: Henry <akhenry@gmail.com>
Date:   Sat Oct 22 14:46:14 2016 -0700

    [Time Conductor] support TOI from real-time tables

commit 029d2b3058
Author: Henry <akhenry@gmail.com>
Date:   Thu Oct 20 14:32:34 2016 -0700

    [Examples] Simplified MSL example, fixed object tree not loading by default, renamed. Fixes #1256. Fixes #1255

commit 482eb4a5e8
Author: Henry <akhenry@gmail.com>
Date:   Sat Oct 22 13:09:05 2016 -0700

    [Time Conductor] Using new API

commit 843c678b0b
Merge: b56ab0a 08ca765
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 21 10:21:22 2016 -0700

    In process of merging

commit b56ab0aac2
Author: Henry <akhenry@gmail.com>
Date:   Wed Oct 19 16:30:26 2016 -0700

    [Time Conductor] Implement default sort, fix unpredictable positioning using % left, set TOI on conductor init. #1193

commit d12ae77d95
Author: Henry <akhenry@gmail.com>
Date:   Wed Oct 19 11:29:42 2016 -0700

    Further TOI improvements

commit 22564473b5
Merge: 9f3ec3b 86b51f6
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 18 16:32:12 2016 -0700

    Merge branch 'open1193' of https://github.com/nasa/openmctweb into open1193

commit 9f3ec3b18f
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 18 16:31:59 2016 -0700

    Fixed issue with scrolling to row after bounds change

commit 86b51f6cde
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Oct 17 17:19:50 2016 -0700

    [Frontend] Small refactor for mct-include

    Fixes #933
    Fixes #1193
    Markup and CSS tweaked to support using mct-include
    as the main container for the TOI element; TC, plots
    and tables all updated.

commit dadca62955
Author: Henry <akhenry@gmail.com>
Date:   Mon Oct 17 15:54:34 2016 -0700

    Positioning of TOI in tables and plots

commit 7a09bc1339
Author: Henry <akhenry@gmail.com>
Date:   Mon Oct 17 10:11:59 2016 -0700

    Migrated TOI functionality to common controller

commit 6bea6b3bc2
Merge: 660757f 8f67cbd
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 14 14:38:57 2016 -0700

    Merge branch 'open1193' of https://github.com/nasa/openmctweb into open1193

commit 660757fc1c
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 14 14:38:46 2016 -0700

    Added TimeOfInterestController

commit 8f67cbd717
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Oct 14 11:33:35 2016 -0700

    [Frontend] Fixed cursor: grab on Time Conductor

    Fixes #933
    Fixes #1193
    Moved cursor: grab into mixin; sass cleanups

commit 07a4e26317
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Oct 14 11:03:23 2016 -0700

    [Frontend] TOI finalizing

    Fixes #933
    Fixes #1193
    HTML template cleaned up; checked in snow theme,
    theme colors tweaked; padding finalized; now uses
    val-to-left instead of -to-right;

commit 271c788f20
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Oct 14 10:22:26 2016 -0700

    [Frontend] TOI in tables

    Fixes #933
    Fixes #1193
    WIP

commit b7e8a1b378
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Oct 13 15:55:48 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    WIP: Table TOI element in progress

commit 6042e4ad58
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Oct 13 13:46:27 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    WIP: plots and TC done, moving on to
    tables; moved sass into conductor-v2;
    moved constants;

commit 1a534301c5
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Oct 13 11:42:10 2016 -0700

    [Frontend] Refactor TOI element

    Fixes #933
    Fixes #1193
    WIP; TOI as mct-include; layout uses
    flex-box; preparing to move TOI sass
    into conductor-v2 directory;

commit 42acf9255e
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Oct 12 18:34:51 2016 -0700

    [Frontend] Adding resync and dedicated unpin buttons

    Fixes #933
    Fixes #1193
    VERY WIP!

commit 3f0eb0b7cb
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Oct 12 18:33:53 2016 -0700

    [Frontend] New glyphs for use by TOI

    Fixes #933
    Fixes #1193
    Symbols font updated

commit 086307ba3a
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 11 17:16:51 2016 -0700

    Fixed scrolling behavior with TOI

commit 938bf3c4df
Merge: 3910437 8b2047c
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 11 13:26:20 2016 -0700

    Merge branch 'open1182' into open1193

commit 8b2047ca32
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 11 13:25:24 2016 -0700

    Fixed issue with setting deltas

commit 3910437033
Merge: 70c4ce2 02c543f
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 11 12:48:37 2016 -0700

    Merged changes to zoom

commit 02c543fddc
Author: Henry <akhenry@gmail.com>
Date:   Tue Oct 11 12:45:18 2016 -0700

    Fixed zoom in real-time mode

commit 70c4ce24e4
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 7 17:57:14 2016 -0700

    Added support for clicking row to set TOI

commit b995a8b87b
Merge: 51a9557 b384e84
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 7 16:11:59 2016 -0700

    Merged from open1182

commit b384e84872
Merge: 5babf72 07140b1
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 7 15:02:41 2016 -0700

    Merge branch 'open933' into open1182

commit 07140b179f
Merge: 3e9c0eb cbd001e
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 7 14:54:18 2016 -0700

    Merge branch 'master' into open933

commit 51a95575f7
Author: Henry <akhenry@gmail.com>
Date:   Fri Oct 7 14:51:59 2016 -0700

    [Time Conductor] Refactored time of interest as optional generic behavior of MctTable

commit dfbbc3b0c5
Merge: 430645b 47a0aba
Author: Henry <akhenry@gmail.com>
Date:   Thu Oct 6 10:23:42 2016 -0700

    alt-click to select TOI from table

commit 3e9c0eb7a5
Merge: f1d2072 8a00181
Author: Henry <akhenry@gmail.com>
Date:   Wed Oct 5 12:25:04 2016 -0700

    Merged from master to resolve build issues

commit f1d2072bb9
Author: Henry <akhenry@gmail.com>
Date:   Wed Oct 5 11:17:22 2016 -0700

    Added license information

commit 430645b1f2
Author: Henry <akhenry@gmail.com>
Date:   Wed Oct 5 09:04:13 2016 -0700

    TOI working in time conductor

commit 47a0aba601
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Tue Oct 4 18:12:01 2016 -0700

    [Frontend] TOI sass and markup sanding

    Fixes #933
    Fixes #1193
    Color tweaks; Cleanups, commented
     code removal, etc.; tightened up
     tabular padding and font sizes;

commit 0ed0a48a8c
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Tue Oct 4 15:49:18 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    Tabular styling for TOI;

commit 1650aae518
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Oct 3 15:56:56 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    WIP: Tabular styling for TOI;
    TODO: make bottom border work

commit d3bf6c5857
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Oct 3 15:15:56 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    WIP: Markup and CSS for plots and TC near complete;
    TODO: revised styling in tabular views;

commit 5cd0c8a4fa
Author: Henry <akhenry@gmail.com>
Date:   Fri Sep 30 12:41:14 2016 -0700

    [Time Conductor] merged from open1182

commit 5babf7274d
Author: Henry <akhenry@gmail.com>
Date:   Thu Sep 29 11:21:11 2016 -0700

    [Time Conductor] Tweaked the break points for zoom level indicator

commit 22da34870d
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 29 10:41:21 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    WIP: Markup and CSS revisions for updated UX approach;
    TODO: cosmetic CSS

commit 99253a5904
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Tue Sep 27 20:42:33 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    WIP: Markup and CSS revisions for updated UX approach

commit 2db4aa6235
Author: Henry <akhenry@gmail.com>
Date:   Fri Sep 23 13:06:22 2016 -0700

    [Time Conductor] Added zoom level label

commit bb2ae2f8d1
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Fri Sep 23 11:07:06 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    Finalized TOI in plots, table and TC

commit 0cf4c92555
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 22 19:15:10 2016 -0700

    [Frontend] Styling for TOI element in tables

    Fixes #933
    Fixes #1193
    WIP: styling in tabular mostly done, needs more unit testing
    TODO: fix hide/show for pinned TOI in plots - don't
    show pinned TOI on hover when not .active

commit 3c95c095f1
Author: Henry <akhenry@gmail.com>
Date:   Thu Sep 22 17:22:25 2016 -0700

    [Time Conductor] Refactored out use of angular event bus in favor of making TimeConductorViewService an event emitter.

commit adbcc407ef
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 22 16:06:45 2016 -0700

    [Frontend] Styling for TOI element

    Fixes #933
    Fixes #1193
    WIP: TOI in tables

commit 1c3bd69b66
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 22 16:06:16 2016 -0700

    [Frontend] Styling for TOI element, some refactoring

    Fixes #933
    Fixes #1193
    Moves some TOI styling into dedicated new scss file;
    Enhancements to TOI in plots to bring into parity
    with TOI in TC approach;

commit 49ee5cb74b
Author: Henry <akhenry@gmail.com>
Date:   Thu Sep 22 15:18:48 2016 -0700

    [Time Conductor] Destroy listeners in ConductorAxisController

commit 1a93ba2c3d
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 22 15:09:42 2016 -0700

    [Frontend] Styling for TOI element in TC

    Fixes #933
    Fixes #1193
    Final for now; both types of TOI added to TC markup;
    Hover behavior; constant values in the right places;

commit 98122cc730
Author: Henry <akhenry@gmail.com>
Date:   Tue Sep 20 11:40:58 2016 -0700

    [Time Conductor] Added Zoom

commit 7fcafb6b58
Author: Henry <akhenry@gmail.com>
Date:   Mon Sep 12 16:53:48 2016 -0700

    [Time Conductor] Added pan to Time Conductor

commit d77922d66c
Author: Pete Richards <pete@pete-richards.com>
Date:   Thu Sep 15 09:37:11 2016 -0700

    Revert "[proxyUrl] pass URL parameters to proxied URL"

commit 2e81550c86
Author: Victor Woeltjen <victor.woeltjen@nasa.gov>
Date:   Wed Sep 14 10:16:33 2016 -0700

    Revert "[Build] Check dependencies for vulnerabilities"

commit 8eb7585653
Author: Victor Woeltjen <victor.woeltjen@nasa.gov>
Date:   Mon Aug 29 10:58:02 2016 -0700

    [README] Warn about root installation issues

    Mitigates #1151.

commit 904d56a089
Author: Henry <akhenry@gmail.com>
Date:   Thu Sep 22 13:32:43 2016 -0700

    [Time Conductor] #933 Clean up time conductor listeners on scope destruction

commit c0a96b3c5f
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 22 10:33:05 2016 -0700

    [Frontend] Styling for TOI element in TC

    Fixes #933
    Fixes #1193
    WIP, tweaking TOI in TC

commit 27e6caf69b
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Sep 16 18:51:51 2016 -0700

    [Frontend] Styling for TOI element in plots

    Fixes #933
    Fixes #1193
    Relates to #1182
    WIP, adding TOI to plot view;
    Integrated Andrew's work from #1182;
    Significant changes to markup and
    additions to plot scss;

commit 2c7ae95106
Merge: 2c81b72 41a160f
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Sep 16 15:11:25 2016 -0700

    Merge branch 'open1182' into open1193

commit 41a160fc4f
Merge: 92a80c3 156ba83
Author: Henry <akhenry@gmail.com>
Date:   Fri Sep 16 14:25:49 2016 -0700

    Merge branch 'master' into open1182

commit 92a80c39cb
Author: Henry <akhenry@gmail.com>
Date:   Mon Sep 12 16:53:48 2016 -0700

    [Time Conductor] Added pan to Time Conductor

commit 2c81b72d60
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 15 16:02:30 2016 -0700

    [Frontend] Styling for TOI element in plots

    Fixes #933
    Fixes #1193
    WIP, adding TOI to plot view.

commit 9e2debf801
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 15 15:43:29 2016 -0700

    [Frontend] Styling for TC's TOI element

    Fixes #933
    Fixes #1193
    I lied in my last commit - one more
    alignment tweak needed. Now I'm done.

commit 35872e284c
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 15 15:40:03 2016 -0700

    [Frontend] Styling for TC's TOI element

    Fixes #933
    Fixes #1193
    TOI in TC done for now.

commit 98e67f8dfb
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Thu Sep 15 14:55:06 2016 -0700

    [Frontend] Styling for TC's TOI element

    Fixes #933
    Fixes #1193
    WIP: adjust spacing;
    added pagination buttons

commit f912b9e273
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Sep 14 18:40:55 2016 -0700

    [Frontend] Styling for TC's TOI element

    Fixes #933
    WIP, TC v2 changes

commit 2df1e2b508
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Sep 14 18:40:29 2016 -0700

    [Frontend] Styling for TC's TOI element

    Fixes #933
    WIP, global changes

commit 9e85341aaa
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Sep 14 15:16:16 2016 -0700

    [Frontend] Fixed color for TC clock hands

    Fixes #933

commit 11e06039ec
Merge: a1331b7 f732387
Author: Henry <akhenry@gmail.com>
Date:   Tue Sep 13 13:25:37 2016 -0700

    Merge branch 'master' into open933

commit a1331b7bb3
Merge: d1960b2 e73bb4f
Author: Henry <akhenry@gmail.com>
Date:   Mon Sep 12 15:07:05 2016 -0700

    Merge branch 'master' into open933

commit d1960b2f46
Author: Henry <akhenry@gmail.com>
Date:   Mon Sep 12 14:54:16 2016 -0700

    [Time Conductor] Resolved merge conflicts

commit 9a06325533
Merge: e639e05 4c6ca58
Author: Henry <akhenry@gmail.com>
Date:   Mon Sep 12 14:39:24 2016 -0700

    Merge branch 'master' into open933

commit e639e056ba
Author: Henry <akhenry@gmail.com>
Date:   Fri Sep 9 16:39:21 2016 -0700

    [Time Conductor] Fixing bugs found in smoke testing. Fixes #933

commit fbab890081
Author: Henry <akhenry@gmail.com>
Date:   Wed Sep 7 14:29:21 2016 -0700

    [Time Conductor] Switched conductor to mct-include rather than mct-representation to avoid warnings

commit d37dd52ee1
Merge: 7af5875 58391de
Author: Henry <akhenry@gmail.com>
Date:   Tue Sep 6 16:43:17 2016 -0700

    Merge branch 'master' into open933

commit 7af5875dd5
Author: Henry <akhenry@gmail.com>
Date:   Tue Sep 6 10:04:29 2016 -0700

    [Time Conductor] #933 Fixed code style errors

commit c6eaa3d528
Author: Andrew Henry <andrew.k.henry@nasa.gov>
Date:   Wed Aug 24 15:28:19 2016 +0100

    [Time Conductor] Adding tests and fixing failing ones. #933

commit 4cf6126d35
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 10 18:22:30 2016 -0700

    Refactoring based on feedback

    Refactoring controller

    Migrating functions off controller onto service class

    Simplified modes

    Adding comments

    Removed unnecessary validation

    Fixing testing issues

commit 4ae6da0334
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Tue Aug 9 17:47:31 2016 -0700

    [Frontend] Data viz in Time Conductor smaller

    Fixes #933
    Reduced height of data viz bar in Time Conductor
    v2;

commit ae39343b76
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Aug 8 12:14:20 2016 -0700

    [Frontend] Fix for bad fix

    Fixes #1112
    Put overflow: hidden back at
    outer wrapper level (now on .t-object.primary-pane
    ) which doens't clip the Inspector expand/collapse;
    did better unit testing;

commit 62ee7e569b
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Aug 8 11:21:01 2016 -0700

    [Frontend] Fix for collapse Inspector button

    Fixes #1112
    Moved min-width and overflow: hidden
    to TC-specific elements; removed
    overflow: hidden from .primary-pane

commit 7557a86208
Merge: 46e644e c8931f8
Author: Henry <akhenry@gmail.com>
Date:   Fri Aug 5 16:37:36 2016 -0700

    Merge branch 'master' into open933

commit 46e644e6dc
Author: Pete Richards <peter.l.richards@nasa.gov>
Date:   Fri Aug 5 14:44:18 2016 -0700

    Use key to retrieve default

commit af7954c5a1
Author: Pete Richards <peter.l.richards@nasa.gov>
Date:   Fri Aug 5 11:24:51 2016 -0700

    Trigger digests when bounds are set

commit 0e0ad64830
Author: Henry <akhenry@gmail.com>
Date:   Thu Aug 4 10:41:58 2016 -0700

    Fixed issue with wrong deltas being applied

commit f3fd386e3b
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 21:03:09 2016 -0700

    Retain time system on mode change

commit 25b9f371e2
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 20:16:03 2016 -0700

    Fixed loss of time system options on navigation

commit 6b482d487b
Merge: f96f78f 9a72c96
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 19:57:03 2016 -0700

    Merged mode-specific defaults, with some refactoring

commit f96f78ff79
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 19:34:31 2016 -0700

    Select appropriate tick source based on mode

commit 579233ade9
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 18:30:01 2016 -0700

    Fixed delta format issue on navigation

commit 9a72c96ea4
Author: Pete Richards <peter.l.richards@nasa.gov>
Date:   Wed Aug 3 18:06:39 2016 -0700

    [TCv2] different defaults by mode

commit f4e1879a2d
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 17:43:07 2016 -0700

    stop listening to tick source on time system change

commit f844495cc1
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 17:40:37 2016 -0700

    Support deltaFormat on timeSystems

commit 900752208f
Author: Pete Richards <peter.l.richards@nasa.gov>
Date:   Wed Aug 3 13:05:43 2016 -0700

    [TCv2] get conductor without service

commit 6501e2eb5f
Author: Henry <akhenry@gmail.com>
Date:   Wed Aug 3 12:22:13 2016 -0700

    Added isUTCBased to TimeSystem interface

commit b9c41107c1
Author: Henry <akhenry@gmail.com>
Date:   Tue Aug 2 22:18:44 2016 -0700

    Time Conductor state retained on navigation

commit 34c62ba405
Author: Henry <akhenry@gmail.com>
Date:   Tue Aug 2 15:16:35 2016 -0700

    Time Conductor in edit mode

commit 1eea5ce480
Merge: 4cd579d 1173828
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 20:29:50 2016 -0700

    merged from master

commit 4cd579d274
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 20:16:46 2016 -0700

    Pass numerical value to format functions

commit 11738286df
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 18:56:33 2016 -0700

    [Frontend] Styling for unsynced elements

    Fixes #933

commit ca5206d4a0
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 18:55:49 2016 -0700

    [Frontend] Fixing issues with theme coloring

    Fixes #933

commit 573f1f9f99
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 18:04:17 2016 -0700

    [Frontend] Hide zoom slider control

    Fixes #933
    Temporarily hiding per request from Andrew
    today;

commit c5c45f0a0e
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 18:01:28 2016 -0700

    [Frontend] Update TC2 markup and sass

    Fixes #933
    Update markup and sass in TC2 to be in line with
    updates from master from #1047 glyphs
    to cssclass approach;

commit 121ab413ff
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 17:51:15 2016 -0700

    Apply formatting, filter modes by tick source availability

commit 753bd97c8a
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 17:12:44 2016 -0700

    Merge remote-tracking branch 'origin/master' into open933-c

    # Conflicts:
    #	platform/commonUI/edit/res/templates/create/create-menu.html
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff
    #	platform/commonUI/general/res/sass/_archetypes.scss
    #	platform/commonUI/general/res/sass/_constants.scss
    #	platform/commonUI/general/res/sass/_icons.scss
    #	platform/commonUI/general/res/sass/_main.scss
    #	platform/commonUI/general/res/sass/_mixins.scss
    #	platform/commonUI/general/res/sass/controls/_buttons.scss
    #	platform/commonUI/general/res/templates/controls/time-controller.html
    #	platform/commonUI/themes/snow/res/sass/_constants.scss

commit fcd7ab93e5
Merge: a75ea67 9b58aa0
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 17:12:00 2016 -0700

    Merge branch 'open933' of https://github.com/nasa/openmctweb into open933

commit c699cb8b4b
Merge: 579c6b6 d1e1ba1
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 17:11:37 2016 -0700

    Merge remote-tracking branch 'origin/master' into open933-c

    # Conflicts:
    #	platform/commonUI/edit/res/templates/create/create-menu.html
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf
    #	platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff
    #	platform/commonUI/general/res/sass/_archetypes.scss
    #	platform/commonUI/general/res/sass/_constants.scss
    #	platform/commonUI/general/res/sass/_icons.scss
    #	platform/commonUI/general/res/sass/_main.scss
    #	platform/commonUI/general/res/sass/_mixins.scss
    #	platform/commonUI/general/res/sass/controls/_buttons.scss
    #	platform/commonUI/general/res/templates/controls/time-controller.html
    #	platform/commonUI/themes/snow/res/sass/_constants.scss

commit a75ea67b8c
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 17:11:01 2016 -0700

    Format updates when time system selected

commit 9b58aa0052
Author: Pete Richards <peter.l.richards@nasa.gov>
Date:   Mon Aug 1 17:03:00 2016 -0700

    [TCv2] Add conductorService for compatibility

    Add conductor service for compatibility with old plugins that depend
    on the conductor service.

commit 579c6b6d24
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 16:30:51 2016 -0700

    [Frontend] Styling TC unsynced elements

    Fixes #933
    WIP: Styling for unsynced elements

commit 762f43fa61
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 16:26:47 2016 -0700

    [Frontend] Styling TC unsynced elements

    Fixes #933
    WIP: Styling for unsynced elements

commit ce5d0ef5bd
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 16:03:27 2016 -0700

    Merged stylesheet changes

commit 142ee2f336
Merge: 482fcbf 523d674
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 15:44:49 2016 -0700

    Added LocalTimeSystem and merged latest styles

commit 482fcbf6ee
Author: Henry <akhenry@gmail.com>
Date:   Mon Aug 1 15:14:23 2016 -0700

    Refactored bundle

commit 523d6743fb
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Mon Aug 1 12:00:53 2016 -0700

    [Frontend] Added support for thematic styling of Time Conductor v2

    Fixes #933
    Added theme sass files

commit 7af22126d4
Author: Henry <akhenry@gmail.com>
Date:   Wed Jul 27 12:05:03 2016 -0400

    Prevent tabbing into end bounds when not in fixed mode

commit 8e59072537
Author: Henry <akhenry@gmail.com>
Date:   Wed Jul 27 11:55:12 2016 -0400

    Removed LAD and Realtime modes

commit c1bbc4f01d
Author: Henry <akhenry@gmail.com>
Date:   Wed Jul 27 10:38:04 2016 -0400

    Code cleanup

commit aa4a5e56f9
Author: Henry <akhenry@gmail.com>
Date:   Tue Jul 26 16:55:00 2016 -0400

    Improved support from plot

commit 5b2eb72b16
Author: Henry <akhenry@gmail.com>
Date:   Tue Jul 26 08:33:30 2016 -0400

    [Time Conductor] Addressed documentation issues

commit 1b7fc57d21
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 25 16:55:27 2016 -0400

    Added status support to plots

commit a4f6f6f50b
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 25 12:09:15 2016 -0400

    Added license

commit 19fd63b850
Merge: c2c8e16 a10ded2
Author: Henry <akhenry@gmail.com>
Date:   Thu Jul 21 20:06:50 2016 -0700

    Merge branch 'open933-frontend-b' into open933

commit c2c8e16453
Author: Henry <akhenry@gmail.com>
Date:   Thu Jul 21 20:03:40 2016 -0700

    Added scale sensitive formatting to UTCTimeFormat

commit a10ded25b4
Merge: da7c636 e6d8944
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 20 18:33:58 2016 -0700

    Merge remote-tracking branch 'origin/open933' into open933-frontend-b

    # Conflicts:
    #	platform/features/conductor-v2/res/sass/time-conductor.scss
    #	platform/features/conductor/res/sass/time-conductor.scss

commit da7c636724
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 20 18:22:20 2016 -0700

    [Frontend] Time Conductor v2 styling

    Fixes #933
    Redo TC icon to use font symbol, added
    new symbol for brackets to font files; font
    anti-aliasing mod for .ui-symbol class;
    layout tweaks; mobile tweaks.

commit b392633bc6
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 20 15:48:22 2016 -0700

    [Frontend] Time Conductor v2 styling

    Fixes #933
    WIP: Significant mobile and desktop style tweaks;
    moved constants into their own include file;

commit ff1678435e
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 20 11:43:40 2016 -0700

    [Frontend] Time Conductor v2 styling

    Fixes #933
    Changed desktop and mobile RT UI to display
    end datetime and hide start;
    WIP: mobile styling for main UI of TC;

commit 2124fe01e1
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 20 10:18:42 2016 -0700

    [Frontend] Renew support for Time Conductor v1

    Fixes #933
    Minor fixes to TCv1 for mobile

commit e6d8944547
Author: Henry <akhenry@gmail.com>
Date:   Tue Jul 19 20:17:06 2016 -0700

    Modified main.js

commit ea1defac28
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Tue Jul 19 18:33:24 2016 -0700

    [Frontend] Renew support for Time Conductor v1

    Fixes #933
    Time Conductors v1 and v2 now build and load their
    own isolated CSS files. All previous styling for TCv1
    should be re-enabled. Note that Conductor v2 mobile
    is not complete yet.

commit 2a19394334
Author: Henry <akhenry@gmail.com>
Date:   Tue Jul 19 19:54:52 2016 -0700

    Added compatibility layer to support existing plots and historical tables

commit f641edbce7
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Tue Jul 19 18:33:24 2016 -0700

    [Frontend] Renew support for Time Conductor v1

    Fixes #933
    Time Conductors v1 and v2 now build and load their
    own isolated CSS files. All previous styling for TCv1
    should be re-enabled. Note that Conductor v2 mobile
    is not complete yet.

commit 15a608a861
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 18 18:44:29 2016 -0700

    Populate format in input fields

commit 334ca64551
Merge: 0af49ef 4087b9c
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 18 14:25:02 2016 -0700

    Merged open933-frontend

commit 0af49efe06
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 18 08:23:27 2016 -0700

    Refactored out modes, time systems, etc.

commit 4087b9cdde
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Fri Jul 15 14:39:29 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    WIP: Fixed look for Firefox

commit 43a804eef4
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Jul 15 07:54:32 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    WIP: Added zoom current range indicator;
    tweaks to style

commit b3a4f52fe2
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Thu Jul 14 18:30:49 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    WIP: Adding zoom control with HTML5
    input range type; Refactored sass slightly
    to move display: inline-block out of mixin
    containerBase and into .s-btn.

commit 671e3016d4
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Thu Jul 14 16:40:05 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    New _animations scss include, moved
    scss around.

commit 379828315f
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Thu Jul 14 16:39:27 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    New _animations scss include, moved
    scss around.

commit 8c5538ec4d
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Thu Jul 14 14:58:18 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    "Sticky" clock anim for LAD mode

commit 2f9fbfef7f
Author: Henry <akhenry@gmail.com>
Date:   Wed Jul 13 20:33:47 2016 -0700

    More refactoring

commit 2baca659ca
Author: Henry <akhenry@gmail.com>
Date:   Wed Jul 13 19:50:58 2016 -0700

    Refactoring

commit 8b694ef337
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 13 19:42:51 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    In-progress: color/size tweaks, fixes for espresso
    theme

commit e193e3dfba
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 13 19:16:27 2016 -0700

    Merge open933 latest, resolve conflicts

    Fixes #933
    Fair amount of manual fixing in time-conductor.html

commit 8214c8e895
Merge: 33b2225 14463d3
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 13 19:16:00 2016 -0700

    Merge open933 latest, resolve conflicts

    Fixes #933
    Fair amount of manual fixing in time-conductor.html

commit 33b2225d10
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 13 18:48:17 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    In-progress: restructured markup to move
    modeModel farther out; animated icon

commit 14463d39a8
Author: Henry <akhenry@gmail.com>
Date:   Wed Jul 13 18:17:27 2016 -0700

    Added end delta

commit fcfda50e73
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 13 15:00:16 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    In-progress: color tweaks, bar sizing,
    field widths

commit 06af84c161
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 13 13:14:32 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    In-progress: fixed SVG text color, field
    styling for fixed vs. real-time, markup cleanup

commit 5238aa2731
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Wed Jul 13 08:07:59 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    In-progress; fixed SVG text color

commit fd29473664
Author: Henry <akhenry@gmail.com>
Date:   Tue Jul 12 15:02:39 2016 -0700

    Support resize

commit 97f3fd516b
Author: Henry <akhenry@gmail.com>
Date:   Tue Jul 12 10:14:26 2016 -0700

    Changed default duration to fifteen minutes

commit 088416905d
Author: Henry <akhenry@gmail.com>
Date:   Tue Jul 12 10:08:08 2016 -0700

    Added duration

commit 2056d87453
Merge: 585da38 64ce8a2
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 11 14:27:30 2016 -0700

    Merge branch 'open933-frontend' into open933

commit 64ce8a2b2a
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Jul 11 14:03:41 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    Color adjusts, mini super-menu size
    and font tweaks, glyphs added to selector,
    SVG style fixes in progress

commit 585da38a16
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 11 13:46:46 2016 -0700

    Fixed some merge issues

commit bf0e85a94c
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Jul 11 11:35:26 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #933
    Renamed main class; removed unused <style>
    defs

commit 84b7a9dc2f
Merge: 7b7b21d 11caa83
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Jul 11 11:29:35 2016 -0700

    Merge remote-tracking branch 'origin/open933' into open933-frontend

    Fixes #933
    Conflicts:
    	platform/features/conductor-v2/src/TimeConductorController.js

commit 11caa8396a
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 11 11:18:23 2016 -0700

    Updated modes

commit 0017b77439
Merge: 5cc81ba 788483e
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 11 11:06:22 2016 -0700

    Merged markup changes

commit 7b7b21d748
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Jul 11 11:05:47 2016 -0700

    [Frontend] Styling of Time Conductor v2

    Fixes #933
    Tweaks to language; tweak to class name in markup

commit 788483ec13
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Jul 11 10:37:08 2016 -0700

    [Frontend] Styling of Time Conductor v2

    Fixes #933
    Tweaks to language

commit 7b19f91ce6
Merge: 0a0bc55 4e7b69c
Author: Charles Hacskaylo <charles.f.hacskaylo@nasa.gov>
Date:   Mon Jul 11 10:31:14 2016 -0700

    [Frontend] Merge latest from open933

    Fixes #933
    Resolve conflicts in
    mode-menu.html, mode-selector.html,
    time-conductor.html; apply tweaks, language, etc.

commit 5cc81ba12a
Author: Henry <akhenry@gmail.com>
Date:   Mon Jul 11 10:26:34 2016 -0700

    [Time Conductor] Added mode class to time conductor

commit 0a0bc55f5f
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Jul 8 17:11:43 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #993
    In-progress; mode menu names and
    descriptors modified, markup cleaned up

commit 4e7b69c4df
Author: Henry <akhenry@gmail.com>
Date:   Fri Jul 8 16:57:50 2016 -0700

    Enabled fixed and real-time modes

commit cf83040c4b
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Jul 8 16:54:49 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #993
    In-progress; Create menu refactoring and new
    mini Create menu

commit 32f7bc86af
Author: Charles Hacskaylo <charlesh88@gmail.com>
Date:   Fri Jul 8 16:54:13 2016 -0700

    [Frontend] Styling for Time Conductor v2

    Fixes #993
    In-progress; class renaming continued,
    cleanups in markup file, in-page styles
    ported to scss

commit e230b92946
Author: Henry <akhenry@gmail.com>
Date:   Fri Jul 8 15:15:12 2016 -0700

    Fixed bug with date selector having to be clicked twice

commit 58ed500ecf
Author: Henry <akhenry@gmail.com>
Date:   Thu Jul 7 16:57:03 2016 -0700

    Time sync via conductor

commit bca5eb0fdb
Author: Henry <akhenry@gmail.com>
Date:   Thu Jul 7 09:47:46 2016 -0700

    [Time Conductor] #933 Initial markup
2016-11-25 15:02:34 -08:00
c98286d426 Merge pull request #1329 from nasa/jscs-reports-1314
[Build] Output JSCS reports
2016-11-17 11:08:30 -08:00
d368bc2351 Merge pull request #1328 from nasa/open1322
[Composition] Modified call to object utils to provide identifier correctly
2016-11-17 11:07:35 -08:00
6a7b77ccf5 Merge pull request #1326 from nasa/image-brightness-contrast
[Imagery] Brightness/contrast controls
2016-11-17 11:06:05 -08:00
242eb6d733 [Build] Restore missing semicolon
Semicolons are our friends.
2016-11-16 09:36:22 -08:00
2991e9894d [Build] Move report to correct location 2016-11-16 09:28:56 -08:00
3dc8bc87fc [Build] Add jscs html reporter
Fixes #1314
2016-11-15 16:00:40 -08:00
cfb99eaf80 [Imagery] Add doc to mct-background-image 2016-11-15 14:08:00 -08:00
5dee588c36 Revert "[Frontend] Updated example images"
This reverts commit 251e3b5646.
2016-11-15 14:00:51 -08:00
2f8c03ecb2 [Imagery] Simplify filter reset 2016-11-15 14:00:12 -08:00
2dfde9a612 [Imagery] Test mct-background-image filters 2016-11-15 13:54:23 -08:00
2f5dc8a887 [Frontend] Styling for controls
Fixes #1324
New reset glyph; Reset button complete,
final sanding.
2016-11-15 12:24:14 -08:00
9b11684ae9 [Frontend] Styling for controls
Fixes #1324
CSS, markup, WIP adding reset button
2016-11-15 10:54:00 -08:00
251e3b5646 [Frontend] Updated example images
Fixes #1324
All images are open licensed for reuse
2016-11-15 10:42:34 -08:00
5c31c6084c [Composition] Modified call to object utils to provide identifier correctly. 2016-11-15 11:37:55 +00:00
b1464efdaf [Frontend] Styling for controls
Fixes #1324
CSS, markup, new glyphs for
brightness and contrast
2016-11-14 18:12:06 -08:00
3e6e068f7f [Imagery] Sketch in brightness/contrast controls
Fixes #1324
2016-11-14 12:19:23 -08:00
a8c9b6f7fe Fixes #1239 make notification icon clickable 2016-10-27 19:20:45 -04:00
313 changed files with 10014 additions and 7782 deletions

View File

@ -1,3 +0,0 @@
{
"presets": ["es2015"]
}

View File

@ -3,7 +3,6 @@
"browser": true,
"curly": true,
"eqeqeq": true,
"esversion": 6,
"forin": true,
"freeze": true,
"funcscope": false,
@ -15,7 +14,8 @@
"nonew": true,
"predef": [
"define",
"Promise"
"Promise",
"WeakMap"
],
"shadow": "outer",
"strict": "implied",

64
API.md
View File

@ -129,8 +129,10 @@ provider.
The "composition" of a domain object is the list of objects it contains,
as shown (for example) in the tree for browsing. Open MCT provides a
default solution for composition, but there may be cases where you want
to provide the composition of a certain object (or type of object) dynamically.
[default solution](#default-composition-provider) for composition, but there
may be cases where you want to provide the composition of a certain object
(or type of object) dynamically.
For instance, you may want to populate a hierarchy under a custom root-level
object based on the contents of a telemetry dictionary.
To do this, you can add a new CompositionProvider:
@ -146,6 +148,29 @@ openmct.composition.addProvider({
});
```
#### Default Composition Provider
The default composition provider applies to any domain object with
a `composition` property. The value of `composition` should be an
array of identifiers, e.g.:
```js
var domainObject = {
name: "My Object",
type: 'folder',
composition: [
{
key: '412229c3-922c-444b-8624-736d85516247',
namespace: 'foo'
},
{
key: 'd6e0ce02-5b85-4e55-8006-a8a505b64c75',
namespace: 'foo'
}
]
};
```
### Adding Telemetry Providers
When connecting to a new telemetry source, you will want to register a new
@ -265,6 +290,41 @@ openmct.install(myPlugin);
The plugin will be invoked to configure Open MCT before it is started.
### Included Plugins
Open MCT is packaged along with a few general-purpose plugins:
* `openmct.plugins.CouchDB` is an adapter for using CouchDB for persistence
of user-created objects. This is a constructor that takes the URL for the
CouchDB database as a parameter, e.g.
`openmct.install(new openmct.plugins.CouchDB('http://localhost:5984/openmct'))`
* `openmct.plugins.Elasticsearch` is an adapter for using Elasticsearch for
persistence of user-created objects. This is a
constructor that takes the URL for the Elasticsearch instance as a
parameter, e.g.
`openmct.install(new openmct.plugins.CouchDB('http://localhost:9200'))`.
Domain objects will be indexed at `/mct/domain_object`.
* `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.localStorage` provides persistence of user-created
objects in browser-local storage. This is particularly useful in
development environments.
* `openmct.plugins.myItems` adds a top-level folder named "My Items"
when the application is first started, providing a place for a
user to store created items.
* `openmct.plugins.utcTimeSystem` provides support for using the time
conductor with UTC time.
Generally, you will want to either install these plugins, or install
different plugins that provide persistence and an initial folder
hierarchy. Installation is as described [above](#installing-plugins):
```
openmct.install(openmct.plugins.localStorage);
openmct.install(openmct.plugins.myItems);
```
### Writing Plugins
Plugins configure Open MCT, and should utilize the

View File

@ -1,6 +1,6 @@
# Open MCT [![license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)
Open MCT is a next-generation mission control framework for visualization of data on desktop and mobile devices. It is developed at NASA's Ames Research Center, and is being used by NASA for data analysis of spacecraft missions, as well as planning and operation of experimental rover systems. As a generalizable and open source framework, Open MCT could be used as the basis for building applications for planning, operation, and analysis of any systems producing telemetry data.
Open MCT (Open Mission Control Technologies) is a next-generation mission control framework for visualization of data on desktop and mobile devices. It is developed at NASA's Ames Research Center, and is being used by NASA for data analysis of spacecraft missions, as well as planning and operation of experimental rover systems. As a generalizable and open source framework, Open MCT could be used as the basis for building applications for planning, operation, and analysis of any systems producing telemetry data.
Please visit our [Official Site](https://nasa.github.io/openmct/) and [Getting Started Guide](https://nasa.github.io/openmct/getting-started/)

View File

@ -23,7 +23,6 @@
"lodash": "3.10.1",
"almond": "~0.3.2",
"d3": "~4.1.0",
"html2canvas": "^0.4.1",
"babel-polyfill": "^0.0.1"
"html2canvas": "^0.4.1"
}
}

View File

@ -131,7 +131,7 @@ Keeping that in mind, there are a few useful patterns supported by the
framework that are useful to keep in mind.
The specific service infrastructure provided by the platform is described
in the [Platform Architecture](Platform.md).
in the [Platform Architecture](platform.md).
## Extension Categories

View File

@ -1338,55 +1338,6 @@ are supported:
Open MCT defines several Angular directives that are intended for use both
internally within the platform, and by plugins.
## Before Unload
The `mct-before-unload` directive is used to listen for (and prompt for user
confirmation) of navigation changes in the browser. This includes reloading,
following links out of Open MCT, or changing routes. It is used to hook into
both `onbeforeunload` event handling as well as route changes from within
Angular.
This directive is useable as an attribute. Its value should be an Angular
expression. When an action that would trigger an unload and/or route change
occurs, this Angular expression is evaluated. Its result should be a message to
display to the user to confirm their navigation change; if this expression
evaluates to a falsy value, no message will be displayed.
## Chart
The `mct-chart` directive is used to support drawing of simple charts. It is
present to support the Plot view, and its functionality is limited to the
functionality that is relevant for that view.
This directive is used at the element level and takes one attribute, `draw`
which is an Angular expression which will should evaluate to a drawing object.
This drawing object should contain the following properties:
* `dimensions`: The size, in logical coordinates, of the chart area. A
two-element array or numbers.
* `origin`: The position, in logical coordinates, of the lower-left corner of
the chart area. A two-element array or numbers.
* `lines`: An array of lines (e.g. as a plot line) to draw, where each line is
expressed as an object containing:
* `buffer`: A Float32Array containing points in the line, in logical
coordinates, in sequential x,y pairs.
* `color`: The color of the line, as a four-element RGBA array, where
each element is a number in the range of 0.0-1.0.
* `points`: The number of points in the line.
* `boxes`: An array of rectangles to draw in the chart area. Each is an object
containing:
* `start`: The first corner of the rectangle, as a two-element array of
numbers, in logical coordinates.
* `end`: The opposite corner of the rectangle, as a two-element array of
numbers, in logical coordinates. color : The color of the line, as a
four-element RGBA array, where each element is a number in the range of
0.0-1.0.
While `mct-chart` is intended to support plots specifically, it does perform
some useful management of canvas objects (e.g. choosing between WebGL and Canvas
2D APIs for drawing based on browser support) so its usage is recommended when
its supported drawing primitives are sufficient for other charting tasks.
## Container
@ -2310,10 +2261,7 @@ The platform understands the following policy categories (specifiable as the
* `action`: Determines whether or not a given action is allowable. The candidate
argument here is an Action; the context is its action context object.
* `composition`: Determines whether or not domain objects of a given type are
allowed to contain domain objects of another type. The candidate argument here
is the container's `Type`; the context argument is the `Type` of the object to be
contained.
* `composition`: Determines whether or not domain objects of a given type (first argument, `parentType`) can contain a given object (second argument, `child`).
* `view`: Determines whether or not a view is applicable for a domain object.
The candidate argument is the view's extension definition; the context argument
is the `DomainObject` to be viewed.

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,7 @@ define([
{
"key": "eventGenerator",
"name": "Event Message Generator",
"cssclass": "icon-folder-new",
"cssClass": "icon-folder-new",
"description": "For development use. Creates sample event message data that mimics a live data stream.",
"priority": 10,
"features": "creation",

View File

@ -36,7 +36,7 @@ define([
"name": "Export Telemetry as CSV",
"implementation": ExportTelemetryAsCSVAction,
"category": "contextual",
"cssclass": "icon-download",
"cssClass": "icon-download",
"depends": [ "exportService" ]
}
]

View File

@ -0,0 +1,87 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define([
'./WorkerInterface'
], function (
WorkerInterface
) {
var REQUEST_DEFAULTS = {
amplitude: 1,
period: 10,
offset: 0,
dataRateInHz: 1
};
function GeneratorProvider() {
this.workerInterface = new WorkerInterface();
}
GeneratorProvider.prototype.canProvideTelemetry = function (domainObject) {
return domainObject.type === 'generator';
};
GeneratorProvider.prototype.supportsRequest =
GeneratorProvider.prototype.supportsSubscribe =
GeneratorProvider.prototype.canProvideTelemetry;
GeneratorProvider.prototype.makeWorkerRequest = function (domainObject, request) {
var props = [
'amplitude',
'period',
'offset',
'dataRateInHz'
];
var workerRequest = {};
props.forEach(function (prop) {
if (domainObject.telemetry && domainObject.telemetry.hasOwnProperty(prop)) {
workerRequest[prop] = domainObject.telemetry[prop];
}
if (request.hasOwnProperty(prop)) {
workerRequest[prop] = request[prop];
}
if (!workerRequest[prop]) {
workerRequest[prop] = REQUEST_DEFAULTS[prop];
}
workerRequest[prop] = Number(workerRequest[prop]);
});
return workerRequest;
};
GeneratorProvider.prototype.request = function (domainObject, request) {
var workerRequest = this.makeWorkerRequest(domainObject, request);
workerRequest.start = request.start;
workerRequest.end = request.end;
return this.workerInterface.request(workerRequest);
};
GeneratorProvider.prototype.subscribe = function (domainObject, callback, request) {
var workerRequest = this.makeWorkerRequest(domainObject, request);
return this.workerInterface.subscribe(workerRequest, callback);
};
return GeneratorProvider;
});

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 define,Promise*/
/*global define*/
define({
START_TIME: Date.now() - 24 * 60 * 60 * 1000 // Now minus a day.

View File

@ -19,12 +19,11 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/*global define*/
define(
['./SinewaveConstants', 'moment'],
function (SinewaveConstants, moment) {
"use strict";
var START_TIME = SinewaveConstants.START_TIME,
FORMAT_REGEX = /^-?\d+:\d+:\d+$/,

View File

@ -0,0 +1,70 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SinewaveTelemetryProvider. Created by vwoeltje on 11/12/14.
*/
define([
"./SinewaveTelemetrySeries",
"./GeneratorProvider"
], function (
SinewaveTelemetrySeries,
GeneratorProvider
) {
function SinewaveTelemetryProvider() {
this.provider = new GeneratorProvider();
}
SinewaveTelemetryProvider.prototype.requestTelemetry = function (requests) {
if (requests[0].source !== 'generator') {
return Promise.resolve({});
}
return this.provider.request({}, requests[0])
.then(function (data) {
var res = {
generator: {}
};
res.generator[requests[0].key] = new SinewaveTelemetrySeries(data);
return res;
});
};
SinewaveTelemetryProvider.prototype.subscribe = function (callback, requests) {
if (requests[0].source !== 'generator') {
return function unsubscribe() {};
}
function wrapper(data) {
var res = {
generator: {}
};
res.generator[requests[0].key] = new SinewaveTelemetrySeries(data);
callback(res);
}
return this.provider.subscribe({}, wrapper, requests[0]);
};
return SinewaveTelemetryProvider;
});

View File

@ -0,0 +1,75 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SinewaveTelemetry. Created by vwoeltje on 11/12/14.
*/
define([
], function (
) {
"use strict";
function SinewaveTelemetrySeries(data) {
if (!Array.isArray(data)) {
data = [data];
}
this.data = data;
}
SinewaveTelemetrySeries.prototype.getPointCount = function () {
return this.data.length;
};
SinewaveTelemetrySeries.prototype.getDomainValue = function (
index,
domain
) {
domain = domain || 'time';
return this.getDatum(index)[domain];
};
SinewaveTelemetrySeries.prototype.getRangeValue = function (
index,
range
) {
range = range || 'sin';
return this.getDatum(index)[range];
};
SinewaveTelemetrySeries.prototype.getDatum = function (index) {
if (index > this.data.length || index < 0) {
throw new Error('IndexOutOfRange: index not available in series.');
}
return this.data[index];
};
SinewaveTelemetrySeries.prototype.getData = function () {
return this.data;
};
return SinewaveTelemetrySeries;
});

View File

@ -0,0 +1,115 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define([
'text!./generatorWorker.js',
'uuid'
], function (
workerText,
uuid
) {
var workerBlob = new Blob(
[workerText],
{type: 'application/javascript'}
);
var workerUrl = URL.createObjectURL(workerBlob);
function WorkerInterface() {
this.worker = new Worker(workerUrl);
this.worker.onmessage = this.onMessage.bind(this);
this.callbacks = {};
}
WorkerInterface.prototype.onMessage = function (message) {
message = message.data;
var callback = this.callbacks[message.id];
if (callback) {
if (callback(message)) {
delete this.callbacks[message.id];
}
}
};
WorkerInterface.prototype.dispatch = function (request, data, callback) {
var message = {
request: request,
data: data,
id: uuid()
};
if (callback) {
this.callbacks[message.id] = callback;
}
this.worker.postMessage(message);
return message.id;
};
WorkerInterface.prototype.request = function (request) {
var deferred = {};
var promise = new Promise(function (resolve, reject) {
deferred.resolve = resolve;
deferred.reject = reject;
});
function callback(message) {
if (message.error) {
deferred.reject(message.error);
} else {
deferred.resolve(message.data);
}
return true;
}
this.dispatch('request', request, callback);
return promise;
};
WorkerInterface.prototype.subscribe = function (request, cb) {
var isCancelled = false;
var callback = function (message) {
if (isCancelled) {
return true;
}
cb(message.data);
};
var messageId = this.dispatch('subscribe', request, callback)
return function () {
isCancelled = true;
this.dispatch('unsubscribe', {
id: messageId
});
}.bind(this);
};
return WorkerInterface;
});

View File

@ -1,144 +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.
*****************************************************************************/
/*global define*/
define([
"./src/SinewaveTelemetryProvider",
"./src/SinewaveLimitCapability",
"./src/SinewaveDeltaFormat",
'legacyRegistry'
], function (
SinewaveTelemetryProvider,
SinewaveLimitCapability,
SinewaveDeltaFormat,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/generator", {
"name": "Sine Wave Generator",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"extensions": {
"components": [
{
"implementation": SinewaveTelemetryProvider,
"type": "provider",
"provides": "telemetryService",
"depends": [
"$q",
"$timeout"
]
}
],
"capabilities": [
{
"key": "limit",
"implementation": SinewaveLimitCapability
}
],
"formats": [
{
"key": "example.delta",
"implementation": SinewaveDeltaFormat
}
],
"constants": [
{
"key": "TIME_CONDUCTOR_DOMAINS",
"value": [
{
"key": "time",
"name": "Time"
},
{
"key": "yesterday",
"name": "Yesterday"
},
{
"key": "delta",
"name": "Delta",
"format": "example.delta"
}
],
"priority": -1
}
],
"types": [
{
"key": "generator",
"name": "Sine Wave Generator",
"cssclass": "icon-telemetry",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"priority": 10,
"features": "creation",
"model": {
"telemetry": {
"period": 10
}
},
"telemetry": {
"source": "generator",
"domains": [
{
"key": "time",
"name": "Time"
},
{
"key": "yesterday",
"name": "Yesterday"
},
{
"key": "delta",
"name": "Delta",
"format": "example.delta"
}
],
"ranges": [
{
"key": "sin",
"name": "Sine"
},
{
"key": "cos",
"name": "Cosine"
}
]
},
"properties": [
{
"name": "Period",
"control": "textfield",
"cssclass": "l-input-sm l-numeric",
"key": "period",
"required": true,
"property": [
"telemetry",
"period"
],
"pattern": "^\\d*(\\.\\d*)?$"
}
]
}
]
}
});
});

View File

@ -0,0 +1,155 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global self*/
(function () {
var FIFTEEN_MINUTES = 15 * 60 * 1000;
var handlers = {
subscribe: onSubscribe,
unsubscribe: onUnsubscribe,
request: onRequest
};
var subscriptions = {};
function workSubscriptions(timestamp) {
var now = Date.now();
var nextWork = Math.min.apply(Math, Object.values(subscriptions).map(function (subscription) {
return subscription(now);
}));
var wait = nextWork - now;
if (wait < 0) {
wait = 0;
}
if (Number.isFinite(wait)) {
setTimeout(workSubscriptions, wait);
}
}
function onSubscribe(message) {
var data = message.data;
// Keep
var start = Date.now();
var step = 1000 / data.dataRateInHz;
var nextStep = start - (start % step) + step;
function work(now) {
while (nextStep < now) {
self.postMessage({
id: message.id,
data: {
utc: nextStep,
yesterday: nextStep - 60*60*24*1000,
delta: 60*60*24*1000,
sin: sin(nextStep, data.period, data.amplitude, data.offset),
cos: cos(nextStep, data.period, data.amplitude, data.offset)
}
});
nextStep += step;
}
return nextStep;
}
subscriptions[message.id] = work;
workSubscriptions();
}
function onUnsubscribe(message) {
delete subscriptions[message.data.id];
}
function onRequest(message) {
var data = message.data;
if (data.end == undefined) {
data.end = Date.now();
}
if (data.start == undefined){
data.start = data.end - FIFTEEN_MINUTES;
}
var now = Date.now();
var start = data.start;
var end = data.end > now ? now : data.end;
var amplitude = data.amplitude;
var period = data.period;
var offset = data.offset;
var dataRateInHz = data.dataRateInHz;
var step = 1000 / dataRateInHz;
var nextStep = start - (start % step) + step;
var data = [];
for (; nextStep < end; nextStep += step) {
data.push({
utc: nextStep,
yesterday: nextStep - 60*60*24*1000,
delta: 60*60*24*1000,
sin: sin(nextStep, period, amplitude, offset),
cos: cos(nextStep, period, amplitude, offset)
});
}
self.postMessage({
id: message.id,
data: data
});
}
function cos(timestamp, period, amplitude, offset) {
return amplitude *
Math.cos(timestamp / period / 1000 * Math.PI * 2) + offset;
}
function sin(timestamp, period, amplitude, offset) {
return amplitude *
Math.sin(timestamp / period / 1000 * Math.PI * 2) + offset;
}
function sendError(error, message) {
self.postMessage({
error: error.name + ': ' + error.message,
message: message,
id: message.id
});
}
self.onmessage = function handleMessage(event) {
var message = event.data;
var handler = handlers[message.request];
if (!handler) {
sendError(new Error('unknown message type'), message);
} else {
try {
handler(message);
} catch (e) {
sendError(e, message);
}
}
};
}());

171
example/generator/plugin.js Normal file
View File

@ -0,0 +1,171 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define([
"./GeneratorProvider",
"./SinewaveLimitCapability",
"./SinewaveDeltaFormat"
], function (
GeneratorProvider,
SinewaveLimitCapability,
SinewaveDeltaFormat
) {
var legacyExtensions = {
"capabilities": [
{
"key": "limit",
"implementation": SinewaveLimitCapability
}
],
"formats": [
{
"key": "example.delta",
"implementation": SinewaveDeltaFormat
}
],
"constants": [
{
"key": "TIME_CONDUCTOR_DOMAINS",
"value": [
{
"key": "time",
"name": "Time"
},
{
"key": "yesterday",
"name": "Yesterday"
},
{
"key": "delta",
"name": "Delta"
}
],
"priority": -1
}
]
}
return function(openmct){
//Register legacy extensions for things not yet supported by the new API
Object.keys(legacyExtensions).forEach(function (type){
var extensionsOfType = legacyExtensions[type];
extensionsOfType.forEach(function (extension) {
openmct.legacyExtension(type, extension)
})
});
openmct.types.addType("generator", {
label: "Sine Wave Generator",
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
cssClass: "icon-telemetry",
creatable: true,
form: [
{
name: "Period",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "period",
required: true,
property: [
"telemetry",
"period"
],
pattern: "^\\d*(\\.\\d*)?$"
},
{
name: "Amplitude",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "amplitude",
required: true,
property: [
"telemetry",
"amplitude"
],
pattern: "^\\d*(\\.\\d*)?$"
},
{
name: "Offset",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "offset",
required: true,
property: [
"telemetry",
"offset"
],
pattern: "^\\d*(\\.\\d*)?$"
},
{
name: "Data Rate (hz)",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "dataRateInHz",
required: true,
property: [
"telemetry",
"dataRateInHz"
],
pattern: "^\\d*(\\.\\d*)?$"
}
],
initialize: function (object) {
object.telemetry = {
period: 10,
amplitude: 1,
offset: 0,
dataRateInHz: 1,
domains: [
{
key: "utc",
name: "Time",
format: "utc"
},
{
key: "yesterday",
name: "Yesterday",
format: "utc"
},
{
key: "delta",
name: "Delta",
format: "example.delta"
}
],
ranges: [
{
key: "sin",
name: "Sine"
},
{
key: "cos",
name: "Cosine"
}
]
};
}
});
openmct.telemetry.addProvider(new GeneratorProvider());
};
});

View File

@ -1,119 +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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SinewaveTelemetryProvider. Created by vwoeltje on 11/12/14.
*/
define(
["./SinewaveTelemetrySeries"],
function (SinewaveTelemetrySeries) {
"use strict";
/**
*
* @constructor
*/
function SinewaveTelemetryProvider($q, $timeout) {
var subscriptions = [],
generating = false;
//
function matchesSource(request) {
return request.source === "generator";
}
// Used internally; this will be repacked by doPackage
function generateData(request) {
return {
key: request.key,
telemetry: new SinewaveTelemetrySeries(request)
};
}
//
function doPackage(results) {
var packaged = {};
results.forEach(function (result) {
packaged[result.key] = result.telemetry;
});
// Format as expected (sources -> keys -> telemetry)
return { generator: packaged };
}
function requestTelemetry(requests) {
return $timeout(function () {
return doPackage(requests.filter(matchesSource).map(generateData));
}, 0);
}
function handleSubscriptions() {
subscriptions.forEach(function (subscription) {
var requests = subscription.requests;
subscription.callback(doPackage(
requests.filter(matchesSource).map(generateData)
));
});
}
function startGenerating() {
generating = true;
$timeout(function () {
handleSubscriptions();
if (generating && subscriptions.length > 0) {
startGenerating();
} else {
generating = false;
}
}, 1000);
}
function subscribe(callback, requests) {
var subscription = {
callback: callback,
requests: requests
};
function unsubscribe() {
subscriptions = subscriptions.filter(function (s) {
return s !== subscription;
});
}
subscriptions.push(subscription);
if (!generating) {
startGenerating();
}
return unsubscribe;
}
return {
requestTelemetry: requestTelemetry,
subscribe: subscribe
};
}
return SinewaveTelemetryProvider;
}
);

View File

@ -1,78 +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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SinewaveTelemetry. Created by vwoeltje on 11/12/14.
*/
define(
['./SinewaveConstants'],
function (SinewaveConstants) {
"use strict";
var ONE_DAY = 60 * 60 * 24,
firstObservedTime = Math.floor(SinewaveConstants.START_TIME / 1000);
/**
*
* @constructor
*/
function SinewaveTelemetrySeries(request) {
var timeOffset = (request.domain === 'yesterday') ? ONE_DAY : 0,
latestTime = Math.floor(Date.now() / 1000) - timeOffset,
firstTime = firstObservedTime - timeOffset,
endTime = (request.end !== undefined) ?
Math.floor(request.end / 1000) : latestTime,
count = Math.min(endTime, latestTime) - firstTime,
period = +request.period || 30,
generatorData = {},
requestStart = (request.start === undefined) ? firstTime :
Math.max(Math.floor(request.start / 1000), firstTime),
offset = requestStart - firstTime;
if (request.size !== undefined) {
offset = Math.max(offset, count - request.size);
}
generatorData.getPointCount = function () {
return count - offset;
};
generatorData.getDomainValue = function (i, domain) {
// delta uses the same numeric values as the default domain,
// so it's not checked for here, just formatted for display
// differently.
return (i + offset) * 1000 + firstTime * 1000 -
(domain === 'yesterday' ? (ONE_DAY * 1000) : 0);
};
generatorData.getRangeValue = function (i, range) {
range = range || "sin";
return Math[range]((i + offset) * Math.PI * 2 / period);
};
return generatorData;
}
return SinewaveTelemetrySeries;
}
);

View File

@ -49,7 +49,7 @@ define([
{
"key": "imagery",
"name": "Example Imagery",
"cssclass": "icon-image",
"cssClass": "icon-image",
"features": "creation",
"description": "For development use. Creates example imagery data that mimics a live imagery stream.",
"priority": 10,

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['../../../platform/features/conductor-v2/conductor/src/timeSystems/LocalClock'], function (LocalClock) {
define(['../../../platform/features/conductor/core/src/timeSystems/LocalClock'], function (LocalClock) {
/**
* @implements TickSource
* @constructor
@ -31,7 +31,7 @@ define(['../../../platform/features/conductor-v2/conductor/src/timeSystems/Local
this.metadata = {
key: 'test-lad',
mode: 'lad',
cssclass: 'icon-clock',
cssClass: 'icon-clock',
label: 'Latest Available Data',
name: 'Latest available data',
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'

View File

@ -21,8 +21,8 @@
*****************************************************************************/
define([
'../../../platform/features/conductor-v2/conductor/src/timeSystems/TimeSystem',
'../../../platform/features/conductor-v2/conductor/src/timeSystems/LocalClock',
'../../../platform/features/conductor/core/src/timeSystems/TimeSystem',
'../../../platform/features/conductor/core/src/timeSystems/LocalClock',
'./LADTickSource'
], function (TimeSystem, LocalClock, LADTickSource) {
var THIRTY_MINUTES = 30 * 60 * 1000,

View File

@ -37,74 +37,79 @@ define([
legacyRegistry.register("example/msl", {
"name" : "Mars Science Laboratory Data Adapter",
"extensions" : {
"types": [
{
"name":"Mars Science Laboratory",
"key": "msl.curiosity",
"cssclass": "icon-object"
},
{
"name": "Instrument",
"key": "msl.instrument",
"cssclass": "icon-object",
"model": {"composition": []}
},
{
"name": "Measurement",
"key": "msl.measurement",
"cssclass": "icon-telemetry",
"model": {"telemetry": {}},
"telemetry": {
"source": "rems.source",
"domains": [
{
"name": "Time",
"key": "timestamp",
"format": "utc"
}
]
"types": [
{
"name":"Mars Science Laboratory",
"key": "msl.curiosity",
"cssClass": "icon-object"
},
{
"name": "Instrument",
"key": "msl.instrument",
"cssClass": "icon-object",
"model": {"composition": []}
},
{
"name": "Measurement",
"key": "msl.measurement",
"cssClass": "icon-telemetry",
"model": {"telemetry": {}},
"telemetry": {
"source": "rems.source",
"domains": [
{
"name": "Time",
"key": "utc",
"format": "utc"
}
]
}
}
}
],
"constants": [
{
"key": "REMS_WS_URL",
"value": "/proxyUrl?url=http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php"
}
],
"roots": [
{
"id": "msl:curiosity",
"priority" : "preferred",
"model": {
"type": "msl.curiosity",
"name": "Mars Science Laboratory",
"composition": ["msl_tlm:rems"]
],
"constants": [
{
"key": "REMS_WS_URL",
"value": "/proxyUrl?url=http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php"
}
}
],
"services": [
{
"key":"rems.adapter",
"implementation": RemsTelemetryServerAdapter,
"depends": ["$q", "$http", "$log", "REMS_WS_URL"]
}
],
"components": [
{
"provides": "modelService",
"type": "provider",
"implementation": RemsTelemetryModelProvider,
"depends": ["rems.adapter"]
},
{
"provides": "telemetryService",
"type": "provider",
"implementation": RemsTelemetryProvider,
"depends": ["rems.adapter", "$q"]
}
]
}
],
"roots": [
{
"id": "msl:curiosity"
}
],
"models": [
{
"id": "msl:curiosity",
"priority": "preferred",
"model": {
"type": "msl.curiosity",
"name": "Mars Science Laboratory",
"composition": ["msl_tlm:rems"]
}
}
],
"services": [
{
"key":"rems.adapter",
"implementation": RemsTelemetryServerAdapter,
"depends": ["$q", "$http", "$log", "REMS_WS_URL"]
}
],
"components": [
{
"provides": "modelService",
"type": "provider",
"implementation": RemsTelemetryModelProvider,
"depends": ["rems.adapter"]
},
{
"provides": "telemetryService",
"type": "provider",
"implementation": RemsTelemetryProvider,
"depends": ["rems.adapter", "$q"]
}
]
}
});
});

View File

@ -81,7 +81,7 @@ define([
{
"key": "plot",
"name": "Example Telemetry Plot",
"cssclass": "icon-telemetry-panel",
"cssClass": "icon-telemetry-panel",
"description": "For development use. A plot for displaying telemetry.",
"priority": 10,
"delegates": [
@ -129,7 +129,7 @@ define([
{
"name": "Period",
"control": "textfield",
"cssclass": "l-input-sm l-numeric",
"cssClass": "l-input-sm l-numeric",
"key": "period",
"required": true,
"property": [

View File

@ -63,7 +63,7 @@ define(
* Get the CSS class that defines the icon
* to display in this indicator. This will appear
* as a dataflow icon.
* @returns {string} the cssclass of the dataflow icon
* @returns {string} the cssClass of the dataflow icon
*/
getCssClass: function () {
return "icon-connectivity";

View File

@ -33,6 +33,11 @@ define([
legacyRegistry.register("example/scratchpad", {
"extensions": {
"roots": [
{
"id": "scratch:root"
}
],
"models": [
{
"id": "scratch:root",
"model": {

View File

@ -35,6 +35,11 @@ define([
"description": "Example illustrating the addition of a static top-level hierarchy",
"extensions": {
"roots": [
{
"id": "exampleTaxonomy"
}
],
"models": [
{
"id": "exampleTaxonomy",
"model": {

View File

@ -42,9 +42,6 @@ var gulp = require('gulp'),
specs: [ 'platform/**/*Spec.js', 'src/**/*Spec.js' ],
},
options = {
babel: {
presets: ['es2015']
},
requirejsOptimize: {
name: 'bower_components/almond/almond.js',
include: paths.main.replace('.js', ''),
@ -72,13 +69,16 @@ var gulp = require('gulp'),
}
};
if (process.env.NODE_ENV === 'development') {
options.requirejsOptimize.optimize = 'none';
}
gulp.task('scripts', function () {
var babel = require('gulp-babel');
var requirejsOptimize = require('gulp-requirejs-optimize');
var replace = require('gulp-replace-task');
return gulp.src(paths.main)
.pipe(sourcemaps.init())
.pipe(babel(options.babel))
.pipe(requirejsOptimize(options.requirejsOptimize))
.pipe(sourcemaps.write('.'))
.pipe(replace(options.replace))
@ -131,10 +131,17 @@ gulp.task('lint', function () {
gulp.task('checkstyle', function () {
var jscs = require('gulp-jscs');
var mkdirp = require('mkdirp');
var reportName = 'jscs-html-report.html';
var reportPath = path.resolve(paths.reports, 'checkstyle', reportName);
var moveReport = fs.rename.bind(fs, reportName, reportPath, _.noop);
mkdirp.sync(path.resolve(paths.reports, 'checkstyle'));
return gulp.src(paths.scripts)
.pipe(jscs())
.pipe(jscs.reporter())
.pipe(jscs.reporter('jscs-html-reporter')).on('finish', moveReport)
.pipe(jscs.reporter('fail'));
});

View File

@ -25,19 +25,32 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title></title>
<script src="openmct-tutorial/lib/http.js">
</script>
<script src="bower_components/requirejs/require.js">
</script>
<script src="openmct-tutorial/dictionary-plugin.js">
</script>
<script src="openmct-tutorial/realtime-telemetry-plugin.js">
</script>
<script src="openmct-tutorial/historical-telemetry-plugin.js">
</script>
<script>
require(['openmct'], function (openmct) {
[
'example/imagery',
'example/eventGenerator',
'example/generator',
'platform/features/my-items',
'platform/persistence/local'
'example/eventGenerator'
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(DictionaryPlugin());
openmct.install(RealtimeTelemetryPlugin());
openmct.install(HistoricalTelemetryPlugin());
openmct.start();
});
</script>

View File

@ -53,14 +53,10 @@ module.exports = function(config) {
// Preprocess matching files before serving them to the browser.
// https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'openmct.js': ['babel'],
'test-main.js': ['babel'],
'src/**/*.js': ['babel'],
'platform/**/src/**/*.js': ['babel'],
'platform/**/test/**/*.js': ['babel'],
'src/**/src/**/!(*Spec).js': [ 'coverage' ],
'platform/**/src/**/!(*Spec).js': [ 'coverage' ]
},
// Test results reporter to use
// Possible values: 'dots', 'progress'
// Available reporters: https://npmjs.org/browse/keyword/karma-reporter
@ -80,7 +76,7 @@ module.exports = function(config) {
// Specify browsers to run tests in.
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'PhantomJS'
'Chrome'
],
// Code coverage reporting.

1
openmct-tutorial Submodule

Submodule openmct-tutorial added at 7076a15d3a

View File

@ -23,7 +23,6 @@
requirejs.config({
"paths": {
"browser-polyfill": "bower_components/babel-polyfill/browser-polyfill", // ES6 browser polyfill, must be included before any other loads
"legacyRegistry": "src/legacyRegistry",
"angular": "bower_components/angular/angular.min",
"angular-route": "bower_components/angular-route/angular-route.min",
@ -85,5 +84,11 @@ define([
return new Main().run(defaultRegistry);
});
// For now, install conductor by default
openmct.install(openmct.plugins.Conductor({
showConductor: false
}));
return openmct;
});

View File

@ -8,12 +8,10 @@
"request": "^2.69.0"
},
"devDependencies": {
"babel-preset-es2015": "^6.18.0",
"bower": "^1.7.7",
"git-rev-sync": "^1.4.0",
"glob": ">= 3.0.0",
"gulp": "^3.9.0",
"gulp-babel": "^6.1.2",
"gulp-jscs": "^3.0.2",
"gulp-jshint": "^2.0.0",
"gulp-jshint-html-reporter": "^0.1.3",
@ -23,17 +21,16 @@
"gulp-sass": "^2.2.0",
"gulp-sourcemaps": "^1.6.0",
"jasmine-core": "^2.3.0",
"jscs-html-reporter": "^0.1.0",
"jsdoc": "^3.3.2",
"jshint": "^2.7.0",
"karma": "^0.13.3",
"karma-babel-preprocessor": "^6.0.1",
"karma-chrome-launcher": "^0.1.8",
"karma-chrome-launcher": "^0.1.12",
"karma-cli": "0.0.4",
"karma-coverage": "^0.5.3",
"karma-html-reporter": "^0.2.7",
"karma-jasmine": "^0.1.5",
"karma-junit-reporter": "^0.3.8",
"karma-phantomjs-launcher": "^1.0.0",
"karma-requirejs": "^0.2.2",
"lodash": "^3.10.1",
"markdown-toc": "^0.11.7",
@ -42,7 +39,6 @@
"mkdirp": "^0.5.1",
"moment": "^2.11.1",
"node-bourbon": "^4.2.3",
"phantomjs-prebuilt": "2.1.11 || >2.1.12 <3.0.0",
"requirejs": "2.1.x",
"split": "^1.0.0"
},

View File

@ -41,7 +41,6 @@ define([
"text!./res/templates/items/items.html",
"text!./res/templates/browse/object-properties.html",
"text!./res/templates/browse/inspector-region.html",
"text!./res/templates/view-object.html",
'legacyRegistry'
], function (
BrowseController,
@ -64,7 +63,6 @@ define([
itemsTemplate,
objectPropertiesTemplate,
inspectorRegionTemplate,
viewObjectTemplate,
legacyRegistry
) {
@ -72,14 +70,13 @@ define([
"extensions": {
"routes": [
{
"when": "/browse/:ids*",
"when": "/browse/:ids*?",
"template": browseTemplate,
"reloadOnSearch": false
},
{
"when": "",
"template": browseTemplate,
"reloadOnSearch": false
"redirectTo": "/browse/"
}
],
"constants": [
@ -142,10 +139,6 @@ define([
}
],
"representations": [
{
"key": "view-object",
"template": viewObjectTemplate
},
{
"key": "browse-object",
"template": browseObjectTemplate,
@ -205,7 +198,10 @@ define([
"services": [
{
"key": "navigationService",
"implementation": NavigationService
"implementation": NavigationService,
"depends": [
"$window"
]
}
],
"actions": [
@ -213,10 +209,7 @@ define([
"key": "navigate",
"implementation": NavigateAction,
"depends": [
"navigationService",
"$q",
"policyService",
"$window"
"navigationService"
]
},
{
@ -233,7 +226,7 @@ define([
"$window"
],
"group": "windowing",
"cssclass": "icon-new-window",
"cssClass": "icon-new-window",
"priority": "preferred"
},
{
@ -248,7 +241,7 @@ define([
{
"key": "items",
"name": "Items",
"cssclass": "icon-thumbs-strip",
"cssClass": "icon-thumbs-strip",
"description": "Grid of available items",
"template": itemsTemplate,
"uses": [

View File

@ -63,7 +63,7 @@
<mct-split-pane class='l-object-and-inspector contents abs' anchor='right'>
<div class='split-pane-component t-object pane primary-pane left'>
<mct-representation mct-object="navigatedObject"
key="'view-object'"
key="navigatedObject.getCapability('status').get('editing') ? 'edit-object' : 'browse-object'"
class="abs holder holder-object">
</mct-representation>
<a class="mini-tab-icon anchor-right mobile-hide toggle-pane toggle-inspect flush-right"

View File

@ -1,33 +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.
-->
<!--
A representation that allows the 'View' region of an object view to change
dynamically (eg. between browse and edit modes). Values correspond to a
representation key, and currently defaults to 'browse-object'.
In the case of edit, the EditRepresenter will change this to editable
representation of the object as needed.
-->
<mct-representation mct-object="domainObject"
key="viewObjectTemplate || 'browse-object'"
class="abs holder">
</mct-representation>

View File

@ -28,8 +28,6 @@ define(
[],
function () {
var ROOT_ID = "ROOT";
/**
* The BrowseController is used to populate the initial scope in Browse
* mode. It loads the root object from the objectService and makes it
@ -49,74 +47,26 @@ define(
urlService,
defaultPath
) {
var path = [ROOT_ID].concat(
($route.current.params.ids || defaultPath).split("/")
);
var initialPath = ($route.current.params.ids || defaultPath).split("/");
var currentIds;
function updateRoute(domainObject) {
var priorRoute = $route.current,
// Act as if params HADN'T changed to avoid page reload
unlisten;
unlisten = $scope.$on('$locationChangeSuccess', function () {
// Checks path to make sure /browse/ is at front
// if so, change $route.current
if ($location.path().indexOf("/browse/") === 0) {
$route.current = priorRoute;
}
unlisten();
});
// urlService.urlForLocation used to adjust current
// path to new, addressed, path based on
// domainObject
$location.path(urlService.urlForLocation("browse", domainObject));
$scope.treeModel = {
selectedObject: undefined,
onSelection: function (object) {
navigationService.setNavigation(object, true);
},
allowSelection: function (object) {
return navigationService.shouldNavigate();
}
};
function idsForObject(domainObject) {
return urlService
.urlForLocation("", domainObject)
.replace('/', '');
}
function setScopeObjects(domainObject, navigationAllowed) {
if (navigationAllowed) {
$scope.navigatedObject = domainObject;
$scope.treeModel.selectedObject = domainObject;
updateRoute(domainObject);
} else {
//If navigation was unsuccessful (ie. blocked), reset
// the selected object in the tree to the currently
// navigated object
$scope.treeModel.selectedObject = $scope.navigatedObject ;
}
}
// Callback for updating the in-scope reference to the object
// that is currently navigated-to.
function setNavigation(domainObject) {
if (domainObject === $scope.navigatedObject) {
//do nothing;
return;
}
if (domainObject) {
domainObject.getCapability("action").perform("navigate").then(setScopeObjects.bind(undefined, domainObject));
} else {
setScopeObjects(domainObject, true);
}
}
function navigateTo(domainObject) {
// Check if an object has been navigated-to already...
// If not, or if an ID path has been explicitly set in the URL,
// navigate to the URL-specified object.
if (!navigationService.getNavigation() || $route.current.params.ids) {
// If not, pick a default as the last
// root-level component (usually "mine")
navigationService.setNavigation(domainObject);
$scope.navigatedObject = domainObject;
} else {
// Otherwise, just expose the currently navigated object.
$scope.navigatedObject = navigationService.getNavigation();
updateRoute($scope.navigatedObject);
}
}
// Find an object in an array of objects.
function findObject(domainObjects, id) {
var i;
for (i = 0; i < domainObjects.length; i += 1) {
@ -126,63 +76,87 @@ define(
}
}
// Navigate to the domain object identified by path[index],
// which we expect to find in the composition of the passed
// domain object.
function doNavigate(domainObject, index) {
var composition = domainObject.useCapability("composition");
if (composition) {
composition.then(function (c) {
var nextObject = findObject(c, path[index]);
if (nextObject) {
if (index + 1 >= path.length) {
navigateTo(nextObject);
} else {
doNavigate(nextObject, index + 1);
}
} else if (index === 1 && c.length > 0) {
// Roots are in a top-level container that we don't
// want to be selected, so if we couldn't find an
// object at the path we wanted, at least select
// one of its children.
navigateTo(c[c.length - 1]);
} else {
// Couldn't find the next element of the path
// so navigate to the last path object we did find
navigateTo(domainObject);
}
// helper, fetch a single object from the object service.
function getObject(id) {
return objectService.getObjects([id])
.then(function (results) {
return results[id];
});
} else {
// Similar to above case; this object has no composition,
// so navigate to it instead of subsequent path elements.
navigateTo(domainObject);
}
// recursively locate and return an object inside of a container
// via a path. If at any point in the recursion it fails to find
// the next object, it will return the parent.
function findViaComposition(containerObject, path) {
var nextId = path.shift();
if (!nextId) {
return containerObject;
}
return containerObject.useCapability('composition')
.then(function (composees) {
var nextObject = findObject(composees, nextId);
if (!nextObject) {
return containerObject;
}
if (!nextObject.hasCapability('composition')) {
return nextObject;
}
return findViaComposition(nextObject, path);
});
}
function navigateToObject(desiredObject) {
$scope.navigatedObject = desiredObject;
$scope.treeModel.selectedObject = desiredObject;
currentIds = idsForObject(desiredObject);
$route.current.pathParams.ids = currentIds;
$location.path('/browse/' + currentIds);
}
function navigateToPath(path) {
return getObject('ROOT')
.then(function (root) {
return findViaComposition(root, path);
})
.then(function (object) {
navigationService.setNavigation(object);
});
}
getObject('ROOT')
.then(function (root) {
$scope.domainObject = root;
navigateToPath(initialPath);
});
// Handle navigation events from view service. Only navigates
// if path has changed.
function navigateDirectlyToModel(domainObject) {
var newIds = idsForObject(domainObject);
if (currentIds !== newIds) {
currentIds = newIds;
navigateToObject(domainObject);
}
}
// Load the root object, put it in the scope.
// Also, load its immediate children, and (possibly)
// navigate to one of them, so that navigation state has
// a useful initial value.
objectService.getObjects([path[0]]).then(function (objects) {
$scope.domainObject = objects[path[0]];
doNavigate($scope.domainObject, 1);
});
// Provide a model for the tree to modify
$scope.treeModel = {
selectedObject: navigationService.getNavigation()
};
// Listen for changes in navigation state.
navigationService.addListener(setNavigation);
navigationService.addListener(navigateDirectlyToModel);
// Also listen for changes which come from the tree. Changes in
// the tree will trigger a change in browse navigation state.
$scope.$watch("treeModel.selectedObject", setNavigation);
// Listen for route changes which are caused by browser events
// (e.g. bookmarks to pages in OpenMCT) and prevent them. Instead,
// navigate to the path ourselves, which results in it being
// properly set.
$scope.$on('$routeChangeStart', function (event, route) {
if (route.$$route === $route.current.$$route &&
route.pathParams.ids !== $route.current.pathParams.ids) {
event.preventDefault();
navigateToPath(route.pathParams.ids.split('/'));
}
});
// Clean up when the scope is destroyed
$scope.$on("$destroy", function () {
navigationService.removeListener(setNavigation);
navigationService.removeListener(navigateDirectlyToModel);
});
}

View File

@ -51,24 +51,16 @@ define(
}
function updateQueryParam(viewKey) {
var unlisten,
priorRoute = $route.current;
if (viewKey) {
if (viewKey && $location.search().view !== viewKey) {
$location.search('view', viewKey);
unlisten = $scope.$on('$locationChangeSuccess', function () {
// Checks path to make sure /browse/ is at front
// if so, change $route.current
if ($location.path().indexOf("/browse/") === 0) {
$route.current = priorRoute;
}
unlisten();
});
}
}
$scope.$watch('domainObject', setViewForDomainObject);
$scope.$watch('representation.selected.key', updateQueryParam);
$scope.$on('$locationChangeSuccess', function () {
setViewForDomainObject($scope.domainObject);
});
$scope.doAction = function (action) {
return $scope[action] && $scope[action]();

View File

@ -64,11 +64,11 @@ define(
attachStatusListener(domainObject);
}
var navigationListener = navigationService.addListener(attachStatusListener);
navigationService.addListener(attachStatusListener);
$scope.$on("$destroy", function () {
statusListener();
navigationListener();
navigationService.removeListener(attachStatusListener);
});
}

View File

@ -33,12 +33,9 @@ define(
* @constructor
* @implements {Action}
*/
function NavigateAction(navigationService, $q, policyService, $window, context) {
function NavigateAction(navigationService, context) {
this.domainObject = context.domainObject;
this.$q = $q;
this.navigationService = navigationService;
this.policyService = policyService;
this.$window = $window;
}
/**
@ -47,36 +44,12 @@ define(
* navigation has been updated
*/
NavigateAction.prototype.perform = function () {
var self = this,
navigateTo = this.domainObject,
currentObject = self.navigationService.getNavigation();
function allow() {
var navigationAllowed = true;
self.policyService.allow("navigation", currentObject, navigateTo, function (message) {
navigationAllowed = self.$window.confirm(message + "\r\n\r\n" +
" Are you sure you want to continue?");
});
return navigationAllowed;
}
function cancelIfEditing() {
var editing = currentObject.hasCapability('editor') &&
currentObject.getCapability('editor').isEditContextRoot();
return self.$q.when(editing && currentObject.getCapability("editor").finish());
}
function navigate() {
return self.navigationService.setNavigation(navigateTo);
}
if (allow()) {
return cancelIfEditing().then(navigate);
} else {
return this.$q.when(false);
if (this.navigationService.shouldNavigate()) {
this.navigationService.setNavigation(this.domainObject, true);
return Promise.resolve({});
}
return Promise.reject('Navigation Prevented by User');
};
/**

View File

@ -30,16 +30,23 @@ define(
/**
* The navigation service maintains the application's current
* navigation state, and allows listening for changes thereto.
*
* @memberof platform/commonUI/browse
* @constructor
*/
function NavigationService() {
function NavigationService($window) {
this.navigated = undefined;
this.callbacks = [];
this.checks = [];
this.$window = $window;
this.oldUnload = $window.onbeforeunload;
$window.onbeforeunload = this.onBeforeUnload.bind(this);
}
/**
* Get the current navigation state.
*
* @returns {DomainObject} the object that is navigated-to
*/
NavigationService.prototype.getNavigation = function () {
@ -47,16 +54,33 @@ define(
};
/**
* Set the current navigation state. This will invoke listeners.
* Navigate to a specified object. If navigation checks exist and
* return reasons to prevent navigation, it will prompt the user before
* continuing. Trying to navigate to the currently navigated object will
* do nothing.
*
* If a truthy value is passed for `force`, it will skip navigation
* and will not prevent navigation to an already selected object.
*
* @param {DomainObject} domainObject the domain object to navigate to
* @param {Boolean} force if true, force navigation to occur.
* @returns {Boolean} true if navigation occured, otherwise false.
*/
NavigationService.prototype.setNavigation = function (value) {
if (this.navigated !== value) {
this.navigated = value;
this.callbacks.forEach(function (callback) {
callback(value);
});
NavigationService.prototype.setNavigation = function (domainObject, force) {
if (force) {
this.doNavigation(domainObject);
return true;
}
if (this.navigated === domainObject) {
return true;
}
var doNotNavigate = this.shouldWarnBeforeNavigate();
if (doNotNavigate && !this.$window.confirm(doNotNavigate)) {
return false;
}
this.doNavigation(domainObject);
return true;
};
@ -64,6 +88,7 @@ define(
* Listen for changes in navigation. The passed callback will
* be invoked with the new domain object of navigation when
* this changes.
*
* @param {function} callback the callback to invoke when
* navigation state changes
*/
@ -73,6 +98,7 @@ define(
/**
* Stop listening for changes in navigation state.
*
* @param {function} callback the callback which should
* no longer be invoked when navigation state
* changes
@ -83,6 +109,89 @@ define(
});
};
/**
* Check if navigation should proceed. May prompt a user for input
* if any checkFns return messages. Returns true if the user wishes to
* navigate, otherwise false. If using this prior to calling
* `setNavigation`, you should call `setNavigation` with `force=true`
* to prevent duplicate dialogs being displayed to the user.
*
* @returns {Boolean} true if the user wishes to navigate, otherwise false.
*/
NavigationService.prototype.shouldNavigate = function () {
var doNotNavigate = this.shouldWarnBeforeNavigate();
return !doNotNavigate || this.$window.confirm(doNotNavigate);
};
/**
* Register a check function to be called before any navigation occurs.
* Check functions should return a human readable "message" if
* there are any reasons to prevent navigation. Otherwise, they should
* return falsy. Returns a function which can be called to remove the
* check function.
*
* @param {Function} checkFn a function to call before navigation occurs.
* @returns {Function} removeCheck call to remove check
*/
NavigationService.prototype.checkBeforeNavigation = function (checkFn) {
this.checks.push(checkFn);
return function removeCheck() {
this.checks = this.checks.filter(function (fn) {
return checkFn !== fn;
});
}.bind(this);
};
/**
* Private method to actually perform navigation.
*
* @private
*/
NavigationService.prototype.doNavigation = function (value) {
this.navigated = value;
this.callbacks.forEach(function (callback) {
callback(value);
});
};
/**
* Returns either a false value, or a string that should be displayed
* to the user before navigation is allowed.
*
* @private
*/
NavigationService.prototype.shouldWarnBeforeNavigate = function () {
var reasons = [];
this.checks.forEach(function (checkFn) {
var reason = checkFn();
if (reason) {
reasons.push(reason);
}
});
if (reasons.length) {
return reasons.join('\n');
}
return false;
};
/**
* Listener for window on before unload event-- will warn before
* navigation is allowed.
*
* @private
*/
NavigationService.prototype.onBeforeUnload = function () {
var shouldWarnBeforeNavigate = this.shouldWarnBeforeNavigate();
if (shouldWarnBeforeNavigate) {
return shouldWarnBeforeNavigate;
}
if (this.oldUnload) {
return this.oldUnload.apply(undefined, [].slice.apply(arguments));
}
};
return NavigationService;
}
);

View File

@ -43,24 +43,24 @@ define([], function () {
return context.getParent();
}
function isOrphan(domainObject) {
var parent = getParent(domainObject),
composition = parent.getModel().composition,
id = domainObject.getId();
return !composition || (composition.indexOf(id) === -1);
}
function navigateToParent(domainObject) {
function preventOrphanNavigation(domainObject) {
var parent = getParent(domainObject);
return parent.getCapability('action').perform('navigate');
parent.useCapability('composition')
.then(function (composees) {
var isOrphan = composees.every(function (c) {
return c.getId() !== domainObject.getId();
});
if (isOrphan) {
parent.getCapability('action').perform('navigate');
}
});
}
function checkNavigation() {
var navigatedObject = navigationService.getNavigation();
if (navigatedObject.hasCapability('context') &&
isOrphan(navigatedObject)) {
if (navigatedObject.hasCapability('context')) {
if (!navigatedObject.getCapability('editor').isEditContextRoot()) {
navigateToParent(navigatedObject);
preventOrphanNavigation(navigatedObject);
}
}
}

View File

@ -46,12 +46,12 @@ define(
};
FullscreenAction.prototype.getMetadata = function () {
// We override getMetadata, because the icon cssclass and
// We override getMetadata, because the icon cssClass and
// description need to be determined at run-time
// based on whether or not we are currently
// full screen.
var metadata = Object.create(FullscreenAction);
metadata.cssclass = screenfull.isFullscreen ? "icon-fullscreen-expand" : "icon-fullscreen-collapse";
metadata.cssClass = screenfull.isFullscreen ? "icon-fullscreen-expand" : "icon-fullscreen-collapse";
metadata.description = screenfull.isFullscreen ?
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
metadata.group = "windowing";

View File

@ -24,8 +24,14 @@
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../src/BrowseController"],
function (BrowseController) {
[
"../src/BrowseController",
"../src/navigation/NavigationService"
],
function (
BrowseController,
NavigationService
) {
describe("The browse controller", function () {
var mockScope,
@ -35,18 +41,17 @@ define(
mockNavigationService,
mockRootObject,
mockUrlService,
mockDomainObject,
mockDefaultRootObject,
mockOtherDomainObject,
mockNextObject,
testDefaultRoot,
mockActionCapability,
controller;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
function waitsForNavigation() {
var calls = mockNavigationService.setNavigation.calls.length;
waitsFor(function () {
return mockNavigationService.setNavigation.calls.length > calls;
});
}
function instantiateController() {
@ -68,85 +73,114 @@ define(
"$scope",
["$on", "$watch"]
);
mockRoute = { current: { params: {} } };
mockLocation = jasmine.createSpyObj(
"$location",
["path"]
);
mockRoute = { current: { params: {}, pathParams: {} } };
mockUrlService = jasmine.createSpyObj(
"urlService",
["urlForLocation"]
);
mockUrlService.urlForLocation.andCallFake(function (mode, object) {
if (object === mockDefaultRootObject) {
return [mode, testDefaultRoot].join('/');
}
if (object === mockOtherDomainObject) {
return [mode, 'other'].join('/');
}
if (object === mockNextObject) {
return [mode, testDefaultRoot, 'next'].join('/');
}
throw new Error('Tried to get url for unexpected object');
});
mockLocation = jasmine.createSpyObj(
"$location",
["path"]
);
mockObjectService = jasmine.createSpyObj(
"objectService",
["getObjects"]
);
mockNavigationService = jasmine.createSpyObj(
"navigationService",
[
"getNavigation",
"setNavigation",
"addListener",
"removeListener"
]
);
mockNavigationService = new NavigationService({});
[
"getNavigation",
"setNavigation",
"addListener",
"removeListener"
].forEach(function (method) {
spyOn(mockNavigationService, method)
.andCallThrough();
});
mockRootObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability", "getModel", "useCapability"]
"rootObjectContainer",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability", "getModel", "useCapability"]
mockDefaultRootObject = jasmine.createSpyObj(
"defaultRootObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockOtherDomainObject = jasmine.createSpyObj(
"otherDomainObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockNextObject = jasmine.createSpyObj(
"nextObject",
["getId", "getCapability", "getModel", "useCapability"]
"nestedDomainObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockObjectService.getObjects.andReturn(mockPromise({
mockObjectService.getObjects.andReturn(Promise.resolve({
ROOT: mockRootObject
}));
mockRootObject.useCapability.andReturn(mockPromise([
mockDomainObject
mockRootObject.useCapability.andReturn(Promise.resolve([
mockOtherDomainObject,
mockDefaultRootObject
]));
mockDomainObject.useCapability.andReturn(mockPromise([
mockRootObject.hasCapability.andReturn(true);
mockDefaultRootObject.useCapability.andReturn(Promise.resolve([
mockNextObject
]));
mockDefaultRootObject.hasCapability.andReturn(true);
mockOtherDomainObject.hasCapability.andReturn(false);
mockNextObject.useCapability.andReturn(undefined);
mockNextObject.hasCapability.andReturn(false);
mockNextObject.getId.andReturn("next");
mockDomainObject.getId.andReturn(testDefaultRoot);
mockActionCapability = jasmine.createSpyObj('actionCapability', ['perform']);
mockDefaultRootObject.getId.andReturn(testDefaultRoot);
instantiateController();
waitsForNavigation();
});
it("uses composition to set the navigated object, if there is none", function () {
instantiateController();
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject);
waitsForNavigation();
runs(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
it("navigates to a root-level object, even when default path is not found", function () {
mockDomainObject.getId
mockDefaultRootObject.getId
.andReturn("something-other-than-the-" + testDefaultRoot);
instantiateController();
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject);
});
waitsForNavigation();
runs(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
//
it("does not try to override navigation", function () {
mockNavigationService.getNavigation.andReturn(mockDomainObject);
mockNavigationService.getNavigation.andReturn(mockDefaultRootObject);
instantiateController();
expect(mockScope.navigatedObject).toBe(mockDomainObject);
waitsForNavigation();
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
});
//
it("updates scope when navigated object changes", function () {
// Should have registered a listener - call it
mockNavigationService.addListener.mostRecentCall.args[0](
mockDomainObject
mockOtherDomainObject
);
expect(mockScope.navigatedObject).toEqual(mockDomainObject);
expect(mockScope.navigatedObject).toEqual(mockOtherDomainObject);
});
@ -166,9 +200,12 @@ define(
it("uses route parameters to choose initially-navigated object", function () {
mockRoute.current.params.ids = testDefaultRoot + "/next";
instantiateController();
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
waitsForNavigation();
runs(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
});
});
it("handles invalid IDs by going as far as possible", function () {
@ -177,9 +214,13 @@ define(
// it hits an invalid ID.
mockRoute.current.params.ids = testDefaultRoot + "/junk";
instantiateController();
expect(mockScope.navigatedObject).toBe(mockDomainObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject);
waitsForNavigation();
runs(function () {
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
it("handles compositionless objects by going as far as possible", function () {
@ -188,84 +229,33 @@ define(
// should stop at it since remaining IDs cannot be loaded.
mockRoute.current.params.ids = testDefaultRoot + "/next/junk";
instantiateController();
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
waitsForNavigation();
runs(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
});
});
it("updates the displayed route to reflect current navigation", function () {
var mockContext = jasmine.createSpyObj('context', ['getPath']),
mockUnlisten = jasmine.createSpy('unlisten'),
mockMode = "browse";
mockContext.getPath.andReturn(
[mockRootObject, mockDomainObject, mockNextObject]
);
//Return true from navigate action
mockActionCapability.perform.andReturn(mockPromise(true));
mockNextObject.getCapability.andCallFake(function (c) {
return (c === 'context' && mockContext) ||
(c === 'action' && mockActionCapability);
// In order to trigger a route update and not a route change,
// the current route must be updated before location.path is
// called.
expect(mockRoute.current.pathParams.ids)
.not
.toBe(testDefaultRoot + '/next');
mockLocation.path.andCallFake(function () {
expect(mockRoute.current.pathParams.ids)
.toBe(testDefaultRoot + '/next');
});
mockScope.$on.andReturn(mockUnlisten);
// Provide a navigation change
mockNavigationService.addListener.mostRecentCall.args[0](
mockNextObject
);
// Allows the path index to be checked
// prior to setting $route.current
mockLocation.path.andReturn("/browse/");
mockNavigationService.setNavigation.andReturn(true);
mockActionCapability.perform.andReturn(mockPromise(true));
// Exercise the Angular workaround
mockNavigationService.addListener.mostRecentCall.args[0]();
mockScope.$on.mostRecentCall.args[1]();
expect(mockUnlisten).toHaveBeenCalled();
// location.path to be called with the urlService's
// urlFor function with the next domainObject and mode
expect(mockLocation.path).toHaveBeenCalledWith(
mockUrlService.urlForLocation(mockMode, mockNextObject)
'/browse/' + testDefaultRoot + '/next'
);
});
it("after successful navigation event sets the selected tree " +
"object", function () {
mockScope.navigatedObject = mockDomainObject;
mockNavigationService.setNavigation.andReturn(true);
mockActionCapability.perform.andReturn(mockPromise(true));
mockNextObject.getCapability.andReturn(mockActionCapability);
//Simulate a change in selected tree object
mockScope.treeModel = {selectedObject: mockDomainObject};
mockScope.$watch.mostRecentCall.args[1](mockNextObject);
expect(mockScope.treeModel.selectedObject).toBe(mockNextObject);
expect(mockScope.treeModel.selectedObject).not.toBe(mockDomainObject);
});
it("after failed navigation event resets the selected tree" +
" object", function () {
mockScope.navigatedObject = mockDomainObject;
//Return false from navigation action
mockActionCapability.perform.andReturn(mockPromise(false));
mockNextObject.getCapability.andReturn(mockActionCapability);
//Simulate a change in selected tree object
mockScope.treeModel = {selectedObject: mockDomainObject};
mockScope.$watch.mostRecentCall.args[1](mockNextObject);
expect(mockScope.treeModel.selectedObject).not.toBe(mockNextObject);
expect(mockScope.treeModel.selectedObject).toBe(mockDomainObject);
});
});
}
);

View File

@ -29,7 +29,6 @@ define(
var mockScope,
mockLocation,
mockRoute,
mockUnlisten,
controller;
// Utility function; look for a $watch on scope and fire it
@ -51,9 +50,7 @@ define(
"$location",
["path", "search"]
);
mockUnlisten = jasmine.createSpy("unlisten");
mockScope.$on.andReturn(mockUnlisten);
mockLocation.search.andReturn({});
controller = new BrowseObjectController(
mockScope,
@ -69,10 +66,6 @@ define(
// Allows the path index to be checked
// prior to setting $route.current
mockLocation.path.andReturn("/browse/");
// Exercise the Angular workaround
mockScope.$on.mostRecentCall.args[1]();
expect(mockUnlisten).toHaveBeenCalled();
});
it("sets the active view from query parameters", function () {

View File

@ -23,145 +23,74 @@
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/navigation/NavigateAction"],
function (NavigateAction) {
define([
"../../src/navigation/NavigateAction"
], function (
NavigateAction
) {
describe("The navigate action", function () {
var mockNavigationService,
mockQ,
mockDomainObject,
mockPolicyService,
mockNavigatedObject,
mockWindow,
capabilities,
action;
describe("The navigate action", function () {
var mockNavigationService,
mockDomainObject,
action;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
capabilities = {};
mockQ = { when: mockPromise };
mockNavigatedObject = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"hasCapability",
"getCapability"
]
);
capabilities.editor = jasmine.createSpyObj("editorCapability", [
"isEditContextRoot",
"finish"
]);
mockNavigatedObject.getCapability.andCallFake(function (capability) {
return capabilities[capability];
});
mockNavigatedObject.hasCapability.andReturn(false);
mockNavigationService = jasmine.createSpyObj(
"navigationService",
[
"setNavigation",
"getNavigation"
]
);
mockNavigationService.getNavigation.andReturn(mockNavigatedObject);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel"
]
);
mockPolicyService = jasmine.createSpyObj("policyService",
[
"allow"
]);
mockWindow = jasmine.createSpyObj("$window",
[
"confirm"
]);
action = new NavigateAction(
mockNavigationService,
mockQ,
mockPolicyService,
mockWindow,
{ domainObject: mockDomainObject }
);
function waitForCall() {
var called = false;
waitsFor(function () {
return called;
});
return function () {
called = true;
};
}
it("invokes the policy service to determine if navigation" +
" allowed", function () {
action.perform();
expect(mockPolicyService.allow)
.toHaveBeenCalledWith("navigation", jasmine.any(Object), jasmine.any(Object), jasmine.any(Function));
});
beforeEach(function () {
mockNavigationService = jasmine.createSpyObj(
"navigationService",
[
"shouldNavigate",
"setNavigation"
]
);
it("prompts user if policy rejection", function () {
action.perform();
expect(mockPolicyService.allow).toHaveBeenCalled();
mockPolicyService.allow.mostRecentCall.args[3]();
expect(mockWindow.confirm).toHaveBeenCalled();
});
describe("shows a prompt", function () {
beforeEach(function () {
// Ensure the allow callback is called synchronously
mockPolicyService.allow.andCallFake(function () {
return arguments[3]();
});
});
it("does not navigate on prompt rejection", function () {
mockWindow.confirm.andReturn(false);
action.perform();
expect(mockNavigationService.setNavigation)
.not.toHaveBeenCalled();
});
it("does navigate on prompt acceptance", function () {
mockWindow.confirm.andReturn(true);
action.perform();
expect(mockNavigationService.setNavigation)
.toHaveBeenCalled();
});
});
describe("in edit mode", function () {
beforeEach(function () {
mockNavigatedObject.hasCapability.andCallFake(function (capability) {
return capability === "editor";
});
capabilities.editor.isEditContextRoot.andReturn(true);
});
it("finishes editing if in edit mode", function () {
action.perform();
expect(capabilities.editor.finish)
.toHaveBeenCalled();
});
});
it("is only applicable when a domain object is in context", function () {
expect(NavigateAction.appliesTo({})).toBeFalsy();
expect(NavigateAction.appliesTo({
domainObject: mockDomainObject
})).toBeTruthy();
});
mockDomainObject = {};
action = new NavigateAction(
mockNavigationService,
{ domainObject: mockDomainObject }
);
});
}
);
it("sets navigation if it is allowed", function () {
mockNavigationService.shouldNavigate.andReturn(true);
action.perform()
.then(waitForCall());
runs(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject, true);
});
});
it("does not set navigation if it is not allowed", function () {
mockNavigationService.shouldNavigate.andReturn(false);
var onSuccess = jasmine.createSpy('onSuccess');
action.perform()
.then(onSuccess, waitForCall());
runs(function () {
expect(onSuccess).not.toHaveBeenCalled();
expect(mockNavigationService.setNavigation)
.not
.toHaveBeenCalledWith(mockDomainObject);
});
});
it("is only applicable when a domain object is in context", function () {
expect(NavigateAction.appliesTo({})).toBeFalsy();
expect(NavigateAction.appliesTo({
domainObject: mockDomainObject
})).toBeTruthy();
});
});
});

View File

@ -28,10 +28,12 @@ define(
function (NavigationService) {
describe("The navigation service", function () {
var navigationService;
var $window,
navigationService;
beforeEach(function () {
navigationService = new NavigationService();
$window = jasmine.createSpyObj('$window', ['confirm']);
navigationService = new NavigationService($window);
});
it("stores navigation state", function () {

View File

@ -33,7 +33,7 @@ define([
mockContext,
mockActionCapability,
mockEditor,
testParentModel,
testParentComposition,
testId,
mockThrottledFns;
@ -41,7 +41,6 @@ define([
testId = 'some-identifier';
mockThrottledFns = [];
testParentModel = {};
mockTopic = jasmine.createSpy('topic');
mockThrottle = jasmine.createSpy('throttle');
@ -55,14 +54,12 @@ define([
mockDomainObject = jasmine.createSpyObj('domainObject', [
'getId',
'getCapability',
'getModel',
'hasCapability'
]);
mockParentObject = jasmine.createSpyObj('domainObject', [
'getId',
'getCapability',
'getModel',
'hasCapability'
'useCapability'
]);
mockContext = jasmine.createSpyObj('context', ['getParent']);
mockActionCapability = jasmine.createSpyObj('action', ['perform']);
@ -75,9 +72,7 @@ define([
mockThrottledFns.push(mockThrottledFn);
return mockThrottledFn;
});
mockTopic.andCallFake(function (k) {
return k === 'mutation' && mockMutationTopic;
});
mockTopic.andReturn(mockMutationTopic);
mockDomainObject.getId.andReturn(testId);
mockDomainObject.getCapability.andCallFake(function (c) {
return {
@ -88,12 +83,13 @@ define([
mockDomainObject.hasCapability.andCallFake(function (c) {
return !!mockDomainObject.getCapability(c);
});
mockParentObject.getModel.andReturn(testParentModel);
mockParentObject.getCapability.andCallFake(function (c) {
return {
action: mockActionCapability
}[c];
});
testParentComposition = [];
mockParentObject.useCapability.andReturn(Promise.resolve(testParentComposition));
mockContext.getParent.andReturn(mockParentObject);
mockNavigationService.getNavigation.andReturn(mockDomainObject);
mockEditor.isEditContextRoot.andReturn(false);
@ -126,7 +122,9 @@ define([
var prefix = isOrphan ? "" : "non-";
describe("for " + prefix + "orphan objects", function () {
beforeEach(function () {
testParentModel.composition = isOrphan ? [] : [testId];
if (!isOrphan) {
testParentComposition.push(mockDomainObject);
}
});
[false, true].forEach(function (isEditRoot) {
@ -136,13 +134,31 @@ define([
function itNavigatesAsExpected() {
if (isOrphan && !isEditRoot) {
it("navigates to the parent", function () {
expect(mockActionCapability.perform)
.toHaveBeenCalledWith('navigate');
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
expect(mockActionCapability.perform)
.toHaveBeenCalledWith('navigate');
});
});
} else {
it("does nothing", function () {
expect(mockActionCapability.perform)
.not.toHaveBeenCalled();
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
expect(mockActionCapability.perform)
.not.toHaveBeenCalled();
});
});
}
}
@ -157,7 +173,6 @@ define([
mockNavigationService.addListener.mostRecentCall
.args[0](mockDomainObject);
});
itNavigatesAsExpected();
});

View File

@ -51,7 +51,7 @@ define(
});
it("provides displayable metadata", function () {
expect(action.getMetadata().cssclass).toBeDefined();
expect(action.getMetadata().cssClass).toBeDefined();
});
});

View File

@ -53,7 +53,8 @@ define([
"depends": [
"overlayService",
"$q",
"$log"
"$log",
"$document"
]
},
{

View File

@ -35,11 +35,15 @@ define(
* @memberof platform/commonUI/dialog
* @constructor
*/
function DialogService(overlayService, $q, $log) {
function DialogService(overlayService, $q, $log, $document) {
this.overlayService = overlayService;
this.$q = $q;
this.$log = $log;
this.activeOverlay = undefined;
this.findBody = function () {
return $document.find('body');
};
}
/**
@ -60,7 +64,8 @@ define(
// input is asynchronous.
var deferred = this.$q.defer(),
self = this,
overlay;
overlay,
handleEscKeydown;
// Confirm function; this will be passed in to the
// overlay-dialog template and associated with a
@ -76,13 +81,22 @@ define(
// Cancel or X button click
function cancel() {
deferred.reject();
self.findBody().off('keydown', handleEscKeydown);
self.dismissOverlay(overlay);
}
handleEscKeydown = function (event) {
if (event.keyCode === 27) {
cancel();
}
};
// Add confirm/cancel callbacks
model.confirm = confirm;
model.cancel = cancel;
this.findBody().on('keydown', handleEscKeydown);
if (this.canShowDialog(model)) {
// Add the overlay using the OverlayService, which
// will handle actual insertion into the DOM

View File

@ -33,6 +33,8 @@ define(
mockLog,
mockOverlay,
mockDeferred,
mockDocument,
mockBody,
dialogService;
beforeEach(function () {
@ -56,6 +58,13 @@ define(
"deferred",
["resolve", "reject"]
);
mockDocument = jasmine.createSpyObj(
"$document",
["find"]
);
mockBody = jasmine.createSpyObj('body', ['on', 'off']);
mockDocument.find.andReturn(mockBody);
mockDeferred.promise = "mock promise";
mockQ.defer.andReturn(mockDeferred);
@ -64,7 +73,8 @@ define(
dialogService = new DialogService(
mockOverlayService,
mockQ,
mockLog
mockLog,
mockDocument
);
});
@ -130,6 +140,36 @@ define(
);
});
it("adds a keydown event listener to the body", function () {
dialogService.getUserInput({}, {});
expect(mockDocument.find).toHaveBeenCalledWith("body");
expect(mockBody.on).toHaveBeenCalledWith("keydown", jasmine.any(Function));
});
it("destroys the event listener when the dialog is cancelled", function () {
dialogService.getUserInput({}, {});
mockOverlayService.createOverlay.mostRecentCall.args[1].cancel();
expect(mockBody.off).toHaveBeenCalledWith("keydown", jasmine.any(Function));
});
it("cancels the dialog when an escape keydown event is triggered", function () {
dialogService.getUserInput({}, {});
mockBody.on.mostRecentCall.args[1]({
keyCode: 27
});
expect(mockDeferred.reject).toHaveBeenCalled();
expect(mockDeferred.resolve).not.toHaveBeenCalled();
});
it("ignores non escape keydown events", function () {
dialogService.getUserInput({}, {});
mockBody.on.mostRecentCall.args[1]({
keyCode: 13
});
expect(mockDeferred.reject).not.toHaveBeenCalled();
expect(mockDeferred.resolve).not.toHaveBeenCalled();
});
describe("the blocking message dialog", function () {
var dialogModel = {};
var dialogHandle;

View File

@ -2,25 +2,6 @@ Contains sources and resources associated with Edit mode.
# Extensions
## Directives
This bundle introduces the `mct-before-unload` directive, primarily for
internal use (to prompt the user to confirm navigation away from unsaved
changes in Edit mode.)
The `mct-before-unload` directive is used as an attribute whose value is
an Angular expression that is evaluated when navigation changes (either
via browser-level changes, such as the refresh button, or changes to
the Angular route, which happens when hitting the back button in Edit
mode.) The result of this evaluation, when truthy, is shown in a browser
dialog to allow the user to confirm navigation. When falsy, no prompt is
shown, allowing these dialogs to be shown conditionally. (For instance, in
Edit mode, prompts are only shown if user-initiated changes have
occurred.)
This directive may be attached to any element; its behavior will be enforced
so long as that element remains within the DOM.
# Toolbars
Views may specify the contents of a toolbar through a `toolbar`

View File

@ -25,7 +25,6 @@ define([
"./src/controllers/EditPanesController",
"./src/controllers/ElementsController",
"./src/controllers/EditObjectController",
"./src/directives/MCTBeforeUnload",
"./src/actions/EditAndComposeAction",
"./src/actions/EditAction",
"./src/actions/PropertiesAction",
@ -37,7 +36,6 @@ define([
"./src/policies/EditActionPolicy",
"./src/policies/EditableLinkPolicy",
"./src/policies/EditableMovePolicy",
"./src/policies/EditNavigationPolicy",
"./src/policies/EditContextualActionPolicy",
"./src/representers/EditRepresenter",
"./src/representers/EditToolbarRepresenter",
@ -65,7 +63,6 @@ define([
EditPanesController,
ElementsController,
EditObjectController,
MCTBeforeUnload,
EditAndComposeAction,
EditAction,
PropertiesAction,
@ -77,7 +74,6 @@ define([
EditActionPolicy,
EditableLinkPolicy,
EditableMovePolicy,
EditNavigationPolicy,
EditContextualActionPolicy,
EditRepresenter,
EditToolbarRepresenter,
@ -132,7 +128,7 @@ define([
"depends": [
"$scope",
"$location",
"policyService"
"navigationService"
]
},
{
@ -152,15 +148,6 @@ define([
]
}
],
"directives": [
{
"key": "mctBeforeUnload",
"implementation": MCTBeforeUnload,
"depends": [
"$window"
]
}
],
"actions": [
{
"key": "compose",
@ -176,7 +163,7 @@ define([
],
"description": "Edit",
"category": "view-control",
"cssclass": "major icon-pencil"
"cssClass": "major icon-pencil"
},
{
"key": "properties",
@ -185,7 +172,7 @@ define([
"view-control"
],
"implementation": PropertiesAction,
"cssclass": "major icon-pencil",
"cssClass": "major icon-pencil",
"name": "Edit Properties...",
"description": "Edit properties of this object.",
"depends": [
@ -196,7 +183,7 @@ define([
"key": "remove",
"category": "contextual",
"implementation": RemoveAction,
"cssclass": "icon-trash",
"cssClass": "icon-trash",
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [
@ -208,10 +195,11 @@ define([
"category": "save",
"implementation": SaveAndStopEditingAction,
"name": "Save and Finish Editing",
"cssclass": "icon-save labeled",
"cssClass": "icon-save labeled",
"description": "Save changes made to these objects.",
"depends": [
"dialogService"
"dialogService",
"notificationService"
]
},
{
@ -219,10 +207,11 @@ define([
"category": "save",
"implementation": SaveAction,
"name": "Save and Continue Editing",
"cssclass": "icon-save labeled",
"cssClass": "icon-save labeled",
"description": "Save changes made to these objects.",
"depends": [
"dialogService"
"dialogService",
"notificationService"
]
},
{
@ -230,13 +219,14 @@ define([
"category": "save",
"implementation": SaveAsAction,
"name": "Save As...",
"cssclass": "icon-save labeled",
"cssClass": "icon-save labeled",
"description": "Save changes made to these objects.",
"depends": [
"$injector",
"policyService",
"dialogService",
"copyService"
"copyService",
"notificationService"
],
"priority": "mandatory"
},
@ -247,7 +237,7 @@ define([
// Because we use the name as label for edit buttons and mct-control buttons need
// the label to be set to undefined in order to not apply the labeled CSS rule.
"name": undefined,
"cssclass": "icon-x no-label",
"cssClass": "icon-x no-label",
"description": "Discard changes made to these objects.",
"depends": []
}
@ -270,11 +260,6 @@ define([
"category": "action",
"implementation": EditableLinkPolicy
},
{
"category": "navigation",
"message": "Continuing will cause the loss of any unsaved changes.",
"implementation": EditNavigationPolicy
},
{
"implementation": CreationPolicy,
"category": "creation"
@ -389,7 +374,6 @@ define([
{
"implementation": EditRepresenter,
"depends": [
"$q",
"$log"
]
},

View File

@ -25,14 +25,14 @@
<li ng-repeat="createAction in createActions" ng-click="createAction.perform()">
<a ng-mouseover="representation.activeMetadata = createAction.getMetadata()"
ng-mouseleave="representation.activeMetadata = undefined"
class="menu-item-a {{ createAction.getMetadata().cssclass }}">
class="menu-item-a {{ createAction.getMetadata().cssClass }}">
{{createAction.getMetadata().name}}
</a>
</li>
</ul>
</div>
<div class="pane right menu-item-description">
<div class="desc-area icon {{ representation.activeMetadata.cssclass }}"></div>
<div class="desc-area icon {{ representation.activeMetadata.cssClass }}"></div>
<div class="desc-area title">
{{representation.activeMetadata.name}}
</div>

View File

@ -26,7 +26,7 @@
structure="{
text: saveActions[0].getMetadata().name,
click: actionPerformer(saveActions[0]),
cssclass: 'major ' + saveActions[0].getMetadata().cssclass
cssClass: 'major ' + saveActions[0].getMetadata().cssClass
}">
</mct-control>
</span>
@ -36,7 +36,7 @@
structure="{
options: saveActionsAsMenuOptions,
click: saveActionMenuClickHandler,
cssclass: 'btn-bar right icon-save no-label major'
cssClass: 'btn-bar right icon-save no-label major'
}">
</mct-control>
</span>
@ -46,7 +46,7 @@
structure="{
text: currentAction.getMetadata().name,
click: actionPerformer(currentAction),
cssclass: currentAction.getMetadata().cssclass
cssClass: currentAction.getMetadata().cssClass
}">
</mct-control>
</span>

View File

@ -20,8 +20,7 @@
at runtime from the About dialog for additional information.
-->
<div class="abs l-flex-col" ng-controller="EditObjectController as EditObjectController">
<div mct-before-unload="EditObjectController.getUnloadWarning()"
class="holder flex-elem l-flex-row object-browse-bar ">
<div class="holder flex-elem l-flex-row object-browse-bar ">
<div class="items-select left flex-elem l-flex-row grows">
<mct-representation key="'back-arrow'"
mct-object="domainObject"

View File

@ -56,13 +56,13 @@ define(
//navigate back to parent because nothing to show.
return domainObject.getCapability("location").getOriginal().then(function (original) {
parent = original.getCapability("context").getParent();
parent.getCapability("action").perform("navigate");
return parent.getCapability("action").perform("navigate");
});
}
}
function cancel(allowed) {
return allowed && domainObject.getCapability("editor").finish();
function cancel() {
return domainObject.getCapability("editor").finish();
}
//Do navigation first in order to trigger unsaved changes dialog

View File

@ -33,10 +33,12 @@ define(
*/
function SaveAction(
dialogService,
notificationService,
context
) {
this.domainObject = (context || {}).domainObject;
this.dialogService = dialogService;
this.notificationService = notificationService;
}
/**
@ -47,7 +49,8 @@ define(
* @memberof platform/commonUI/edit.SaveAction#
*/
SaveAction.prototype.perform = function () {
var domainObject = this.domainObject,
var self = this,
domainObject = this.domainObject,
dialog = new SaveInProgressDialog(this.dialogService);
// Invoke any save behavior introduced by the editor capability;
@ -58,15 +61,21 @@ define(
return domainObject.getCapability("editor").save();
}
function hideBlockingDialog() {
function onSuccess() {
dialog.hide();
self.notificationService.info("Save Succeeded");
}
function onFailure() {
dialog.hide();
self.notificationService.error("Save Failed");
}
dialog.show();
return doSave()
.then(hideBlockingDialog)
.catch(hideBlockingDialog);
.then(onSuccess)
.catch(onFailure);
};
/**

View File

@ -33,11 +33,13 @@ define(
*/
function SaveAndStopEditingAction(
dialogService,
notificationService,
context
) {
this.context = context;
this.domainObject = (context || {}).domainObject;
this.dialogService = dialogService;
this.notificationService = notificationService;
}
/**
@ -49,7 +51,7 @@ define(
*/
SaveAndStopEditingAction.prototype.perform = function () {
var domainObject = this.domainObject,
saveAction = new SaveAction(this.dialogService, this.context);
saveAction = new SaveAction(this.dialogService, this.notificationService, this.context);
function closeEditor() {
return domainObject.getCapability("editor").finish();

View File

@ -43,6 +43,7 @@ define([
policyService,
dialogService,
copyService,
notificationService,
context
) {
this.domainObject = (context || {}).domainObject;
@ -52,6 +53,7 @@ define([
this.policyService = policyService;
this.dialogService = dialogService;
this.copyService = copyService;
this.notificationService = notificationService;
}
/**
@ -117,8 +119,10 @@ define([
return self.dialogService
.getUserInput(wizard.getFormStructure(true),
wizard.getInitialFormValue()
).then(wizard.populateObjectFromInput.bind(wizard));
wizard.getInitialFormValue())
.then(wizard.populateObjectFromInput.bind(wizard), function (failureReason) {
return Promise.reject("user canceled");
});
}
function showBlockingDialog(object) {
@ -176,8 +180,16 @@ define([
});
}
function onFailure() {
function onSuccess(object) {
self.notificationService.info("Save Succeeded");
return object;
}
function onFailure(reason) {
hideBlockingDialog();
if (reason !== "user canceled") {
self.notificationService.error("Save Failed");
}
return false;
}
@ -190,6 +202,7 @@ define([
.then(saveAfterClone)
.then(finishEditing)
.then(hideBlockingDialog)
.then(onSuccess)
.catch(onFailure);
};

View File

@ -48,9 +48,10 @@ define(
* Decorate PersistenceCapability to queue persistence calls when a
* transaction is in progress.
*/
TransactionCapabilityDecorator.prototype.getCapabilities = function (model) {
TransactionCapabilityDecorator.prototype.getCapabilities = function () {
var self = this,
capabilities = this.capabilityService.getCapabilities(model),
capabilities = this.capabilityService.getCapabilities
.apply(this.capabilityService, arguments),
persistenceCapability = capabilities.persistence;
capabilities.persistence = function (domainObject) {

View File

@ -41,7 +41,7 @@ define(
return {
key: action,
name: action.getMetadata().name,
cssclass: action.getMetadata().cssclass
cssClass: action.getMetadata().cssClass
};
}

View File

@ -28,18 +28,49 @@ 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 &&
navigatedObject.getCapability("editor");
return editorCapability &&
editorCapability.finish();
}
/**
* Controller which is responsible for populating the scope for
* Edit mode
* @memberof platform/commonUI/edit
* @constructor
*/
function EditObjectController($scope, $location, policyService) {
function EditObjectController($scope, $location, navigationService) {
this.scope = $scope;
this.policyService = policyService;
var domainObject = $scope.domainObject;
var navigatedObject;
function setViewForDomainObject(domainObject) {
var removeCheck = navigationService
.checkBeforeNavigation(function () {
if (isDirty(domainObject)) {
return "Continuing will cause the loss of any unsaved changes.";
}
return false;
});
$scope.$on('$destroy', function () {
removeCheck();
cancelEditing(domainObject);
});
function setViewForDomainObject() {
var locationViewKey = $location.search().view;
@ -54,34 +85,15 @@ define(
((domainObject && domainObject.useCapability('view')) || [])
.forEach(selectViewIfMatching);
}
navigatedObject = domainObject;
}
$scope.$watch('domainObject', setViewForDomainObject);
setViewForDomainObject();
$scope.doAction = function (action) {
return $scope[action] && $scope[action]();
};
}
/**
* Get the warning to show if the user attempts to navigate
* away from Edit mode while unsaved changes are present.
* @returns {string} the warning to show, or undefined if
* there are no unsaved changes
*/
EditObjectController.prototype.getUnloadWarning = function () {
var navigatedObject = this.scope.domainObject,
policyMessage;
this.policyService.allow("navigation", navigatedObject, undefined, function (message) {
policyMessage = message;
});
return policyMessage;
};
return EditObjectController;
}
);

View File

@ -51,7 +51,7 @@ define(
function AddAction(type, parent, context, $q, dialogService, policyService) {
this.metadata = {
key: 'add',
cssclass: type.getCssClass(),
cssClass: type.getCssClass(),
name: type.getName(),
type: type.getKey(),
description: type.getDescription(),

View File

@ -54,8 +54,7 @@ define(
AddActionProvider.prototype.getActions = function (actionContext) {
var context = actionContext || {},
key = context.key,
destination = context.domainObject,
self = this;
destination = context.domainObject;
// We only provide Add actions, and we need a
// domain object to serve as the container for the
@ -66,18 +65,16 @@ define(
}
// Introduce one create action per type
return this.typeService.listTypes().filter(function (type) {
return self.policyService.allow("creation", type) && self.policyService.allow("composition", destination.getCapability('type'), type);
}).map(function (type) {
return ['timeline', 'activity'].map(function (type) {
return new AddAction(
type,
this.typeService.getType(type),
destination,
context,
self.$q,
self.dialogService,
self.policyService
this.$q,
this.dialogService,
this.policyService
);
});
}, this);
};
return AddActionProvider;

View File

@ -47,7 +47,7 @@ define(
function CreateAction(type, parent, context) {
this.metadata = {
key: 'create',
cssclass: type.getCssClass(),
cssClass: type.getCssClass(),
name: type.getName(),
type: type.getKey(),
description: type.getDescription(),

View File

@ -56,16 +56,16 @@ define(
*/
CreateWizard.prototype.getFormStructure = function (includeLocation) {
var sections = [],
type = this.type,
domainObject = this.domainObject,
policyService = this.policyService;
function validateLocation(locatingObject) {
var locatingType = locatingObject &&
locatingObject.getCapability('type');
return locatingType && policyService.allow(
function validateLocation(parent) {
var parentType = parent &&
parent.getCapability('type');
return parentType && policyService.allow(
"composition",
locatingType,
type
parentType,
domainObject
);
}
@ -91,7 +91,7 @@ define(
if (includeLocation) {
sections.push({
name: 'Location',
cssclass: "grows",
cssClass: "grows",
rows: [{
name: "Save In",
control: "locator",

View File

@ -1,104 +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.
*****************************************************************************/
define(
[],
function () {
/**
* Defines the `mct-before-unload` directive. The expression bound
* to this attribute will be evaluated during page navigation events
* and, if it returns a truthy value, will be used to populate a
* prompt to the user to confirm this navigation.
* @memberof platform/commonUI/edit
* @constructor
* @param $window the window
*/
function MCTBeforeUnload($window) {
var unloads = [],
oldBeforeUnload = $window.onbeforeunload;
// Run all unload functions, returning the first returns truthily.
function checkUnloads() {
var result;
unloads.forEach(function (unload) {
result = result || unload();
});
return result;
}
// Link function for an mct-before-unload directive usage
function link(scope, element, attrs) {
// Invoke the
function unload() {
return scope.$eval(attrs.mctBeforeUnload);
}
// Stop using this unload expression
function removeUnload() {
unloads = unloads.filter(function (callback) {
return callback !== unload;
});
if (unloads.length === 0) {
$window.onbeforeunload = oldBeforeUnload;
}
}
// Show a dialog before allowing a location change
function checkLocationChange(event) {
// Get an unload message (if any)
var warning = unload();
// Prompt the user if there's an unload message
if (warning && !$window.confirm(warning)) {
// ...and prevent the route change if it was confirmed
event.preventDefault();
}
}
// If this is the first active instance of this directive,
// register as the window's beforeunload handler
if (unloads.length === 0) {
$window.onbeforeunload = checkUnloads;
}
// Include this instance of the directive's unload function
unloads.push(unload);
// Remove it when the scope is destroyed
scope.$on("$destroy", removeUnload);
// Also handle route changes
scope.$on("$locationChangeStart", checkLocationChange);
}
return {
// Applicable as an attribute
restrict: "A",
// Link with the provided function
link: link
};
}
return MCTBeforeUnload;
}
);

View File

@ -1,64 +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.
*****************************************************************************/
define(
[],
function () {
/**
* Policy controlling whether navigation events should proceed
* when object is being edited.
* @memberof platform/commonUI/edit
* @constructor
* @implements {Policy.<Action, ActionContext>}
*/
function EditNavigationPolicy(policyService) {
this.policyService = policyService;
}
/**
* @private
*/
EditNavigationPolicy.prototype.isDirty = function (domainObject) {
var navigatedObject = domainObject,
editorCapability = navigatedObject &&
navigatedObject.getCapability("editor");
return editorCapability &&
editorCapability.isEditContextRoot() &&
editorCapability.dirty();
};
/**
* Allow navigation if an object is not dirty, or if the user elects
* to proceed anyway.
* @param currentNavigation
* @returns {boolean|*} true if the object model is clean; or if
* it's dirty and the user wishes to proceed anyway.
*/
EditNavigationPolicy.prototype.allow = function (currentNavigation) {
return !this.isDirty(currentNavigation);
};
return EditNavigationPolicy;
}
);

View File

@ -43,98 +43,55 @@ define(
* @implements {Representer}
* @constructor
*/
function EditRepresenter($q, $log, scope) {
var self = this;
this.scope = scope;
this.listenHandle = undefined;
// Mutate and persist a new version of a domain object's model.
function doMutate(model) {
var domainObject = self.domainObject;
// First, mutate; then, persist.
return $q.when(domainObject.useCapability("mutation", function () {
return model;
}));
}
// Handle changes to model and/or view configuration
function commit(message) {
// Look up from scope; these will have been populated by
// mct-representation.
var model = scope.model,
configuration = scope.configuration,
domainObject = self.domainObject;
// Log the commit message
$log.debug([
"Committing ",
domainObject && domainObject.getModel().name,
"(" + (domainObject && domainObject.getId()) + "):",
message
].join(" "));
// Update the configuration stored in the model, and persist.
if (domainObject) {
// Configurations for specific views are stored by
// key in the "configuration" field of the model.
if (self.key && configuration) {
model.configuration = model.configuration || {};
model.configuration[self.key] = configuration;
}
doMutate(model);
}
}
// Place the "commit" method in the scope
scope.commit = commit;
// Clean up when the scope is destroyed
scope.$on("$destroy", function () {
self.destroy();
});
function EditRepresenter($log, $scope) {
this.$log = $log;
this.$scope = $scope;
this.$scope.commit = this.commit.bind(this);
}
// Handle a specific representation of a specific domain object
EditRepresenter.prototype.represent = function represent(representation, representedObject) {
var scope = this.scope;
/**
* Commit any changes made to the in-scope model to the domain object.
* Also commits any changes made to $scope.configuration to the proper
* configuration value for the current representation.
*
* @param {String} message a message to log with the commit message.
*/
EditRepresenter.prototype.commit = function (message) {
var model = this.$scope.model,
configuration = this.$scope.configuration,
domainObject = this.domainObject;
// Track the key, to know which view configuration to save to.
this.key = (representation || {}).key;
// Track the represented object
this.domainObject = representedObject;
this.$log.debug([
"Committing ",
domainObject && domainObject.getModel().name,
"(" + (domainObject && domainObject.getId()) + "):",
message
].join(" "));
// Ensure existing watches are released
this.destroy();
function setEditing() {
scope.viewObjectTemplate = 'edit-object';
}
/**
* Listen for changes in object state. If the object becomes
* editable then change the view and inspector regions
* object representation accordingly
*/
this.listenHandle = this.domainObject.getCapability('status').listen(function (statuses) {
if (statuses.indexOf('editing') !== -1) {
setEditing();
} else {
delete scope.viewObjectTemplate;
if (this.domainObject) {
if (this.key && configuration) {
model.configuration = model.configuration || {};
model.configuration[this.key] = configuration;
}
});
domainObject.useCapability('mutation', function () {
return model;
});
}
};
if (representedObject.hasCapability('editor') && representedObject.getCapability('editor').isEditContextRoot()) {
setEditing();
// Handle a specific representation of a specific domain object
EditRepresenter.prototype.represent = function (representation, representedObject) {
this.domainObject = representedObject;
if (representation) {
this.key = representation.key;
} else {
delete this.key;
}
};
// Respond to the destruction of the current representation.
EditRepresenter.prototype.destroy = function destroy() {
return this.listenHandle && this.listenHandle();
};
EditRepresenter.prototype.destroy = function () {};
return EditRepresenter;
}

View File

@ -19,6 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global describe,it,expect,beforeEach,jasmine,waitsFor,runs*/
define(
["../../src/actions/SaveAction"],
@ -28,7 +29,8 @@ define(
var mockDomainObject,
mockEditorCapability,
actionContext,
dialogService,
mockDialogService,
mockNotificationService,
mockActionCapability,
capabilities = {},
action;
@ -68,11 +70,17 @@ define(
actionContext = {
domainObject: mockDomainObject
};
dialogService = jasmine.createSpyObj(
mockDialogService = jasmine.createSpyObj(
"dialogService",
["showBlockingMessage"]
);
mockNotificationService = jasmine.createSpyObj(
"notificationService",
["info", "error"]
);
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andCallFake(function (capability) {
return capabilities[capability];
@ -81,7 +89,7 @@ define(
mockEditorCapability.save.andReturn(mockPromise(true));
mockEditorCapability.isEditContextRoot.andReturn(true);
action = new SaveAction(dialogService, actionContext);
action = new SaveAction(mockDialogService, mockNotificationService, actionContext);
});
it("only applies to domain object with an editor capability", function () {
@ -105,30 +113,54 @@ define(
expect(mockEditorCapability.save).toHaveBeenCalled();
});
describe("a blocking dialog", function () {
describe("in order to keep the user in the loop", function () {
var mockDialogHandle;
beforeEach(function () {
mockDialogHandle = jasmine.createSpyObj("dialogHandle", ["dismiss"]);
dialogService.showBlockingMessage.andReturn(mockDialogHandle);
mockDialogService.showBlockingMessage.andReturn(mockDialogHandle);
});
it("shows a dialog while saving", function () {
mockEditorCapability.save.andReturn(new Promise(function () {
}));
action.perform();
expect(dialogService.showBlockingMessage).toHaveBeenCalled();
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
expect(mockDialogHandle.dismiss).not.toHaveBeenCalled();
});
it("hides a dialog when saving is complete", function () {
it("hides the dialog when saving is complete", function () {
action.perform();
expect(dialogService.showBlockingMessage).toHaveBeenCalled();
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
expect(mockDialogHandle.dismiss).toHaveBeenCalled();
});
});
it("notifies if saving succeeded", function () {
var mockCallback = jasmine.createSpy("callback");
mockEditorCapability.save.andReturn(Promise.resolve("success"));
action.perform().then(mockCallback);
waitsFor(function () {
return mockCallback.calls.length > 0;
});
runs(function () {
expect(mockNotificationService.info).toHaveBeenCalled();
expect(mockNotificationService.error).not.toHaveBeenCalled();
});
});
it("notifies if saving failed", function () {
var mockCallback = jasmine.createSpy("callback");
mockEditorCapability.save.andReturn(Promise.reject("some failure reason"));
action.perform().then(mockCallback);
waitsFor(function () {
return mockCallback.calls.length > 0;
});
runs(function () {
expect(mockNotificationService.error).toHaveBeenCalled();
expect(mockNotificationService.info).not.toHaveBeenCalled();
});
});
});
});
}
);

View File

@ -19,6 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global describe,it,expect,beforeEach,jasmine*/
define(
["../../src/actions/SaveAndStopEditingAction"],
@ -35,6 +36,7 @@ define(
mockEditorCapability,
actionContext,
dialogService,
notificationService,
mockActionCapability,
capabilities = {},
action;
@ -79,6 +81,11 @@ define(
["showBlockingMessage"]
);
notificationService = jasmine.createSpyObj(
"notificationService",
["info", "error"]
);
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andCallFake(function (capability) {
return capabilities[capability];
@ -87,7 +94,7 @@ define(
mockEditorCapability.save.andReturn(mockPromise(true));
mockEditorCapability.isEditContextRoot.andReturn(true);
action = new SaveAndStopEditingAction(dialogService, actionContext);
action = new SaveAndStopEditingAction(dialogService, notificationService, actionContext);
});

View File

@ -27,11 +27,13 @@ define(
describe("The Save As action", function () {
var mockDomainObject,
mockClonedObject,
mockEditorCapability,
mockActionCapability,
mockObjectService,
mockDialogService,
mockCopyService,
mockNotificationService,
mockParent,
actionContext,
capabilities = {},
@ -57,7 +59,8 @@ define(
[
"getCapability",
"hasCapability",
"getModel"
"getModel",
"getId"
]
);
mockDomainObject.hasCapability.andReturn(true);
@ -65,6 +68,15 @@ define(
return capabilities[capability];
});
mockDomainObject.getModel.andReturn({location: 'a', persisted: undefined});
mockDomainObject.getId.andReturn(0);
mockClonedObject = jasmine.createSpyObj(
"clonedObject",
[
"getId"
]
);
mockClonedObject.getId.andReturn(1);
mockParent = jasmine.createSpyObj(
"parentObject",
@ -111,12 +123,27 @@ define(
"perform"
]
);
mockCopyService.perform.andReturn(mockPromise(mockClonedObject));
mockNotificationService = jasmine.createSpyObj(
"notificationService",
[
"info",
"error"
]
);
actionContext = {
domainObject: mockDomainObject
};
action = new SaveAsAction(undefined, undefined, mockDialogService, mockCopyService, actionContext);
action = new SaveAsAction(
undefined,
undefined,
mockDialogService,
mockCopyService,
mockNotificationService,
actionContext);
spyOn(action, "getObjectService");
action.getObjectService.andReturn(mockObjectService);
@ -186,7 +213,7 @@ define(
expect(mockDialogService.getUserInput).toHaveBeenCalled();
});
describe("a blocking dialog", function () {
describe("in order to keep the user in the loop", function () {
var mockDialogHandle;
beforeEach(function () {
@ -194,14 +221,14 @@ define(
mockDialogService.showBlockingMessage.andReturn(mockDialogHandle);
});
it("indicates that a save is taking place", function () {
it("shows a blocking dialog indicating that saving is in progress", function () {
mockEditorCapability.save.andReturn(new Promise(function () {}));
action.perform();
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
expect(mockDialogHandle.dismiss).not.toHaveBeenCalled();
});
it("is hidden after saving", function () {
it("hides the blocking dialog after saving finishes", function () {
var mockCallback = jasmine.createSpy();
action.perform().then(mockCallback);
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
@ -212,6 +239,31 @@ define(
expect(mockDialogHandle.dismiss).toHaveBeenCalled();
});
});
it("notifies if saving succeeded", function () {
var mockCallback = jasmine.createSpy();
action.perform().then(mockCallback);
waitsFor(function () {
return mockCallback.calls.length > 0;
});
runs(function () {
expect(mockNotificationService.info).toHaveBeenCalled();
expect(mockNotificationService.error).not.toHaveBeenCalled();
});
});
it("notifies if saving failed", function () {
mockCopyService.perform.andReturn(Promise.reject("some failure reason"));
var mockCallback = jasmine.createSpy();
action.perform().then(mockCallback);
waitsFor(function () {
return mockCallback.calls.length > 0;
});
runs(function () {
expect(mockNotificationService.error).toHaveBeenCalled();
expect(mockNotificationService.info).not.toHaveBeenCalled();
});
});
});
});
}

View File

@ -28,7 +28,7 @@ define(
describe("The Edit Action controller", function () {
var mockSaveActionMetadata = {
name: "mocked-save-action",
cssclass: "mocked-save-action-css"
cssClass: "mocked-save-action-css"
};
function fakeGetActions(actionContext) {
@ -86,7 +86,7 @@ define(
expect(menuOptions[1].key).toEqual(mockScope.saveActions[1]);
menuOptions.forEach(function (option) {
expect(option.name).toEqual(mockSaveActionMetadata.name);
expect(option.cssclass).toEqual(mockSaveActionMetadata.cssclass);
expect(option.cssClass).toEqual(mockSaveActionMetadata.cssClass);
});
});

View File

@ -24,32 +24,19 @@ define(
["../../src/controllers/EditObjectController"],
function (EditObjectController) {
describe("The Edit mode controller", function () {
describe("The Edit Object controller", function () {
var mockScope,
mockObject,
mockType,
testViews,
mockEditorCapability,
mockLocation,
mockNavigationService,
removeCheck,
mockStatusCapability,
mockCapabilities,
mockPolicyService,
controller;
// Utility function; look for a $watch on scope and fire it
function fireWatch(expr, value) {
mockScope.$watch.calls.forEach(function (call) {
if (call.args[0] === expr) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockPolicyService = jasmine.createSpyObj(
"policyService",
[
"allow"
]
);
mockScope = jasmine.createSpyObj(
"$scope",
["$on", "$watch"]
@ -58,16 +45,16 @@ define(
"domainObject",
["getId", "getModel", "getCapability", "hasCapability", "useCapability"]
);
mockType = jasmine.createSpyObj(
"type",
["hasFeature"]
mockEditorCapability = jasmine.createSpyObj(
"mockEditorCapability",
["isEditContextRoot", "dirty", "finish"]
);
mockStatusCapability = jasmine.createSpyObj('statusCapability',
["get"]
);
mockCapabilities = {
"type" : mockType,
"editor" : mockEditorCapability,
"status": mockStatusCapability
};
@ -75,52 +62,70 @@ define(
["search"]
);
mockLocation.search.andReturn({"view": "fixed"});
mockNavigationService = jasmine.createSpyObj('navigationService',
["checkBeforeNavigation"]
);
removeCheck = jasmine.createSpy('removeCheck');
mockNavigationService.checkBeforeNavigation.andReturn(removeCheck);
mockObject.getId.andReturn("test");
mockObject.getModel.andReturn({ name: "Test object" });
mockObject.getCapability.andCallFake(function (key) {
return mockCapabilities[key];
});
mockType.hasFeature.andReturn(true);
mockScope.domainObject = mockObject;
controller = new EditObjectController(
mockScope,
mockLocation,
mockPolicyService
);
});
it("exposes a warning message for unload", function () {
var errorMessage = "Unsaved changes";
// Normally, should be undefined
expect(controller.getUnloadWarning()).toBeUndefined();
// Override the policy service to prevent navigation
mockPolicyService.allow.andCallFake(function (category, object, context, callback) {
callback(errorMessage);
});
// Should have some warning message here now
expect(controller.getUnloadWarning()).toEqual(errorMessage);
});
it("sets the active view from query parameters", function () {
var testViews = [
{ key: 'abc' },
{ key: 'def', someKey: 'some value' },
{ key: 'xyz' }
];
testViews = [
{ key: 'abc' },
{ key: 'def', someKey: 'some value' },
{ key: 'xyz' }
];
mockObject.useCapability.andCallFake(function (c) {
return (c === 'view') && testViews;
});
mockLocation.search.andReturn({ view: 'def' });
fireWatch('domainObject', mockObject);
mockScope.domainObject = mockObject;
controller = new EditObjectController(
mockScope,
mockLocation,
mockNavigationService
);
});
it("adds a check before navigation", function () {
expect(mockNavigationService.checkBeforeNavigation)
.toHaveBeenCalledWith(jasmine.any(Function));
var checkFn = mockNavigationService.checkBeforeNavigation.mostRecentCall.args[0];
mockEditorCapability.isEditContextRoot.andReturn(false);
mockEditorCapability.dirty.andReturn(false);
expect(checkFn()).toBe(false);
mockEditorCapability.isEditContextRoot.andReturn(true);
expect(checkFn()).toBe(false);
mockEditorCapability.dirty.andReturn(true);
expect(checkFn())
.toBe("Continuing will cause the loss of any unsaved changes.");
});
it("cleans up on destroy", function () {
expect(mockScope.$on)
.toHaveBeenCalledWith("$destroy", jasmine.any(Function));
mockScope.$on.mostRecentCall.args[1]();
expect(mockEditorCapability.finish).toHaveBeenCalled();
expect(removeCheck).toHaveBeenCalled();
});
it("sets the active view from query parameters", function () {
expect(mockScope.representation.selected)
.toEqual(testViews[1]);
});

View File

@ -31,9 +31,7 @@ define(
var mockTypeService,
mockDialogService,
mockPolicyService,
mockCreationPolicy,
mockCompositionPolicy,
mockPolicyMap = {},
mockTypeMap,
mockTypes,
mockDomainObject,
mockQ,
@ -55,49 +53,33 @@ define(
);
mockType.hasFeature.andReturn(true);
mockType.getName.andReturn(name);
mockType.getKey.andReturn(name);
return mockType;
}
beforeEach(function () {
mockTypeService = jasmine.createSpyObj(
"typeService",
["listTypes"]
);
mockDialogService = jasmine.createSpyObj(
"dialogService",
["getUserInput"]
);
mockPolicyService = jasmine.createSpyObj(
"policyService",
["allow"]
["getType"]
);
mockDialogService = {};
mockPolicyService = {};
mockDomainObject = {};
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getCapability"]
);
//Mocking getCapability because AddActionProvider uses the
// type capability of the destination object.
mockDomainObject.getCapability.andReturn({});
mockTypes = ["A", "B", "C"].map(createMockType);
mockTypes = [
"timeline",
"activity",
"other"
].map(createMockType);
mockTypeMap = {};
mockTypes.forEach(function (type) {
mockPolicyMap[type.getName()] = true;
mockTypeMap[type.getKey()] = type;
});
mockCreationPolicy = function (type) {
return mockPolicyMap[type.getName()];
};
mockCompositionPolicy = function () {
return true;
};
mockPolicyService.allow.andReturn(true);
mockTypeService.listTypes.andReturn(mockTypes);
mockTypeService.getType.andCallFake(function (key) {
return mockTypeMap[key];
});
provider = new AddActionProvider(
mockQ,
@ -107,29 +89,16 @@ define(
);
});
it("checks for creatability", function () {
provider.getActions({
it("provides actions for timeline and activity", function () {
var actions = provider.getActions({
key: "add",
domainObject: mockDomainObject
});
expect(actions.length).toBe(2);
expect(actions[0].metadata.type).toBe('timeline');
expect(actions[1].metadata.type).toBe('activity');
// Make sure it was creation which was used to check
expect(mockPolicyService.allow)
.toHaveBeenCalledWith("creation", mockTypes[0]);
});
it("checks for composability of type", function () {
provider.getActions({
key: "add",
domainObject: mockDomainObject
});
expect(mockPolicyService.allow).toHaveBeenCalledWith(
"composition",
jasmine.any(Object),
jasmine.any(Object)
);
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('type');
});
});
}

View File

@ -138,7 +138,7 @@ define(
expect(metadata.name).toEqual("Test");
expect(metadata.description).toEqual("a test type");
expect(metadata.cssclass).toEqual("icon-telemetry");
expect(metadata.cssClass).toEqual("icon-telemetry");
});
describe("the perform function", function () {

View File

@ -175,7 +175,7 @@ define(
expect(mockPolicyService.allow).toHaveBeenCalledWith(
'composition',
mockOtherType,
mockType
mockDomainObject
);
});

View File

@ -1,114 +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.
*****************************************************************************/
define(
["../../src/directives/MCTBeforeUnload"],
function (MCTBeforeUnload) {
describe("The mct-before-unload directive", function () {
var mockWindow,
mockScope,
testAttrs,
mockEvent,
directive;
function fireListener(eventType, value) {
mockScope.$on.calls.forEach(function (call) {
if (call.args[0] === eventType) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockWindow = jasmine.createSpyObj("$window", ['confirm']);
mockScope = jasmine.createSpyObj("$scope", ['$eval', '$on']);
testAttrs = { mctBeforeUnload: "someExpression" };
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
directive = new MCTBeforeUnload(mockWindow);
directive.link(mockScope, {}, testAttrs);
});
it("can be used only as an attribute", function () {
expect(directive.restrict).toEqual('A');
});
it("listens for beforeunload", function () {
expect(mockWindow.onbeforeunload).toEqual(jasmine.any(Function));
});
it("listens for route changes", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
"$locationChangeStart",
jasmine.any(Function)
);
});
it("listens for its scope's destroy event", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
"$destroy",
jasmine.any(Function)
);
});
it("uses result of evaluated expression as a warning", function () {
mockScope.$eval.andReturn(undefined);
expect(mockWindow.onbeforeunload(mockEvent)).toBeUndefined();
mockScope.$eval.andReturn("some message");
expect(mockWindow.onbeforeunload(mockEvent)).toEqual("some message");
// Verify that the right expression was evaluated
expect(mockScope.$eval).toHaveBeenCalledWith(testAttrs.mctBeforeUnload);
});
it("confirms route changes", function () {
// First, try with no unsaved changes;
// should not confirm or preventDefault
mockScope.$eval.andReturn(undefined);
fireListener("$locationChangeStart", mockEvent);
expect(mockWindow.confirm).not.toHaveBeenCalled();
expect(mockEvent.preventDefault).not.toHaveBeenCalled();
// Next, try with unsaved changes that the user confirms;
// should prompt, but not preventDefault
mockScope.$eval.andReturn("some message");
mockWindow.confirm.andReturn(true);
fireListener("$locationChangeStart", mockEvent);
expect(mockWindow.confirm).toHaveBeenCalledWith("some message");
expect(mockEvent.preventDefault).not.toHaveBeenCalled();
// Finally, act as if the user said no to this dialog;
// this should preventDefault on the location change.
mockWindow.confirm.andReturn(false);
fireListener("$locationChangeStart", mockEvent);
expect(mockWindow.confirm).toHaveBeenCalledWith("some message");
expect(mockEvent.preventDefault).toHaveBeenCalled();
});
it("cleans up listeners when destroyed", function () {
fireListener("$destroy", mockEvent);
expect(mockWindow.onbeforeunload).toBeUndefined();
});
});
}
);

View File

@ -20,103 +20,70 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
["../../src/representers/EditRepresenter"],
function (EditRepresenter) {
define([
'../../src/representers/EditRepresenter'
], function (
EditRepresenter
) {
describe('EditRepresenter', function () {
var $log,
$scope,
representer;
describe("The Edit mode representer", function () {
var mockQ,
mockLog,
mockScope,
testRepresentation,
mockDomainObject,
mockStatusCapability,
mockEditorCapability,
mockCapabilities,
representer;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
$log = jasmine.createSpyObj('$log', ['debug']);
$scope = {};
representer = new EditRepresenter($log, $scope);
});
it('injects a commit function in scope', function () {
expect($scope.commit).toEqual(jasmine.any(Function));
});
describe('representation', function () {
var domainObject,
representation;
beforeEach(function () {
mockQ = { when: mockPromise };
mockLog = jasmine.createSpyObj("$log", ["info", "debug"]);
mockScope = jasmine.createSpyObj("$scope", ["$watch", "$on"]);
testRepresentation = { key: "test" };
mockDomainObject = jasmine.createSpyObj("domainObject", [
"getId",
"getModel",
"getCapability",
"useCapability",
"hasCapability"
domainObject = jasmine.createSpyObj('domainObject', [
'getId',
'getModel',
'useCapability'
]);
mockStatusCapability =
jasmine.createSpyObj("statusCapability", ["listen"]);
mockEditorCapability =
jasmine.createSpyObj("editorCapability", ["isEditContextRoot"]);
mockCapabilities = {
'status': mockStatusCapability,
'editor': mockEditorCapability
domainObject.getId.andReturn('anId');
domainObject.getModel.andReturn({name: 'anObject'});
representation = {
key: 'someRepresentation'
};
mockDomainObject.getModel.andReturn({});
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.useCapability.andReturn(true);
mockDomainObject.getCapability.andCallFake(function (capability) {
return mockCapabilities[capability];
});
representer = new EditRepresenter(mockQ, mockLog, mockScope);
representer.represent(testRepresentation, mockDomainObject);
$scope.model = {name: 'anotherName'};
$scope.configuration = {some: 'config'};
representer.represent(representation, domainObject);
});
it("provides a commit method in scope", function () {
expect(mockScope.commit).toEqual(jasmine.any(Function));
it('logs a message when commiting', function () {
$scope.commit('Test Message');
expect($log.debug)
.toHaveBeenCalledWith('Committing anObject (anId): Test Message');
});
it("Sets edit view template on edit mode", function () {
mockStatusCapability.listen.mostRecentCall.args[0](['editing']);
mockEditorCapability.isEditContextRoot.andReturn(true);
expect(mockScope.viewObjectTemplate).toEqual('edit-object');
it('mutates the object when committing', function () {
$scope.commit('Test Message');
expect(domainObject.useCapability)
.toHaveBeenCalledWith('mutation', jasmine.any(Function));
var mutateValue = domainObject.useCapability.calls[0].args[1]();
expect(mutateValue.configuration.someRepresentation)
.toEqual({some: 'config'});
expect(mutateValue.name).toEqual('anotherName');
});
it("Cleans up listeners on scope destroy", function () {
representer.listenHandle = jasmine.createSpy('listen');
mockScope.$on.mostRecentCall.args[1]();
expect(representer.listenHandle).toHaveBeenCalled();
});
it("mutates upon observed changes", function () {
mockScope.model = { someKey: "some value" };
mockScope.configuration = { someConfiguration: "something" };
mockScope.commit("Some message");
// Should have mutated the object...
expect(mockDomainObject.useCapability).toHaveBeenCalledWith(
"mutation",
jasmine.any(Function)
);
// Finally, check that the provided mutation function
// includes both model and configuration
expect(
mockDomainObject.useCapability.mostRecentCall.args[1]()
).toEqual({
someKey: "some value",
configuration: {
test: { someConfiguration: "something" }
}
});
});
});
}
);
});
});

View File

@ -95,6 +95,45 @@ define([
})[0][0];
}
/**
* Returns a description of the current range of the time conductor's
* bounds.
* @param timeRange
* @returns {*}
*/
UTCTimeFormat.prototype.timeUnits = function (timeRange) {
var momentified = moment.duration(timeRange);
return [
["Decades", function (r) {
return r.years() > 15;
}],
["Years", function (r) {
return r.years() > 1;
}],
["Months", function (r) {
return r.years() === 1 || r.months() > 1;
}],
["Days", function (r) {
return r.months() === 1 || r.days() > 1;
}],
["Hours", function (r) {
return r.days() === 1 || r.hours() > 1;
}],
["Minutes", function (r) {
return r.hours() === 1 || r.minutes() > 1;
}],
["Seconds", function (r) {
return r.minutes() === 1 || r.seconds() > 1;
}],
["Milliseconds", function (r) {
return true;
}]
].filter(function (row) {
return row[1](momentified);
})[0][0];
};
/**
*
* @param value

View File

@ -58,5 +58,26 @@ define([
expect(format.format(APRIL, scale)).toBe("April");
expect(format.format(TWENTY_SIXTEEN, scale)).toBe("2016");
});
it("Returns appropriate time units for a given time span", function () {
var ONE_DAY = 1000 * 60 * 60 * 24;
var FIVE_DAYS = 5 * ONE_DAY;
var FIVE_MONTHS = 60 * ONE_DAY;
var ONE_YEAR = 365 * ONE_DAY;
var SEVEN_YEARS = 7 * ONE_YEAR;
var TWO_DECADES = 20 * ONE_YEAR;
//A span of one day should show a zoom label of "Hours"
expect(format.timeUnits(ONE_DAY)).toEqual("Hours");
//Multiple days should display "Days"
expect(format.timeUnits(FIVE_DAYS)).toEqual("Days");
expect(format.timeUnits(FIVE_MONTHS)).toEqual("Days");
//A span of one year should show a zoom level of "Months".
// Multiple years will show "Years"
expect(format.timeUnits(ONE_YEAR)).toEqual("Months");
expect(format.timeUnits(SEVEN_YEARS)).toEqual("Years");
expect(format.timeUnits(TWO_DECADES)).toEqual("Decades");
});
});
});

View File

@ -1,8 +1,8 @@
{
"metadata": {
"name": "openmct-symbols-16px",
"lastOpened": 1469724858940,
"created": 1469724856623
"lastOpened": 1481575258437,
"created": 1481575255265
},
"iconSets": [
{
@ -535,18 +535,50 @@
{
"order": 21,
"prevSize": 24,
"name": "icon-x-in-circle",
"name": "icon-resync",
"id": 16,
"code": 921654,
"tempChar": ""
},
{
"order": 121,
"id": 103,
"name": "icon-x-in-circle",
"prevSize": 24,
"code": 921656,
"tempChar": ""
},
{
"order": 118,
"id": 102,
"name": "icon-brightness",
"prevSize": 24,
"code": 921657,
"tempChar": ""
},
{
"order": 119,
"id": 104,
"name": "icon-contrast",
"prevSize": 24,
"code": 921664,
"tempChar": ""
},
{
"order": 120,
"id": 105,
"name": "icon-reset",
"prevSize": 24,
"code": 921655,
"tempChar": ""
},
{
"order": 37,
"prevSize": 24,
"name": "icon-activity",
"id": 32,
"code": 921856,
"tempChar": ""
"tempChar": ""
},
{
"order": 36,
@ -554,7 +586,7 @@
"name": "icon-activity-mode",
"id": 31,
"code": 921857,
"tempChar": ""
"tempChar": ""
},
{
"order": 52,
@ -562,7 +594,7 @@
"name": "icon-autoflow-tabular",
"id": 47,
"code": 921858,
"tempChar": ""
"tempChar": ""
},
{
"order": 55,
@ -570,7 +602,7 @@
"name": "icon-clock",
"id": 50,
"code": 921859,
"tempChar": ""
"tempChar": ""
},
{
"order": 58,
@ -578,7 +610,7 @@
"name": "icon-database",
"id": 53,
"code": 921860,
"tempChar": ""
"tempChar": ""
},
{
"order": 57,
@ -586,7 +618,7 @@
"name": "icon-database-query",
"id": 52,
"code": 921861,
"tempChar": ""
"tempChar": ""
},
{
"order": 17,
@ -594,7 +626,7 @@
"name": "icon-dataset",
"id": 12,
"code": 921862,
"tempChar": ""
"tempChar": ""
},
{
"order": 22,
@ -602,7 +634,7 @@
"name": "icon-datatable",
"id": 17,
"code": 921863,
"tempChar": ""
"tempChar": ""
},
{
"order": 59,
@ -610,7 +642,7 @@
"name": "icon-dictionary",
"id": 54,
"code": 921864,
"tempChar": ""
"tempChar": ""
},
{
"order": 62,
@ -618,7 +650,7 @@
"name": "icon-folder",
"id": 57,
"code": 921865,
"tempChar": ""
"tempChar": ""
},
{
"order": 66,
@ -626,7 +658,7 @@
"name": "icon-image",
"id": 61,
"code": 921872,
"tempChar": ""
"tempChar": ""
},
{
"order": 68,
@ -634,7 +666,7 @@
"name": "icon-layout",
"id": 63,
"code": 921873,
"tempChar": ""
"tempChar": ""
},
{
"order": 77,
@ -642,7 +674,7 @@
"name": "icon-object",
"id": 72,
"code": 921874,
"tempChar": ""
"tempChar": ""
},
{
"order": 78,
@ -650,7 +682,7 @@
"name": "icon-object-unknown",
"id": 73,
"code": 921875,
"tempChar": ""
"tempChar": ""
},
{
"order": 79,
@ -658,7 +690,7 @@
"name": "icon-packet",
"id": 74,
"code": 921876,
"tempChar": ""
"tempChar": ""
},
{
"order": 80,
@ -666,7 +698,7 @@
"name": "icon-page",
"id": 75,
"code": 921877,
"tempChar": ""
"tempChar": ""
},
{
"order": 114,
@ -674,7 +706,7 @@
"name": "icon-plot-overlay",
"prevSize": 24,
"code": 921878,
"tempChar": ""
"tempChar": ""
},
{
"order": 113,
@ -682,7 +714,7 @@
"name": "icon-plot-stacked",
"prevSize": 24,
"code": 921879,
"tempChar": ""
"tempChar": ""
},
{
"order": 10,
@ -690,7 +722,7 @@
"name": "icon-session",
"id": 5,
"code": 921880,
"tempChar": ""
"tempChar": ""
},
{
"order": 24,
@ -698,7 +730,7 @@
"name": "icon-tabular",
"id": 19,
"code": 921881,
"tempChar": ""
"tempChar": ""
},
{
"order": 7,
@ -706,7 +738,7 @@
"name": "icon-tabular-lad",
"id": 2,
"code": 921888,
"tempChar": ""
"tempChar": ""
},
{
"order": 6,
@ -714,7 +746,7 @@
"name": "icon-tabular-lad-set",
"id": 1,
"code": 921889,
"tempChar": ""
"tempChar": ""
},
{
"order": 8,
@ -722,7 +754,7 @@
"name": "icon-tabular-realtime",
"id": 3,
"code": 921890,
"tempChar": ""
"tempChar": ""
},
{
"order": 23,
@ -730,7 +762,7 @@
"name": "icon-tabular-scrolling",
"id": 18,
"code": 921891,
"tempChar": ""
"tempChar": ""
},
{
"order": 112,
@ -738,7 +770,7 @@
"name": "icon-telemetry",
"id": 86,
"code": 921892,
"tempChar": ""
"tempChar": ""
},
{
"order": 90,
@ -746,7 +778,7 @@
"name": "icon-telemetry-panel",
"id": 85,
"code": 921893,
"tempChar": ""
"tempChar": ""
},
{
"order": 93,
@ -754,7 +786,7 @@
"name": "icon-timeline",
"id": 88,
"code": 921894,
"tempChar": ""
"tempChar": ""
},
{
"order": 116,
@ -762,7 +794,7 @@
"name": "icon-timer-v1.5",
"prevSize": 24,
"code": 921895,
"tempChar": ""
"tempChar": ""
},
{
"order": 11,
@ -770,7 +802,7 @@
"name": "icon-topic",
"id": 6,
"code": 921896,
"tempChar": ""
"tempChar": ""
},
{
"order": 115,
@ -778,13 +810,13 @@
"name": "icon-box-with-dashed-lines",
"id": 29,
"code": 921897,
"tempChar": ""
"tempChar": ""
}
],
"metadata": {
"name": "openmct-symbols-16px",
"importSize": {
"width": 448,
"width": 512,
"height": 512
},
"designer": "Charles Hacskaylo",
@ -1973,7 +2005,7 @@
},
{
"paths": [
"M1012.8 414.2v-391.6l-127.6 127.4c-96.6-96.8-225.2-150-362-150s-265.2 53.2-362 150c-96.8 96.8-150 225.2-150 362s53.2 265.4 150 362c96.8 96.8 225.2 150 362 150s265.4-53.2 362-150l-136.6-136.6c-124.2 124.2-326.4 124.2-450.8 0-124.2-124.2-124.2-326.4 0-450.8 124.2-124.2 326.4-124.2 450.8 0l-127.4 127.4h391.6z"
"M960 432v-432l-164.8 164.8c-79.8-65.2-178.8-100.8-283.2-100.8-119.6 0-232.2 46.6-316.8 131.2s-131.2 197.2-131.2 316.8 46.6 232.2 131.2 316.8c84.6 84.6 197.2 131.2 316.8 131.2s232.2-46.6 316.8-131.2c69.4-69.4 113.2-157.4 126.6-252.8h-130c-29.8 145.8-159 256-313.6 256-176.4 0-320-143.6-320-320s143.8-320 320.2-320c72 0 138.4 23.8 192 64l-176 176h432z"
],
"grid": 16,
"tags": [
@ -1981,9 +2013,19 @@
],
"defaultCode": 114,
"id": 27,
"attrs": [],
"attrs": [
{
"fill": "rgb(0, 161, 75)"
}
],
"isMulticolor": false,
"isMulticolor2": false,
"colorPermutations": {
"1161751207457516161751": []
"1161751207457516161751": [
{
"f": 1
}
]
}
},
{
@ -2110,6 +2152,37 @@
"1161751207457516161751": []
}
},
{
"id": 105,
"paths": [
"M795.2 164.8c-79.8-65.2-178.8-100.8-283.2-100.8-119.6 0-232.2 46.6-316.8 131.2-69.4 69.4-113.2 157.4-126.6 252.8h130c29.6-145.8 158.8-256 313.4-256 72 0 138.4 23.8 192 64l-176 176h432v-432l-164.8 164.8z",
"M512 832c-72 0-138.4-23.8-192-64l176-176h-432v432l164.8-164.8c79.8 65.2 178.8 100.8 283.2 100.8 119.6 0 232.2-46.6 316.8-131.2 69.4-69.4 113.2-157.4 126.6-252.8h-130c-29.6 145.8-158.8 256-313.4 256z"
],
"attrs": [
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-resync"
],
"colorPermutations": {
"1161751207457516161751": [
{
"f": 1
},
{
"f": 1
}
]
}
},
{
"paths": [
"M512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512zM832 704l-128 128-192-192-192 192-128-128 192-192-192-192 128-128 192 192 192-192 128 128-192 192 192 192z"
@ -2125,6 +2198,134 @@
"1161751207457516161751": []
}
},
{
"id": 103,
"paths": [
"M253.414 318.061l-155.172-116.384c-50.233 66.209-85.127 146.713-97.91 234.39l191.586 30.216c8.145-56.552 29.998-106.879 62.068-149.006z",
"M191.98 557.717l-191.919 27.434c13.115 90.459 48.009 170.963 99.174 238.453l154.18-117.665c-31.476-41.347-53.309-91.675-61.231-146.504z",
"M466.283 191.98l-27.434-191.919c-90.459 13.115-170.963 48.009-238.453 99.174l117.665 154.18c41.347-31.476 91.675-53.309 146.504-61.231z",
"M822.323 98.242c-66.209-50.233-146.713-85.127-234.39-97.91l-30.216 191.586c56.552 8.145 106.879 29.998 149.006 62.068z",
"M832.020 466.283l191.919-27.434c-13.115-90.459-48.009-170.963-99.174-238.453l-154.18 117.665c31.476 41.347 53.309 91.675 61.231 146.504z",
"M201.677 925.758c66.209 50.233 146.713 85.127 234.39 97.91l30.216-191.586c-56.552-8.145-106.879-29.998-149.006-62.068z",
"M770.586 705.939l155.131 116.343c50.233-66.209 85.127-146.713 97.91-234.39l-191.586-30.216c-8.125 56.564-29.966 106.906-62.028 149.049z",
"M557.717 832.020l27.434 191.919c90.459-13.115 170.963-48.009 238.453-99.174l-117.665-154.18c-41.347 31.476-91.675 53.309-146.504 61.231z",
"M770.586 512c0 142.813-115.773 258.586-258.586 258.586s-258.586-115.773-258.586-258.586c0-142.813 115.773-258.586 258.586-258.586s258.586 115.773 258.586 258.586z"
],
"attrs": [
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
},
{
"fill": "rgb(0, 161, 75)"
}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-brightness"
],
"colorPermutations": {
"1161751207457516161751": [
{
"f": 1
},
{
"f": 1
},
{
"f": 1
},
{
"f": 1
},
{
"f": 1
},
{
"f": 1
},
{
"f": 1
},
{
"f": 1
},
{
"f": 1
}
]
}
},
{
"id": 102,
"paths": [
"M512 0c-282.78 0-512 229.24-512 512s229.22 512 512 512 512-229.24 512-512-229.22-512-512-512zM783.52 783.52c-69.111 69.481-164.785 112.481-270.502 112.481-0.358 0-0.716-0-1.074-0.001l0.055-768c212.070 0.010 383.982 171.929 383.982 384 0 106.034-42.977 202.031-112.462 271.52z"
],
"attrs": [
{
"fill": "rgb(0, 161, 75)"
}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-contrast"
],
"colorPermutations": {
"1161751207457516161751": [
{
"f": 1
}
]
}
},
{
"id": 104,
"paths": [
"M460.8 460.8l-187.8-187.8c57.2-42.8 128-68.2 204.8-68.2 188.2 0 341.6 153.2 341.6 341.4s-153.2 341.2-341.4 341.2c-165 0-302.8-117.6-334.6-273h-138.4c14.2 101.8 61 195.6 135 269.6 90.2 90.2 210.4 140 338 140s247.6-49.8 338-140 140-210.4 140-338-49.8-247.6-140-338-210.4-140-338-140c-111.4 0-217 38-302 107.6l-176-175.6v460.8h460.8z"
],
"attrs": [
{
"fill": "rgb(0, 161, 75)"
}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 16,
"tags": [
"icon-reset"
],
"colorPermutations": {
"1161751207457516161751": [
{
"f": 1
}
]
}
},
{
"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"

View File

@ -65,14 +65,18 @@
<glyph unicode="&#xe1026;" glyph-name="icon-plot-resource" d="M255.884 256c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h255.884c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h143.658c-93.832 117.038-237.98 192-399.658 192-282.77 0-512-229.23-512-512 0-67.904 13.25-132.704 37.256-192h218.628zM768.116 640c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-255.884c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-143.658c93.832-117.038 237.98-192 399.658-192 282.77 0 512 229.23 512 512 0 67.904-13.25 132.704-37.256 192h-218.628z" />
<glyph unicode="&#xe1027;" glyph-name="icon-pointer-left" horiz-adv-x="512" d="M510-64l-256 512 256 512h-256l-256-512 256-512z" />
<glyph unicode="&#xe1028;" glyph-name="icon-pointer-right" horiz-adv-x="512" d="M-2 960l256-512-256-512h256l256 512-256 512z" />
<glyph unicode="&#xe1029;" glyph-name="icon-refresh" d="M1012.8 545.8v391.6l-127.6-127.4c-96.6 96.8-225.2 150-362 150s-265.2-53.2-362-150c-96.8-96.8-150-225.2-150-362s53.2-265.4 150-362c96.8-96.8 225.2-150 362-150s265.4 53.2 362 150l-136.6 136.6c-124.2-124.2-326.4-124.2-450.8 0-124.2 124.2-124.2 326.4 0 450.8 124.2 124.2 326.4 124.2 450.8 0l-127.4-127.4h391.6z" />
<glyph unicode="&#xe1029;" glyph-name="icon-refresh" d="M960 528v432l-164.8-164.8c-79.8 65.2-178.8 100.8-283.2 100.8-119.6 0-232.2-46.6-316.8-131.2s-131.2-197.2-131.2-316.8 46.6-232.2 131.2-316.8c84.6-84.6 197.2-131.2 316.8-131.2s232.2 46.6 316.8 131.2c69.4 69.4 113.2 157.4 126.6 252.8h-130c-29.8-145.8-159-256-313.6-256-176.4 0-320 143.6-320 320s143.8 320 320.2 320c72 0 138.4-23.8 192-64l-176-176h432z" />
<glyph unicode="&#xe1030;" glyph-name="icon-save" d="M192.2 384c-0.2 0-0.2 0 0 0l-0.2-448h640v447.8c0 0 0 0-0.2 0.2h-639.6zM978.8 749.2l-165.4 165.4c-25 25-74.2 45.4-109.4 45.4h-576c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128v448c0 35.2 28.8 64 64 64h640c35.2 0 64-28.8 64-64v-448c70.4 0 128 57.6 128 128v576c0 35.2-20.4 84.4-45.2 109.2zM704 704c0-35.2-28.8-64-64-64h-448c-35.2 0-64 28.8-64 64v192h320v-192h128v192h128v-192z" />
<glyph unicode="&#xe1031;" glyph-name="icon-sine" d="M1022.294 448c-1.746 7.196-3.476 14.452-5.186 21.786-20.036 85.992-53.302 208.976-98 306.538-22.42 48.938-45.298 86.556-69.946 115.006-48.454 55.93-98.176 67.67-131.356 67.67s-82.902-11.74-131.356-67.672c-24.648-28.45-47.528-66.068-69.948-115.006-44.696-97.558-77.962-220.544-98-306.538-21.646-92.898-46.444-175.138-71.71-237.836-16.308-40.46-30.222-66.358-40.6-82.604-10.378 16.246-24.292 42.142-40.6 82.604-23.272 57.75-46.144 132.088-66.524 216.052h-197.362c1.746-7.196 3.476-14.452 5.186-21.786 20.036-85.992 53.302-208.976 98-306.538 22.42-48.938 45.298-86.556 69.946-115.006 48.454-55.932 98.176-67.672 131.356-67.672s82.902 11.74 131.356 67.672c24.648 28.45 47.528 66.068 69.948 115.006 44.696 97.558 77.962 220.544 98 306.538 21.646 92.898 46.444 175.138 71.71 237.836 16.308 40.46 30.222 66.358 40.6 82.604 10.378-16.246 24.292-42.142 40.6-82.604 23.274-57.748 46.146-132.086 66.526-216.050h197.36z" />
<glyph unicode="&#xe1032;" glyph-name="icon-T" d="M0 960v-256h128v64h256v-704h-192v-128h640v128h-192v704h256v-64h128v256z" />
<glyph unicode="&#xe1033;" glyph-name="icon-thumbs-strip" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
<glyph unicode="&#xe1034;" glyph-name="icon-two-parts-both" 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 128zM128 832h320v-768h-320v768zM896 64h-320v768h320v-768z" />
<glyph unicode="&#xe1035;" glyph-name="icon-two-parts-one-only" 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 128zM896 64h-320v768h320v-768z" />
<glyph unicode="&#xe1036;" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
<glyph unicode="&#xe1036;" glyph-name="icon-resync" d="M795.2 795.2c-79.8 65.2-178.8 100.8-283.2 100.8-119.6 0-232.2-46.6-316.8-131.2-69.4-69.4-113.2-157.4-126.6-252.8h130c29.6 145.8 158.8 256 313.4 256 72 0 138.4-23.8 192-64l-176-176h432v432l-164.8-164.8zM512 128c-72 0-138.4 23.8-192 64l176 176h-432v-432l164.8 164.8c79.8-65.2 178.8-100.8 283.2-100.8 119.6 0 232.2 46.6 316.8 131.2 69.4 69.4 113.2 157.4 126.6 252.8h-130c-29.6-145.8-158.8-256-313.4-256z" />
<glyph unicode="&#xe1037;" glyph-name="icon-reset" d="M460.8 499.2l-187.8 187.8c57.2 42.8 128 68.2 204.8 68.2 188.2 0 341.6-153.2 341.6-341.4s-153.2-341.2-341.4-341.2c-165 0-302.8 117.6-334.6 273h-138.4c14.2-101.8 61-195.6 135-269.6 90.2-90.2 210.4-140 338-140s247.6 49.8 338 140 140 210.4 140 338-49.8 247.6-140 338-210.4 140-338 140c-111.4 0-217-38-302-107.6l-176 175.6v-460.8h460.8z" />
<glyph unicode="&#xe1038;" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
<glyph unicode="&#xe1039;" glyph-name="icon-brightness" d="M253.414 641.939l-155.172 116.384c-50.233-66.209-85.127-146.713-97.91-234.39l191.586-30.216c8.145 56.552 29.998 106.879 62.068 149.006zM191.98 402.283l-191.919-27.434c13.115-90.459 48.009-170.963 99.174-238.453l154.18 117.665c-31.476 41.347-53.309 91.675-61.231 146.504zM466.283 768.020l-27.434 191.919c-90.459-13.115-170.963-48.009-238.453-99.174l117.665-154.18c41.347 31.476 91.675 53.309 146.504 61.231zM822.323 861.758c-66.209 50.233-146.713 85.127-234.39 97.91l-30.216-191.586c56.552-8.145 106.879-29.998 149.006-62.068zM832.020 493.717l191.919 27.434c-13.115 90.459-48.009 170.963-99.174 238.453l-154.18-117.665c31.476-41.347 53.309-91.675 61.231-146.504zM201.677 34.242c66.209-50.233 146.713-85.127 234.39-97.91l30.216 191.586c-56.552 8.145-106.879 29.998-149.006 62.068zM770.586 254.061l155.131-116.343c50.233 66.209 85.127 146.713 97.91 234.39l-191.586 30.216c-8.125-56.564-29.966-106.906-62.028-149.049zM557.717 127.98l27.434-191.919c90.459 13.115 170.963 48.009 238.453 99.174l-117.665 154.18c-41.347-31.476-91.675-53.309-146.504-61.231zM770.586 448c0-142.813-115.773-258.586-258.586-258.586s-258.586 115.773-258.586 258.586c0 142.813 115.773 258.586 258.586 258.586s258.586-115.773 258.586-258.586z" />
<glyph unicode="&#xe1040;" glyph-name="icon-contrast" d="M512 960c-282.78 0-512-229.24-512-512s229.22-512 512-512 512 229.24 512 512-229.22 512-512 512zM783.52 176.48c-69.111-69.481-164.785-112.481-270.502-112.481-0.358 0-0.716 0-1.074 0.001l0.055 768c212.070-0.010 383.982-171.929 383.982-384 0-106.034-42.977-202.031-112.462-271.52z" />
<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" />

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -78,7 +78,7 @@ $treeContextTriggerW: 20px;
/*************** Tabular */
$tabularHeaderH: 22px;
$tabularTdPadLR: $itemPadLR;
$tabularTdPadTB: 3px;
$tabularTdPadTB: 2px;
/*************** Imagery */
$imageMainControlBarH: 25px;
$imageThumbsD: 120px;
@ -99,7 +99,7 @@ $plotXBarH: 32px;
$plotLegendH: 20px;
$plotSwatchD: 8px;
// 1: Top, 2: right, 3: bottom, 4: left
$plotDisplayArea: ($plotLegendH + $interiorMargin, 0, $plotXBarH + $interiorMargin, $plotYBarW);
$plotDisplayArea: ($plotLegendH + $interiorMargin, 0, $plotXBarH, $plotYBarW);
/* min plot height is based on user testing to find minimum useful height */
$plotMinH: 95px;
/*************** Bubbles */

View File

@ -191,6 +191,19 @@ a.disabled {
overflow-y: auto;
}
.slidable {
cursor: move; // Fallback
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
&.horz {
cursor: col-resize;
}
&.vert {
cursor: row-resize;
}
}
.no-margin {
margin: 0;
}
@ -204,6 +217,11 @@ a.disabled {
display: none !important;
}
.hide-nice {
opacity: 0;
pointer-events: none;
}
.off {
visibility: hidden;
opacity: 0;

View File

@ -40,7 +40,6 @@ $glyph-icon-brackets: '\e929';
$glyph-icon-arrows-out: '\e1000';
$glyph-icon-arrows-right-left: '\e1001';
$glyph-icon-arrows-up-down: '\e1002';
$glyph-icon-box-with-dashed-lines: '';
$glyph-icon-bullet: '\e1004';
$glyph-icon-calendar: '\e1005';
$glyph-icon-chain-links: '\e1006';
@ -73,7 +72,11 @@ $glyph-icon-T: '\e1032';
$glyph-icon-thumbs-strip: '\e1033';
$glyph-icon-two-parts-both: '\e1034';
$glyph-icon-two-parts-one-only: '\e1035';
$glyph-icon-x-in-circle: '\e1036';
$glyph-icon-resync: '\e1036';
$glyph-icon-x-in-circle: '\e1038';
$glyph-icon-brightness: '\e1039';
$glyph-icon-contrast: '\e1040';
$glyph-icon-reset: '\e1037';
$glyph-icon-activity: '\e1100';
$glyph-icon-activity-mode: '\e1101';
$glyph-icon-autoflow-tabular: '\e1102';
@ -173,6 +176,10 @@ $glyph-icon-box-with-dashed-lines: '\e1129';
.icon-two-parts-both { @include glyph($glyph-icon-two-parts-both); }
.icon-two-parts-one-only { @include glyph($glyph-icon-two-parts-one-only); }
.icon-x-in-circle { @include glyph($glyph-icon-x-in-circle); }
.icon-brightness { @include glyph($glyph-icon-brightness); }
.icon-contrast { @include glyph($glyph-icon-contrast); }
.icon-reset { @include glyph($glyph-icon-reset); }
.icon-resync { @include glyph($glyph-icon-resync); }
.icon-activity { @include glyph($glyph-icon-activity); }
.icon-activity-mode { @include glyph($glyph-icon-activity-mode); }
.icon-autoflow-tabular { @include glyph($glyph-icon-autoflow-tabular); }
@ -209,4 +216,4 @@ $glyph-icon-box-with-dashed-lines: '\e1129';
.icon-eye-open-12px { @include glyph($glyph-icon-eye-open,'symbolsfont-12px'); }
.icon-collapse-pane-left-12px { @include glyph($glyph-icon-collapse-pane-left,'symbolsfont-12px'); }
.icon-collapse-pane-right-12px { @include glyph($glyph-icon-collapse-pane-right,'symbolsfont-12px'); }
.icon-folder-12px { @include glyph($glyph-icon-folder,'symbolsfont-12px'); }
.icon-folder-12px { @include glyph($glyph-icon-folder,'symbolsfont-12px'); }

View File

@ -363,14 +363,13 @@
}
}
@mixin webkitProp($name, $val) {
#{$name}: #{$val};
-webkit-#{$name}: #{$val};
}
@mixin webkitVal($name, $val) {
#{$name}: #{$val};
#{$name}: -webkit-#{$val};
@mixin cursorGrab() {
cursor: grab;
cursor: -webkit-grab;
&:active {
cursor: grabbing;
cursor: -webkit-grabbing;
}
}
@mixin verticalCenter {
@ -392,6 +391,14 @@
white-space: nowrap;
}
@mixin reverseEllipsis() {
direction: rtl;
unicode-bidi:bidi-override;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
@mixin scrollH($showBar: auto) {
overflow-x: $showBar;
overflow-y: hidden;

View File

@ -122,13 +122,21 @@
// Default position is upper right
$p: $interiorMargin;
position: absolute;
top: $p;
right: $p;
top: $p; right: $p; bottom: auto;
text-align: right;
z-index: 5;
}
.s-local-controls {
@include trans-prop-nice(opacity);
font-size: 0.7rem;
&.s-wrapper-transluc {
// Semi-opaque wrapper to visually distinguish a control
// from the background
background: rgba($colorTransLucBg, 0.7);
box-sizing: border-box;
border-radius: $controlCr;
}
}
/******************************************************** CUSTOM CHECKBOXES */
@ -459,7 +467,7 @@ input[type="search"] {
width: $h;
height: $h;
margin-top: 1 + floor($h/2) * -1;
@include btnSubtle(pullForward($colorBtnBg, 10%));
@include btnSubtle(pullForward($colorBtnBg, 20%));
border-radius: 50% !important;
}
@ -653,3 +661,4 @@ body.desktop {
background: $scrollbarTrackColorBg;
}
}

View File

@ -1,5 +1,6 @@
.l-image-main-wrapper,
.l-image-thumbs-wrapper {
.l-image-thumbs-wrapper,
.image-main {
@include absPosDefault(0, false);
}
@ -32,7 +33,7 @@
/*************************************** MAIN IMAGE */
.l-image-main,
.image-main,
.l-image-thumb-item .l-thumb {
background-size: contain;
background-position: center;
@ -134,6 +135,54 @@
}
}
/*************************************** LOCAL CONTROLS */
.l-local-controls {
max-width: 200px;
width: 35%;
input[type="range"] {
display: block;
width: 100%;
&:not(:first-child) {
margin-top: $interiorMarginLg;
}
&:before {
margin-right: $interiorMarginSm;
}
}
.t-reset-btn-holder {
$bc: $scrollbarTrackColorBg;
&:before,
&:after {
border-right: 1px solid $bc;
content:'';
display: block;
width: 5px;
height: 4px;
}
&:before {
border-top: 1px solid $bc;
margin-bottom: 2px;
}
&:after {
border-bottom: 1px solid $bc;
margin-top: 2px;
}
}
&.s-wrapper-transluc {
left: auto;
padding: $interiorMargin $interiorMarginLg;
}
&.l-flex-row {
align-items: center;
}
}
/*************************************** WHEN IN FRAME */
.frame .t-imagery {
.l-image-main-wrapper {

View File

@ -51,13 +51,9 @@ table {
tbody, .tbody {
display: table-row-group;
tr, .tr {
&:hover {
background: rgba($colorTabBodyFg, 0.1);
}
}
}
tr, .tr {
border-top: 1px solid $colorTabBorder;
display: table-row;
&:first-child .td {
border-top: none;
@ -71,11 +67,12 @@ table {
}
th, .th, td, .td {
display: table-cell;
font-size: 0.7rem;
}
th, .th {
border-left: 1px solid $colorTabHeaderBorder;
color: $colorTabHeaderFg;
padding: $tabularTdPadLR $tabularTdPadLR;
padding: $tabularTdPadTB $tabularTdPadLR;
white-space: nowrap;
vertical-align: middle; // This is crucial to hiding f**king 4px height injected by browser by default
&:first-child {
@ -99,7 +96,6 @@ table {
}
}
td, .td {
border-bottom: 1px solid $colorTabBorder;
min-width: 20px;
color: $colorTelemFresh;
padding: $tabularTdPadTB $tabularTdPadLR;

View File

@ -55,9 +55,7 @@
height: 70%;
width: 50%;
min-height: 300px;
max-height: 800px;
min-width: 600px;
max-width: 1000px;
z-index: 101;
> .contents {
$m: $overlayMargin;
@ -141,4 +139,4 @@
$h: 225px;
min-height: $h;
height: $h;
}
}

View File

@ -46,18 +46,42 @@
}
}
.gl-plot-wrapper-display-area-and-x-axis {
// Holds the plot area and the X-axis only
position: absolute;
top: nth($plotDisplayArea, 1);
right: nth($plotDisplayArea, 2);
bottom: 0;
left: nth($plotDisplayArea, 4);
.gl-plot-display-area {
//@include test(yellow);
@if $colorPlotBg != none {
background-color: $colorPlotBg;
}
position: absolute;
top: 0;
right: 0;
bottom: nth($plotDisplayArea, 3);
left: 0;
cursor: crosshair;
border: 1px solid $colorPlotAreaBorder;
}
.gl-plot-axis-area.gl-plot-x {
//@include test(green);
top: auto;
right: 0;
bottom: 0;
left: 0;
height: $plotXBarH;
width: auto;
overflow: hidden;
}
}
.gl-plot-axis-area {
//@include test();
position: absolute;
&.gl-plot-x {
top: auto;
right: 0;
bottom: $interiorMargin;
left: $plotYBarW;
height: $plotXBarH;
width: auto;
overflow: hidden;
}
&.gl-plot-y {
top: $plotLegendH + $interiorMargin;
right: auto;
@ -84,19 +108,6 @@
}
}
.gl-plot-display-area {
@if $colorPlotBg != none {
background-color: $colorPlotBg;
}
position: absolute;
top: nth($plotDisplayArea, 1);
right: nth($plotDisplayArea, 2);
bottom: nth($plotDisplayArea, 3);
left: nth($plotDisplayArea, 4);
cursor: crosshair;
border: 1px solid $colorPlotAreaBorder;
}
.gl-plot-label,
.l-plot-label {
color: $colorPlotLabelFg;
@ -265,13 +276,9 @@
.gl-plot-tick,
.tick-label {
direction: rtl;
unicode-bidi:bidi-override;
@include reverseEllipsis();
font-size: 0.7rem;
position: absolute;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&.gl-plot-x-tick-label,
&.tick-label-x {
right: auto;

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