Compare commits

...

185 Commits

Author SHA1 Message Date
Victor Woeltjen
08c4302011 [Build] Bump version number to close release 2015-12-18 12:21:11 -08:00
Victor Woeltjen
5f96861c44 [Duplicate] Handle single-element ID arrays
Avoid type coercion related errors when testing to
see if a value is an ID that needs to be remapped.
2015-12-17 15:10:15 -08:00
Victor Woeltjen
995d71f901 [Duplicate] Add test case
Add test case for single-element string arrays, to
replicate bug around type coercion.

https://github.com/nasa/openmctweb/issues/444
2015-12-17 15:07:16 -08:00
Pete Richards
82e4a53472 Merge remote-tracking branch 'github-open/open-warp1596b' into open-master 2015-12-17 14:20:18 -08:00
Charles Hacskaylo
e7a41061c6 [Frontend] Hiding filter input in autoflow element when in Layout
open #425
(cherry picked from commit 119613e)
2015-12-17 14:11:39 -08:00
Victor Woeltjen
4848a61e21 Merge pull request #439 from nasa/open428
Fixed bug in copying #428
2015-12-17 13:55:55 -08:00
Henry
6302e45c10 Fixed bug in copying #428 2015-12-17 13:47:31 -08:00
Victor Woeltjen
451157b653 Merge pull request #432 from nasa/open426
Review and integrate open426
2015-12-17 13:38:45 -08:00
Pete Richards
f55168d1ac Merge remote-tracking branch 'github-open/open-warp1596' into open-master 2015-12-17 09:39:38 -08:00
Victor Woeltjen
c4f99a6cab Merge pull request #435 from nasa/open428
[Copy] Duplication of layouts does not retain position and size of all elements. #428
2015-12-16 11:45:22 -08:00
Henry
83e77303aa [Copy] Duplication of layouts does not retain position and size of all elements. #428 2015-12-16 11:11:20 -08:00
Charles Hacskaylo
6e1cadf338 [Frontend] Fixed splitter and related elements when collapsed
open #426
Adds CSS to turn off pointer-events for the splitter, treeview
and inspect elements when they are in a collapsed state;
2015-12-15 15:47:32 -08:00
Charles Hacskaylo
83a9b984e5 [Frontend] Recompile CSS after integration of open1596
open #425
warp#1596
Recompile CSS after integration of cherry-pick from open1596;
2015-12-14 15:28:48 -08:00
Charles Hacskaylo
978df93ffd [Frontend] Cherry-picking platform CSS mods for autoflow view
warp #1596
open #425
Changes to autoflow styles, particularly in header;
Cleanup in effects.scss; CSS to be re-compiled;
(cherry picked from commit 5848077)
2015-12-14 15:22:08 -08:00
akhenry
0cfc070f3c Merge pull request #394 from nasa/open332
[Duplicate] Rewrite identifiers in clones
2015-12-11 15:06:34 -08:00
akhenry
5ad150a17e Merge pull request #413 from nasa/open411
[Documentation] Fix type declaration
2015-12-11 11:28:38 -08:00
Victor Woeltjen
de88bf94d4 [Documentation] Fix type declaration
Rephrase parameter type to something JSDoc can parse.

https://github.com/nasa/openmctweb/issues/411
2015-12-11 10:51:16 -08:00
Victor Woeltjen
19f07aa398 [Duplicate] Add trailing newline 2015-12-08 16:34:36 -08:00
Victor Woeltjen
46f9b31cff [Duplicate] Test rewriting of identifiers 2015-12-08 16:27:46 -08:00
Victor Woeltjen
e32feb29e2 [Duplicate] Rewrite identifiers in clones
Traverse object models of clones and rewrite domain object
identifiers that have changed during duplication.

Addresses https://github.com/nasa/openmctweb/issues/332
2015-12-08 15:45:45 -08:00
Pete Richards
89a93e2966 Merge remote-tracking branch 'github-open/open384' into open-master 2015-12-08 15:18:21 -08:00
Victor Woeltjen
038322e9aa [Layout] Update raw positions on drop
When handling a drop into the layout, store the panel's
new position to the LayoutController's internal table of
raw positions (in addition to writing it to the configuration.)

Avoids https://github.com/nasa/openmctweb/issues/384
2015-12-08 15:08:30 -08:00
Victor Woeltjen
6cef663db5 [Representation] Add ending newline 2015-12-08 13:43:41 -08:00
Victor Woeltjen
b2f5861458 [Representation] Test template prefetcher 2015-12-08 13:29:11 -08:00
Victor Woeltjen
f8809ce67f [Representation] Also prefetch containers 2015-12-08 13:06:24 -08:00
Victor Woeltjen
3c97eb6014 [Representation] Remove obsolete template definition 2015-12-08 12:59:41 -08:00
Victor Woeltjen
3498b0a50a [Representation] Prefetch templates
...to ensure that dialogs et al can be displayed, even
after loss of network connectivity.

https://github.com/nasa/openmctweb/issues/383
2015-12-08 12:59:18 -08:00
akhenry
ed7e0d8b0a Merge pull request #376 from nasa/open169b
Review and integrate open169b
2015-12-04 16:29:32 -08:00
Charles Hacskaylo
f3828ba516 [Frontend] Adjusted desktop breakpoint
open #169
2015-12-04 15:55:32 -08:00
akhenry
2a48c25453 Merge pull request #375 from nasa/open137
Show warning for unsupported browsers
2015-12-04 15:43:23 -08:00
akhenry
096da0cb94 Merge pull request #347 from nasa/open259b
[Time Conductor] Don't update model while typing (v2)
2015-12-04 15:34:03 -08:00
Charles Hacskaylo
ca8a07e1ae Merge remote-tracking branch 'github/open169a' into open169b 2015-12-04 15:33:49 -08:00
Victor Woeltjen
c02f965460 [Time Conductor] Remove unused property
...from structure passed into date-time field. Note in
code review, https://github.com/nasa/openmctweb/pull/347
2015-12-04 15:19:34 -08:00
Victor Woeltjen
5f440bb6de Merge pull request #372 from nasa/open58_notification
[Persistence] Errors in persistence (after creating/modifying objects) should be visible to user #58
2015-12-04 15:15:29 -08:00
Victor Woeltjen
fc729279ec [Common UI] Add spec for unsupported browser warning 2015-12-04 15:11:40 -08:00
akhenry
dd0f9ab74e Merge pull request #349 from nasa/open1573
[Documentation] Document test process
2015-12-04 14:34:59 -08:00
Victor Woeltjen
d2a4a85e04 [Common UI] Test agentService.isBrowser 2015-12-04 14:12:00 -08:00
Victor Woeltjen
37890280ae [Common UI] Only show warning for unsupported browsers 2015-12-04 14:08:42 -08:00
Victor Woeltjen
a6ceae4045 [Common UI] Show warning at startup
Show a warning about unsupported browsers at startup,
https://github.com/nasa/openmctweb/issues/137
2015-12-04 13:53:45 -08:00
akhenry
3447e735dc Merge pull request #362 from nasa/open346
[Entanglement] Add "Set Primary Location" action
2015-12-04 13:48:27 -08:00
Victor Woeltjen
989c937ce1 [Documentation] Fix typo in HTML entity 2015-12-04 13:29:19 -08:00
Victor Woeltjen
e0608ddee0 [Documentation] Simplify Author Checklist
...as discussed in https://github.com/nasa/openmctweb/pull/349
2015-12-04 13:25:20 -08:00
akhenry
b35224061f Merge pull request #374 from nasa/open305
[Edit] Return a promise from editable persistence capability
2015-12-04 12:44:08 -08:00
Victor Woeltjen
b25576aed8 [Documentation] Sketch initial test procedures
Sketch initial test procedures; add explanation on the difference between
sprint and release testing.
2015-12-04 12:20:05 -08:00
Victor Woeltjen
d5f054e328 [Edit] Test return type
...from the edit-mode-wrapped persistence capability.
2015-12-04 11:20:19 -08:00
Henry
eb4959cf49 [persistence] #58 renamed alertService to notificationService 2015-12-04 10:45:49 -08:00
Victor Woeltjen
cce415fc51 Merge pull request #371 from nasa/open338
#338 [Copy] Copying an object with telemetry from the data dictionary results in a number of unknown objects in copied tree
2015-12-04 09:46:24 -08:00
Henry
00f96c314a [persistence] #58 added tests for notification on persistence error 2015-12-03 20:32:03 -08:00
Victor Woeltjen
fefd27162c [Entanglement] Allow cross-space linking
Allow links across spaces; only disallow move or copy.
Addresses WTD-1587
2015-12-03 20:32:03 -08:00
Henry
b388c76e45 [copy] #338 Modified check to set object location, added setLocation flag, Removed unused parameter 2015-12-03 19:00:44 -08:00
akhenry
aaeaf3a096 Merge pull request #370 from nasa/open369
[Performance] Fix usages of $interval
2015-12-03 18:31:17 -08:00
Henry
57efe4e0d1 Removed UUID reference 2015-12-03 17:10:28 -08:00
Victor Woeltjen
dd4dbc9326 [Performance] Update spec for ElasticIndicator
...to reflect changes in  call to reduce digest frequency.
2015-12-03 16:45:30 -08:00
Henry
6aa77ff468 #338 fixed failing test 2015-12-03 16:41:06 -08:00
Henry
f8099550bd [Copy] #338 updated code style in CreationPolicy 2015-12-03 16:22:45 -08:00
Henry
96249e6bcc Removed redundant line in test spec 2015-12-03 15:51:27 -08:00
Henry
6e391098a3 Fixed jslint error 2015-12-03 15:32:26 -08:00
Henry
baec0f9719 #338 added new test case for creation of links when object type is not createable 2015-12-03 15:28:07 -08:00
Henry
6aab9f4e34 Added test for linking 2015-12-03 14:47:42 -08:00
Victor Woeltjen
1bf73935e4 [Performance] Add test case for mct-split-pane 2015-12-03 13:56:57 -08:00
Victor Woeltjen
49e51d0a62 [Performance] Update mct-chart spec 2015-12-03 13:39:37 -08:00
Victor Woeltjen
3e7bc2f37f [Performance] Don't invoke apply from indicator
Don't invoke apply while polling from ElasticSearch
indicator; let the corresponding  request trigger
this.
2015-12-03 13:29:54 -08:00
Victor Woeltjen
0f56fd2561 [Performance] Only invoke apply on size changes
...as detected from mct-chart.
2015-12-03 13:28:32 -08:00
Victor Woeltjen
9f0114eb39 [Performance] Don't invoke apply from MCTSplitPane
Don't invoke apply on every  from MCTSplitPane
(this had been intended behavior, but argument was misplaced.)
2015-12-03 13:27:59 -08:00
Victor Woeltjen
4b82893c36 [Performance] Improve digests/sec indication
Don't let past digest counts bias current rate shown;
https://github.com/nasa/openmctweb/issues/369
2015-12-03 13:27:19 -08:00
Henry
734e979c94 #338 Fixed failing tests after refactor 2015-12-03 12:49:54 -08:00
akhenry
983973843e Merge pull request #363 from nasa/open302
[Representation] Check full path when comparing domain objects
2015-12-03 10:01:35 -08:00
Henry
3b427c31a2 Fixed error with not properly referenced 2015-12-02 19:18:50 -08:00
Henry
cee0ecf0ef Removed use of composition and mutation because they trigger the search indexer too early and it tries to retrieve objects that have not been persisted yet 2015-12-02 19:10:10 -08:00
Henry
8e3c5db3bf #338 fixed incorrect 'allow' function specification in CreationPolicy 2015-12-02 14:14:04 -08:00
Henry
11d8daf3ed #338 Fixed incorrect specification of CreationPolicy in bundle.json 2015-12-02 14:07:08 -08:00
Henry
9953e16415 #338 Copy now using target persistence space 2015-12-02 14:06:22 -08:00
Henry
fe600de0f7 [Copy] #338 added CreationPolicy and appropriate tests, amended CreateActionProvider, and updated existing tests 2015-12-02 11:28:49 -08:00
Victor Woeltjen
386f1f20ff [Representation] Test switching between links
Add test case to verify that representation gets refreshed
when switching among two linked instances of the same
domain object.
2015-12-02 10:49:18 -08:00
Victor Woeltjen
5e07951892 [Representation] Handle missing context
Handle missing context when generating an ID path;
this is missing in the root object.
2015-12-02 10:23:11 -08:00
Victor Woeltjen
2514e44083 [Representation] Check full ID path
...when determining if a representation needs to be
refreshed. Avoids representations becoming stale
when switching or navigating among linked instances
of the same domain object.

https://github.com/nasa/openmctweb/issues/302
2015-12-02 10:21:00 -08:00
Henry
20d9c7158e Added jslint es5 mode 2015-12-01 22:40:50 -08:00
Henry
d8e319ebf8 Fixing jslint errors 2015-12-01 22:36:23 -08:00
Henry
a39cbbd917 Fixing jslint errors 2015-12-01 22:35:28 -08:00
Henry
8df27a1c05 Fixing jslint errors 2015-12-01 22:34:26 -08:00
Henry
26cf9c14f4 [Persistence] Errors in persistence (after creating/modifying objects) should be visible to user #58 2015-12-01 22:03:53 -08:00
Victor Woeltjen
03edd26e17 [Edit] Return promise from editable persistence
https://github.com/nasa/openmctweb/issues/305
2015-12-01 16:45:08 -08:00
Victor Woeltjen
571f6d183a [Entanglement] Expose Set Primary Location 2015-12-01 16:26:19 -08:00
Victor Woeltjen
1292e39c46 [Entanglement] Implement Set Primary Location 2015-12-01 16:20:30 -08:00
Victor Woeltjen
6fe3f82fb1 [Entanglement] Add test for Set Primary Location
https://github.com/nasa/openmctweb/issues/346
2015-12-01 15:59:37 -08:00
Charles Hacskaylo
da8fb99e82 [Frontend] Fixing bad breakpoints for tablet vs. desktop
open #169
2015-11-30 15:57:45 -08:00
Victor Woeltjen
c8d77bc2db [Entanglement] Allow cross-space linking
Allow links across spaces; only disallow move or copy.
Addresses WTD-1587
2015-11-30 15:27:10 -08:00
Victor Woeltjen
b5e52fce75 [Time Conductor] Remove redundant test block 2015-11-27 14:48:48 -08:00
Victor Woeltjen
3afcb52934 [Time Conductor] Use ng-blur from template 2015-11-27 14:35:51 -08:00
Victor Woeltjen
677b0cffec [Time Conductor] Test form isolation
Verify that form inputs are ignored until some explicit trigger
2015-11-27 14:33:35 -08:00
Victor Woeltjen
248bc68f0d [Time Conductor] Test restoration of old values
...and clarify name of the function in scope which does this.
2015-11-27 14:23:30 -08:00
Victor Woeltjen
02050fa3ef [Time Conductor] Document ng-blur on mct-control 2015-11-27 14:02:16 -08:00
Victor Woeltjen
57d23c3696 [Time Conductor] Add missing license header 2015-11-27 12:37:51 -08:00
Victor Woeltjen
8babfc5ca9 [Time Conductor] Propogate blur from text field 2015-11-27 12:37:23 -08:00
Victor Woeltjen
271b5d1a73 [Time Conductor] Test choices via picker
...to ensure that they trigger blur events. Also, test changes
via text entry to ensure that they don't (the template is responsible
for this.)
2015-11-27 12:36:40 -08:00
Victor Woeltjen
7d4e7a0925 [Time Conductor] Allow ng-blur on mct-controls 2015-11-27 12:29:53 -08:00
Victor Woeltjen
92f5d5f190 [Documentation] Replace redundant docs with link 2015-11-27 12:00:25 -08:00
Victor Woeltjen
1731b985fc [Documentation] Fix broken markdown tag 2015-11-27 11:30:55 -08:00
Victor Woeltjen
bd4590ad9d [Documentation] Update terminology
Update terminology in Development Cycle to reflect
descriptions in Test Plan.
2015-11-27 11:22:11 -08:00
Victor Woeltjen
55fc60ec82 [Documentation] Describe long-duration testing 2015-11-27 11:15:13 -08:00
Victor Woeltjen
ab075e9ad8 [Documentation] Complete test plan 2015-11-27 11:08:47 -08:00
Victor Woeltjen
3ac1710d83 [Documentation] Document evaluation criteria
...for per-release and per-sprint testing. WTD-1573
2015-11-27 10:58:16 -08:00
Victor Woeltjen
730878938e [Documentation] Document pre-merge testing 2015-11-27 10:39:25 -08:00
Victor Woeltjen
3fd4304de1 Merge pull request #345 from nasa/open32
[Layout] Layout rebuilds after resize/reposition #32
2015-11-27 09:59:01 -08:00
Henry
db7224486c [Layout] Layout rebuilds after resize/reposition - Fixed potential race condition #32 2015-11-25 19:11:29 -08:00
Henry
424953c894 [Layout] Layout rebuilds after resize/reposition #32
- Refactored layoutPanels member function, and updated tests.
- Changed $scope.$watch to $scope.$watchCollection
2015-11-25 15:32:33 -08:00
Henry
6d0f3c7faa [Layout] Layout rebuilds after resize/reposition #32
Refactored layoutPanels method

Fixed JSLint errors

fixed failing tests
2015-11-25 15:30:33 -08:00
Victor Woeltjen
434a52ded3 [Build] Bump version number
...to begin work for new sprint.
2015-11-25 14:11:53 -08:00
Victor Woeltjen
2ec906e2d4 [Build] Remove snapshot status
Remove snapshot status in preparation to bump version number
at end of sprint Banks.
2015-11-25 14:10:48 -08:00
Victor Woeltjen
ffff13205a [Time Conductor] Check for value changes
...on watches triggered from the picker. Only want to
trigger a submit when this actually constitutes a change from
the datetime field's underlying model (to avoid triggering
form submission when datetime picker is initialized.)
2015-11-25 11:21:51 -08:00
Victor Woeltjen
16efd85dfc [Time Conductor] Submit immediately on picker changes 2015-11-25 11:16:31 -08:00
Victor Woeltjen
1ef09ffbdd [Time Conductor] Restore last valid values
Restore last valid values on blur, in a date-time entry field.
2015-11-25 11:12:41 -08:00
Victor Woeltjen
976ecce075 [Time Conductor] Update model on submit/blur 2015-11-25 11:09:11 -08:00
Victor Woeltjen
87a51a9eb3 [Time Conductor] Listen for blur, submit
https://github.com/nasa/openmctweb/issues/259
2015-11-25 11:02:03 -08:00
Henry
c84de00e80 [Layout] Layout rebuilds after resize/reposition #32 2015-11-24 21:51:10 -08:00
Victor Woeltjen
91997ced01 [Documentation] Define test levels 2015-11-24 17:08:59 -08:00
Victor Woeltjen
7a4be9e67e [Documentation] Add test procedure template 2015-11-24 15:56:02 -08:00
Victor Woeltjen
eb942b0bf7 [Documentation] Intermediary commit
Begin adding test plan, procedures. WTD-1573.
2015-11-24 13:08:59 -08:00
Victor Woeltjen
1cf23c7ad6 [Documentation] Rename development cycle
...as it will no longer be the index of the process
category as information about testing is added.
2015-11-24 10:57:52 -08:00
Victor Woeltjen
15ec9df538 Merge pull request #327 from nasa/open208b
[Timelines] Bring over CSS
2015-11-23 10:38:02 -08:00
Victor Woeltjen
d6e2895666 Merge pull request #257 from nasa/open245b
[Persistence] Support multiple persistence spaces
2015-11-21 07:13:54 -08:00
Victor Woeltjen
7974ffdda2 Merge remote-tracking branch 'github/master' into open245b
...in preparation to complete merge nasa/openmctweb#257

Conflicts:
	platform/entanglement/src/actions/CopyAction.js
	platform/entanglement/src/actions/LinkAction.js
	platform/entanglement/src/actions/MoveAction.js
2015-11-21 07:05:51 -08:00
Victor Woeltjen
d5858622ba [Persistence] Fix grammar in JSDoc
...and add some explanation of METHOD_DEFAULTS.
2015-11-21 06:59:12 -08:00
Victor Woeltjen
9656e09066 [Documentation] Clarify identifier syntax
...in plain English, for the humans.

Per code review in nasa/openmctweb#257
2015-11-21 06:52:19 -08:00
Victor Woeltjen
096fee8b6d Merge remote-tracking branch 'github/master' into open208b
Conflicts:
	platform/commonUI/themes/espresso/res/css/theme-espresso.css
	platform/commonUI/themes/snow/res/css/theme-snow.css
2015-11-21 06:42:45 -08:00
Victor Woeltjen
0635e7c38e [Timeline] Disambiguate datetime control
Timeline uses a custom date-time control on creation;
use a distinct key for this to avoid a naming collision
with platform's datetime. Addresses abnormal behavior
identified in nasa/openmctweb#208
2015-11-20 17:26:43 -08:00
Victor Woeltjen
845b1dcd6f Merge pull request #321 from nasa/open169
Review and integrate open169
2015-11-20 17:13:39 -08:00
Victor Woeltjen
2e959e8503 Revert "[Mobile] Deploy via CircleCI"
This reverts commit 49b3d67272.
2015-11-20 17:09:37 -08:00
Victor Woeltjen
e6c9cbf0cd [Persistence] Clarify JSDoc
Per code review feedback, nasa/openmctweb#257
2015-11-20 17:08:39 -08:00
akhenry
fb0ba0cff9 Merge pull request #323 from nasa/open251
Review and integrate open251
2015-11-20 13:30:24 -08:00
akhenry
573e5608fc Merge pull request #319 from nasa/open-status-tracking
[Status] Add status tracking
2015-11-20 13:18:09 -08:00
Victor Woeltjen
37a7c2b1df Merge pull request #309 from nasa/open308
[Workers] Allow web workers to be shared
2015-11-20 11:40:26 -08:00
Victor Woeltjen
38274728f6 [Workers] Update JSDoc
...per review feedback, nasa/openmctweb#309
2015-11-20 11:12:29 -08:00
Victor Woeltjen
49b3d67272 [Mobile] Deploy via CircleCI
...to enable testing of changes for nasa/openmctweb#169.
2015-11-20 11:05:25 -08:00
Victor Woeltjen
400b992ec3 [Status] Revise API
Change method names, add a getter to status capability;
per code review feedback, nasa/openmctweb#319.
2015-11-20 09:46:08 -08:00
Charles Hacskaylo
32815d8427 [Frontend] Markup and CSS fixes
open #251
Fixed markup and CSS to remove erroneously
applied "select" class;
Modified .select to not use overflow: hidden;
Better positioning for *-options elements;
2015-11-19 18:50:10 -08:00
Charles Hacskaylo
3e25d17702 [Mobile / Frontend] Modified media query device detection approach
open #169
Significant simplification of media query device detection
to focus on width only; tablet max-width and desktop
min-width modified to create gapless ranges;
2015-11-19 15:16:21 -08:00
Victor Woeltjen
b5d1118a3f [Status] Document status capability
...in the developer guide. Includes a table for listing
status names and classes, per code review feedback,
nasa/openmctweb#319.
2015-11-19 15:12:03 -08:00
Victor Woeltjen
5b9e43f8ff [Status] Test platform/status 2015-11-19 14:22:44 -08:00
Victor Woeltjen
3ffa6f70aa [Status] Add empty specs 2015-11-19 13:47:39 -08:00
Victor Woeltjen
0d07c3c289 [Status] Clean up classes when destroyed 2015-11-19 13:44:06 -08:00
Victor Woeltjen
29fdb6d641 [Status] Add JSDoc 2015-11-19 13:43:18 -08:00
Victor Woeltjen
39d007470a [Status] Active platform/status bundle 2015-11-18 17:23:31 -08:00
Victor Woeltjen
285c8cbd1e [Status] Add status tracking
Add status tracking for domain objects, and decoration of
representations with status-related classes. Supports WTD-1575
by allowing pending state of taxonomy to be handled by
status tracking and custom CSS, instead of by overriding platform
templates.
2015-11-18 17:22:38 -08:00
Victor Woeltjen
ef5a26dfcc [Documentation] Specify default value
...for shared property of workers.
2015-11-16 16:16:22 -08:00
Victor Woeltjen
8363302caf [Workers] Allow web workers to be shared
Support an additional flag in the  extension category
such that SharedWorkers may be used. nasa/openmctweb#308.
2015-11-16 15:16:44 -08:00
Victor Woeltjen
04ce2f985a [Persistence] Add JSDoc
Add JSDoc to classes added/modified to support multiple persistence
spaces, nasa/openmctweb#245.
2015-11-10 14:16:07 -08:00
Victor Woeltjen
a14f30c03c [Persistence] Test PersistenceAggregator 2015-11-10 13:43:22 -08:00
Victor Woeltjen
bd85392b54 [Persistence] Test cross-space policy
Verify that move/copy/link across spaces is disallowed.
2015-11-10 13:29:12 -08:00
Victor Woeltjen
7c427e0b6e [Persistence] Test IdentifierProvider 2015-11-10 13:15:24 -08:00
Victor Woeltjen
6cf8335f31 [Persistence] Test Identifier parsing
...and add empty spec for IdentifierProvider
2015-11-10 13:11:21 -08:00
Victor Woeltjen
647a1403d0 [Persistence] Update developer guide
Replay changes to developer guide regarding identifier syntax
and persistence spaces.
2015-11-10 13:01:32 -08:00
Victor Woeltjen
1d9b8f34e2 Merge remote-tracking branch 'github/master' into open245b
...to resolve merge conflicts for pull request for
nasa/openmctweb#245

Conflicts:
	docs/src/guide/index.md
2015-11-10 12:56:11 -08:00
Victor Woeltjen
adf119007b [Persistence] Test validator
Exercise the validation function provided by move/copy/link
actions when prompting for a location with a dialog.
2015-11-10 12:46:58 -08:00
Victor Woeltjen
7114e9b150 [Persistence] Update move/copy/link specs
...to reflect re-consultation of policyService when the action
context changes due to dialog input.
2015-11-10 12:40:52 -08:00
Victor Woeltjen
76c1f5bfe9 [Persistence] Update spec for instantiate
...to reflect usage of identifierService.
2015-11-10 12:34:54 -08:00
Victor Woeltjen
33f88d30ed [Persistence] Update bundle definition
...to reflect dependency on identifierService to interpret an
object's persistence space based on its identifier.
2015-11-10 12:34:30 -08:00
Victor Woeltjen
ffdcbece56 [Persistence] Update failing spec
...to reflect changes to the persistence capability, utilizing the
identifierService for consistent interpretation of spaces by id.
2015-11-10 12:33:52 -08:00
Victor Woeltjen
44eb723efb [Persistence] Update failing spec
...for instantiation capability, to reflect usage of identifier
parser in determining which space an object should belong to.
2015-11-10 12:26:59 -08:00
Victor Woeltjen
689f80bb23 [Persistence] Use identifierService from persistence
User identifierService from the persistence capability, for
consistent interpretation of spaces associated with domain
object identifiers.
2015-11-10 12:21:53 -08:00
Victor Woeltjen
a2db98d275 [Persistence] Update failing spec
...to reflect changes to PersistedModelProvider
2015-11-10 12:12:11 -08:00
Victor Woeltjen
49b983cd3a [Persistence] Fix cross-space policy
Fix logic in cross-space policy; only disallow when a move, copy
or link would really cross spaces.
2015-11-10 10:57:48 -08:00
Victor Woeltjen
ad60b9225e [Persistence] Clean up instantiation
Fix typo to correctly reuse defined identifiers, remove
unused dependency of instantiation capability.
2015-11-10 10:53:48 -08:00
Victor Woeltjen
0c096db8bd [Persistence] Suppress Move/Copy/Link
Disallow move/copy/link when crossing persistence spaces,
nasa/openmctweb#245
2015-11-10 10:44:21 -08:00
Victor Woeltjen
87684e0945 [Persistence] User identifierService from instantiate 2015-11-09 15:25:07 -08:00
Victor Woeltjen
1d13b245f9 [Persistence] Update bundle definition
...after merging latest changes from master branch into
topic branch for nasa/openmctweb#245.
2015-11-09 15:21:41 -08:00
Victor Woeltjen
e31d9decdc Merge remote-tracking branch 'github/master' into open245b
Conflicts:
	docs/src/guide/index.md
	platform/core/src/capabilities/InstantiationCapability.js
2015-11-09 15:17:53 -08:00
Victor Woeltjen
06436bb876 [Creation] Use identifierService
...from CreationCapability.
2015-11-06 13:10:51 -08:00
Victor Woeltjen
d8f3f0f430 [Persistence] Expose IdentifierService 2015-11-06 13:05:27 -08:00
Victor Woeltjen
177c1874b9 [Persistence] Add identifierService 2015-11-06 13:03:54 -08:00
Victor Woeltjen
eef801f1ae [Persistence] Fix read in example
Values are stored in the scratchpad as JSON, so parse them
as JSON before returning them.
2015-11-05 18:00:51 -08:00
Victor Woeltjen
d69cf6c6fe [Persistence] Parse out key
When an identifier is a space-key pair, parse out the key before
persisting.
2015-11-05 17:58:16 -08:00
Victor Woeltjen
0a9c162f26 [Persistence] Fix method delegation
...used by PersistenceAggregator
2015-11-05 17:53:04 -08:00
Victor Woeltjen
942fa46022 [Persistence] Expose aggregator 2015-11-05 17:51:14 -08:00
Victor Woeltjen
74aff1b407 [Persistence] Implement aggregator 2015-11-05 17:48:43 -08:00
Victor Woeltjen
dbff9e2125 [Persistence] Add example provider
...to serve as a secondary persistence store.
2015-11-05 17:38:51 -08:00
Victor Woeltjen
bed1556a3a [Persistence] Begin adding example bundle
Begin adding example bundle illustrating usage of secondary persistence
stores. Scratchpad will 'persist' objects only in memory.
2015-11-05 17:30:27 -08:00
Victor Woeltjen
822b4ae96f [Persistence] Report space by identifier 2015-11-05 17:26:48 -08:00
Victor Woeltjen
99f3b986b6 [Creation] Retain space prefix
Retain space prefix from a parent when creating a new domain object,
if there is a space prefix.
2015-11-05 17:25:39 -08:00
Victor Woeltjen
fd4c1ea747 [Persistence] Retain original id
...after parsing out space and key, to aid in assembling
the result of getModels as an object where IDs are keys.
2015-11-05 17:22:05 -08:00
Victor Woeltjen
944a5a7424 [Persistence] Update JSDoc 2015-11-05 17:16:53 -08:00
Victor Woeltjen
dda2c89a58 [Persistence] Update bunde definition
...to reflect removal of 'additional persistence spaces'; parse
these out of identifiers instead.
2015-11-05 17:13:19 -08:00
Victor Woeltjen
c8cfbf5281 [Persistence] Refactor model loading
...such that ids are only parsed for space/key pairs once.
2015-11-05 17:11:24 -08:00
Victor Woeltjen
9f383ab101 [Persistence] Parse space from id
Parse spaces from domain object identifiers, if these have
been specified.
2015-11-05 17:04:55 -08:00
Victor Woeltjen
7811d50372 [Persistence] Document identifier syntax
Document identifier syntax to account for space-prefixing
for nasa/openmctweb#245.
2015-11-05 16:50:24 -08:00
109 changed files with 4497 additions and 928 deletions

View File

@@ -291,7 +291,7 @@ checklist.)
1. Changes address original issue?
2. Unit tests included and/or updated with changes?
3. Command line build passes?
4. Expect to pass code review?
4. Changes have been smoke-tested?
### Reviewer Checklist

View File

@@ -25,11 +25,13 @@
"platform/features/timeline",
"platform/forms",
"platform/identity",
"platform/persistence/aggregator",
"platform/persistence/local",
"platform/persistence/queue",
"platform/policy",
"platform/entanglement",
"platform/search",
"platform/status",
"example/imagery",
"example/eventGenerator",

View File

@@ -677,6 +677,40 @@ If the provided capability has no invoke method, the return value here functions
as `getCapability` including returning `undefined` if the capability is not
exposed.
### Identifier Syntax
For most purposes, a domain object identifier can be treated as a purely
symbolic string; these are typically generated by Open MCT Web and plug-ins
should rarely be concerned with its internal structure.
A domain object identifier has one or two parts, separated by a colon.
* If two parts are present, the part before the colon refers to the space
in which the domain object resides. This may be a persistence space or
a purely symbolic space recognized by a specific model provider. The
part after the colon is the key to use when looking up the domain object
model within that space.
* If only one part is present, the domain object has no space specified,
and may presume to reside in the application-configured default space
defined by the `PERSISTENCE_SPACE` constant.
* Both the key and the space identifier may consist of any combination
of alphanumeric characters, underscores, dashes, and periods.
Some examples:
* A domain object with the identifier `foo:xyz` would have its model
loaded using key `xyz` from persistence space `foo`.
* A domain object with the identifier `bar` would have its model loaded
using key `bar` from the space identified by the `PERSISTENCE_SPACE`
constant.
```bnf
<identifier> ::= <space> ":" <key> | <key>
<space> ::= <id char>+
<key> ::= <id char>+
<id char> ::= <letter> | <digit> | "-" | "." | "_"
```
## Domain Object Actions
An `Action` is behavior that can be performed upon/using a `DomainObject`. An
@@ -907,6 +941,12 @@ look at field (see below) to determine which field in the model should be
modified.
* `ngRequired`: True if input is required.
* `ngPattern`: The pattern to match against (for text entry)
* `ngBlur`: A function that may be invoked to evaluate the expression
associated with the `ng-blur` attribute associated with the control.
* This should be called when the control has lost focus; for controls
which simply wrap or augment `input` elements, this should be fired
on `blur` events associated with those elements, while more complex
custom controls may fire this at the end of more specific interactions.
* `options`: The options for this control, as passed from the `options` property
of an individual row definition.
* `field`: Name of the field in `ngModel` which will hold the value for this
@@ -1254,6 +1294,22 @@ object, or the current view proxy.
* `all()`: Get an array of all objects in the selection state. Will include
either or both of the view proxy and selected object.
## Workers Category
The `workers` extension category allows scripts to be run as web workers
using the `workerService`.
An extension of this category has no implementation. The following properties
are supported:
* `key`: A symbolic string used to identify this worker.
* `workerUrl`: The path, relative to this bundle's `src` folder, where
this worker's source code resides.
* `shared`: Optional; a boolean flag which, if true, indicates that this
worker should be instantiated as a
[`SharedWorker`](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker/SharedWorker).
Default value is `false`.
# Directives
Open MCT Web defines several Angular directives that are intended for use both
@@ -1849,6 +1905,14 @@ the TelemetrySeries itself, in that order.
* `getSeries(domainObject)`: Get the latest `TelemetrySeries` (as resulted from
a previous `request(...)` call) available for this domain object.
### Worker Service
The `workerService` may be used to run web workers defined via the
`workers` extension category. It has the following method:
* `run(key)`: Run the worker identified by the provided `key`. Returns
a `Worker` (or `SharedWorker`, if the specified worker is defined
as a shared worker); if the `key` is unknown, returns `undefined`.
# Models
Domain object models in Open MCT Web are JavaScript objects describing the
@@ -2056,6 +2120,31 @@ objects which has a `relationships` property in their model, whose value is an
object containing key-value pairs, where keys are strings identifying
relationship types, and values are arrays of domain object identifiers.
## Status Capability
The `status` capability provides a way to flag domain objects as possessing
certain states, represented as simple strings. These states, in turn, are
reflected on `mct-representation` elements as classes (prefixed with
`s-status-`.) The `status` capability has the following interface:
* `get()`: Returns an array of all status strings that currently apply
to this object.
* `set(status, state)`: Adds or removes a status flag to this domain object.
The `status` argument is the string to set; `state` is a boolean
indicating whether this status should be included (true) or removed (false).
* `listen(callback)`: Listen for changes in status. The provided `callback`
will be invoked with an array of all current status strings whenever status
changes.
Plug-ins may add and/or recognize arbitrary status flags. Flags defined
and/or supported by the platform are:
Status | CSS Class | Meaning
-----------|--------------------|-----------------------------------
`editing` | `s-status-editing` | Domain object is being edited.
`pending` | `s-status-pending` | Domain object is partially loaded.
## Telemetry Capability
The telemetry capability provides a means for accessing telemetry data
@@ -2328,6 +2417,11 @@ default paths to reach external services are all correct.
### Configuration Constants
The following constants have global significance:
* `PERSISTENCE_SPACE`: The space in which domain objects should be persisted
(or read from) when not otherwise specified. Typically this will not need
to be overridden by other bundles, but persistence adapters may wish to
consume this constant in order to provide persistence for that space.
The following configuration constants are recognized by Open MCT Web bundles:
* Common UI elements - `platform/commonUI/general`

161
docs/src/process/cycle.md Normal file
View File

@@ -0,0 +1,161 @@
# Development Cycle
Development of Open MCT Web occurs on an iterative cycle of
sprints and releases.
* A _sprint_ is three weeks in duration, and represents a
set of improvements that can be completed and tested by the
development team. Software at the end of the sprint is
"semi-stable"; it will have undergone reduced testing and may carry
defects or usability issues of lower severity, particularly if
there are workarounds.
* A _release_ occurs every four sprints. Releases are stable, and
will have undergone full acceptance testing to ensure that the
software behaves correctly and usably.
## Roles
The sprint process assumes the presence of a __project manager.__
The project manager is responsible for
making tactical decisions about what development work will be
performed, and for coordinating with stakeholders to arrive at
higher-level strategic decisions about desired functionality
and characteristics of the software, major external milestones,
and so forth.
In the absence of a dedicated project manager, this role may be rotated
among members of the development team on a per-sprint basis.
Responsibilities of the project manager including:
* Maintaining (with agreement of stakeholders) a "road map" of work
planned for future releases/sprints; this should be higher-level,
usually expressed as "themes",
with just enough specificity to gauge feasibility of plans,
relate work back to milestones, and identify longer-term
dependencies.
* Determining (with assistance from the rest of the team) which
issues to work on in a given sprint and how they shall be
assigned.
* Pre-planning subsequent sprints to ensure that all members of the
team always have a clear direction.
* Scheduling and/or ensuring adherence to
[process points](#process-points).
* Responding to changes within the sprint (shifting priorities,
new issues) and re-allocating work for the sprint as needed.
## Sprint Calendar
Certain [process points](#process-points) are regularly scheduled in
the sprint cycle.
### Sprints by Release
Allocation of work among sprints should be planned relative to release
goals and milestones. As a general guideline, higher-risk work (large
new features which may carry new defects, major refactoring, design
changes with uncertain effects on usability) should be allocated to
earlier sprints, allowing for time in later sprints to ensure stability.
| Sprint | Focus |
|:------:|:--------------------------------------------------------|
| __1__ | Prototyping, design, experimentation. |
| __2__ | New features, refinements, enhancements. |
| __3__ | Feature completion, low-risk enhancements, bug fixing. |
| __4__ | Stability & quality assurance. |
### Sprints 1-3
The first three sprints of a release are primarily centered around
development work, with regular acceptance testing in the third
week. During this third week, the top priority should be passing
acceptance testing (e.g. by resolving any blockers found); any
resources not needed for this effort should be used to begin work
for the subsequent sprint.
| Week | Mon | Tue | Wed | Thu | Fri |
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
| __1__ | Sprint plan | Tag-up | | | |
| __2__ | | Tag-up | | | Code freeze |
| __3__ | Per-sprint testing | Triage | | _Per-sprint testing*_ | Ship |
&ast; If necessary.
### Sprint 4
The software must be stable at the end of the fourth sprint; because of
this, the fourth sprint is scheduled differently, with a heightened
emphasis on testing.
| Week | Mon | Tue | Wed | Thu | Fri |
|-------:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
| __1__ | Sprint plan | Tag-up | | | Code freeze |
| __2__ | Per-release testing | Triage | | | |
| __3__ | _Per-release testing*_ | Triage | | _Per-release testing*_ | Ship |
&ast; If necessary.
## Process Points
* __Sprint plan.__ Project manager allocates issues based on
theme(s) for sprint, then reviews with team. Each team member
should have roughly two weeks of work allocated (to allow time
in the third week for testing of work completed.)
* Project manager should also sketch out subsequent sprint so
that team may begin work for that sprint during the
third week, since testing and blocker resolution is unlikely
to require all available resources.
* __Tag-up.__ Check in and status update among development team.
May amend plan for sprint as-needed.
* __Code freeze.__ Any new work from this sprint
(features, bug fixes, enhancements) must be integrated by the
end of the second week of the sprint. After code freeze
(and until the end of the sprint) the only changes that should be
merged into the master branch should directly address issues
needed to pass acceptance testing.
* [__Per-release Testing.__](testing/plan.md#per-release-testing)
Structured testing with predefined
success criteria. No release should ship without passing
acceptance tests. Time is allocated in each sprint for subsequent
rounds of acceptance testing if issues are identified during a
prior round. Specific details of acceptance testing need to be
agreed-upon with relevant stakeholders and delivery recipients,
and should be flexible enough to allow changes to plans
(e.g. deferring delivery of some feature in order to ensure
stability of other features.) Baseline testing includes:
* [__Testathon.__](testing/plan.md#user-testing)
Multi-user testing, involving as many users as
is feasible, plus development team. Open-ended; should verify
completed work from this sprint, test exploratorily for
regressions, et cetera.
* [__Long-Duration Test.__](testing/plan.md#long-duration-testing) A
test to verify that the software remains
stable after running for longer durations. May include some
combination of automated testing and user verification (e.g.
checking to verify that software remains subjectively
responsive at conclusion of test.)
* [__Unit Testing.__](testing/plan.md#unit-testing)
Automated testing integrated into the
build. (These tests are verified to pass more often than once
per sprint, as they run before any merge to master, but still
play an important role in per-release testing.)
* [__Per-sprint Testing.__](testing/plan.md#per-sprint-testing)
Subset of Pre-release Testing
which should be performed before shipping at the end of any
sprint. Time is allocated for a second round of
Pre-release Testing if the first round is not passed.
* __Triage.__ Team reviews issues from acceptance testing and uses
success criteria to determine whether or not they should block
release, then formulates a plan to address these issues before
the next round of acceptance testing. Focus here should be on
ensuring software passes that testing in order to ship on time;
may prefer to disable malfunctioning components and fix them
in a subsequent sprint, for example.
* __Ship.__ Tag a code snapshot that has passed acceptance
testing and deploy that version. (Only true if acceptance
testing has passed by this point; if acceptance testing has not
been passed, will need to make ad hoc decisions with stakeholders,
e.g. "extend the sprint" or "defer shipment until end of next
sprint.")

View File

@@ -1,156 +1,13 @@
# Development Cycle
Development of Open MCT Web occurs on an iterative cycle of
sprints and releases.
* A _sprint_ is three weeks in duration, and represents a
set of improvements that can be completed and tested by the
development team. Software at the end of the sprint is
"semi-stable"; it will have undergone reduced testing and may carry
defects or usability issues of lower severity, particularly if
there are workarounds.
* A _release_ occurs every four sprints. Releases are stable, and
will have undergone full acceptance testing to ensure that the
software behaves correctly and usably.
## Roles
The sprint process assumes the presence of a __project manager.__
The project manager is responsible for
making tactical decisions about what development work will be
performed, and for coordinating with stakeholders to arrive at
higher-level strategic decisions about desired functionality
and characteristics of the software, major external milestones,
and so forth.
In the absence of a dedicated project manager, this role may be rotated
among members of the development team on a per-sprint basis.
Responsibilities of the project manager including:
* Maintaining (with agreement of stakeholders) a "road map" of work
planned for future releases/sprints; this should be higher-level,
usually expressed as "themes",
with just enough specificity to gauge feasibility of plans,
relate work back to milestones, and identify longer-term
dependencies.
* Determining (with assistance from the rest of the team) which
issues to work on in a given sprint and how they shall be
assigned.
* Pre-planning subsequent sprints to ensure that all members of the
team always have a clear direction.
* Scheduling and/or ensuring adherence to
[process points](#process-points).
* Responding to changes within the sprint (shifting priorities,
new issues) and re-allocating work for the sprint as needed.
## Sprint Calendar
Certain [process points](#process-points) are regularly scheduled in
the sprint cycle.
### Sprints by Release
Allocation of work among sprints should be planned relative to release
goals and milestones. As a general guideline, higher-risk work (large
new features which may carry new defects, major refactoring, design
changes with uncertain effects on usability) should be allocated to
earlier sprints, allowing for time in later sprints to ensure stability.
| Sprint | Focus |
|:------:|:--------------------------------------------------------|
| __1__ | Prototyping, design, experimentation. |
| __2__ | New features, refinements, enhancements. |
| __3__ | Feature completion, low-risk enhancements, bug fixing. |
| __4__ | Stability & quality assurance. |
### Sprints 1-3
The first three sprints of a release are primarily centered around
development work, with regular acceptance testing in the third
week. During this third week, the top priority should be passing
acceptance testing (e.g. by resolving any blockers found); any
resources not needed for this effort should be used to begin work
for the subsequent sprint.
| Week | Mon | Tue | Wed | Thu | Fri |
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
| __1__ | Sprint plan | Tag-up | | | |
| __2__ | | Tag-up | | | Code freeze |
| __3__ | Sprint acceptance testing | Triage | | _Sprint acceptance testing*_ | Ship |
&ast; If necessary.
### Sprint 4
The software must be stable at the end of the fourth sprint; because of
this, the fourth sprint is scheduled differently, with a heightened
emphasis on testing.
| Week | Mon | Tue | Wed | Thu | Fri |
|-------:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
| __1__ | Sprint plan | Tag-up | | | Code freeze |
| __2__ | Acceptance testing | Triage | | | |
| __3__ | _Acceptance testing*_ | Triage | | _Acceptance testing*_ | Ship |
&ast; If necessary.
## Process Points
* __Sprint plan.__ Project manager allocates issues based on
theme(s) for sprint, then reviews with team. Each team member
should have roughly two weeks of work allocated (to allow time
in the third week for testing of work completed.)
* Project manager should also sketch out subsequent sprint so
that team may begin work for that sprint during the
third week, since testing and blocker resolution is unlikely
to require all available resources.
* __Tag-up.__ Check in and status update among development team.
May amend plan for sprint as-needed.
* __Code freeze.__ Any new work from this sprint
(features, bug fixes, enhancements) must be integrated by the
end of the second week of the sprint. After code freeze
(and until the end of the sprint) the only changes that should be
merged into the master branch should directly address issues
needed to pass acceptance testing.
* __Acceptance Testing.__ Structured testing with predefined
success criteria. No release should ship without passing
acceptance tests. Time is allocated in each sprint for subsequent
rounds of acceptance testing if issues are identified during a
prior round. Specific details of acceptance testing need to be
agreed-upon with relevant stakeholders and delivery recipients,
and should be flexible enough to allow changes to plans
(e.g. deferring delivery of some feature in order to ensure
stability of other features.) Baseline testing includes:
* __Testathon.__ Multi-user testing, involving as many users as
is feasible, plus development team. Open-ended; should verify
completed work from this sprint, test exploratorily for
regressions, et cetera.
* __24-Hour Test.__ A test to verify that the software remains
stable after running for longer durations. May include some
combination of automated testing and user verification (e.g.
checking to verify that software remains subjectively
responsive at conclusion of test.)
* __Automated Testing.__ Automated testing integrated into the
build. (These tests are verified to pass more often than once
per sprint, as they run before any merge to master, but still
play an important role in acceptance testing.)
* __Sprint Acceptance Testing.__ Subset of Acceptance Testing
which should be performed before shipping at the end of any
sprint. Time is allocated for a second round of
Sprint Acceptance Testing if the first round is not passed.
* __Triage.__ Team reviews issues from acceptance testing and uses
success criteria to determine whether or not they should block
release, then formulates a plan to address these issues before
the next round of acceptance testing. Focus here should be on
ensuring software passes that testing in order to ship on time;
may prefer to disable malfunctioning components and fix them
in a subsequent sprint, for example.
* __Ship.__ Tag a code snapshot that has passed acceptance
testing and deploy that version. (Only true if acceptance
testing has passed by this point; if acceptance testing has not
been passed, will need to make ad hoc decisions with stakeholders,
e.g. "extend the sprint" or "defer shipment until end of next
sprint.")
# Development Process
The process used to develop Open MCT Web is described in the following
documents:
* [Development Cycle](cycle.md): Describes how and when specific
process points are repeated during development.
* Testing is described in two documents:
* The [Test Plan](testing/plan.md) summarizes the approaches used
to test Open MCT Web.
* The [Test Procedures](testing/procedures.md) document what
specific tests are performed to verify correctness, and how
they should be carried out.

View File

@@ -0,0 +1,127 @@
# Test Plan
## Test Levels
Testing for Open MCT Web includes:
* _Smoke testing_: Brief, informal testing to verify that no major issues
or regressions are present in the software, or in specific features of
the software.
* _Unit testing_: Automated verification of the performance of individual
software components.
* _User testing_: Testing with a representative user base to verify
that application behaves usably and as specified.
* _Long-duration testing_: Testing which takes place over a long period
of time to detect issues which are not readily noticeable during
shorter test periods.
### Smoke Testing
Manual, non-rigorous testing of the software and/or specific features
of interest. Verifies that the software runs and that basic functionality
is present.
### Unit Testing
Unit tests are automated tests which exercise individual software
components. Tests are subject to code review along with the actual
implementation, to ensure that tests are applicable and useful.
Unit tests should meet
[test standards](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#test-standards)
as described in the contributing guide.
### User Testing
User testing is performed at scheduled times involving target users
of the software or reasonable representatives, along with members of
the development team exercising known use cases. Users test the
software directly; the software should be configured as similarly to
its planned production configuration as is feasible without introducing
other risks (e.g. damage to data in a production instance.)
User testing will focus on the following activities:
* Verifying issues resolved since the last test session.
* Checking for regressions in areas related to recent changes.
* Using major or important features of the software,
as determined by the user.
* General "trying to break things."
During user testing, users will
[report issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
as they are encountered.
Desired outcomes of user testing are:
* Identified software defects.
* Areas for usability improvement.
* Feature requests (particularly missed requirements.)
* Recorded issue verification.
### Long-duration Testing
Long-duration testing occurs over a twenty-four hour period. The
software is run in one or more stressing cases representative of expected
usage. After twenty-four hours, the software is evaluated for:
* Performance metrics: Have memory usage or CPU utilization increased
during this time period in unexpected or undesirable ways?
* Subjective usability: Does the software behave in the same way it did
at the start of the test? Is it as responsive?
Any defects or unexpected behavior identified during testing should be
[reported as issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
and reviewed for severity.
## Test Performance
Tests are performed at various levels of frequency.
* _Per-merge_: Performed before any new changes are integrated into
the software.
* _Per-sprint_: Performed at the end of every [sprint](../cycle.md).
* _Per-release_: Performed at the end of every [release](../cycle.md).
### Per-merge Testing
Before changes are merged, the author of the changes must perform:
* _Smoke testing_ (both generally, and for areas which interact with
the new changes.)
* _Unit testing_ (as part of the automated build step.)
Changes are not merged until the author has affirmed that both
forms of testing have been performed successfully; this is documented
by the [Author Checklist](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#author-checklist).
### Per-sprint Testing
Before a sprint is closed, the development team must additionally
perform:
* A relevant subset of [_user testing_](procedures.md#user-test-procedures)
identified by the acting [project manager](../cycle.md#roles).
* [_Long-duration testing_](procedures.md#long-duration-testng)
(specifically, for 24 hours.)
Issues are reported as a product of both forms of testing.
A sprint is not closed until both categories have been performed on
the latest snapshot of the software, _and_ no issues labelled as
["blocker"](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
remain open.
### Per-release Testing
As [per-sprint testing](#per-sprint-testing), except that _user testing_
should cover all test cases, with less focus on changes from the specific
sprint or release.
Per-release testing should also include any acceptance testing steps
agreed upon with recipients of the software.
A release is not closed until both categories have been performed on
the latest snapshot of the software, _and_ no issues labelled as
["blocker" or "critical"](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
remain open.

View File

@@ -0,0 +1,169 @@
# Test Procedures
## Introduction
This document is intended to be used:
* By testers, to verify that Open MCT Web behaves as specified.
* By the development team, to document new test cases and to provide
guidance on how to author these.
## Writing Procedures
### Template
Procedures for individual tests should use the following template,
adapted from [https://swehb.nasa.gov/display/7150/SWE-114]().
Property | Value
---------------|---------------------------------------------------------------
Test ID |
Relevant reqs. |
Prerequisites |
Test input |
Instructions |
Expectation |
Eval. criteria |
For multi-line descriptions, use an asterisk or similar indicator to refer
to a longer-form description below.
#### Example Procedure - Edit a Layout
Property | Value
---------------|---------------------------------------------------------------
Test ID | MCT-TEST-000X - Edit a layout
Relevant reqs. | MCT-EDIT-000Y
Prerequisites | Create a layout, as in MCT-TEST-000Z
Test input | Domain object database XYZ
Instructions | See below &ast;
Expectation | Change to editing context &dagger;
Eval. criteria | Visual inspection
&ast; Follow the following steps:
1. Verify that the created layout is currently navigated-to,
as in MCT-TEST-00ZZ.
2. Click the Edit button, identified by a pencil icon and the text "Edit"
displayed on hover.
&dagger; Right-hand viewing area should be surrounded by a dashed
blue border when a domain object is being edited.
### Guidelines
Test procedures should be written assuming minimal prior knowledge of the
application: Non-standard terms should only be used when they are documented
in [the glossary](#glossary), and shorthands used for user actions should
be accompanied by useful references to test procedures describing those
actions (when available) or descriptions in user documentation.
Test cases should be narrow in scope; if a list of steps is excessively
long (or must be written vaguely to be kept short) it should be broken
down into multiple tests which reference one another.
All requirements satisfied by Open MCT Web should be verifiable using
one or more test procedures.
## Glossary
This section will contain terms used in test procedures. This may link to
a common glossary, to avoid replication of content.
## Procedures
This section will contain specific test procedures. Presently, procedures
are placeholders describing general patterns for setting up and conducting
testing.
### User Testing Setup
These procedures describes a general pattern for setting up for user
testing. Specific deployments should customize this pattern with
relevant data and any additional steps necessary.
Property | Value
---------------|---------------------------------------------------------------
Test ID | MCT-TEST-SETUP0 - User Testing Setup
Relevant reqs. | TBD
Prerequisites | Build of relevant components
Test input | Exemplary database; exemplary telemetry data set
Instructions | See below
Expectation | Able to load application in a web browser (Google Chrome)
Eval. criteria | Visual inspection
Instructions:
1. Start telemetry server.
2. Start ElasticSearch.
3. Restore database snapshot to ElasticSearch.
4. Start telemetry playback.
5. Start HTTP server for client sources.
### User Test Procedures
Specific user test cases have not yet been authored. In their absence,
user testing is conducted by:
* Reviewing the text of issues from the issue tracker to understand the
desired behavior, and exercising this behavior in the running application.
(For instance, by following steps to reproduce from the original issue.)
* Issues which appear to be resolved should be marked as such with comments
on the original issue (e.g. "verified during user testing MM/DD/YYYY".)
* Issues which appear not to have been resolved should be reopened with an
explanation of what unexpected behavior has been observed.
* In cases where an issue appears resolved as-worded but other related
undesirable behavior is observed during testing, a new issue should be
opened, and linked to from a comment in the original issues.
* General usage of new features and/or existing features which have undergone
recent changes. Defects or problems with usability should be documented
by filing issues in the issue tracker.
* Open-ended testing to discover defects, identify usability issues, and
generate feature requests.
### Long-Duration Testing
The purpose of long-duration testing is to identify performance issues
and/or other defects which are sensitive to the amount of time the
application is kept running. (Memory leaks, for instance.)
Property | Value
---------------|---------------------------------------------------------------
Test ID | MCT-TEST-LDT0 - Long-duration Testing
Relevant reqs. | TBD
Prerequisites | MCT-TEST-SETUP0
Test input | (As for test setup.)
Instructions | See "Instructions" below &ast;
Expectation | See "Expectations" below &dagger;
Eval. criteria | Visual inspection
&ast; Instructions:
1. Start `top` or a similar tool to measure CPU usage and memory utilization.
2. Open several user-created displays (as many as would be realistically
opened during actual usage in a stressing case) in some combination of
separate tabs and windows (approximately as many tabs-per-window as
total windows.)
3. Ensure that playback data is set to run continuously for at least 24 hours
(e.g. on a loop.)
4. Record CPU usage and memory utilization.
5. In at least one tab, try some general user interface gestures and make
notes about the subjective experience of using the application. (Particularly,
the degree of responsiveness.)
6. Leave client displays open for 24 hours.
7. Record CPU usage and memory utilization again.
8. Make additional notes about the subjective experience of using the
application (again, particularly responsiveness.)
9. Check logs for any unexpected warnings or errors.
&dagger; Expectations:
* At the end of the test, CPU usage and memory usage should both be similar
to their levels at the start of the test.
* At the end of the test, subjective usage of the application should not
be observably different from the way it was at the start of the test.
(In particular, responsiveness should not decrease.)
* Logs should not contain any unexpected warnings or errors ("expected"
warnings or errors are those that have been documented and prioritized
as known issues, or those that are explained by transient conditions
external to the software, such as network outages.)

View File

@@ -39,8 +39,11 @@ define(
start = Date.now();
function update() {
var secs = (Date.now() - start) / 1000;
var now = Date.now(),
secs = (now - start) / 1000;
displayed = Math.round(digests / secs);
start = now;
digests = 0;
}
function increment() {

View File

@@ -0,0 +1,2 @@
Example of using multiple persistence stores by exposing a root
object with a different space prefix.

View File

@@ -0,0 +1,23 @@
{
"extensions": {
"roots": [
{
"id": "scratch:root",
"model": {
"type": "folder",
"composition": [],
"name": "Scratchpad"
},
"priority": "preferred"
}
],
"components": [
{
"provides": "persistenceService",
"type": "provider",
"implementation": "ScratchPersistenceProvider.js",
"depends": [ "$q" ]
}
]
}
}

View File

@@ -0,0 +1,79 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,window*/
define(
[],
function () {
'use strict';
/**
* The ScratchPersistenceProvider keeps JSON documents in memory
* and provides a persistence interface, but changes are lost on reload.
* @memberof example/scratchpad
* @constructor
* @implements {PersistenceService}
* @param q Angular's $q, for promises
*/
function ScratchPersistenceProvider($q) {
this.$q = $q;
this.table = {};
}
ScratchPersistenceProvider.prototype.listSpaces = function () {
return this.$q.when(['scratch']);
};
ScratchPersistenceProvider.prototype.listObjects = function (space) {
return this.$q.when(
space === 'scratch' ? Object.keys(this.table) : []
);
};
ScratchPersistenceProvider.prototype.createObject = function (space, key, value) {
if (space === 'scratch') {
this.table[key] = JSON.stringify(value);
}
return this.$q.when(space === 'scratch');
};
ScratchPersistenceProvider.prototype.readObject = function (space, key) {
return this.$q.when(
(space === 'scratch' && this.table[key]) ?
JSON.parse(this.table[key]) : undefined
);
};
ScratchPersistenceProvider.prototype.deleteObject = function (space, key, value) {
if (space === 'scratch') {
delete this.table[key];
}
return this.$q.when(space === 'scratch');
};
ScratchPersistenceProvider.prototype.updateObject =
ScratchPersistenceProvider.prototype.createObject;
return ScratchPersistenceProvider;
}
);

View File

@@ -102,6 +102,12 @@
"implementation": "navigation/NavigationService.js"
}
],
"policies": [
{
"implementation": "creation/CreationPolicy.js",
"category": "creation"
}
],
"actions": [
{
"key": "navigate",

View File

@@ -69,7 +69,7 @@ define(
// Introduce one create action per type
return this.typeService.listTypes().filter(function (type) {
return type.hasFeature("creation");
return self.policyService.allow("creation", type);
}).map(function (type) {
return new CreateAction(
type,

View File

@@ -0,0 +1,45 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
[],
function () {
"use strict";
/**
* A policy for determining whether objects of a given type can be
* created.
* @constructor
* @implements {Policy}
* @memberof platform/commonUI/browse
*/
function CreationPolicy() {
}
CreationPolicy.prototype.allow = function (type) {
return type.hasFeature("creation");
};
return CreationPolicy;
}
);

View File

@@ -33,6 +33,9 @@ define(
var mockTypeService,
mockDialogService,
mockCreationService,
mockPolicyService,
mockCreationPolicy,
mockPolicyMap = {},
mockTypes,
provider;
@@ -67,14 +70,32 @@ define(
"creationService",
[ "createObject" ]
);
mockPolicyService = jasmine.createSpyObj(
"policyService",
[ "allow" ]
);
mockTypes = [ "A", "B", "C" ].map(createMockType);
mockTypes.forEach(function(type){
mockPolicyMap[type.getName()] = true;
});
mockCreationPolicy = function(type){
return mockPolicyMap[type.getName()];
};
mockPolicyService.allow.andCallFake(function(category, type){
return category === "creation" && mockCreationPolicy(type) ? true : false;
});
mockTypeService.listTypes.andReturn(mockTypes);
provider = new CreateActionProvider(
mockTypeService,
mockDialogService,
mockCreationService
mockCreationService,
mockPolicyService
);
});
@@ -94,15 +115,15 @@ define(
it("does not expose non-creatable types", function () {
// One of the types won't have the creation feature...
mockTypes[1].hasFeature.andReturn(false);
mockPolicyMap[mockTypes[0].getName()] = false;
// ...so it should have been filtered out.
expect(provider.getActions({
key: "create",
domainObject: {}
}).length).toEqual(2);
// Make sure it was creation which was used to check
expect(mockTypes[1].hasFeature)
.toHaveBeenCalledWith("creation");
expect(mockPolicyService.allow)
.toHaveBeenCalledWith("creation", mockTypes[0]);
});
});
}

View File

@@ -0,0 +1,53 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,it,expect,beforeEach,jasmine*/
define(
["../../src/creation/CreationPolicy"],
function (CreationPolicy) {
"use strict";
describe("The creation policy", function () {
var mockType,
policy;
beforeEach(function () {
mockType = jasmine.createSpyObj(
'type',
['hasFeature']
);
policy = new CreationPolicy();
});
it("allows creation of types with the creation feature", function () {
mockType.hasFeature.andReturn(true);
expect(policy.allow(mockType)).toBeTruthy();
});
it("disallows creation of types without the creation feature", function () {
mockType.hasFeature.andReturn(false);
expect(policy.allow(mockType)).toBeFalsy();
});
});
}
);

View File

@@ -8,6 +8,7 @@
"creation/CreateMenuController",
"creation/CreateWizard",
"creation/CreationService",
"creation/CreationPolicy",
"creation/LocatorController",
"navigation/NavigateAction",
"navigation/NavigationService",

View File

@@ -50,7 +50,7 @@ define(
// Simply trigger refresh of in-view objects; do not
// write anything to database.
persistence.persist = function () {
cache.markDirty(editableObject);
return cache.markDirty(editableObject);
};
// Delegate refresh to the original object; this avoids refreshing

View File

@@ -111,6 +111,7 @@ define(
*/
EditableDomainObjectCache.prototype.markDirty = function (domainObject) {
this.dirtyObjects[domainObject.getId()] = domainObject;
return this.$q.when(true);
};
/**

View File

@@ -31,6 +31,7 @@ define(
mockEditableObject,
mockDomainObject,
mockCache,
mockPromise,
capability;
beforeEach(function () {
@@ -50,7 +51,9 @@ define(
"cache",
[ "markDirty" ]
);
mockPromise = jasmine.createSpyObj("promise", ["then"]);
mockCache.markDirty.andReturn(mockPromise);
mockDomainObject.getCapability.andReturn(mockPersistence);
capability = new EditablePersistenceCapability(
@@ -84,6 +87,10 @@ define(
expect(mockPersistence.refresh).toHaveBeenCalled();
});
it("returns a promise from persist", function () {
expect(capability.persist().then).toEqual(jasmine.any(Function));
});
});
}
);

View File

@@ -19,6 +19,10 @@
{
"implementation": "StyleSheetLoader.js",
"depends": [ "stylesheets[]", "$document", "THEME" ]
},
{
"implementation": "UnsupportedBrowserWarning.js",
"depends": [ "notificationService", "agentService" ]
}
],
"stylesheets": [
@@ -225,10 +229,6 @@
"templateUrl": "templates/subtree.html",
"uses": [ "composition" ]
},
{
"key": "test",
"templateUrl": "templates/test.html"
},
{
"key": "tree-node",
"templateUrl": "templates/tree-node.html",

View File

@@ -35,24 +35,23 @@
}
}
.l-autoflow-header {
bottom: auto;
height: $headerH;
line-height: $headerH;
min-width: $colW;
span {
vertical-align: middle;
}
min-width: $colW;
.t-last-update {
overflow: hidden;
}
.s-btn.change-column-width {
@include trans-prop-nice-fade(500ms);
opacity: 0;
}
.l-filter {
margin-left: $interiorMargin;
display: block;
margin-right: $interiorMargin;
input.t-filter-input {
width: 100px;
width: 150px;
}
}
}
@@ -127,4 +126,12 @@
}
}
}
}
.frame {
&.child-frame.panel {
.autoflow .l-autoflow-header .l-filter {
display: none;
}
}
}

View File

@@ -31,10 +31,6 @@ a.disabled {
border-bottom: 1px solid rgba(#fff, 0.3);
}
.outline {
@include boxOutline();
}
.test-stripes {
@include bgDiagonalStripes();
}

View File

@@ -25,7 +25,6 @@
margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
}
padding: 0 $interiorMargin;
overflow: hidden;
position: relative;
line-height: $formInputH;
select {

View File

@@ -34,51 +34,31 @@ $mobileTreeItemH: 35px;
$mobileTreeItemIndent: 20px;
$mobileTreeRightArrowW: 30px;
/************************** WINDOW DIMENSIONS FOR RWD */
$phoMaxW: 514px;
$phoMaxH: 740px;
$tabMinW: 515px;
$tabMaxW: 799px;
$tabMinH: 741px;
$tabMaxH: 1024px;
$compMinW: 800px;
$compMinH: 1025px;
/************************** DEVICE WIDTHS */
// IMPORTANT! Usage assumes that ranges are mutually exclusive and have no gaps
$phoMaxW: 767px;
$tabMinW: 768px;
$tabMaxW: 1024px;
$desktopMinW: 1025px;
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
$screenPortrait: "screen and (orientation: portrait)";
$screenLandscape: "screen and (orientation: landscape)";
$screenPortrait: "(orientation: portrait)";
$screenLandscape: "(orientation: landscape)";
$mobileDevice: "(max-device-width: #{$tabMaxW}) and (max-device-height: #{$tabMaxH})";
$mobileDeviceEmu: "(max-device-width: #{$tabMaxH}) and (max-device-height: #{$tabMaxW})";
//$mobileDevice: "(max-device-width: #{$tabMaxW})";
$phonePortraitCheck: "(max-width: #{$phoMaxW}) and (max-height: #{$phoMaxH})";
$phoneLandscapeCheck: "(max-height: #{$phoMaxW}) and (max-width: #{$phoMaxH})";
$tabWidPorCheck: "(min-width: #{$tabMinW}) and (max-width: #{$tabMaxW})";
$tabHeiPorCheck: "(min-height: #{$tabMinH}) and (max-height: #{$tabMaxH})";
$tabletPortraitCheck: "#{$tabWidPorCheck} and #{$tabHeiPorCheck}";
$tabWidLanCheck: "(min-height: #{$tabMinW}) and (max-height: #{$tabMaxW})";
$tabHeiLanCheck: "(min-width: #{$tabMinH}) and (max-width: #{$tabMaxH})";
$tabletLandscapeCheck: "#{$tabWidLanCheck} and #{$tabHeiLanCheck}";
$desktopPortraitCheck: "(min-device-width: #{$compMinW}) and (min-device-height: #{$compMinH})";
$desktopLandscapeCheck: "(min-device-width: #{$compMinH}) and (min-device-height: #{$compMinW})";
$phoneCheck: "(max-device-width: #{$phoMaxW})";
$tabletCheck: "(min-device-width: #{$tabMinW}) and (max-device-width: #{$tabMaxW})";
$desktopCheck: "(min-device-width: #{$desktopMinW}) and (-webkit-min-device-pixel-ratio: 1)";
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
$phonePortrait: "#{$screenPortrait} and #{$phonePortraitCheck} and #{$mobileDevice}";
$phoneLandscape: "#{$screenLandscape} and #{$phoneLandscapeCheck} and #{$mobileDevice}";
$phoneLandscapeEmu: "#{$screenLandscape} and #{$phoneLandscapeCheck} and #{$mobileDeviceEmu}";
$phonePortrait: "only screen and #{$screenPortrait} and #{$phoneCheck}";
$phoneLandscape: "only screen and #{$screenLandscape} and #{$phoneCheck}";
$tabletPortrait: "#{$screenPortrait} and #{$tabletPortraitCheck} and #{$mobileDevice}";
$tabletLandscape: "#{$screenLandscape} and #{$tabletLandscapeCheck} and #{$mobileDevice}";
$tabletLandscapeEmu: "#{$screenLandscape} and #{$tabletLandscapeCheck} and #{$mobileDeviceEmu}";
$tabletPortrait: "only screen and #{$screenPortrait} and #{$tabletCheck}";
$tabletLandscape: "only screen and #{$screenLandscape} and #{$tabletCheck}";
$desktopPortrait: "screen and #{$desktopPortraitCheck}";
$desktopLandscape: "screen and #{$desktopLandscapeCheck}";
$desktop: "only screen and #{$desktopCheck}";
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
$proporMenuOnly: 90%;

View File

@@ -25,8 +25,7 @@
// Phones in any orientation
@mixin phone {
@media #{$phonePortrait},
#{$phoneLandscape},
#{$phoneLandscapeEmu} {
#{$phoneLandscape} {
@content
}
}
@@ -40,8 +39,7 @@
// Phones in landscape orientation
@mixin phoneLandscape {
@media #{$phoneLandscape},
#{$phoneLandscapeEmu} {
@media #{$phoneLandscape} {
@content
}
}
@@ -49,8 +47,7 @@
// Tablets in any orientation
@mixin tablet {
@media #{$tabletPortrait},
#{$tabletLandscape},
#{$tabletLandscapeEmu} {
#{$tabletLandscape} {
@content
}
}
@@ -64,8 +61,7 @@
// Tablets in landscape orientation
@mixin tabletLandscape {
@media #{$tabletLandscape},
#{$tabletLandscapeEmu} {
@media #{$tabletLandscape} {
@content
}
}
@@ -74,10 +70,8 @@
@mixin phoneandtablet {
@media #{$phonePortrait},
#{$phoneLandscape},
#{$phoneLandscapeEmu},
#{$tabletPortrait},
#{$tabletLandscape},
#{$tabletLandscapeEmu} {
#{$tabletLandscape} {
@content
}
}
@@ -86,17 +80,14 @@
@mixin desktopandtablet {
@media #{$tabletPortrait},
#{$tabletLandscape},
#{$tabletLandscapeEmu},
#{$desktopPortrait},
#{$desktopLandscape} {
#{$desktop} {
@content
}
}
// Desktop monitors in any orientation
@mixin desktop {
@media #{$desktopPortrait},
#{$desktopLandscape} {
@media #{$desktop} {
@content
}
}

View File

@@ -20,11 +20,9 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
$yBarW: 60px;
$yLabelW: auto;
$yLabelW: 10px;
$xBarH: 32px;
$legendH: 20px;
//$colorHash: rgba(white, 0.3); // MOVED INTO CONSTANTS
//$styleHash: dashed; // MOVED INTO CONSTANTS
$swatchD: 8px;
$plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBarW); // Top, right, bottom, left
@@ -36,7 +34,6 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
height: 100%;
.gl-plot-axis-area {
// @include test(green);
position: absolute;
&.gl-plot-x {
top: auto;
@@ -59,7 +56,7 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
.gl-plot-coords {
@include box-sizing(border-box);
@include border-radius($controlCr);
background: black; //rgba($colorKey, 0.5);
background: black;
color: lighten($colorBodyFg, 30%);
padding: 2px 5px;
position: absolute;
@@ -88,11 +85,9 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
.gl-plot-label,
.l-plot-label {
// @include test(yellow);
color: $colorPlotLabelFg;
position: absolute;
text-align: center;
// text-transform: uppercase;
&.gl-plot-x-label,
&.l-plot-x-label {
@@ -117,20 +112,26 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
}
}
.gl-plot-y-options {
.gl-plot-x-options,
.gl-plot-y-options {
$h: 32px;
// @include test();
position: absolute;
top: 50%;
right: auto;
bottom: auto;
left: $yLabelW + $interiorMargin;
margin-top: $h / -2;
height: auto;
min-height: $h;
width: $h;
z-index: 2;
}
.gl-plot-x-options {
top: $interiorMargin;
}
.gl-plot-y-options {
@include transform(translateY(-50%));
min-width: 150px; // Need this due to enclosure of .select
top: 50%;
left: $yLabelW + $interiorMargin * 2;
}
.gl-plot-hash {
position: absolute;
border: 0 $colorPlotHash $stylePlotHash;
@@ -214,21 +215,13 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
display: inline-block;
height: $swatchD;
width: $swatchD;
//margin-right: $interiorMarginSm;
}
&[class*='s-limit'] {
.title-label {
//color: #fff;
}
}
}
}
.gl-plot-legend {
.plot-legend-item {
//@include test();
@include border-radius($smallCr);
//color: #fff;
line-height: 1.5em;
padding: 0px $itemPadLR;
.plot-color-swatch {
@@ -250,7 +243,6 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
.gl-plot-tick,
.tick-label {
// @include test(red);
font-size: 0.7rem;
position: absolute;
overflow: hidden;
@@ -277,7 +269,6 @@ $plotDisplayArea: ($legendH + $interiorMargin, 0, $xBarH + $interiorMargin, $yBa
}
.gl-plot-tick {
// @include test(red);
&.gl-plot-x-tick-label {
top: $interiorMargin;
}

View File

@@ -270,6 +270,7 @@
.splitter-treeview,
.holder-treeview-elements {
opacity: 0;
pointer-events: none;
}
}
@@ -304,6 +305,7 @@
.l-inspect,
.splitter-inspect {
opacity: 0;
pointer-events: none;
}
}
}

View File

@@ -1,7 +1,29 @@
<!--
Open MCT Web, Copyright (c) 2014-2015, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT Web is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT Web includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<span class="s-btn"
ng-controller="DateTimeFieldController">
<input type="text"
ng-model="textValue"
ng-blur="restoreTextValue(); ngBlur()"
ng-class="{ error: textInvalid }">
</input>
<a class="ui-symbol icon icon-calendar"
@@ -11,8 +33,8 @@
<mct-popup ng-if="picker.active">
<div mct-click-elsewhere="picker.active = false">
<mct-control key="'datetime-picker'"
ng-model="ngModel"
field="field"
ng-model="pickerModel"
field="'value'"
options="{ hours: true }">
</mct-control>
</div>

View File

@@ -20,12 +20,14 @@
at runtime from the About dialog for additional information.
-->
<div ng-controller="TimeRangeController">
<div class="l-time-range-inputs-holder">
<form class="l-time-range-inputs-holder"
ng-submit="updateBoundsFromForm()">
<span class="l-time-range-inputs-elem ui-symbol type-icon">&#x43;</span>
<span class="l-time-range-input">
<mct-control key="'datetime-field'"
structure="{ format: parameters.format }"
ng-model="ngModel.outer"
ng-model="formModel"
ng-blur="updateBoundsFromForm()"
field="'start'"
class="time-range-start">
</mct-control>
@@ -36,12 +38,15 @@
<span class="l-time-range-input" ng-controller="ToggleController as t2">
<mct-control key="'datetime-field'"
structure="{ format: parameters.format }"
ng-model="ngModel.outer"
ng-model="formModel"
ng-blur="updateBoundsFromForm()"
field="'end'"
class="time-range-end">
</mct-control>&nbsp;
</span>
</div>
<input type="submit" class="hidden">
</form>
<div class="l-time-range-slider-holder">
<div class="l-time-range-slider">

View File

@@ -0,0 +1,64 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
/**
* This bundle provides various general-purpose UI elements, including
* platform styling.
* @namespace platform/commonUI/general
*/
define(
[],
function () {
"use strict";
var WARNING_TITLE = "Unsupported browser",
WARNING_DESCRIPTION = [
"This software has been developed and tested",
"using the latest Google Chrome,",
"and may be unstable in other browsers."
].join(" "),
MOBILE_BROWSER = "Safari",
DESKTOP_BROWSER = "Chrome";
/**
* Shows a warning if a user's browser is unsupported.
* @memberof platform/commonUI/general
* @constructor
* @param {NotificationService} notificationService the notification
* service
*/
function UnsupportedBrowserWarning(notificationService, agentService) {
var testToBrowser = agentService.isMobile() ?
MOBILE_BROWSER : DESKTOP_BROWSER;
if (!agentService.isBrowser(testToBrowser)) {
notificationService.alert({
title: WARNING_TITLE,
actionText: WARNING_DESCRIPTION
});
}
}
return UnsupportedBrowserWarning;
}
);

View File

@@ -53,7 +53,9 @@ define(
formatter.parse($scope.textValue) !== value) {
$scope.textValue = formatter.format(value);
$scope.textInvalid = false;
$scope.lastValidValue = $scope.textValue;
}
$scope.pickerModel = { value: value };
}
function updateFromView(textValue) {
@@ -61,6 +63,17 @@ define(
if (!$scope.textInvalid) {
$scope.ngModel[$scope.field] =
formatter.parse(textValue);
$scope.lastValidValue = $scope.textValue;
}
}
function updateFromPicker(value) {
if (value !== $scope.ngModel[$scope.field]) {
$scope.ngModel[$scope.field] = value;
updateFromModel(value);
if ($scope.ngBlur) {
$scope.ngBlur();
}
}
}
@@ -69,10 +82,18 @@ define(
updateFromModel($scope.ngModel[$scope.field]);
}
function restoreTextValue() {
$scope.textValue = $scope.lastValidValue;
updateFromView($scope.textValue);
}
$scope.restoreTextValue = restoreTextValue;
$scope.picker = { active: false };
$scope.$watch('structure.format', setFormat);
$scope.$watch('ngModel[field]', updateFromModel);
$scope.$watch('pickerModel.value', updateFromPicker);
$scope.$watch('textValue', updateFromView);
}

View File

@@ -175,6 +175,13 @@ define(
updateViewFromModel($scope.ngModel);
}
function updateFormModel() {
$scope.formModel = {
start: (($scope.ngModel || {}).outer || {}).start,
end: (($scope.ngModel || {}).outer || {}).end
};
}
function updateOuterStart(t) {
var ngModel = $scope.ngModel;
@@ -192,6 +199,7 @@ define(
ngModel.inner.end
);
updateFormModel();
updateViewForInnerSpanFromModel(ngModel);
updateTicks();
}
@@ -213,6 +221,7 @@ define(
ngModel.inner.start
);
updateFormModel();
updateViewForInnerSpanFromModel(ngModel);
updateTicks();
}
@@ -223,6 +232,14 @@ define(
updateTicks();
}
function updateBoundsFromForm() {
$scope.ngModel = $scope.ngModel || {};
$scope.ngModel.outer = {
start: $scope.formModel.start,
end: $scope.formModel.end
};
}
$scope.startLeftDrag = startLeftDrag;
$scope.startRightDrag = startRightDrag;
$scope.startMiddleDrag = startMiddleDrag;
@@ -230,10 +247,13 @@ define(
$scope.rightDrag = rightDrag;
$scope.middleDrag = middleDrag;
$scope.updateBoundsFromForm = updateBoundsFromForm;
$scope.ticks = [];
// Initialize scope to defaults
updateViewFromModel($scope.ngModel);
updateFormModel();
$scope.$watchCollection("ngModel", updateViewFromModel);
$scope.$watch("spanWidth", updateSpanWidth);

View File

@@ -204,7 +204,7 @@ define(
// And poll for position changes enforced by styles
activeInterval = $interval(function () {
getSetPosition(getSetPosition());
}, POLLING_INTERVAL, false);
}, POLLING_INTERVAL, 0, false);
// ...and stop polling when we're destroyed.
$scope.$on('$destroy', function () {

View File

@@ -0,0 +1,98 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/UnsupportedBrowserWarning"],
function (UnsupportedBrowserWarning) {
"use strict";
var MOBILE_BROWSER = "Safari",
DESKTOP_BROWSER = "Chrome",
UNSUPPORTED_BROWSERS = [
"Firefox",
"IE",
"Opera",
"Iceweasel"
];
describe("The unsupported browser warning", function () {
var mockNotificationService,
mockAgentService,
testAgent;
function instantiateWith(browser) {
testAgent = "Mozilla/5.0 " + browser + "/12.34.56";
return new UnsupportedBrowserWarning(
mockNotificationService,
mockAgentService
);
}
beforeEach(function () {
testAgent = "chrome";
mockNotificationService = jasmine.createSpyObj(
"notificationService",
[ "alert" ]
);
mockAgentService = jasmine.createSpyObj(
"agentService",
[ "isMobile", "isBrowser" ]
);
mockAgentService.isBrowser.andCallFake(function (substr) {
substr = substr.toLowerCase();
return testAgent.toLowerCase().indexOf(substr) !== -1;
});
});
[ false, true ].forEach(function (isMobile) {
var deviceType = isMobile ? "mobile" : "desktop",
goodBrowser = isMobile ? MOBILE_BROWSER : DESKTOP_BROWSER,
badBrowsers = UNSUPPORTED_BROWSERS.concat([
isMobile ? DESKTOP_BROWSER : MOBILE_BROWSER
]);
describe("on " + deviceType + " devices", function () {
beforeEach(function () {
mockAgentService.isMobile.andReturn(isMobile);
});
it("is not shown for " + goodBrowser, function () {
instantiateWith(goodBrowser);
expect(mockNotificationService.alert)
.not.toHaveBeenCalled();
});
badBrowsers.forEach(function (badBrowser) {
it("is shown for " + badBrowser, function () {
instantiateWith(badBrowser);
expect(mockNotificationService.alert)
.toHaveBeenCalled();
});
});
});
});
});
}
);

View File

@@ -67,21 +67,13 @@ define(
mockScope.ngModel = { testField: 12321 };
mockScope.field = "testField";
mockScope.structure = { format: "someFormat" };
mockScope.ngBlur = jasmine.createSpy('blur');
controller = new DateTimeFieldController(
mockScope,
mockFormatService
);
});
it("updates models from user-entered text", function () {
var newText = "1977-05-25 17:30:00";
mockScope.textValue = newText;
fireWatch("textValue", newText);
expect(mockScope.ngModel.testField)
.toEqual(mockFormat.parse(newText));
expect(mockScope.textInvalid).toBeFalsy();
fireWatch("ngModel[field]", mockScope.ngModel.testField);
});
it("updates text from model values", function () {
@@ -91,16 +83,55 @@ define(
expect(mockScope.textValue).toEqual("1977-05-25 17:30:00");
});
describe("when valid text is entered", function () {
var newText;
beforeEach(function () {
newText = "1977-05-25 17:30:00";
mockScope.textValue = newText;
fireWatch("textValue", newText);
});
it("updates models from user-entered text", function () {
expect(mockScope.ngModel.testField)
.toEqual(mockFormat.parse(newText));
expect(mockScope.textInvalid).toBeFalsy();
});
it("does not indicate a blur event", function () {
expect(mockScope.ngBlur).not.toHaveBeenCalled();
});
});
describe("when a date is chosen via the date picker", function () {
var newValue;
beforeEach(function () {
newValue = 12345654321;
mockScope.pickerModel.value = newValue;
fireWatch("pickerModel.value", newValue);
});
it("updates models", function () {
expect(mockScope.ngModel.testField).toEqual(newValue);
});
it("fires a blur event", function () {
expect(mockScope.ngBlur).toHaveBeenCalled();
});
});
it("exposes toggle state for date-time picker", function () {
expect(mockScope.picker.active).toBe(false);
});
describe("when user input is invalid", function () {
var newText, oldValue;
var newText, oldText, oldValue;
beforeEach(function () {
newText = "Not a date";
oldValue = mockScope.ngModel.testField;
oldText = mockScope.textValue;
mockScope.textValue = newText;
fireWatch("textValue", newText);
});
@@ -116,6 +147,11 @@ define(
it("does not modify user input", function () {
expect(mockScope.textValue).toEqual(newText);
});
it("restores valid text values on request", function () {
mockScope.restoreTextValue();
expect(mockScope.textValue).toEqual(oldText);
});
});
it("does not modify valid but irregular user input", function () {

View File

@@ -91,6 +91,39 @@ define(
.toHaveBeenCalledWith("ngModel", jasmine.any(Function));
});
describe("when changes are made via form entry", function () {
beforeEach(function () {
mockScope.ngModel = {
outer: { start: DAY * 2, end: DAY * 3 },
inner: { start: DAY * 2.25, end: DAY * 2.75 }
};
mockScope.formModel = {
start: DAY * 10000,
end: DAY * 11000
};
// These watches may not exist, but Angular would fire
// them if they did.
fireWatchCollection("formModel", mockScope.formModel);
fireWatch("formModel.start", mockScope.formModel.start);
fireWatch("formModel.end", mockScope.formModel.end);
});
it("does not immediately make changes to the model", function () {
expect(mockScope.ngModel.outer.start)
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.not.toEqual(mockScope.formModel.end);
});
it("updates model bounds on request", function () {
mockScope.updateBoundsFromForm();
expect(mockScope.ngModel.outer.start)
.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.toEqual(mockScope.formModel.end);
});
});
describe("when dragged", function () {
beforeEach(function () {
mockScope.ngModel = {

View File

@@ -0,0 +1,95 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../../src/directives/MCTSplitPane"],
function (MCTSplitPane) {
'use strict';
var JQLITE_METHODS = [
'on',
'addClass',
'children',
'eq'
];
describe("The mct-split-pane directive", function () {
var mockParse,
mockLog,
mockInterval,
mctSplitPane;
beforeEach(function () {
mockParse = jasmine.createSpy('$parse');
mockLog =
jasmine.createSpyObj('$log', ['warn', 'info', 'debug']);
mockInterval = jasmine.createSpy('$interval');
mockInterval.cancel = jasmine.createSpy('mockCancel');
mctSplitPane = new MCTSplitPane(
mockParse,
mockLog,
mockInterval
);
});
it("is only applicable as an element", function () {
expect(mctSplitPane.restrict).toEqual("E");
});
describe("when its controller is applied", function () {
var mockScope,
mockElement,
testAttrs,
mockChildren,
controller;
beforeEach(function () {
mockScope =
jasmine.createSpyObj('$scope', ['$apply', '$watch', '$on']);
mockElement =
jasmine.createSpyObj('element', JQLITE_METHODS);
testAttrs = {};
mockChildren =
jasmine.createSpyObj('children', JQLITE_METHODS);
mockElement.children.andReturn(mockChildren);
mockChildren.eq.andReturn(mockChildren);
mockChildren[0] = {};
controller = mctSplitPane.controller[3](
mockScope,
mockElement,
testAttrs
);
});
it("sets an interval which does not trigger digests", function () {
expect(mockInterval.mostRecentCall.args[3]).toBe(false);
});
});
});
}
);

View File

@@ -19,8 +19,10 @@
"directives/MCTPopup",
"directives/MCTResize",
"directives/MCTScroll",
"directives/MCTSplitPane",
"services/Popup",
"services/PopupService",
"services/UrlService",
"StyleSheetLoader"
"StyleSheetLoader",
"UnsupportedBrowserWarning"
]

View File

@@ -43,6 +43,7 @@ define(
var userAgent = $window.navigator.userAgent,
matches = userAgent.match(/iPad|iPhone|Android/i) || [];
this.userAgent = userAgent;
this.mobileName = matches[0];
this.$window = $window;
}
@@ -91,6 +92,18 @@ define(
return !this.isPortrait();
};
/**
* Check if the user agent matches a certain named device,
* as indicated by checking for a case-insensitive substring
* match.
* @param {string} name the name to check for
* @returns {boolean} true if the user agent includes that name
*/
AgentService.prototype.isBrowser = function (name) {
name = name.toLowerCase();
return this.userAgent.toLowerCase().indexOf(name) !== -1;
};
return AgentService;
}
);

View File

@@ -81,6 +81,13 @@ define(
expect(agentService.isPortrait()).toBeTruthy();
expect(agentService.isLandscape()).toBeFalsy();
});
it("allows for checking browser type", function () {
testWindow.navigator.userAgent = "Chromezilla Safarifox";
agentService = new AgentService(testWindow);
expect(agentService.isBrowser("Chrome")).toBe(true);
expect(agentService.isBrowser("Firefox")).toBe(false);
});
});
}
);

View File

@@ -20,7 +20,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* line 5, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
@@ -41,38 +41,38 @@ time, mark, audio, video {
font-size: 100%;
vertical-align: baseline; }
/* line 22, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html {
line-height: 1; }
/* line 24, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
ol, ul {
list-style: none; }
/* line 26, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
table {
border-collapse: collapse;
border-spacing: 0; }
/* line 28, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle; }
/* line 30, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q, blockquote {
quotes: none; }
/* line 103, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after {
content: "";
content: none; }
/* line 32, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
a img {
border: none; }
/* line 116, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
display: block; }
@@ -173,7 +173,7 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu,
/* REQUIRES /platform/commonUI/general/res/sass/_constants.scss */
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
/************************** MOBILE TREE MENU DIMENSIONS */
/************************** WINDOW DIMENSIONS FOR RWD */
/************************** DEVICE WIDTHS */
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
@@ -235,10 +235,6 @@ a.disabled {
border-bottom: 1px solid rgba(255, 255, 255, 0.3); }
/* line 34, ../../../../general/res/sass/_effects.scss */
.outline {
border: 1px solid #666666; }
/* line 38, ../../../../general/res/sass/_effects.scss */
.test-stripes {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjEuMCIgeTE9IjEuMCIgeDI9IjAuMCIgeTI9IjAuMCI+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjMDAwMDAwIiBzdG9wLW9wYWNpdHk9IjAuMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
@@ -248,7 +244,7 @@ a.disabled {
background-repeat: repeat;
background-size: 40px 40px; }
/* line 42, ../../../../general/res/sass/_effects.scss */
/* line 38, ../../../../general/res/sass/_effects.scss */
.test {
background-color: rgba(255, 204, 0, 0.2) !important; }
@@ -267,7 +263,7 @@ a.disabled {
opacity: 0.5; }
100% {
opacity: 1; } }
/* line 69, ../../../../general/res/sass/_effects.scss */
/* line 65, ../../../../general/res/sass/_effects.scss */
.pulse {
-moz-animation-name: pulse;
-webkit-animation-name: pulse;
@@ -990,7 +986,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left .l-infobubble::before {
right: 100%; }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left .l-infobubble::before {
width: 0;
@@ -998,14 +994,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
border-top: 6.66667px solid transparent;
border-bottom: 6.66667px solid transparent;
border-right: 10px solid #ddd; } }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 88, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right {
margin-right: 20px; } }
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right .l-infobubble::before {
left: 100%; }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right .l-infobubble::before {
width: 0;
@@ -1647,7 +1643,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.s-btn.major .icon, .major.s-menu-btn .icon, .s-btn.major .t-item-icon, .major.s-menu-btn .t-item-icon {
color: #fff; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.s-btn.major:not(.disabled):hover, .major.s-menu-btn:not(.disabled):hover {
background: linear-gradient(#1ac6ff, #00bfff); }
@@ -1686,7 +1682,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.s-btn:not(.major) .icon, .s-menu-btn:not(.major) .icon, .s-btn:not(.major) .t-item-icon, .s-menu-btn:not(.major) .t-item-icon {
color: #0099cc; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.s-btn:not(.major):not(.disabled):hover, .s-menu-btn:not(.major):not(.disabled):hover {
background: linear-gradient(#6b6b6b, #5e5e5e); }
@@ -1728,7 +1724,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.s-btn.pause-play.paused .icon, .pause-play.paused.s-menu-btn .icon, .s-btn.pause-play.paused .t-item-icon, .pause-play.paused.s-menu-btn .t-item-icon {
color: #fff; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.s-btn.pause-play.paused:not(.disabled):hover, .pause-play.paused.s-menu-btn:not(.disabled):hover {
background: linear-gradient(#fe9815, #f88c01); }
@@ -1759,7 +1755,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
.s-btn.show-thumbs .icon:before, .show-thumbs.s-menu-btn .icon:before, .s-btn.show-thumbs .t-item-icon:before, .show-thumbs.s-menu-btn .t-item-icon:before {
content: "\000039"; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 101, ../../../../general/res/sass/controls/_buttons.scss */
.mini-tab {
-moz-border-radius: 3px;
@@ -1829,14 +1825,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.mini-tab.collapsed .icon, .mini-tab.collapsed .t-item-icon {
color: #0099cc; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 1025px) and (min-device-height: 800px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.mini-tab.collapsed:not(.disabled):hover {
background: linear-gradient(#6b6b6b, #5e5e5e); }
/* line 304, ../../../../general/res/sass/_mixins.scss */
.mini-tab.collapsed:not(.disabled):hover > .icon, .mini-tab.collapsed:not(.disabled):hover > .t-item-icon {
color: #33ccff; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 138, ../../../../general/res/sass/controls/_buttons.scss */
.mini-tab.collapsed:before {
opacity: 0; }
@@ -1925,7 +1921,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
.mini-tab.anchor-right.collapsed:hover:before {
right: 2px; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 208, ../../../../general/res/sass/controls/_buttons.scss */
.mini-tab-icon {
color: #595959;
@@ -2314,7 +2310,7 @@ label.checkbox.custom {
font-size: 0.7em;
flex: 0 0 1;
-webkit-flex: 0 0 1; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 240, ../../../../general/res/sass/controls/_controls.scss */
.object-header .context-available {
-moz-transition-property: opacity;
@@ -2657,7 +2653,7 @@ label.checkbox.custom {
color: inherit; }
/******************************************************** BROWSER ELEMENTS */
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 485, ../../../../general/res/sass/controls/_controls.scss */
::-webkit-scrollbar {
-moz-border-radius: 2px;
@@ -3359,7 +3355,7 @@ label.checkbox.custom {
/* line 213, ../../../../general/res/sass/controls/_messages.scss */
.t-message-single .message-severity-error .type-icon.message-type:before {
content: "\21"; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 259, ../../../../general/res/sass/controls/_messages.scss */
.t-message-single .l-message,
.t-message-single .bottom-bar {
@@ -3430,7 +3426,7 @@ label.checkbox.custom {
.t-message-list .message-contents .l-message .top-bar,
.t-message-list .message-contents .l-message .message-body {
margin-bottom: 10px; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 304, ../../../../general/res/sass/controls/_messages.scss */
.t-message-list .message-contents .l-message {
margin-right: 10px; } }
@@ -3682,7 +3678,7 @@ mct-include.l-time-controller {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 25, ../../../../general/res/sass/mobile/controls/_menus.scss */
.super-menu {
width: 250px;
@@ -3956,20 +3952,19 @@ textarea {
text-shadow: rgba(0, 0, 0, 0.1) 0 1px 2px;
margin: 0 0 2px 0;
padding: 0 5px;
overflow: hidden;
position: relative;
line-height: 22px; }
/* line 297, ../../../../general/res/sass/_mixins.scss */
.select .icon, .select .t-item-icon {
color: #0099cc; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.select:not(.disabled):hover {
background: linear-gradient(#6b6b6b, #5e5e5e); }
/* line 304, ../../../../general/res/sass/_mixins.scss */
.select:not(.disabled):hover > .icon, .select:not(.disabled):hover > .t-item-icon {
color: #33ccff; } }
/* line 31, ../../../../general/res/sass/forms/_selects.scss */
/* line 30, ../../../../general/res/sass/forms/_selects.scss */
.select select {
-moz-appearance: none;
-webkit-appearance: none;
@@ -3982,10 +3977,10 @@ textarea {
border: none !important;
padding: 4px 25px 2px 0px;
width: 120%; }
/* line 40, ../../../../general/res/sass/forms/_selects.scss */
/* line 39, ../../../../general/res/sass/forms/_selects.scss */
.select select option {
margin: 5px 0; }
/* line 44, ../../../../general/res/sass/forms/_selects.scss */
/* line 43, ../../../../general/res/sass/forms/_selects.scss */
.select:after {
text-shadow: none;
content: '\76';
@@ -4473,7 +4468,7 @@ span.req {
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
.pane .mini-tab-icon.toggle-pane {
z-index: 5; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
.pane .mini-tab-icon.toggle-pane {
top: 10px;
@@ -4629,9 +4624,10 @@ span.req {
.pane-tree-hidden .tree-holder,
.pane-tree-hidden .splitter-treeview,
.pane-tree-hidden .holder-treeview-elements {
opacity: 0; }
opacity: 0;
pointer-events: none; }
/* line 278, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 279, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-tree-showing .tree-holder,
.pane-tree-showing .splitter-treeview {
-moz-transition-property: opacity;
@@ -4651,7 +4647,7 @@ span.req {
-webkit-transition-delay: 250ms;
transition-delay: 250ms;
opacity: 1; }
/* line 284, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 285, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-tree-showing .holder-treeview-elements {
-moz-transition-property: opacity;
-o-transition-property: opacity;
@@ -4670,7 +4666,7 @@ span.req {
-webkit-transition-delay: 200ms;
transition-delay: 200ms; }
/* line 291, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 292, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-showing .l-object-and-inspector .l-inspect,
.pane-inspect-showing .l-object-and-inspector .splitter-inspect {
-moz-transition-property: opacity;
@@ -4691,44 +4687,45 @@ span.req {
transition-delay: 250ms;
opacity: 1; }
/* line 301, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 302, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-hidden .l-object-and-inspector .t-inspect {
z-index: 1 !important; }
/* line 304, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 305, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-hidden .l-object-and-inspector .l-inspect,
.pane-inspect-hidden .l-object-and-inspector .splitter-inspect {
opacity: 0; }
opacity: 0;
pointer-events: none; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
/* line 312, ../../../../general/res/sass/user-environ/_layout.scss */
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 314, ../../../../general/res/sass/user-environ/_layout.scss */
.holder-all {
min-width: 600px; }
/* line 317, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 319, ../../../../general/res/sass/user-environ/_layout.scss */
.split-layout .split-pane-component.pane.treeview.left {
min-width: 150px;
max-width: 35%;
width: 25%; }
/* line 322, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 324, ../../../../general/res/sass/user-environ/_layout.scss */
.split-layout .split-pane-component.pane.t-inspect.right {
min-width: 200px;
max-width: 35%;
width: 20%;
z-index: 3; }
/* line 330, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 332, ../../../../general/res/sass/user-environ/_layout.scss */
.pane.treeview.left .tree-holder {
padding-right: 5px; }
/* line 334, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 336, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-tree-hidden .pane.right.primary-pane {
left: 22px !important; }
/* line 337, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-hidden .l-object-and-inspector .pane.left {
right: 22px !important; }
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 341, ../../../../general/res/sass/user-environ/_layout.scss */
.pane:not(.resizing) {
-moz-transition-property: width, left, right;
-o-transition-property: width, left, right;
@@ -4747,7 +4744,7 @@ span.req {
-webkit-transition-delay: 0;
transition-delay: 0; }
/* line 342, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 344, ../../../../general/res/sass/user-environ/_layout.scss */
.pane.primary-pane .object-browse-bar {
min-width: 200px; } }
/*****************************************************************************
@@ -4771,7 +4768,7 @@ span.req {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 26, ../../../../general/res/sass/mobile/_layout.scss */
.browse-wrapper,
.pane {
@@ -4947,7 +4944,7 @@ span.req {
-webkit-transition-delay: 0;
transition-delay: 0;
opacity: 1; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
/* line 146, ../../../../general/res/sass/mobile/_layout.scss */
.pane-tree-showing .pane.left.treeview {
width: 90% !important; }
@@ -4961,7 +4958,7 @@ span.req {
/* line 152, ../../../../general/res/sass/mobile/_layout.scss */
.pane-tree-showing .pane.right.items .holder-object-and-inspector {
opacity: 0; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 160, ../../../../general/res/sass/mobile/_layout.scss */
.desktop-hide {
display: none; } }
@@ -5276,7 +5273,7 @@ span.req {
margin-left: 50%;
white-space: nowrap; }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
/* line 5, ../../../../general/res/sass/mobile/search/_search.scss */
.search .search-bar .menu-icon {
display: none; }
@@ -5453,7 +5450,7 @@ span.req {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.overlay .bottom-bar .s-btn:not(.major) .icon, .overlay .bottom-bar .s-menu-btn:not(.major) .icon, .overlay .bottom-bar .s-btn:not(.major) .t-item-icon, .overlay .bottom-bar .s-menu-btn:not(.major) .t-item-icon {
color: #fff; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.overlay .bottom-bar .s-btn:not(.major):not(.disabled):hover, .overlay .bottom-bar .s-menu-btn:not(.major):not(.disabled):hover {
background: linear-gradient(#a6a6a6, #999999); }
@@ -5486,7 +5483,7 @@ span.req {
min-height: 225px;
height: 225px; }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 3, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay .clk-icon.close {
top: 20px;
@@ -5504,7 +5501,7 @@ span.req {
/* line 17, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay > .holder > .contents .top-bar > .title {
margin-right: 1.2em; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
/* line 27, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay > .holder {
-moz-border-radius: 0;
@@ -5575,7 +5572,7 @@ span.req {
.t-dialog-sm .overlay > .holder {
height: auto;
max-height: 100%; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
/* line 77, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay > .holder .contents .bottom-bar {
text-align: center; } }
@@ -5648,7 +5645,7 @@ ul.tree {
margin-left: 5px;
font-size: 0.75em;
width: 10px; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 56, ../../../../general/res/sass/tree/_tree.scss */
.tree-item .view-control:hover,
.search-result-item .view-control:hover {
@@ -5781,7 +5778,7 @@ ul.tree {
.tree-item.selected .t-object-label .t-item-icon,
.search-result-item.selected .t-object-label .t-item-icon {
color: #cccccc; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 136, ../../../../general/res/sass/tree/_tree.scss */
.tree-item:not(.selected):hover,
.search-result-item:not(.selected):hover {
@@ -5833,7 +5830,7 @@ ul.tree {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 27, ../../../../general/res/sass/mobile/_tree.scss */
ul.tree ul.tree {
margin-left: 20px; }
@@ -5924,7 +5921,7 @@ ul.tree {
/* line 65, ../../../../general/res/sass/user-environ/_frame.scss */
.frame.frame-template .view-switcher {
z-index: 10; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 71, ../../../../general/res/sass/user-environ/_frame.scss */
.frame.frame-template .view-switcher {
opacity: 0; }
@@ -6426,7 +6423,7 @@ table {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* line 31, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 29, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot {
color: #999;
font-size: 0.7rem;
@@ -6434,10 +6431,10 @@ table {
width: 100%;
height: 100%;
/****************************** Limits and Out-of-Bounds data */ }
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 36, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area {
position: absolute; }
/* line 41, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area.gl-plot-x {
top: auto;
right: 0;
@@ -6446,14 +6443,14 @@ table {
height: 32px;
width: auto;
overflow: hidden; }
/* line 50, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 47, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area.gl-plot-y {
top: 25px;
right: auto;
bottom: 37px;
left: 0;
width: 60px; }
/* line 59, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 56, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-coords {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -6470,10 +6467,10 @@ table {
bottom: auto;
left: 70px;
z-index: 10; }
/* line 71, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 68, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-coords:empty {
display: none; }
/* line 76, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 73, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-display-area {
background-color: rgba(0, 0, 0, 0.1);
position: absolute;
@@ -6483,13 +6480,13 @@ table {
left: 60px;
cursor: crosshair;
border: 1px solid rgba(153, 153, 153, 0.1); }
/* line 89, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 86, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label,
.gl-plot .l-plot-label {
color: #666666;
position: absolute;
text-align: center; }
/* line 97, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 92, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label.gl-plot-x-label, .gl-plot .gl-plot-label.l-plot-x-label,
.gl-plot .l-plot-label.gl-plot-x-label,
.gl-plot .l-plot-label.l-plot-x-label {
@@ -6498,7 +6495,7 @@ table {
bottom: 0;
left: 0;
height: auto; }
/* line 106, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 101, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label.gl-plot-y-label, .gl-plot .gl-plot-label.l-plot-y-label,
.gl-plot .l-plot-label.gl-plot-y-label,
.gl-plot .l-plot-label.l-plot-y-label {
@@ -6515,30 +6512,38 @@ table {
left: 0;
top: 50%;
white-space: nowrap; }
/* line 120, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 115, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-x-options,
.gl-plot .gl-plot-y-options {
position: absolute;
top: 50%;
right: auto;
bottom: auto;
left: auto5px;
margin-top: -16px;
height: auto;
min-height: 32px;
width: 32px; }
/* line 134, ../../../../general/res/sass/plots/_plots-main.scss */
z-index: 2; }
/* line 124, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-x-options {
top: 5px; }
/* line 128, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-y-options {
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
min-width: 150px;
top: 50%;
left: 20px; }
/* line 135, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash {
position: absolute;
border: 0 rgba(255, 255, 255, 0.2) dashed; }
/* line 137, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 138, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash.hash-v {
border-right-width: 1px;
height: 100%; }
/* line 141, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 142, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash.hash-h {
border-bottom-width: 1px;
width: 100%; }
/* line 147, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 148, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-legend {
position: absolute;
top: 0;
@@ -6548,24 +6553,24 @@ table {
height: 20px;
overflow-x: hidden;
overflow-y: auto; }
/* line 160, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 161, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar,
.gl-plot .l-oob-data {
position: absolute;
left: 0;
right: 0;
width: auto; }
/* line 168, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 169, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar {
height: auto;
z-index: 0; }
/* line 176, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar.s-limit-yellow {
background: rgba(255, 170, 0, 0.2); }
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 178, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar.s-limit-red {
background: rgba(255, 0, 0, 0.2); }
/* line 180, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 181, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-oob-data {
overflow: hidden;
position: absolute;
@@ -6578,7 +6583,7 @@ table {
pointer-events: none;
height: 10px;
z-index: 1; }
/* line 188, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 189, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-oob-data.l-oob-data-up {
top: 0;
bottom: auto;
@@ -6587,7 +6592,7 @@ table {
background-image: -moz-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: -webkit-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: linear-gradient(0deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
/* line 193, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 194, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-oob-data.l-oob-data-dwn {
bottom: 0;
top: auto;
@@ -6597,7 +6602,7 @@ table {
background-image: -webkit-linear-gradient(270deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: linear-gradient(180deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
/* line 203, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 204, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item,
.gl-plot-legend .legend-item,
.legend .plot-legend-item,
@@ -6605,13 +6610,13 @@ table {
display: inline-block;
margin-right: 10px;
margin-bottom: 3px; }
/* line 208, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 209, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item span,
.gl-plot-legend .legend-item span,
.legend .plot-legend-item span,
.legend .legend-item span {
vertical-align: middle; }
/* line 211, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 212, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item .plot-color-swatch,
.gl-plot-legend .plot-legend-item .color-swatch,
.gl-plot-legend .legend-item .plot-color-swatch,
@@ -6627,29 +6632,29 @@ table {
height: 8px;
width: 8px; }
/* line 228, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 223, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item {
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
line-height: 1.5em;
padding: 0px 5px; }
/* line 234, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 227, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item .plot-color-swatch {
border: 1px solid #333;
height: 9px;
width: 9px; }
/* line 242, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 235, ../../../../general/res/sass/plots/_plots-main.scss */
.tick {
position: absolute;
border: 0 rgba(255, 255, 255, 0.2) solid; }
/* line 245, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 238, ../../../../general/res/sass/plots/_plots-main.scss */
.tick.tick-x {
border-right-width: 1px;
height: 100%; }
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 244, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick,
.tick-label {
font-size: 0.7rem;
@@ -6657,7 +6662,7 @@ table {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; }
/* line 259, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-x-tick-label, .gl-plot-tick.tick-label-x,
.tick-label.gl-plot-x-tick-label,
.tick-label.tick-label-x {
@@ -6668,7 +6673,7 @@ table {
width: 20%;
margin-left: -10%;
text-align: center; }
/* line 269, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 261, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-y-tick-label, .gl-plot-tick.tick-label-y,
.tick-label.gl-plot-y-tick-label,
.tick-label.tick-label-y {
@@ -6678,18 +6683,18 @@ table {
margin-bottom: -0.5em;
text-align: right; }
/* line 281, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 272, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-x-tick-label {
top: 5px; }
/* line 284, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 275, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-y-tick-label {
right: 5px;
left: 5px; }
/* line 291, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 282, ../../../../general/res/sass/plots/_plots-main.scss */
.tick-label.tick-label-x {
top: 0; }
/* line 294, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 285, ../../../../general/res/sass/plots/_plots-main.scss */
.tick-label.tick-label-y {
right: 0;
left: 0; }
@@ -6816,7 +6821,7 @@ table {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.items-holder .item.grid-item .icon, .items-holder .item.grid-item .t-item-icon {
color: #0099cc; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.items-holder .item.grid-item:not(.disabled):hover {
background: linear-gradient(#666666, #595959); }
@@ -6947,7 +6952,7 @@ table {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.items-holder .item.grid-item.selected .icon, .items-holder .item.grid-item.selected .t-item-icon {
color: #0099cc; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.items-holder .item.grid-item.selected:not(.disabled):hover {
background: linear-gradient(#1ac6ff, #00bfff); }
@@ -6988,7 +6993,7 @@ table {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item {
width: 100%; }
@@ -7022,7 +7027,7 @@ table {
opacity: 1;
font-size: 1em;
width: auto; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item {
height: 50px; }
@@ -7042,7 +7047,7 @@ table {
/* line 83, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item .item-main .item-open {
line-height: 50px; } }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item {
height: 66px; }
@@ -7107,16 +7112,16 @@ table {
-webkit-transition-delay: 0;
transition-delay: 0;
opacity: 1; }
/* line 40, ../../../../general/res/sass/_autoflow.scss */
/* line 38, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header {
bottom: auto;
height: 22px;
line-height: 22px;
min-width: 225px; }
/* line 45, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header span {
vertical-align: middle; }
/* line 48, ../../../../general/res/sass/_autoflow.scss */
/* line 43, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .t-last-update {
overflow: hidden; }
/* line 46, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .s-btn.change-column-width, .autoflow .l-autoflow-header .change-column-width.s-menu-btn {
-moz-transition-property: opacity, background-color, border-color, color;
-o-transition-property: opacity, background-color, border-color, color;
@@ -7135,19 +7140,20 @@ table {
-webkit-transition-delay: 0;
transition-delay: 0;
opacity: 0; }
/* line 52, ../../../../general/res/sass/_autoflow.scss */
/* line 50, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .l-filter {
margin-left: 5px; }
/* line 54, ../../../../general/res/sass/_autoflow.scss */
display: block;
margin-right: 5px; }
/* line 53, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .l-filter input.t-filter-input {
width: 100px; }
/* line 60, ../../../../general/res/sass/_autoflow.scss */
width: 150px; }
/* line 59, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items {
overflow-x: scroll;
overflow-y: hidden;
top: 32px;
white-space: nowrap; }
/* line 66, ../../../../general/res/sass/_autoflow.scss */
/* line 65, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -7158,7 +7164,7 @@ table {
padding-right: 5px;
vertical-align: top;
width: 225px; }
/* line 76, ../../../../general/res/sass/_autoflow.scss */
/* line 75, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -7170,37 +7176,37 @@ table {
margin-bottom: 1px;
margin-top: 1px;
position: relative; }
/* line 85, ../../../../general/res/sass/_autoflow.scss */
/* line 84, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:first-child {
border-top: none; }
/* line 88, ../../../../general/res/sass/_autoflow.scss */
/* line 87, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:hover {
background: rgba(255, 255, 255, 0.1); }
/* line 93, ../../../../general/res/sass/_autoflow.scss */
/* line 92, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.l {
color: rgba(204, 204, 204, 0.3) !important;
font-style: italic; }
/* line 94, ../../../../general/res/sass/_autoflow.scss */
/* line 93, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.r {
color: rgba(204, 204, 204, 0.5) !important;
font-style: italic; }
/* line 97, ../../../../general/res/sass/_autoflow.scss */
/* line 96, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:not(.s-stale) .l-autoflow-item.r {
color: #b3b3b3; }
/* line 101, ../../../../general/res/sass/_autoflow.scss */
/* line 100, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.first-in-group {
border-top: 1px solid rgba(204, 204, 204, 0.1); }
/* line 104, ../../../../general/res/sass/_autoflow.scss */
/* line 103, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item {
display: block; }
/* line 106, ../../../../general/res/sass/_autoflow.scss */
/* line 105, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.l {
float: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: auto; }
/* line 113, ../../../../general/res/sass/_autoflow.scss */
/* line 112, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.r {
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
@@ -7210,11 +7216,15 @@ table {
padding-left: 5px;
padding-right: 5px;
text-align: right; }
/* line 124, ../../../../general/res/sass/_autoflow.scss */
/* line 123, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col:first-child {
border-left: none;
padding-left: 0; }
/* line 133, ../../../../general/res/sass/_autoflow.scss */
.frame.child-frame.panel .autoflow .l-autoflow-header .l-filter {
display: none; }
/* line 1, ../../../../general/res/sass/features/_imagery.scss */
.l-image-main-wrapper,
.l-image-main,

View File

@@ -20,7 +20,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* line 5, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
@@ -41,38 +41,38 @@ time, mark, audio, video {
font-size: 100%;
vertical-align: baseline; }
/* line 22, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html {
line-height: 1; }
/* line 24, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
ol, ul {
list-style: none; }
/* line 26, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
table {
border-collapse: collapse;
border-spacing: 0; }
/* line 28, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle; }
/* line 30, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q, blockquote {
quotes: none; }
/* line 103, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after {
content: "";
content: none; }
/* line 32, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
a img {
border: none; }
/* line 116, ../../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
display: block; }
@@ -173,7 +173,7 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu,
/* REQUIRES /platform/commonUI/general/res/sass/_constants.scss */
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
/************************** MOBILE TREE MENU DIMENSIONS */
/************************** WINDOW DIMENSIONS FOR RWD */
/************************** DEVICE WIDTHS */
/************************** MEDIA QUERIES: WINDOW CHECKS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
/************************** MEDIA QUERIES: WINDOWS FOR SPECIFIC ORIENTATIONS FOR EACH DEVICE */
/************************** DEVICE PARAMETERS FOR MENUS/REPRESENTATIONS */
@@ -235,10 +235,6 @@ a.disabled {
border-bottom: 1px solid rgba(255, 255, 255, 0.3); }
/* line 34, ../../../../general/res/sass/_effects.scss */
.outline {
border: 1px solid white; }
/* line 38, ../../../../general/res/sass/_effects.scss */
.test-stripes {
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjEuMCIgeTE9IjEuMCIgeDI9IjAuMCIgeTI9IjAuMCI+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSIyNSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSI1MCUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiNmZmZmMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjMDAwMDAwIiBzdG9wLW9wYWNpdHk9IjAuMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
background-size: 100%;
@@ -248,7 +244,7 @@ a.disabled {
background-repeat: repeat;
background-size: 40px 40px; }
/* line 42, ../../../../general/res/sass/_effects.scss */
/* line 38, ../../../../general/res/sass/_effects.scss */
.test {
background-color: rgba(255, 204, 0, 0.2) !important; }
@@ -267,7 +263,7 @@ a.disabled {
opacity: 0.5; }
100% {
opacity: 1; } }
/* line 69, ../../../../general/res/sass/_effects.scss */
/* line 65, ../../../../general/res/sass/_effects.scss */
.pulse {
-moz-animation-name: pulse;
-webkit-animation-name: pulse;
@@ -990,7 +986,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left .l-infobubble::before {
right: 100%; }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 76, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left .l-infobubble::before {
width: 0;
@@ -998,14 +994,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
border-top: 6.66667px solid transparent;
border-bottom: 6.66667px solid transparent;
border-right: 10px solid white; } }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 88, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right {
margin-right: 20px; } }
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right .l-infobubble::before {
left: 100%; }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 95, ../../../../general/res/sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right .l-infobubble::before {
width: 0;
@@ -1619,7 +1615,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.s-btn.major .icon, .major.s-menu-btn .icon, .s-btn.major .t-item-icon, .major.s-menu-btn .t-item-icon {
color: #fff; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.s-btn.major:not(.disabled):hover, .major.s-menu-btn:not(.disabled):hover {
background: deepskyblue; }
@@ -1649,7 +1645,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.s-btn:not(.major) .icon, .s-menu-btn:not(.major) .icon, .s-btn:not(.major) .t-item-icon, .s-menu-btn:not(.major) .t-item-icon {
color: #eee; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.s-btn:not(.major):not(.disabled):hover, .s-menu-btn:not(.major):not(.disabled):hover {
background: #0099cc; }
@@ -1682,7 +1678,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.s-btn.pause-play.paused .icon, .pause-play.paused.s-menu-btn .icon, .s-btn.pause-play.paused .t-item-icon, .pause-play.paused.s-menu-btn .t-item-icon {
color: #fff; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.s-btn.pause-play.paused:not(.disabled):hover, .pause-play.paused.s-menu-btn:not(.disabled):hover {
background: #ffad33; }
@@ -1713,7 +1709,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
.s-btn.show-thumbs .icon:before, .show-thumbs.s-menu-btn .icon:before, .s-btn.show-thumbs .t-item-icon:before, .show-thumbs.s-menu-btn .t-item-icon:before {
content: "\000039"; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 101, ../../../../general/res/sass/controls/_buttons.scss */
.mini-tab {
-moz-border-radius: 4px;
@@ -1774,14 +1770,14 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.mini-tab.collapsed .icon, .mini-tab.collapsed .t-item-icon {
color: #eee; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 800px) and (min-device-height: 1025px) and (min-device-width: 1025px) and (min-device-height: 800px), screen and (min-device-width: 1025px) and (min-device-height: 800px) and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.mini-tab.collapsed:not(.disabled):hover {
background: #0099cc; }
/* line 304, ../../../../general/res/sass/_mixins.scss */
.mini-tab.collapsed:not(.disabled):hover > .icon, .mini-tab.collapsed:not(.disabled):hover > .t-item-icon {
color: white; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 138, ../../../../general/res/sass/controls/_buttons.scss */
.mini-tab.collapsed:before {
opacity: 0; }
@@ -1870,7 +1866,7 @@ tr[class*="s-limit"].s-limit-lwr td:first-child:before {
.mini-tab.anchor-right.collapsed:hover:before {
right: 2px; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 208, ../../../../general/res/sass/controls/_buttons.scss */
.mini-tab-icon {
color: #d6d6d6;
@@ -2259,7 +2255,7 @@ label.checkbox.custom {
font-size: 0.7em;
flex: 0 0 1;
-webkit-flex: 0 0 1; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 240, ../../../../general/res/sass/controls/_controls.scss */
.object-header .context-available {
-moz-transition-property: opacity;
@@ -2602,7 +2598,7 @@ label.checkbox.custom {
color: inherit; }
/******************************************************** BROWSER ELEMENTS */
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 485, ../../../../general/res/sass/controls/_controls.scss */
::-webkit-scrollbar {
-moz-border-radius: 2px;
@@ -3298,7 +3294,7 @@ label.checkbox.custom {
/* line 213, ../../../../general/res/sass/controls/_messages.scss */
.t-message-single .message-severity-error .type-icon.message-type:before {
content: "\21"; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 259, ../../../../general/res/sass/controls/_messages.scss */
.t-message-single .l-message,
.t-message-single .bottom-bar {
@@ -3369,7 +3365,7 @@ label.checkbox.custom {
.t-message-list .message-contents .l-message .top-bar,
.t-message-list .message-contents .l-message .message-body {
margin-bottom: 10px; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 304, ../../../../general/res/sass/controls/_messages.scss */
.t-message-list .message-contents .l-message {
margin-right: 10px; } }
@@ -3621,7 +3617,7 @@ mct-include.l-time-controller {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 25, ../../../../general/res/sass/mobile/controls/_menus.scss */
.super-menu {
width: 250px;
@@ -3885,13 +3881,12 @@ textarea {
transition: background, 0.25s;
text-shadow: none;
padding: 0 5px;
overflow: hidden;
position: relative;
line-height: 22px; }
/* line 297, ../../../../general/res/sass/_mixins.scss */
.select .icon, .select .t-item-icon {
color: #eee; }
/* line 31, ../../../../general/res/sass/forms/_selects.scss */
/* line 30, ../../../../general/res/sass/forms/_selects.scss */
.select select {
-moz-appearance: none;
-webkit-appearance: none;
@@ -3904,10 +3899,10 @@ textarea {
border: none !important;
padding: 4px 25px 2px 0px;
width: 120%; }
/* line 40, ../../../../general/res/sass/forms/_selects.scss */
/* line 39, ../../../../general/res/sass/forms/_selects.scss */
.select select option {
margin: 5px 0; }
/* line 44, ../../../../general/res/sass/forms/_selects.scss */
/* line 43, ../../../../general/res/sass/forms/_selects.scss */
.select:after {
text-shadow: none;
content: '\76';
@@ -4395,7 +4390,7 @@ span.req {
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
.pane .mini-tab-icon.toggle-pane {
z-index: 5; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 138, ../../../../general/res/sass/user-environ/_layout.scss */
.pane .mini-tab-icon.toggle-pane {
top: 10px;
@@ -4551,9 +4546,10 @@ span.req {
.pane-tree-hidden .tree-holder,
.pane-tree-hidden .splitter-treeview,
.pane-tree-hidden .holder-treeview-elements {
opacity: 0; }
opacity: 0;
pointer-events: none; }
/* line 278, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 279, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-tree-showing .tree-holder,
.pane-tree-showing .splitter-treeview {
-moz-transition-property: opacity;
@@ -4573,7 +4569,7 @@ span.req {
-webkit-transition-delay: 250ms;
transition-delay: 250ms;
opacity: 1; }
/* line 284, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 285, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-tree-showing .holder-treeview-elements {
-moz-transition-property: opacity;
-o-transition-property: opacity;
@@ -4592,7 +4588,7 @@ span.req {
-webkit-transition-delay: 200ms;
transition-delay: 200ms; }
/* line 291, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 292, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-showing .l-object-and-inspector .l-inspect,
.pane-inspect-showing .l-object-and-inspector .splitter-inspect {
-moz-transition-property: opacity;
@@ -4613,44 +4609,45 @@ span.req {
transition-delay: 250ms;
opacity: 1; }
/* line 301, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 302, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-hidden .l-object-and-inspector .t-inspect {
z-index: 1 !important; }
/* line 304, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 305, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-hidden .l-object-and-inspector .l-inspect,
.pane-inspect-hidden .l-object-and-inspector .splitter-inspect {
opacity: 0; }
opacity: 0;
pointer-events: none; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
/* line 312, ../../../../general/res/sass/user-environ/_layout.scss */
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 314, ../../../../general/res/sass/user-environ/_layout.scss */
.holder-all {
min-width: 600px; }
/* line 317, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 319, ../../../../general/res/sass/user-environ/_layout.scss */
.split-layout .split-pane-component.pane.treeview.left {
min-width: 150px;
max-width: 35%;
width: 25%; }
/* line 322, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 324, ../../../../general/res/sass/user-environ/_layout.scss */
.split-layout .split-pane-component.pane.t-inspect.right {
min-width: 200px;
max-width: 35%;
width: 20%;
z-index: 3; }
/* line 330, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 332, ../../../../general/res/sass/user-environ/_layout.scss */
.pane.treeview.left .tree-holder {
padding-right: 5px; }
/* line 334, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 336, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-tree-hidden .pane.right.primary-pane {
left: 22px !important; }
/* line 337, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
.pane-inspect-hidden .l-object-and-inspector .pane.left {
right: 22px !important; }
/* line 339, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 341, ../../../../general/res/sass/user-environ/_layout.scss */
.pane:not(.resizing) {
-moz-transition-property: width, left, right;
-o-transition-property: width, left, right;
@@ -4669,7 +4666,7 @@ span.req {
-webkit-transition-delay: 0;
transition-delay: 0; }
/* line 342, ../../../../general/res/sass/user-environ/_layout.scss */
/* line 344, ../../../../general/res/sass/user-environ/_layout.scss */
.pane.primary-pane .object-browse-bar {
min-width: 200px; } }
/*****************************************************************************
@@ -4693,7 +4690,7 @@ span.req {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 26, ../../../../general/res/sass/mobile/_layout.scss */
.browse-wrapper,
.pane {
@@ -4869,7 +4866,7 @@ span.req {
-webkit-transition-delay: 0;
transition-delay: 0;
opacity: 1; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
/* line 146, ../../../../general/res/sass/mobile/_layout.scss */
.pane-tree-showing .pane.left.treeview {
width: 90% !important; }
@@ -4883,7 +4880,7 @@ span.req {
/* line 152, ../../../../general/res/sass/mobile/_layout.scss */
.pane-tree-showing .pane.right.items .holder-object-and-inspector {
opacity: 0; } }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 160, ../../../../general/res/sass/mobile/_layout.scss */
.desktop-hide {
display: none; } }
@@ -5198,7 +5195,7 @@ span.req {
margin-left: 50%;
white-space: nowrap; }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
/* line 5, ../../../../general/res/sass/mobile/search/_search.scss */
.search .search-bar .menu-icon {
display: none; }
@@ -5357,7 +5354,7 @@ span.req {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.overlay .bottom-bar .s-btn:not(.major) .icon, .overlay .bottom-bar .s-menu-btn:not(.major) .icon, .overlay .bottom-bar .s-btn:not(.major) .t-item-icon, .overlay .bottom-bar .s-menu-btn:not(.major) .t-item-icon {
color: #fff; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.overlay .bottom-bar .s-btn:not(.major):not(.disabled):hover, .overlay .bottom-bar .s-menu-btn:not(.major):not(.disabled):hover {
background: #7d7d7d; }
@@ -5390,7 +5387,7 @@ span.req {
min-height: 225px;
height: 225px; }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 3, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay .clk-icon.close {
top: 20px;
@@ -5408,7 +5405,7 @@ span.req {
/* line 17, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay > .holder > .contents .top-bar > .title {
margin-right: 1.2em; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
/* line 27, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay > .holder {
-moz-border-radius: 0;
@@ -5479,7 +5476,7 @@ span.req {
.t-dialog-sm .overlay > .holder {
height: auto;
max-height: 100%; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px) {
/* line 77, ../../../../general/res/sass/mobile/overlay/_overlay.scss */
.overlay > .holder .contents .bottom-bar {
text-align: center; } }
@@ -5552,7 +5549,7 @@ ul.tree {
margin-left: 5px;
font-size: 0.75em;
width: 10px; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 56, ../../../../general/res/sass/tree/_tree.scss */
.tree-item .view-control:hover,
.search-result-item .view-control:hover {
@@ -5683,7 +5680,7 @@ ul.tree {
.tree-item.selected .t-object-label .t-item-icon,
.search-result-item.selected .t-object-label .t-item-icon {
color: #fcfcfc; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 136, ../../../../general/res/sass/tree/_tree.scss */
.tree-item:not(.selected):hover,
.search-result-item:not(.selected):hover {
@@ -5735,7 +5732,7 @@ ul.tree {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 27, ../../../../general/res/sass/mobile/_tree.scss */
ul.tree ul.tree {
margin-left: 20px; }
@@ -5826,7 +5823,7 @@ ul.tree {
/* line 65, ../../../../general/res/sass/user-environ/_frame.scss */
.frame.frame-template .view-switcher {
z-index: 10; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 71, ../../../../general/res/sass/user-environ/_frame.scss */
.frame.frame-template .view-switcher {
opacity: 0; }
@@ -6328,7 +6325,7 @@ table {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* line 31, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 29, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot {
color: #666;
font-size: 0.7rem;
@@ -6336,10 +6333,10 @@ table {
width: 100%;
height: 100%;
/****************************** Limits and Out-of-Bounds data */ }
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 36, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area {
position: absolute; }
/* line 41, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 38, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area.gl-plot-x {
top: auto;
right: 0;
@@ -6348,14 +6345,14 @@ table {
height: 32px;
width: auto;
overflow: hidden; }
/* line 50, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 47, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-axis-area.gl-plot-y {
top: 25px;
right: auto;
bottom: 37px;
left: 0;
width: 60px; }
/* line 59, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 56, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-coords {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -6372,10 +6369,10 @@ table {
bottom: auto;
left: 70px;
z-index: 10; }
/* line 71, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 68, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-coords:empty {
display: none; }
/* line 76, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 73, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-display-area {
background-color: rgba(0, 0, 0, 0.05);
position: absolute;
@@ -6385,13 +6382,13 @@ table {
left: 60px;
cursor: crosshair;
border: 1px solid rgba(102, 102, 102, 0.2); }
/* line 89, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 86, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label,
.gl-plot .l-plot-label {
color: #999999;
position: absolute;
text-align: center; }
/* line 97, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 92, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label.gl-plot-x-label, .gl-plot .gl-plot-label.l-plot-x-label,
.gl-plot .l-plot-label.gl-plot-x-label,
.gl-plot .l-plot-label.l-plot-x-label {
@@ -6400,7 +6397,7 @@ table {
bottom: 0;
left: 0;
height: auto; }
/* line 106, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 101, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-label.gl-plot-y-label, .gl-plot .gl-plot-label.l-plot-y-label,
.gl-plot .l-plot-label.gl-plot-y-label,
.gl-plot .l-plot-label.l-plot-y-label {
@@ -6417,30 +6414,38 @@ table {
left: 0;
top: 50%;
white-space: nowrap; }
/* line 120, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 115, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-x-options,
.gl-plot .gl-plot-y-options {
position: absolute;
top: 50%;
right: auto;
bottom: auto;
left: auto5px;
margin-top: -16px;
height: auto;
min-height: 32px;
width: 32px; }
/* line 134, ../../../../general/res/sass/plots/_plots-main.scss */
z-index: 2; }
/* line 124, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-x-options {
top: 5px; }
/* line 128, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-y-options {
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
min-width: 150px;
top: 50%;
left: 20px; }
/* line 135, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash {
position: absolute;
border: 0 rgba(0, 0, 0, 0.2) dashed; }
/* line 137, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 138, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash.hash-v {
border-right-width: 1px;
height: 100%; }
/* line 141, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 142, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-hash.hash-h {
border-bottom-width: 1px;
width: 100%; }
/* line 147, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 148, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .gl-plot-legend {
position: absolute;
top: 0;
@@ -6450,24 +6455,24 @@ table {
height: 20px;
overflow-x: hidden;
overflow-y: auto; }
/* line 160, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 161, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar,
.gl-plot .l-oob-data {
position: absolute;
left: 0;
right: 0;
width: auto; }
/* line 168, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 169, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar {
height: auto;
z-index: 0; }
/* line 176, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar.s-limit-yellow {
background: rgba(255, 170, 0, 0.2); }
/* line 177, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 178, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-limit-bar.s-limit-red {
background: rgba(255, 0, 0, 0.2); }
/* line 180, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 181, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-oob-data {
overflow: hidden;
position: absolute;
@@ -6480,7 +6485,7 @@ table {
pointer-events: none;
height: 10px;
z-index: 1; }
/* line 188, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 189, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-oob-data.l-oob-data-up {
top: 0;
bottom: auto;
@@ -6489,7 +6494,7 @@ table {
background-image: -moz-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: -webkit-linear-gradient(90deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: linear-gradient(0deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
/* line 193, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 194, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot .l-oob-data.l-oob-data-dwn {
bottom: 0;
top: auto;
@@ -6499,7 +6504,7 @@ table {
background-image: -webkit-linear-gradient(270deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%);
background-image: linear-gradient(180deg, rgba(119, 72, 214, 0), rgba(119, 72, 214, 0.5) 100%); }
/* line 203, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 204, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item,
.gl-plot-legend .legend-item,
.legend .plot-legend-item,
@@ -6507,13 +6512,13 @@ table {
display: inline-block;
margin-right: 10px;
margin-bottom: 3px; }
/* line 208, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 209, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item span,
.gl-plot-legend .legend-item span,
.legend .plot-legend-item span,
.legend .legend-item span {
vertical-align: middle; }
/* line 211, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 212, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item .plot-color-swatch,
.gl-plot-legend .plot-legend-item .color-swatch,
.gl-plot-legend .legend-item .plot-color-swatch,
@@ -6529,29 +6534,29 @@ table {
height: 8px;
width: 8px; }
/* line 228, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 223, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
line-height: 1.5em;
padding: 0px 5px; }
/* line 234, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 227, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-legend .plot-legend-item .plot-color-swatch {
border: 1px solid #fcfcfc;
height: 9px;
width: 9px; }
/* line 242, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 235, ../../../../general/res/sass/plots/_plots-main.scss */
.tick {
position: absolute;
border: 0 rgba(0, 0, 0, 0.2) solid; }
/* line 245, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 238, ../../../../general/res/sass/plots/_plots-main.scss */
.tick.tick-x {
border-right-width: 1px;
height: 100%; }
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 244, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick,
.tick-label {
font-size: 0.7rem;
@@ -6559,7 +6564,7 @@ table {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; }
/* line 259, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 251, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-x-tick-label, .gl-plot-tick.tick-label-x,
.tick-label.gl-plot-x-tick-label,
.tick-label.tick-label-x {
@@ -6570,7 +6575,7 @@ table {
width: 20%;
margin-left: -10%;
text-align: center; }
/* line 269, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 261, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-y-tick-label, .gl-plot-tick.tick-label-y,
.tick-label.gl-plot-y-tick-label,
.tick-label.tick-label-y {
@@ -6580,18 +6585,18 @@ table {
margin-bottom: -0.5em;
text-align: right; }
/* line 281, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 272, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-x-tick-label {
top: 5px; }
/* line 284, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 275, ../../../../general/res/sass/plots/_plots-main.scss */
.gl-plot-tick.gl-plot-y-tick-label {
right: 5px;
left: 5px; }
/* line 291, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 282, ../../../../general/res/sass/plots/_plots-main.scss */
.tick-label.tick-label-x {
top: 0; }
/* line 294, ../../../../general/res/sass/plots/_plots-main.scss */
/* line 285, ../../../../general/res/sass/plots/_plots-main.scss */
.tick-label.tick-label-y {
right: 0;
left: 0; }
@@ -6709,7 +6714,7 @@ table {
/* line 297, ../../../../general/res/sass/_mixins.scss */
.items-holder .item.grid-item .icon, .items-holder .item.grid-item .t-item-icon {
color: #0099cc; }
@media screen and (min-device-width: 800px) and (min-device-height: 1025px), screen and (min-device-width: 1025px) and (min-device-height: 800px) {
@media only screen and (min-device-width: 1025px) and (-webkit-min-device-pixel-ratio: 1) {
/* line 302, ../../../../general/res/sass/_mixins.scss */
.items-holder .item.grid-item:not(.disabled):hover {
background: #d0d0d0; }
@@ -6865,7 +6870,7 @@ table {
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px), only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item {
width: 100%; }
@@ -6899,7 +6904,7 @@ table {
opacity: 1;
font-size: 1em;
width: auto; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (max-device-width: 767px), only screen and (orientation: landscape) and (max-device-width: 767px) {
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item {
height: 50px; }
@@ -6919,7 +6924,7 @@ table {
/* line 83, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item .item-main .item-open {
line-height: 50px; } }
@media screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
@media only screen and (orientation: portrait) and (min-device-width: 768px) and (max-device-width: 1024px), only screen and (orientation: landscape) and (min-device-width: 768px) and (max-device-width: 1024px) {
/* line 29, ../../../../general/res/sass/mobile/_item.scss */
.items-holder .item.grid-item {
height: 66px; }
@@ -6984,16 +6989,16 @@ table {
-webkit-transition-delay: 0;
transition-delay: 0;
opacity: 1; }
/* line 40, ../../../../general/res/sass/_autoflow.scss */
/* line 38, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header {
bottom: auto;
height: 22px;
line-height: 22px;
min-width: 225px; }
/* line 45, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header span {
vertical-align: middle; }
/* line 48, ../../../../general/res/sass/_autoflow.scss */
/* line 43, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .t-last-update {
overflow: hidden; }
/* line 46, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .s-btn.change-column-width, .autoflow .l-autoflow-header .change-column-width.s-menu-btn {
-moz-transition-property: opacity, background-color, border-color, color;
-o-transition-property: opacity, background-color, border-color, color;
@@ -7012,19 +7017,20 @@ table {
-webkit-transition-delay: 0;
transition-delay: 0;
opacity: 0; }
/* line 52, ../../../../general/res/sass/_autoflow.scss */
/* line 50, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .l-filter {
margin-left: 5px; }
/* line 54, ../../../../general/res/sass/_autoflow.scss */
display: block;
margin-right: 5px; }
/* line 53, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-header .l-filter input.t-filter-input {
width: 100px; }
/* line 60, ../../../../general/res/sass/_autoflow.scss */
width: 150px; }
/* line 59, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items {
overflow-x: scroll;
overflow-y: hidden;
top: 32px;
white-space: nowrap; }
/* line 66, ../../../../general/res/sass/_autoflow.scss */
/* line 65, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -7035,7 +7041,7 @@ table {
padding-right: 5px;
vertical-align: top;
width: 225px; }
/* line 76, ../../../../general/res/sass/_autoflow.scss */
/* line 75, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -7047,37 +7053,37 @@ table {
margin-bottom: 1px;
margin-top: 1px;
position: relative; }
/* line 85, ../../../../general/res/sass/_autoflow.scss */
/* line 84, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:first-child {
border-top: none; }
/* line 88, ../../../../general/res/sass/_autoflow.scss */
/* line 87, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:hover {
background: rgba(255, 255, 255, 0.1); }
/* line 93, ../../../../general/res/sass/_autoflow.scss */
/* line 92, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.l {
color: rgba(51, 51, 51, 0.3) !important;
font-style: italic; }
/* line 94, ../../../../general/res/sass/_autoflow.scss */
/* line 93, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.s-stale .l-autoflow-item.r {
color: rgba(51, 51, 51, 0.5) !important;
font-style: italic; }
/* line 97, ../../../../general/res/sass/_autoflow.scss */
/* line 96, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row:not(.s-stale) .l-autoflow-item.r {
color: gray; }
/* line 101, ../../../../general/res/sass/_autoflow.scss */
/* line 100, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row.first-in-group {
border-top: 1px solid rgba(153, 153, 153, 0.2); }
/* line 104, ../../../../general/res/sass/_autoflow.scss */
/* line 103, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item {
display: block; }
/* line 106, ../../../../general/res/sass/_autoflow.scss */
/* line 105, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.l {
float: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: auto; }
/* line 113, ../../../../general/res/sass/_autoflow.scss */
/* line 112, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col .l-autoflow-row .l-autoflow-item.r {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
@@ -7087,11 +7093,15 @@ table {
padding-left: 5px;
padding-right: 5px;
text-align: right; }
/* line 124, ../../../../general/res/sass/_autoflow.scss */
/* line 123, ../../../../general/res/sass/_autoflow.scss */
.autoflow .l-autoflow-items .l-autoflow-col:first-child {
border-left: none;
padding-left: 0; }
/* line 133, ../../../../general/res/sass/_autoflow.scss */
.frame.child-frame.panel .autoflow .l-autoflow-header .l-filter {
display: none; }
/* line 1, ../../../../general/res/sass/features/_imagery.scss */
.l-image-main-wrapper,
.l-image-main,

View File

@@ -72,8 +72,7 @@
"persistenceService",
"$q",
"now",
"PERSISTENCE_SPACE",
"ADDITIONAL_PERSISTENCE_SPACES"
"PERSISTENCE_SPACE"
]
},
{
@@ -115,6 +114,12 @@
"type": "provider",
"implementation": "views/ViewProvider.js",
"depends": [ "views[]", "$log" ]
},
{
"provides": "identifierService",
"type": "provider",
"implementation": "identifiers/IdentifierProvider.js",
"depends": [ "PERSISTENCE_SPACE" ]
}
],
"types": [
@@ -183,7 +188,8 @@
{
"key": "persistence",
"implementation": "capabilities/PersistenceCapability.js",
"depends": [ "persistenceService", "PERSISTENCE_SPACE" ]
"depends": [ "persistenceService", "identifierService",
"notificationService", "$q" ]
},
{
"key": "metadata",
@@ -202,7 +208,7 @@
{
"key": "instantiation",
"implementation": "capabilities/InstantiationCapability.js",
"depends": [ "$injector" ]
"depends": [ "$injector", "identifierService" ]
}
],
"services": [
@@ -245,11 +251,6 @@
{
"key": "PERSISTENCE_SPACE",
"value": "mct"
},
{
"key": "ADDITIONAL_PERSISTENCE_SPACES",
"value": [],
"description": "An array of additional persistence spaces to load models from."
}
],
"licenses": [

View File

@@ -22,8 +22,8 @@
/*global define,Promise*/
define(
['../objects/DomainObjectImpl', 'uuid'],
function (DomainObjectImpl, uuid) {
['../objects/DomainObjectImpl'],
function (DomainObjectImpl) {
'use strict';
/**
@@ -33,9 +33,12 @@ define(
* @constructor
* @memberof platform/core
* @param $injector Angular's `$injector`
* @implements {Capability}
*/
function InstantiationCapability($injector) {
function InstantiationCapability($injector, identifierService, domainObject) {
this.$injector = $injector;
this.identifierService = identifierService;
this.domainObject = domainObject;
}
/**
@@ -45,19 +48,26 @@ define(
* have been persisted, nor will it have been added to the
* composition of the object which exposed this capability.
*
* @param {object} the model for the new domain object
* @returns {DomainObject} the new domain object
*/
InstantiationCapability.prototype.instantiate = function (model) {
var parsedId =
this.identifierService.parse(this.domainObject.getId()),
space = parsedId.getDefinedSpace(),
id = this.identifierService.generate(space);
// Lazily initialize; instantiate depends on capabilityService,
// which depends on all capabilities, including this one.
this.instantiateFn = this.instantiateFn ||
this.$injector.get("instantiate");
return this.instantiateFn(model);
return this.instantiateFn(model, id);
};
/**
* Alias of `create`.
* @see {platform/core.CreationCapability#create}
* Alias of `instantiate`.
* @see {platform/core.CreationCapability#instantiate}
*/
InstantiationCapability.prototype.invoke =
InstantiationCapability.prototype.instantiate;

View File

@@ -20,6 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
/*jslint es5: true */
define(
@@ -44,13 +45,21 @@ define(
* @constructor
* @implements {Capability}
*/
function PersistenceCapability(persistenceService, space, domainObject) {
function PersistenceCapability(
persistenceService,
identifierService,
notificationService,
$q,
domainObject
) {
// Cache modified timestamp
this.modified = domainObject.getModel().modified;
this.domainObject = domainObject;
this.space = space;
this.identifierService = identifierService;
this.persistenceService = persistenceService;
this.notificationService = notificationService;
this.$q = $q;
}
// Utility function for creating promise-like objects which
@@ -63,6 +72,51 @@ define(
};
}
function getKey(id) {
var parts = id.split(":");
return parts.length > 1 ? parts.slice(1).join(":") : id;
}
/**
* Checks if the value returned is falsey, and if so returns a
* rejected promise
*/
function rejectIfFalsey(value, $q){
if (!value){
return $q.reject("Error persisting object");
} else {
return value;
}
}
function formatError(error){
if (error && error.message) {
return error.message;
} else if (error && typeof error === "string"){
return error;
} else {
return "unknown error";
}
}
/**
* Display a notification message if an error has occurred during
* persistence.
*/
function notifyOnError(error, domainObject, notificationService, $q){
var errorMessage = "Unable to persist " + domainObject.getModel().name;
if (error) {
errorMessage += ": " + formatError(error);
}
notificationService.error({
title: "Error persisting " + domainObject.getModel().name,
hint: errorMessage || "Unknown error"
});
return $q.reject(error);
}
/**
* Persist any changes which have been made to this
* domain object's model.
@@ -71,7 +125,8 @@ define(
* if not.
*/
PersistenceCapability.prototype.persist = function () {
var domainObject = this.domainObject,
var self = this,
domainObject = this.domainObject,
model = domainObject.getModel(),
modified = model.modified,
persistenceService = this.persistenceService,
@@ -87,9 +142,13 @@ define(
// ...and persist
return persistenceFn.apply(persistenceService, [
this.getSpace(),
domainObject.getId(),
getKey(domainObject.getId()),
domainObject.getModel()
]);
]).then(function(result){
return rejectIfFalsey(result, self.$q);
}).catch(function(error){
return notifyOnError(error, domainObject, self.notificationService, self.$q);
});
};
/**
@@ -130,7 +189,8 @@ define(
* be used to persist this object
*/
PersistenceCapability.prototype.getSpace = function () {
return this.space;
var id = this.domainObject.getId();
return this.identifierService.parse(id).getSpace();
};
return PersistenceCapability;

View File

@@ -0,0 +1,86 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
[],
function () {
'use strict';
var SEPARATOR = ":";
/**
* Provides an interface for interpreting domain object identifiers;
* in particular, parses out persistence space/key pairs associated
* with the domain object.
*
* @memberof platform/core
* @constructor
* @param {string} id the domain object identifier
* @param {string} defaultSpace the persistence space to use if
* one is not encoded in the identifier
*/
function Identifier(id, defaultSpace) {
var separatorIndex = id.indexOf(SEPARATOR);
if (separatorIndex > -1) {
this.key = id.substring(separatorIndex + 1);
this.space = id.substring(0, separatorIndex);
this.definedSpace = this.space;
} else {
this.key = id;
this.space = defaultSpace;
this.definedSpace = undefined;
}
}
/**
* Get the key under which the identified domain object's model
* should be persisted, within its persistence space.
* @returns {string} the key within its persistence space
*/
Identifier.prototype.getKey = function () {
return this.key;
};
/**
* Get the space in which the identified domain object's model should
* be persisted.
* @returns {string} the persistence space
*/
Identifier.prototype.getSpace = function () {
return this.space;
};
/**
* Get the persistence space, if any, which has been explicitly
* encoded in this domain object's identifier. Returns undefined
* if no such space has been specified.
* @returns {string} the persistence space, or undefined
*/
Identifier.prototype.getDefinedSpace = function () {
return this.definedSpace;
};
return Identifier;
}
);

View File

@@ -0,0 +1,66 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
["uuid", "./Identifier"],
function (uuid, Identifier) {
'use strict';
/**
* Parses and generates domain object identifiers.
* @param {string} defaultSpace the default persistence space
* @constructor
* @memberof {platform/core}
*/
function IdentifierProvider(defaultSpace) {
this.defaultSpace = defaultSpace;
}
/**
* Generate a new domain object identifier. A persistence space
* may optionally be included; if not specified, no space will
* be encoded into the identifier.
* @param {string} [space] the persistence space to encode
* in this identifier
* @returns {string} a new domain object identifier
*/
IdentifierProvider.prototype.generate = function (space) {
var id = uuid();
if (space !== undefined) {
id = space + ":" + id;
}
return id;
};
/**
* Parse a domain object identifier to examine its component
* parts (e.g. its persistence space.)
* @returns {platform/core.Identifier} the parsed identifier
*/
IdentifierProvider.prototype.parse = function (id) {
return new Identifier(id, this.defaultSpace);
};
return IdentifierProvider;
}
);

View File

@@ -33,6 +33,15 @@ define(
* A model service which reads domain object models from an external
* persistence service.
*
* Identifiers will be interpreted as follows:
* * If no colon is present, the model will be read from the default
* persistence space.
* * If a colon is present, everything before the first colon will be
* taken to refer to the persistence space, and everything after
* will be taken to be that model's key within this space. (If
* no such space exists within the `persistenceService`, that
* identifier will simply be ignored.)
*
* @memberof platform/core
* @constructor
* @implements {ModelService}
@@ -41,39 +50,26 @@ define(
* @param $q Angular's $q service, for working with promises
* @param {function} now a function which provides the current time
* @param {string} space the name of the persistence space(s)
* from which models should be retrieved.
* @param {string} spaces additional persistence spaces to use
* from which models should be retrieved by default
*/
function PersistedModelProvider(persistenceService, $q, now, space, spaces) {
function PersistedModelProvider(persistenceService, $q, now, space) {
this.persistenceService = persistenceService;
this.$q = $q;
this.spaces = [space].concat(spaces || []);
this.now = now;
}
// Take the most recently modified model, for cases where
// multiple persistence spaces return models.
function takeMostRecent(modelA, modelB) {
return (!modelB || modelB.modified === undefined) ? modelA :
(!modelA || modelA.modified === undefined) ? modelB :
modelB.modified > modelA.modified ? modelB :
modelA;
this.defaultSpace = space;
}
PersistedModelProvider.prototype.getModels = function (ids) {
var persistenceService = this.persistenceService,
$q = this.$q,
spaces = this.spaces,
space = this.space,
now = this.now;
now = this.now,
defaultSpace = this.defaultSpace,
parsedIds;
// Load a single object model from any persistence spaces
function loadModel(id) {
return $q.all(spaces.map(function (space) {
return persistenceService.readObject(space, id);
})).then(function (models) {
return models.reduce(takeMostRecent);
});
function loadModel(parsedId) {
return persistenceService
.readObject(parsedId.space, parsedId.key);
}
// Ensure that models read from persistence have some
@@ -88,24 +84,43 @@ define(
}
// Package the result as id->model
function packageResult(models) {
function packageResult(parsedIds, models) {
var result = {};
ids.forEach(function (id, index) {
parsedIds.forEach(function (parsedId, index) {
var id = parsedId.id;
if (models[index]) {
result[id] = addPersistedTimestamp(models[index]);
result[id] = models[index];
}
});
return result;
}
// Filter out "namespaced" identifiers; these are
// not expected to be found in database. See WTD-659.
ids = ids.filter(function (id) {
return id.indexOf(":") === -1;
function loadModels(parsedIds) {
return $q.all(parsedIds.map(loadModel))
.then(function (models) {
return packageResult(
parsedIds,
models.map(addPersistedTimestamp)
);
});
}
function restrictToSpaces(spaces) {
return parsedIds.filter(function (parsedId) {
return spaces.indexOf(parsedId.space) !== -1;
});
}
parsedIds = ids.map(function (id) {
var parts = id.split(":");
return (parts.length > 1) ?
{ id: id, space: parts[0], key: parts.slice(1).join(":") } :
{ id: id, space: defaultSpace, key: id };
});
// Give a promise for all persistence lookups...
return $q.all(ids.map(loadModel)).then(packageResult);
return persistenceService.listSpaces()
.then(restrictToSpaces)
.then(loadModels);
};
return PersistedModelProvider;

View File

@@ -22,8 +22,8 @@
/*global define,Promise*/
define(
['../objects/DomainObjectImpl', 'uuid'],
function (DomainObjectImpl, uuid) {
['../objects/DomainObjectImpl'],
function (DomainObjectImpl) {
'use strict';
/**
@@ -39,12 +39,15 @@ define(
*
* @constructor
* @memberof platform/core
* @param $injector Angular's `$injector`
* @param {CapabilityService} capabilityService the service which will
* provide instantiated domain objects with their capabilities
* @param {IdentifierService} identifierService service to generate
* new identifiers
*/
function Instantiate(capabilityService) {
function Instantiate(capabilityService, identifierService) {
return function (model, id) {
var capabilities = capabilityService.getCapabilities(model);
id = id || uuid();
id = id || identifierService.generate();
return new DomainObjectImpl(id, model, capabilities);
};
}

View File

@@ -28,19 +28,40 @@ define(
describe("The 'instantiation' capability", function () {
var mockInjector,
mockIdentifierService,
mockInstantiate,
mockIdentifier,
mockDomainObject,
instantiation;
beforeEach(function () {
mockInjector = jasmine.createSpyObj("$injector", ["get"]);
mockInstantiate = jasmine.createSpy("instantiate");
mockIdentifierService = jasmine.createSpyObj(
'identifierService',
[ 'parse', 'generate' ]
);
mockIdentifier = jasmine.createSpyObj(
'identifier',
[ 'getSpace', 'getKey', 'getDefinedSpace' ]
);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
[ 'getId', 'getCapability', 'getModel' ]
);
mockInjector.get.andCallFake(function (key) {
return key === 'instantiate' ?
mockInstantiate : undefined;
});
mockIdentifierService.parse.andReturn(mockIdentifier);
mockIdentifierService.generate.andReturn("some-id");
instantiation = new InstantiationCapability(mockInjector);
instantiation = new InstantiationCapability(
mockInjector,
mockIdentifierService,
mockDomainObject
);
});
@@ -59,7 +80,8 @@ define(
mockInstantiate.andReturn(mockDomainObject);
expect(instantiation.instantiate(testModel))
.toBe(mockDomainObject);
expect(mockInstantiate).toHaveBeenCalledWith(testModel);
expect(mockInstantiate)
.toHaveBeenCalledWith(testModel, jasmine.any(String));
});
});

View File

@@ -20,6 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
/*jslint es5: true */
/**
* PersistenceCapabilitySpec. Created by vwoeltje on 11/6/14.
@@ -31,25 +32,56 @@ define(
describe("The persistence capability", function () {
var mockPersistenceService,
mockIdentifierService,
mockDomainObject,
mockIdentifier,
mockNofificationService,
mockQ,
id = "object id",
model = { someKey: "some value"},
model,
SPACE = "some space",
persistence;
persistence,
happyPromise;
function asPromise(value) {
function asPromise(value, doCatch) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
},
catch: function(callback) {
//Define a default 'happy' catch, that skips over the
// catch callback
return doCatch ? asPromise(callback(value)): asPromise(value);
}
};
}
beforeEach(function () {
happyPromise = asPromise(true);
model = { someKey: "some value", name: "domain object"};
mockPersistenceService = jasmine.createSpyObj(
"persistenceService",
[ "updateObject", "readObject", "createObject", "deleteObject" ]
);
mockIdentifierService = jasmine.createSpyObj(
'identifierService',
[ 'parse', 'generate' ]
);
mockIdentifier = jasmine.createSpyObj(
'identifier',
[ 'getSpace', 'getKey', 'getDefinedSpace' ]
);
mockQ = jasmine.createSpyObj(
"$q",
["reject"]
);
mockNofificationService = jasmine.createSpyObj(
"notificationService",
["error"]
);
mockDomainObject = {
getId: function () { return id; },
getModel: function () { return model; },
@@ -61,69 +93,104 @@ define(
model = mutator(model) || model;
}
});
mockIdentifierService.parse.andReturn(mockIdentifier);
mockIdentifier.getSpace.andReturn(SPACE);
persistence = new PersistenceCapability(
mockPersistenceService,
SPACE,
mockIdentifierService,
mockNofificationService,
mockQ,
mockDomainObject
);
});
it("creates unpersisted objects with the persistence service", function () {
// Verify precondition; no call made during constructor
expect(mockPersistenceService.createObject).not.toHaveBeenCalled();
describe("successful persistence", function() {
beforeEach(function () {
mockPersistenceService.updateObject.andReturn(happyPromise);
mockPersistenceService.createObject.andReturn(happyPromise);
});
it("creates unpersisted objects with the persistence service", function () {
// Verify precondition; no call made during constructor
expect(mockPersistenceService.createObject).not.toHaveBeenCalled();
persistence.persist();
persistence.persist();
expect(mockPersistenceService.createObject).toHaveBeenCalledWith(
SPACE,
id,
model
);
expect(mockPersistenceService.createObject).toHaveBeenCalledWith(
SPACE,
id,
model
);
});
it("updates previously persisted objects with the persistence service", function () {
// Verify precondition; no call made during constructor
expect(mockPersistenceService.updateObject).not.toHaveBeenCalled();
model.persisted = 12321;
persistence.persist();
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
SPACE,
id,
model
);
});
it("reports which persistence space an object belongs to", function () {
expect(persistence.getSpace()).toEqual(SPACE);
});
it("updates persisted timestamp on persistence", function () {
model.modified = 12321;
persistence.persist();
expect(model.persisted).toEqual(12321);
});
it("refreshes the domain object model from persistence", function () {
var refreshModel = {someOtherKey: "some other value"};
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
persistence.refresh();
expect(model).toEqual(refreshModel);
});
it("does not overwrite unpersisted changes on refresh", function () {
var refreshModel = {someOtherKey: "some other value"},
mockCallback = jasmine.createSpy();
model.modified = 2;
model.persisted = 1;
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
persistence.refresh().then(mockCallback);
expect(model).not.toEqual(refreshModel);
// Should have also indicated that no changes were actually made
expect(mockCallback).toHaveBeenCalledWith(false);
});
it("does not trigger error notification on successful" +
" persistence", function () {
persistence.persist();
expect(mockQ.reject).not.toHaveBeenCalled();
expect(mockNofificationService.error).not.toHaveBeenCalled();
});
});
describe("unsuccessful persistence", function() {
var sadPromise = {
then: function(callback){
return asPromise(callback(0), true);
}
};
beforeEach(function () {
mockPersistenceService.createObject.andReturn(sadPromise);
});
it("rejects on falsey persistence result", function () {
persistence.persist();
expect(mockQ.reject).toHaveBeenCalled();
});
it("updates previously persisted objects with the persistence service", function () {
// Verify precondition; no call made during constructor
expect(mockPersistenceService.updateObject).not.toHaveBeenCalled();
model.persisted = 12321;
persistence.persist();
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
SPACE,
id,
model
);
it("notifies user on persistence failure", function () {
persistence.persist();
expect(mockQ.reject).toHaveBeenCalled();
expect(mockNofificationService.error).toHaveBeenCalled();
});
});
it("reports which persistence space an object belongs to", function () {
expect(persistence.getSpace()).toEqual(SPACE);
});
it("updates persisted timestamp on persistence", function () {
model.modified = 12321;
persistence.persist();
expect(model.persisted).toEqual(12321);
});
it("refreshes the domain object model from persistence", function () {
var refreshModel = { someOtherKey: "some other value" };
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
persistence.refresh();
expect(model).toEqual(refreshModel);
});
it("does not overwrite unpersisted changes on refresh", function () {
var refreshModel = { someOtherKey: "some other value" },
mockCallback = jasmine.createSpy();
model.modified = 2;
model.persisted = 1;
mockPersistenceService.readObject.andReturn(asPromise(refreshModel));
persistence.refresh().then(mockCallback);
expect(model).not.toEqual(refreshModel);
// Should have also indicated that no changes were actually made
expect(mockCallback).toHaveBeenCalledWith(false);
});
});
}
);

View File

@@ -0,0 +1,58 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../../src/identifiers/IdentifierProvider"],
function (IdentifierProvider) {
'use strict';
describe("IdentifierProvider", function () {
var defaultSpace,
provider;
beforeEach(function () {
defaultSpace = "some-default-space";
provider = new IdentifierProvider(defaultSpace);
});
it("generates unique identifiers", function () {
expect(provider.generate())
.not.toEqual(provider.generate());
});
it("allows spaces to be specified for generated identifiers", function () {
var specificSpace = "some-specific-space",
id = provider.generate(specificSpace);
expect(id).toEqual(jasmine.any(String));
expect(provider.parse(id).getDefinedSpace())
.toEqual(specificSpace);
});
it("parses identifiers using the default space", function () {
expect(provider.parse("some-unprefixed-id").getSpace())
.toEqual(defaultSpace);
});
});
}
);

View File

@@ -0,0 +1,82 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../../src/identifiers/Identifier"],
function (Identifier) {
'use strict';
describe("A parsed domain object identifier", function () {
var id,
defaultSpace,
identifier;
beforeEach(function () {
defaultSpace = "someDefaultSpace";
});
describe("when space is encoded", function () {
var idSpace, idKey, spacedId;
beforeEach(function () {
idSpace = "a-specific-space";
idKey = "a-specific-key";
id = idSpace + ":" + idKey;
identifier = new Identifier(id, defaultSpace);
});
it("provides the encoded space", function () {
expect(identifier.getSpace()).toEqual(idSpace);
});
it("provides the key within that space", function () {
expect(identifier.getKey()).toEqual(idKey);
});
it("provides the defined space", function () {
expect(identifier.getDefinedSpace()).toEqual(idSpace);
});
});
describe("when space is not encoded", function () {
beforeEach(function () {
id = "a-generic-id";
identifier = new Identifier(id, defaultSpace);
});
it("provides the default space", function () {
expect(identifier.getSpace()).toEqual(defaultSpace);
});
it("provides the id as the key", function () {
expect(identifier.getKey()).toEqual(id);
});
it("provides no defined space", function () {
expect(identifier.getDefinedSpace()).toEqual(undefined);
});
});
});
}
);

View File

@@ -33,13 +33,12 @@ define(
var mockQ,
mockPersistenceService,
SPACE = "space0",
spaces = [ "space1" ],
modTimes,
mockNow,
provider;
function mockPromise(value) {
return {
return (value || {}).then ? value : {
then: function (callback) {
return mockPromise(callback(value));
},
@@ -78,13 +77,14 @@ define(
persisted: 0
});
});
mockPersistenceService.listSpaces
.andReturn(mockPromise([SPACE]));
provider = new PersistedModelProvider(
mockPersistenceService,
mockQ,
mockNow,
SPACE,
spaces
SPACE
);
});
@@ -103,25 +103,6 @@ define(
});
it("reads object models from multiple spaces", function () {
var models;
modTimes.space1 = {
'x': 12321
};
provider.getModels(["a", "x", "zz"]).then(function (m) {
models = m;
});
expect(models).toEqual({
a: { space: SPACE, id: "a", persisted: 0 },
x: { space: 'space1', id: "x", modified: 12321, persisted: 0 },
zz: { space: SPACE, id: "zz", persisted: 0 }
});
});
it("ensures that persisted timestamps are present", function () {
var mockCallback = jasmine.createSpy("callback"),
testModels = {

View File

@@ -29,18 +29,27 @@ define(
describe("The 'instantiate' service", function () {
var mockCapabilityService,
mockIdentifierService,
mockCapabilityConstructor,
mockCapabilityInstance,
mockCapabilities,
mockIdentifier,
idCounter,
testModel,
instantiate,
domainObject;
beforeEach(function () {
idCounter = 0;
mockCapabilityService = jasmine.createSpyObj(
'capabilityService',
['getCapabilities']
);
mockIdentifierService = jasmine.createSpyObj(
'identifierService',
[ 'parse', 'generate' ]
);
mockCapabilityConstructor = jasmine.createSpy('capability');
mockCapabilityInstance = {};
mockCapabilityService.getCapabilities.andReturn({
@@ -48,9 +57,17 @@ define(
});
mockCapabilityConstructor.andReturn(mockCapabilityInstance);
mockIdentifierService.generate.andCallFake(function (space) {
return (space ? (space + ":") : "") +
"some-id-" + (idCounter += 1);
});
testModel = { someKey: "some value" };
instantiate = new Instantiate(mockCapabilityService);
instantiate = new Instantiate(
mockCapabilityService,
mockIdentifierService
);
domainObject = instantiate(testModel);
});

View File

@@ -15,6 +15,9 @@
"capabilities/PersistenceCapability",
"capabilities/RelationshipCapability",
"identifiers/Identifier",
"identifiers/IdentifierProvider",
"models/ModelAggregator",
"models/MissingModelDecorator",
"models/PersistedModelProvider",

View File

@@ -11,7 +11,7 @@
"glyph": "f",
"category": "contextual",
"implementation": "actions/MoveAction.js",
"depends": ["locationService", "moveService"]
"depends": ["policyService", "locationService", "moveService"]
},
{
"key": "copy",
@@ -20,7 +20,7 @@
"glyph": "+",
"category": "contextual",
"implementation": "actions/CopyAction.js",
"depends": ["$log", "locationService", "copyService",
"depends": ["$log", "policyService", "locationService", "copyService",
"dialogService", "notificationService"]
},
{
@@ -30,7 +30,7 @@
"glyph": "\u00E8",
"category": "contextual",
"implementation": "actions/LinkAction.js",
"depends": ["locationService", "linkService"]
"depends": ["policyService", "locationService", "linkService"]
},
{
"key": "follow",
@@ -39,6 +39,15 @@
"glyph": "\u00F4",
"category": "contextual",
"implementation": "actions/GoToOriginalAction.js"
},
{
"key": "locate",
"name": "Set Primary Location",
"description": "Set a domain object's primary location.",
"glyph": "",
"category": "contextual",
"implementation": "actions/SetPrimaryLocationAction.js"
}
],
"components": [
@@ -54,7 +63,11 @@
"depends": ["contextualize", "$q", "$log"]
}
],
"controllers": [
"policies": [
{
"category": "action",
"implementation": "policies/CrossSpacePolicy.js"
}
],
"capabilities": [
{
@@ -85,8 +98,7 @@
"name": "Copy Service",
"description": "Provides a service for copying objects",
"implementation": "services/CopyService.js",
"depends": ["$q", "creationService", "policyService",
"persistenceService", "now"]
"depends": ["$q", "policyService", "now"]
},
{
"key": "locationService",

View File

@@ -62,6 +62,8 @@ define(
* @constructor
* @private
* @memberof platform/entanglement
* @param {PolicyService} policyService the policy service to use to
* verify that variants of this action are allowed
* @param {platform/entanglement.LocationService} locationService a
* service to request destinations from the user
* @param {platform/entanglement.AbstractComposeService} composeService
@@ -71,7 +73,14 @@ define(
* @param {string} [suffix] a string to display in the dialog title;
* default is "to a new location"
*/
function AbstractComposeAction(locationService, composeService, context, verb, suffix) {
function AbstractComposeAction(
policyService,
locationService,
composeService,
context,
verb,
suffix
) {
if (context.selectedObject) {
this.newParent = context.domainObject;
this.object = context.selectedObject;
@@ -83,16 +92,27 @@ define(
.getCapability('context')
.getParent();
this.context = context;
this.policyService = policyService;
this.locationService = locationService;
this.composeService = composeService;
this.verb = verb || "Compose";
this.suffix = suffix || "to a new location";
}
AbstractComposeAction.prototype.cloneContext = function () {
var clone = {}, original = this.context;
Object.keys(original).forEach(function (k) {
clone[k] = original[k];
});
return clone;
};
AbstractComposeAction.prototype.perform = function () {
var dialogTitle,
label,
validateLocation,
self = this,
locationService = this.locationService,
composeService = this.composeService,
currentParent = this.currentParent,
@@ -109,7 +129,11 @@ define(
label = this.verb + " To";
validateLocation = function (newParent) {
return composeService.validate(object, newParent);
var newContext = self.cloneContext();
newContext.selectedObject = object;
newContext.domainObject = newParent;
return composeService.validate(object, newParent) &&
self.policyService.allow("action", self, newContext);
};
return locationService.getLocationFromUser(

View File

@@ -34,18 +34,34 @@ define(
* @constructor
* @memberof platform/entanglement
*/
function CopyAction($log, locationService, copyService, dialogService,
notificationService, context) {
function CopyAction(
$log,
policyService,
locationService,
copyService,
dialogService,
notificationService,
context
) {
this.dialog = undefined;
this.notification = undefined;
this.dialogService = dialogService;
this.notificationService = notificationService;
this.$log = $log;
//Extend the behaviour of the Abstract Compose Action
AbstractComposeAction.call(this, locationService, copyService,
context, "Duplicate", "to a location");
AbstractComposeAction.call(
this,
policyService,
locationService,
copyService,
context,
"Duplicate",
"to a location"
);
}
CopyAction.prototype = Object.create(AbstractComposeAction.prototype);
/**
* Updates user about progress of copy. Should not be invoked by
* client code under any circumstances.

View File

@@ -34,10 +34,10 @@ define(
* @constructor
* @memberof platform/entanglement
*/
function LinkAction(locationService, linkService, context) {
function LinkAction(policyService, locationService, linkService, context) {
AbstractComposeAction.apply(
this,
[locationService, linkService, context, "Link"]
[policyService, locationService, linkService, context, "Link"]
);
}

View File

@@ -34,12 +34,11 @@ define(
* @constructor
* @memberof platform/entanglement
*/
function MoveAction(locationService, moveService, context) {
function MoveAction(policyService, locationService, moveService, context) {
AbstractComposeAction.apply(
this,
[locationService, moveService, context, "Move"]
[policyService, locationService, moveService, context, "Move"]
);
}
MoveAction.prototype = Object.create(AbstractComposeAction.prototype);

View File

@@ -0,0 +1,60 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
function () {
"use strict";
/**
* Implements the "Set Primary Location" action, which sets a
* location property for objects to match their contextual
* location.
*
* @implements {Action}
* @constructor
* @private
* @memberof platform/entanglement
* @param {ActionContext} context the context in which the action
* will be performed
*/
function SetPrimaryLocationAction(context) {
this.domainObject = context.domainObject;
}
SetPrimaryLocationAction.prototype.perform = function () {
var location = this.domainObject.getCapability('location');
return location.setPrimaryLocation(
location.getContextualLocation()
);
};
SetPrimaryLocationAction.appliesTo = function (context) {
var domainObject = context.domainObject;
return domainObject && domainObject.hasCapability("location")
&& (domainObject.getModel().location === undefined);
};
return SetPrimaryLocationAction;
}
);

View File

@@ -0,0 +1,73 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define(
[],
function () {
'use strict';
var DISALLOWED_ACTIONS = [
"move",
"copy"
];
/**
* This policy prevents performing move/copy/link actions across
* different persistence spaces (e.g. linking to an object in
* a private space from an object in a public space.)
* @memberof {platform/entanglement}
* @constructor
* @implements {Policy}
*/
function CrossSpacePolicy() {
}
function lookupSpace(domainObject) {
var persistence = domainObject &&
domainObject.getCapability("persistence");
return persistence && persistence.getSpace();
}
function isCrossSpace(context) {
var domainObject = context.domainObject,
selectedObject = context.selectedObject,
spaces = [ domainObject, selectedObject ].map(lookupSpace);
return selectedObject !== undefined &&
domainObject !== undefined &&
lookupSpace(domainObject) !== lookupSpace(selectedObject);
}
CrossSpacePolicy.prototype.allow = function (action, context) {
var key = action.getMetadata().key;
if (DISALLOWED_ACTIONS.indexOf(key) !== -1) {
return !isCrossSpace(context);
}
return true;
};
return CrossSpacePolicy;
}
);

View File

@@ -38,12 +38,9 @@ define(
* @memberof platform/entanglement
* @implements {platform/entanglement.AbstractComposeService}
*/
function CopyService($q, creationService, policyService, persistenceService, now) {
function CopyService($q, policyService) {
this.$q = $q;
this.creationService = creationService;
this.policyService = policyService;
this.persistenceService = persistenceService;
this.now = now;
}
CopyService.prototype.validate = function (object, parentCandidate) {
@@ -71,7 +68,7 @@ define(
*/
CopyService.prototype.perform = function (domainObject, parent) {
var $q = this.$q,
copyTask = new CopyTask(domainObject, parent, this.persistenceService, this.$q, this.now);
copyTask = new CopyTask(domainObject, parent, this.policyService, this.$q);
if (this.validate(domainObject, parent)) {
return copyTask.perform();
} else {

View File

@@ -23,8 +23,8 @@
/*global define */
define(
["uuid"],
function (uuid) {
[],
function () {
"use strict";
/**
@@ -33,36 +33,51 @@ define(
*
* @param domainObject The object to copy
* @param parent The new location of the cloned object tree
* @param persistenceService
* @param $q
* @param now
* @constructor
*/
function CopyTask (domainObject, parent, persistenceService, $q, now){
function CopyTask (domainObject, parent, policyService, $q){
this.domainObject = domainObject;
this.parent = parent;
this.firstClone = undefined;
this.$q = $q;
this.deferred = undefined;
this.persistenceService = persistenceService;
this.policyService = policyService;
this.persisted = 0;
this.now = now;
this.clones = [];
this.idMap = {};
}
function composeChild(child, parent) {
function composeChild(child, parent, setLocation) {
//Once copied, associate each cloned
// composee with its parent clone
child.model.location = parent.id;
parent.model.composition = parent.model.composition || [];
return parent.model.composition.push(child.id);
parent.getModel().composition.push(child.getId());
//If a location is not specified, set it.
if (setLocation && child.getModel().location === undefined) {
child.getModel().location = parent.getId();
}
return child;
}
function cloneObjectModel(objectModel) {
var clone = JSON.parse(JSON.stringify(objectModel));
delete clone.composition;
/**
* Reset certain fields.
*/
//If has a composition, set it to an empty array. Will be
// recomposed later with the ids of its cloned children.
if (clone.composition) {
//Important to set it to an empty array here, otherwise
// hasCapability("composition") returns false;
clone.composition = [];
}
delete clone.persisted;
delete clone.modified;
delete clone.location;
return clone;
}
@@ -73,13 +88,10 @@ define(
* result in automatic request batching by the browser.
*/
function persistObjects(self) {
return self.$q.all(self.clones.map(function(clone){
clone.model.persisted = self.now();
return self.persistenceService.createObject(clone.persistenceSpace, clone.id, clone.model)
.then(function(){
self.deferred.notify({phase: "copying", totalObjects: self.clones.length, processed: ++self.persisted});
});
return clone.getCapability("persistence").persist().then(function(){
self.deferred.notify({phase: "copying", totalObjects: self.clones.length, processed: ++self.persisted});
});
})).then(function(){
return self;
});
@@ -89,19 +101,40 @@ define(
* Will add a list of clones to the specified parent's composition
*/
function addClonesToParent(self) {
var parentClone = self.clones[self.clones.length-1];
return self.firstClone.getCapability("persistence").persist()
.then(function(){self.parent.getCapability("composition").add(self.firstClone.getId());})
.then(function(){return self.parent.getCapability("persistence").persist();})
.then(function(){return self.firstClone;});
}
if (!self.parent.hasCapability('composition')){
return self.$q.reject();
/**
* Update identifiers in a cloned object model (or part of
* a cloned object model) to reflect new identifiers after
* copying.
* @private
*/
CopyTask.prototype.rewriteIdentifiers = function (obj, idMap) {
function lookupValue(value) {
return (typeof value === 'string' && idMap[value]) || value;
}
return self.persistenceService
.updateObject(parentClone.persistenceSpace, parentClone.id, parentClone.model)
.then(function(){return self.parent.getCapability("composition").add(parentClone.id);})
.then(function(){return self.parent.getCapability("persistence").persist();})
.then(function(){return parentClone;});
// Ensure the clone of the original domainObject is returned
}
if (Array.isArray(obj)) {
obj.forEach(function (value, index) {
obj[index] = lookupValue(value);
this.rewriteIdentifiers(obj[index], idMap);
}, this);
} else if (obj && typeof obj === 'object') {
Object.keys(obj).forEach(function (key) {
var value = obj[key];
obj[key] = lookupValue(value);
if (idMap[key]) {
delete obj[key];
obj[idMap[key]] = value;
}
this.rewriteIdentifiers(value, idMap);
}, this);
}
};
/**
* Given an array of objects composed by a parent, clone them, then
@@ -110,18 +143,37 @@ define(
* @returns {*}
*/
CopyTask.prototype.copyComposees = function(composees, clonedParent, originalParent){
var self = this;
var self = this,
idMap = {};
return (composees || []).reduce(function(promise, composee){
return (composees || []).reduce(function(promise, originalComposee){
//If the composee is composed of other
// objects, chain a promise..
return promise.then(function(){
// ...to recursively copy it (and its children)
return self.copy(composee, originalParent).then(function(composee){
composeChild(composee, clonedParent);
return self.copy(originalComposee, originalParent).then(function(clonedComposee){
//Map the original composee's ID to that of its
// clone so that we can replace any references to it
// in the parent
idMap[originalComposee.getId()] = clonedComposee.getId();
//Compose the child within its parent. Cloned
// objects will need to also have their location
// set, however linked objects will not.
return composeChild(clonedComposee, clonedParent, clonedComposee !== originalComposee);
});
});}, self.$q.when(undefined)
);
).then(function(){
//Replace any references in the cloned parent to
// contained objects that have been composed with the
// Ids of the clones
self.rewriteIdentifiers(clonedParent.getModel(), idMap);
//Add the clone to the list of clones that will
//be returned by this function
self.clones.push(clonedParent);
return clonedParent;
});
};
/**
@@ -131,29 +183,38 @@ define(
* cloning objects, and composing them with their child clones
* as it goes
* @private
* @param originalObject
* @param originalParent
* @returns {*}
* @returns {DomainObject} If the type of the original object allows for
* duplication, then a duplicate of the object, otherwise the object
* itself (to allow linking to non duplicatable objects).
*/
CopyTask.prototype.copy = function(originalObject, originalParent) {
CopyTask.prototype.copy = function(originalObject) {
var self = this,
modelClone = {
id: uuid(),
model: cloneObjectModel(originalObject.getModel()),
persistenceSpace: originalParent.hasCapability('persistence') && originalParent.getCapability('persistence').getSpace()
};
clone;
return this.$q.when(originalObject.useCapability('composition')).then(function(composees){
self.deferred.notify({phase: "preparing"});
//Duplicate the object's children, and their children, and
// so on down to the leaf nodes of the tree.
return self.copyComposees(composees, modelClone, originalObject).then(function (){
//Add the clone to the list of clones that will
//be returned by this function
self.clones.push(modelClone);
return modelClone;
//Check if the type of the object being copied allows for
// creation of new instances. If it does not, then a link to the
// original will be created instead.
if (this.policyService.allow("creation", originalObject.getCapability("type"))){
//create a new clone of the original object. Use the
// creation capability of the targetParent to create the
// new clone. This will ensure that the correct persistence
// space is used.
clone = this.parent.useCapability("instantiation", cloneObjectModel(originalObject.getModel()));
//Iterate through child tree
return this.$q.when(originalObject.useCapability('composition')).then(function(composees){
self.deferred.notify({phase: "preparing"});
//Duplicate the object's children, and their children, and
// so on down to the leaf nodes of the tree.
//If it is a link, don't both with children
return self.copyComposees(composees, clone, originalObject);
});
});
} else {
//Creating a link, no need to iterate children
return self.$q.when(originalObject);
}
};
/**
@@ -172,7 +233,10 @@ define(
var self = this;
return this.copy(self.domainObject, self.parent).then(function(domainObjectClone){
domainObjectClone.model.location = self.parent.getId();
if (domainObjectClone !== self.domainObject) {
domainObjectClone.getModel().location = self.parent.getId();
}
self.firstClone = domainObjectClone;
return self;
});
};

View File

@@ -34,6 +34,7 @@ define(
describe("Move/copy/link Actions", function () {
var action,
policyService,
locationService,
locationServicePromise,
composeService,
@@ -44,6 +45,11 @@ define(
newParent;
beforeEach(function () {
policyService = jasmine.createSpyObj(
'policyService',
[ 'allow' ]
);
selectedObjectContextCapability = jasmine.createSpyObj(
'selectedObjectContextCapability',
[
@@ -87,6 +93,8 @@ define(
]
);
policyService.allow.andReturn(true);
locationService
.getLocationFromUser
.andReturn(locationServicePromise);
@@ -124,6 +132,7 @@ define(
};
action = new AbstractComposeAction(
policyService,
locationService,
composeService,
context,
@@ -164,6 +173,30 @@ define(
expect(composeService.perform)
.toHaveBeenCalledWith(selectedObject, newParent);
});
describe("provides a validator which", function () {
var validator;
beforeEach(function () {
validator = locationService.getLocationFromUser
.mostRecentCall.args[2];
composeService.validate.andReturn(true);
policyService.allow.andReturn(true);
});
it("is sensitive to policy", function () {
expect(validator()).toBe(true);
policyService.allow.andReturn(false);
expect(validator()).toBe(false);
});
it("is sensitive to service-specific validation", function () {
expect(validator()).toBe(true);
composeService.validate.andReturn(false);
expect(validator()).toBe(false);
});
});
});
});
@@ -175,6 +208,7 @@ define(
};
action = new AbstractComposeAction(
policyService,
locationService,
composeService,
context,

View File

@@ -34,6 +34,7 @@ define(
describe("Copy Action", function () {
var copyAction,
policyService,
locationService,
locationServicePromise,
copyService,
@@ -50,6 +51,12 @@ define(
progress = {phase: "copying", totalObjects: 10, processed: 1};
beforeEach(function () {
policyService = jasmine.createSpyObj(
'policyService',
[ 'allow' ]
);
policyService.allow.andReturn(true);
selectedObjectContextCapability = jasmine.createSpyObj(
'selectedObjectContextCapability',
[
@@ -142,6 +149,7 @@ define(
copyAction = new CopyAction(
mockLog,
policyService,
locationService,
copyService,
dialogService,
@@ -201,6 +209,7 @@ define(
copyAction = new CopyAction(
mockLog,
policyService,
locationService,
copyService,
dialogService,

View File

@@ -34,6 +34,7 @@ define(
describe("Link Action", function () {
var linkAction,
policyService,
locationService,
locationServicePromise,
linkService,
@@ -44,6 +45,12 @@ define(
newParent;
beforeEach(function () {
policyService = jasmine.createSpyObj(
'policyService',
[ 'allow' ]
);
policyService.allow.andReturn(true);
selectedObjectContextCapability = jasmine.createSpyObj(
'selectedObjectContextCapability',
[
@@ -102,6 +109,7 @@ define(
};
linkAction = new LinkAction(
policyService,
locationService,
linkService,
context
@@ -152,6 +160,7 @@ define(
};
linkAction = new LinkAction(
policyService,
locationService,
linkService,
context

View File

@@ -34,6 +34,7 @@ define(
describe("Move Action", function () {
var moveAction,
policyService,
locationService,
locationServicePromise,
moveService,
@@ -44,6 +45,12 @@ define(
newParent;
beforeEach(function () {
policyService = jasmine.createSpyObj(
'policyService',
[ 'allow' ]
);
policyService.allow.andReturn(true);
selectedObjectContextCapability = jasmine.createSpyObj(
'selectedObjectContextCapability',
[
@@ -102,6 +109,7 @@ define(
};
moveAction = new MoveAction(
policyService,
locationService,
moveService,
context
@@ -152,6 +160,7 @@ define(
};
moveAction = new MoveAction(
policyService,
locationService,
moveService,
context

View File

@@ -0,0 +1,80 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect */
define(
[
'../../src/actions/SetPrimaryLocationAction',
'../DomainObjectFactory'
],
function (SetPrimaryLocation, domainObjectFactory) {
'use strict';
describe("The 'set primary location' action", function () {
var testContext,
testModel,
testId,
mockLocationCapability,
mockContextCapability;
beforeEach(function () {
testId = "some-id";
testModel = { name: "some name" };
mockLocationCapability = jasmine.createSpyObj(
'location',
[ 'setPrimaryLocation', 'getContextualLocation' ]
);
mockLocationCapability.getContextualLocation.andReturn(testId);
testContext = {
domainObject: domainObjectFactory({
capabilities: {
location: mockLocationCapability
},
model: testModel
})
};
});
it("is applicable to objects with no location specified", function () {
expect(SetPrimaryLocation.appliesTo(testContext))
.toBe(true);
testContext.domainObject.getModel.andReturn({
location: "something",
name: "some name"
});
expect(SetPrimaryLocation.appliesTo(testContext))
.toBe(false);
});
it("sets the location contextually when performed", function () {
new SetPrimaryLocation(testContext).perform();
expect(mockLocationCapability.setPrimaryLocation)
.toHaveBeenCalledWith(testId);
});
});
}
);

View File

@@ -0,0 +1,120 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
define(
[
'../../src/policies/CrossSpacePolicy',
'../DomainObjectFactory'
],
function (CrossSpacePolicy, domainObjectFactory) {
"use strict";
describe("CrossSpacePolicy", function () {
var mockAction,
testActionMetadata,
sameSpaceContext,
crossSpaceContext,
policy;
function makeObject(space) {
var mockPersistence = jasmine.createSpyObj(
'persistence',
['getSpace']
);
mockPersistence.getSpace.andReturn(space);
return domainObjectFactory({
id: space + ":foo",
model: {},
capabilities: { persistence: mockPersistence }
});
}
beforeEach(function () {
testActionMetadata = {};
// Policy should only call passive methods, so
// only define those in mocks.
mockAction = jasmine.createSpyObj(
'action',
[ 'getMetadata' ]
);
mockAction.getMetadata.andReturn(testActionMetadata);
sameSpaceContext = {
domainObject: makeObject('a'),
selectedObject: makeObject('a')
};
crossSpaceContext = {
domainObject: makeObject('a'),
selectedObject: makeObject('b')
};
policy = new CrossSpacePolicy();
});
['move', 'copy'].forEach(function (key) {
describe("for " + key + " actions", function () {
beforeEach(function () {
testActionMetadata.key = key;
});
it("allows same-space changes", function () {
expect(policy.allow(mockAction, sameSpaceContext))
.toBe(true);
});
it("disallows cross-space changes", function () {
expect(policy.allow(mockAction, crossSpaceContext))
.toBe(false);
});
it("allows actions with no selectedObject", function () {
expect(policy.allow(mockAction, {
domainObject: makeObject('a')
})).toBe(true);
});
});
});
describe("for other actions", function () {
beforeEach(function () {
testActionMetadata.key = "some-other-action";
});
it("allows same-space and cross-space changes", function () {
expect(policy.allow(mockAction, crossSpaceContext))
.toBe(true);
expect(policy.allow(mockAction, sameSpaceContext))
.toBe(true);
});
it("allows actions with no selectedObject", function () {
expect(policy.allow(mockAction, {
domainObject: makeObject('a')
})).toBe(true);
});
});
});
}
);

View File

@@ -63,7 +63,6 @@ define(
beforeEach(function () {
copyService = new CopyService(
null,
null,
policyService
);
@@ -130,47 +129,50 @@ define(
creationService,
createObjectPromise,
copyService,
mockPersistenceService,
mockNow,
object,
newParent,
copyResult,
copyFinished,
persistObjectPromise,
parentPersistenceCapability,
persistenceCapability,
instantiationCapability,
compositionCapability,
locationCapability,
resolvedValue;
beforeEach(function () {
creationService = jasmine.createSpyObj(
'creationService',
['createObject']
);
createObjectPromise = synchronousPromise(undefined);
creationService.createObject.andReturn(createObjectPromise);
policyService.allow.andReturn(true);
mockPersistenceService = jasmine.createSpyObj(
'persistenceService',
['createObject', 'updateObject']
);
persistObjectPromise = synchronousPromise(undefined);
mockPersistenceService.createObject.andReturn(persistObjectPromise);
mockPersistenceService.updateObject.andReturn(persistObjectPromise);
parentPersistenceCapability = jasmine.createSpyObj(
"persistence",
instantiationCapability = jasmine.createSpyObj(
"instantiation",
[ "invoke" ]
);
persistenceCapability = jasmine.createSpyObj(
"persistenceCapability",
[ "persist", "getSpace" ]
);
persistenceCapability.persist.andReturn(persistObjectPromise);
parentPersistenceCapability.persist.andReturn(persistObjectPromise);
parentPersistenceCapability.getSpace.andReturn("testSpace");
compositionCapability = jasmine.createSpyObj(
'compositionCapability',
['invoke', 'add']
);
mockNow = jasmine.createSpyObj("mockNow", ["now"]);
mockNow.now.andCallFake(function(){
return 1234;
});
locationCapability = jasmine.createSpyObj(
'locationCapability',
['isLink']
);
locationCapability.isLink.andReturn(false);
mockDeferred = jasmine.createSpyObj('mockDeferred', ['notify', 'resolve']);
mockDeferred = jasmine.createSpyObj(
'mockDeferred',
['notify', 'resolve', 'reject']
);
mockDeferred.notify.andCallFake(function(notification){});
mockDeferred.resolve.andCallFake(function(value){resolvedValue = value;});
mockDeferred.promise = {
@@ -179,7 +181,11 @@ define(
}
};
mockQ = jasmine.createSpyObj('mockQ', ['when', 'all', 'reject', 'defer']);
mockQ = jasmine.createSpyObj(
'mockQ',
['when', 'all', 'reject', 'defer']
);
mockQ.reject.andReturn(synchronousPromise(undefined));
mockQ.when.andCallFake(synchronousPromise);
mockQ.all.andCallFake(function (promises) {
var result = {};
@@ -194,6 +200,8 @@ define(
describe("on domain object without composition", function () {
beforeEach(function () {
var objectCopy;
newParent = domainObjectFactory({
name: 'newParent',
id: '456',
@@ -201,7 +209,9 @@ define(
composition: []
},
capabilities: {
persistence: parentPersistenceCapability
instantiation: instantiationCapability,
persistence: persistenceCapability,
composition: compositionCapability
}
});
@@ -210,31 +220,46 @@ define(
id: 'abc',
model: {
name: 'some object',
location: newParent.id,
persisted: mockNow.now()
location: '456',
someOtherAttribute: 'some other value',
embeddedObjectAttribute: {
name: 'Some embedded object'
}
},
capabilities: {
persistence: persistenceCapability
}
});
copyService = new CopyService(mockQ, creationService, policyService, mockPersistenceService, mockNow.now);
objectCopy = domainObjectFactory({
name: 'object',
id: 'abc.copy.fdgdfgdf',
capabilities: {
persistence: persistenceCapability,
location: locationCapability
}
});
instantiationCapability.invoke.andCallFake(
function(model){
objectCopy.model = model;
return objectCopy;
}
);
copyService = new CopyService(mockQ, policyService);
copyResult = copyService.perform(object, newParent);
copyFinished = jasmine.createSpy('copyFinished');
copyResult.then(copyFinished);
});
it("uses persistence service", function () {
expect(mockPersistenceService.createObject)
.toHaveBeenCalledWith(parentPersistenceCapability.getSpace(), jasmine.any(String), object.getModel());
expect(persistObjectPromise.then)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("uses persistence capability", function () {
expect(persistenceCapability.persist)
.toHaveBeenCalled();
});
it("deep clones object model", function () {
//var newModel = creationService
var newModel = mockPersistenceService
.createObject
.mostRecentCall
.args[2];
var newModel = copyFinished.calls[0].args[0].getModel();
expect(newModel).toEqual(object.model);
expect(newModel).not.toBe(object.model);
});
@@ -249,27 +274,57 @@ define(
describe("on domainObject with composition", function () {
var newObject,
childObject,
compositionCapability,
locationCapability,
objectClone,
childObjectClone,
compositionPromise;
beforeEach(function () {
var invocationCount = 0,
objectClones;
instantiationCapability.invoke.andCallFake(
function(model){
var cloneToReturn = objectClones[invocationCount++];
cloneToReturn.model = model;
return cloneToReturn;
}
);
locationCapability = jasmine.createSpyObj('locationCapability', ['isLink']);
locationCapability.isLink.andReturn(true);
newParent = domainObjectFactory({
name: 'newParent',
id: '456',
model: {
composition: []
},
capabilities: {
instantiation: instantiationCapability,
persistence: persistenceCapability,
composition: compositionCapability
}
});
childObject = domainObjectFactory({
name: 'childObject',
id: 'def',
model: {
name: 'a child object'
name: 'a child object',
location: 'abc'
},
capabilities: {
persistence: persistenceCapability,
location: locationCapability
}
});
compositionCapability = jasmine.createSpyObj(
'compositionCapability',
['invoke', 'add']
);
childObjectClone = domainObjectFactory({
name: 'childObject',
id: 'def.clone',
capabilities: {
persistence: persistenceCapability,
location: locationCapability
}
});
compositionPromise = jasmine.createSpyObj(
'compositionPromise',
['then']
@@ -280,7 +335,7 @@ define(
.andReturn(synchronousPromise([childObject]));
object = domainObjectFactory({
name: 'object',
name: 'some object',
id: 'abc',
model: {
name: 'some object',
@@ -288,36 +343,27 @@ define(
location: 'testLocation'
},
capabilities: {
instantiation: instantiationCapability,
composition: compositionCapability,
location: locationCapability
}
});
newObject = domainObjectFactory({
name: 'object',
id: 'abc2',
model: {
name: 'some object',
composition: []
},
capabilities: {
composition: compositionCapability
}
});
newParent = domainObjectFactory({
name: 'newParent',
id: '456',
model: {
composition: []
},
capabilities: {
composition: compositionCapability,
persistence: parentPersistenceCapability
location: locationCapability,
persistence: persistenceCapability
}
});
createObjectPromise = synchronousPromise(newObject);
creationService.createObject.andReturn(createObjectPromise);
copyService = new CopyService(mockQ, creationService, policyService, mockPersistenceService, mockNow.now);
objectClone = domainObjectFactory({
name: 'some object',
id: 'abc.clone',
capabilities: {
instantiation: instantiationCapability,
composition: compositionCapability,
location: locationCapability,
persistence: persistenceCapability
}
});
objectClones = [objectClone, childObjectClone];
copyService = new CopyService(mockQ, policyService);
});
describe("the cloning process", function(){
@@ -327,10 +373,9 @@ define(
copyResult.then(copyFinished);
});
it("copies object and children in a bottom-up" +
" fashion", function () {
expect(mockPersistenceService.createObject.calls[0].args[2].name).toEqual(childObject.model.name);
expect(mockPersistenceService.createObject.calls[1].args[2].name).toEqual(object.model.name);
it("returns a promise", function () {
expect(copyResult.then).toBeDefined();
expect(copyFinished).toHaveBeenCalled();
});
it("returns a promise", function () {
@@ -338,15 +383,27 @@ define(
expect(copyFinished).toHaveBeenCalled();
});
it("clears modified and sets persisted", function () {
expect(copyFinished.mostRecentCall.args[0].model.modified).toBeUndefined();
expect(copyFinished.mostRecentCall.args[0].model.persisted).toBe(mockNow.now());
});
it ("correctly locates cloned objects", function() {
expect(mockPersistenceService.createObject.calls[0].args[2].location).toEqual(mockPersistenceService.createObject.calls[1].args[1]);
expect(childObjectClone.getModel().location).toEqual(objectClone.getId());
});
});
describe("when cloning non-creatable objects", function() {
beforeEach(function () {
policyService.allow.andCallFake(function(category){
//Return false for 'creation' policy
return category !== 'creation';
});
copyResult = copyService.perform(object, newParent);
copyFinished = jasmine.createSpy('copyFinished');
copyResult.then(copyFinished);
});
it ("creates link instead of clone", function() {
var copiedObject = copyFinished.calls[0].args[0];
expect(copiedObject).toBe(object);
expect(compositionCapability.add).toHaveBeenCalledWith(copiedObject.getId());
//expect(newParent.getModel().composition).toContain(copiedObject.getId());
});
});
});
@@ -355,20 +412,28 @@ define(
object = domainObjectFactory({
name: 'object',
capabilities: {
type: { type: 'object' }
type: { type: 'object' },
location: locationCapability,
persistence: persistenceCapability
}
});
newParent = domainObjectFactory({
name: 'parentCandidate',
capabilities: {
type: { type: 'parentCandidate' }
type: { type: 'parentCandidate' },
instantiation: instantiationCapability,
composition: compositionCapability,
persistence: persistenceCapability
}
});
instantiationCapability.invoke.andReturn(object);
});
it("throws an error", function () {
var copyService =
new CopyService(mockQ, creationService, policyService, mockPersistenceService, mockNow.now);
new CopyService(mockQ, policyService);
function perform() {
copyService.perform(object, newParent);

View File

@@ -0,0 +1,277 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
define(
[
'../../src/services/CopyTask',
'../DomainObjectFactory'
],
function (CopyTask, domainObjectFactory) {
'use strict';
var ID_A = "some-string-with-vaguely-uuidish-uniqueness",
ID_B = "some-other-similarly-unique-string";
function synchronousPromise(value) {
return (value && value.then) ? value : {
then: function (callback) {
return synchronousPromise(callback(value));
}
};
}
describe("CopyTask", function () {
var mockDomainObject,
mockParentObject,
mockPolicyService,
mockQ,
mockDeferred,
testModel,
mockCallback,
counter,
cloneIds,
task;
function makeMockCapabilities(childIds) {
var mockCapabilities = {
persistence: jasmine.createSpyObj(
'persistence',
['persist']
),
composition: jasmine.createSpyObj(
'composition',
['add', 'invoke']
),
instantiation: jasmine.createSpyObj(
'instantiation',
['instantiate', 'invoke']
)
},
mockChildren = (childIds || []).map(function (id) {
return domainObjectFactory({
id: id,
capabilities: makeMockCapabilities([]),
model: { originalId: id }
});
});
mockCapabilities.persistence.persist
.andReturn(synchronousPromise(true));
mockCapabilities.composition.add.andCallFake(function (obj) {
return synchronousPromise(obj);
});
mockCapabilities.composition.invoke
.andReturn(synchronousPromise(mockChildren));
mockCapabilities.instantiation.invoke
.andCallFake(function (model) {
var id = "some-id-" + counter;
cloneIds[model.originalId] = id;
counter += 1;
return domainObjectFactory({
id: id,
model: model,
capabilities: makeMockCapabilities()
});
});
return mockCapabilities;
}
beforeEach(function () {
counter = 0;
cloneIds = {};
testModel = {
composition: [ ID_A, ID_B ],
someObj: {},
someArr: [ ID_A, ID_B ],
objArr: [{"id": ID_A}, {"id": ID_B}],
singleElementArr: [ ID_A ]
};
testModel.someObj[ID_A] = "some value";
testModel.someObj.someProperty = ID_B;
mockDomainObject = domainObjectFactory({
capabilities: makeMockCapabilities(testModel.composition),
model: testModel
});
mockParentObject = domainObjectFactory({
capabilities: makeMockCapabilities()
});
mockPolicyService = jasmine.createSpyObj(
'policyService',
[ 'allow' ]
);
mockQ = jasmine.createSpyObj('$q', ['when', 'defer', 'all']);
mockDeferred = jasmine.createSpyObj(
'deferred',
[ 'notify', 'resolve', 'reject' ]
);
mockPolicyService.allow.andReturn(true);
mockQ.when.andCallFake(synchronousPromise);
mockQ.defer.andReturn(mockDeferred);
mockQ.all.andCallFake(function (promises) {
return synchronousPromise(promises.map(function (promise) {
var value;
promise.then(function (v) { value = v; });
return value;
}));
});
mockDeferred.resolve.andCallFake(function (value) {
mockDeferred.promise = synchronousPromise(value);
});
});
describe("produces models which", function () {
var model;
beforeEach(function () {
task = new CopyTask(
mockDomainObject,
mockParentObject,
mockPolicyService,
mockQ
);
task.perform().then(function (clone) {
model = clone.getModel();
});
});
it("contain rewritten identifiers in arrays", function () {
expect(model.someArr)
.toEqual(testModel.someArr.map(function (id) {
return cloneIds[id];
}));
});
it("contain rewritten identifiers in properties", function () {
expect(model.someObj.someProperty)
.toEqual(cloneIds[testModel.someObj.someProperty]);
});
it("contain rewritten identifiers in property names", function () {
expect(model.someObj[cloneIds[ID_A]])
.toEqual(testModel.someObj[ID_A]);
});
it("contain rewritten identifiers in single-element arrays", function () {
expect(model.singleElementArr)
.toEqual(testModel.singleElementArr.map(function (id) {
return cloneIds[id];
}));
});
});
describe("copies object trees with multiple references to the" +
" same object", function () {
var model,
mockDomainObjectB,
mockComposingObject,
composingObjectModel,
domainObjectClone,
domainObjectBClone;
beforeEach(function () {
mockDomainObjectB = domainObjectFactory({
capabilities: makeMockCapabilities(testModel.composition),
model: testModel
});
composingObjectModel = {
name: 'mockComposingObject',
composition: [mockDomainObject.getId(), mockDomainObjectB.getId()]
};
mockComposingObject = domainObjectFactory({
capabilities: makeMockCapabilities(composingObjectModel.composition),
model: composingObjectModel
});
mockComposingObject.capabilities.composition.invoke.andReturn([mockDomainObject, mockDomainObjectB]);
task = new CopyTask(
mockComposingObject,
mockParentObject,
mockPolicyService,
mockQ
);
task.perform();
domainObjectClone = task.clones[2];
domainObjectBClone = task.clones[5];
});
/**
* mockDomainObject and mockDomainObjectB have the same
* model with references to children ID_A and ID_B. Expect
* that after duplication the references should differ
* because they are each now referencing different child
* objects. This tests the issue reported in #428
*/
it(" and correctly updates child identifiers in models ", function () {
var childA_ID = task.clones[0].getId(),
childB_ID = task.clones[1].getId(),
childC_ID = task.clones[3].getId(),
childD_ID = task.clones[4].getId();
expect(domainObjectClone.model.someArr[0]).toNotBe(domainObjectBClone.model.someArr[0]);
expect(domainObjectClone.model.someArr[0]).toBe(childA_ID);
expect(domainObjectBClone.model.someArr[0]).toBe(childC_ID);
expect(domainObjectClone.model.someArr[1]).toNotBe(domainObjectBClone.model.someArr[1]);
expect(domainObjectClone.model.someArr[1]).toBe(childB_ID);
expect(domainObjectBClone.model.someArr[1]).toBe(childD_ID);
expect(domainObjectClone.model.someObj.someProperty).toNotBe(domainObjectBClone.model.someObj.someProperty);
expect(domainObjectClone.model.someObj.someProperty).toBe(childB_ID);
expect(domainObjectBClone.model.someObj.someProperty).toBe(childD_ID);
});
/**
* This a bug found in testathon when testing issue #428
*/
it(" and correctly updates child identifiers in object" +
" arrays within models ", function () {
var childA_ID = task.clones[0].getId(),
childB_ID = task.clones[1].getId(),
childC_ID = task.clones[3].getId(),
childD_ID = task.clones[4].getId();
expect(domainObjectClone.model.objArr[0].id).not.toBe(ID_A);
expect(domainObjectClone.model.objArr[0].id).toBe(childA_ID);
expect(domainObjectClone.model.objArr[1].id).not.toBe(ID_B);
expect(domainObjectClone.model.objArr[1].id).toBe(childB_ID);
});
});
});
}
);

View File

@@ -4,7 +4,10 @@
"actions/GoToOriginalAction",
"actions/LinkAction",
"actions/MoveAction",
"actions/SetPrimaryLocationAction",
"policies/CrossSpacePolicy",
"services/CopyService",
"services/CopyTask",
"services/LinkService",
"services/MoveService",
"services/LocationService",

View File

@@ -38,7 +38,8 @@ define(
* @constructor
*/
function WorkerService($window, workers) {
var workerUrls = {};
var workerUrls = {},
sharedWorkers = {};
function addWorker(worker) {
var key = worker.key;
@@ -48,12 +49,15 @@ define(
worker.bundle.sources,
worker.scriptUrl
].join("/");
sharedWorkers[key] = worker.shared;
}
}
(workers || []).forEach(addWorker);
this.workerUrls = workerUrls;
this.sharedWorkers = sharedWorkers;
this.Worker = $window.Worker;
this.SharedWorker = $window.SharedWorker;
}
/**
@@ -61,12 +65,17 @@ define(
* that has been registered under the `workers` category
* of extension.
*
* This will return either a Worker or a SharedWorker,
* depending on whether a `shared` flag has been specified
* on the the extension definition for the referenced worker.
*
* @param {string} key symbolic identifier for the worker
* @returns {Worker} the running Worker
* @returns {Worker | SharedWorker} the running Worker
*/
WorkerService.prototype.run = function (key) {
var scriptUrl = this.workerUrls[key],
Worker = this.Worker;
Worker = this.sharedWorkers[key] ?
this.SharedWorker : this.Worker;
return scriptUrl && Worker && new Worker(scriptUrl);
};

View File

@@ -30,10 +30,14 @@ define(
var mockWindow,
testWorkers,
mockWorker,
mockSharedWorker,
service;
beforeEach(function () {
mockWindow = jasmine.createSpyObj('$window', ['Worker']);
mockWindow = jasmine.createSpyObj(
'$window',
['Worker', 'SharedWorker']
);
testWorkers = [
{
key: 'abc',
@@ -49,11 +53,19 @@ define(
key: 'xyz',
scriptUrl: 'bad.js',
bundle: { path: 'bad', sources: 'bad' }
},
{
key: 'a-shared-worker',
shared: true,
scriptUrl: 'c.js',
bundle: { path: 'a', sources: 'b' }
}
];
mockWorker = {};
mockSharedWorker = {};
mockWindow.Worker.andReturn(mockWorker);
mockWindow.SharedWorker.andReturn(mockSharedWorker);
service = new WorkerService(mockWindow, testWorkers);
});
@@ -68,6 +80,12 @@ define(
expect(mockWindow.Worker).toHaveBeenCalledWith('x/y/z.js');
});
it("allows workers to be shared", function () {
expect(service.run('a-shared-worker')).toBe(mockSharedWorker);
expect(mockWindow.SharedWorker)
.toHaveBeenCalledWith('a/b/c.js');
});
it("returns undefined for unknown workers", function () {
expect(service.run('def')).toBeUndefined();
});

View File

@@ -9,7 +9,7 @@
"glyph": "L",
"type": "layout",
"templateUrl": "templates/layout.html",
"uses": [ "composition" ],
"uses": [],
"gestures": [ "drop" ]
},
{

View File

@@ -45,43 +45,8 @@ define(
* @param {Scope} $scope the controller's Angular scope
*/
function LayoutController($scope) {
var self = this;
// Utility function to copy raw positions from configuration,
// without writing directly to configuration (to avoid triggering
// persistence from watchers during drags).
function shallowCopy(obj, keys) {
var copy = {};
keys.forEach(function (k) {
copy[k] = obj[k];
});
return copy;
}
// Compute panel positions based on the layout's object model
function lookupPanels(ids) {
var configuration = $scope.configuration || {};
// ids is read from model.composition and may be undefined;
// fall back to an array if that occurs
ids = ids || [];
// Pull panel positions from configuration
self.rawPositions =
shallowCopy(configuration.panels || {}, ids);
// Clear prior computed positions
self.positions = {};
// Update width/height that we are tracking
self.gridSize =
($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
// Compute positions and add defaults where needed
ids.forEach(function (id, index) {
self.populatePosition(id, index);
});
}
var self = this,
callbackCount = 0;
// Update grid size when it changed
function updateGridSize(layoutGrid) {
@@ -92,7 +57,7 @@ define(
// Only update panel positions if this actually changed things
if (self.gridSize[0] !== oldSize[0] ||
self.gridSize[1] !== oldSize[1]) {
lookupPanels(Object.keys(self.positions));
self.layoutPanels(Object.keys(self.positions));
}
}
@@ -120,6 +85,8 @@ define(
$scope.commit("Dropped a frame.");
}
// Populate template-facing position for this id
self.rawPositions[id] =
$scope.configuration.panels[id];
self.populatePosition(id);
// Layout may contain embedded views which will
// listen for drops, so call preventDefault() so
@@ -127,6 +94,28 @@ define(
e.preventDefault();
}
//Will fetch fully contextualized composed objects, and populate
// scope with them.
function refreshComposition() {
//Keep a track of how many composition callbacks have been made
var thisCount = ++callbackCount;
$scope.domainObject.useCapability('composition').then(function(composition){
var ids;
//Is this callback for the most recent composition
// request? If not, discard it. Prevents race condition
if (thisCount === callbackCount){
ids = composition.map(function (object) {
return object.getId();
}) || [];
$scope.composition = composition;
self.layoutPanels(ids);
}
});
}
// End drag; we don't want to put $scope into this
// because it triggers "cpws" (copy window or scope)
// errors in Angular.
@@ -156,8 +145,8 @@ define(
// Watch for changes to the grid size in the model
$scope.$watch("model.layoutGrid", updateGridSize);
// Position panes when the model field changes
$scope.$watch("model.composition", lookupPanels);
// Update composed objects on screen, and position panes
$scope.$watchCollection("model.composition", refreshComposition);
// Position panes where they are dropped
$scope.$on("mctDrop", handleDrop);
@@ -263,6 +252,43 @@ define(
}
};
// Utility function to copy raw positions from configuration,
// without writing directly to configuration (to avoid triggering
// persistence from watchers during drags).
function shallowCopy(obj, keys) {
var copy = {};
keys.forEach(function (k) {
copy[k] = obj[k];
});
return copy;
}
/**
* Compute panel positions based on the layout's object model.
* Defined as member function to facilitate testing.
* @private
*/
LayoutController.prototype.layoutPanels = function (ids) {
var configuration = this.$scope.configuration || {},
self = this;
// Pull panel positions from configuration
this.rawPositions =
shallowCopy(configuration.panels || {}, ids);
// Clear prior computed positions
this.positions = {};
// Update width/height that we are tracking
this.gridSize =
(this.$scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
// Compute positions and add defaults where needed
ids.forEach(function (id, index) {
self.populatePosition(id, index);
});
};
/**
* End the active drag gesture. This will update the
* view configuration.

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,describe,it,expect,beforeEach,jasmine*/
/*global define,describe,it,expect,beforeEach,jasmine,spyOn*/
define(
["../src/LayoutController"],
@@ -31,21 +31,44 @@ define(
mockEvent,
testModel,
testConfiguration,
controller;
controller,
mockCompositionCapability,
mockComposition,
mockCompositionObjects;
function mockPromise(value){
return {
then: function (thenFunc) {
return mockPromise(thenFunc(value));
}
};
}
function mockDomainObject(id){
return {
getId: function() {
return id;
},
useCapability: function() {
return mockCompositionCapability;
}
};
}
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
[ "$watch", "$on", "commit" ]
[ "$watch", "$watchCollection", "$on", "commit" ]
);
mockEvent = jasmine.createSpyObj(
'event',
[ 'preventDefault' ]
);
testModel = {
composition: [ "a", "b", "c" ]
};
testModel = {};
mockComposition = ["a", "b", "c"];
mockCompositionObjects = mockComposition.map(mockDomainObject);
testConfiguration = {
panels: {
@@ -56,23 +79,62 @@ define(
}
};
mockCompositionCapability = mockPromise(mockCompositionObjects);
mockScope.domainObject = mockDomainObject("mockDomainObject");
mockScope.model = testModel;
mockScope.configuration = testConfiguration;
spyOn(mockScope.domainObject, "useCapability").andCallThrough();
controller = new LayoutController(mockScope);
spyOn(controller, "layoutPanels").andCallThrough();
});
// Model changes will indicate that panel positions
// may have changed, for instance.
it("watches for changes to composition", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
expect(mockScope.$watchCollection).toHaveBeenCalledWith(
"model.composition",
jasmine.any(Function)
);
});
it("Retrieves updated composition from composition capability", function () {
mockScope.$watchCollection.mostRecentCall.args[1]();
expect(mockScope.domainObject.useCapability).toHaveBeenCalledWith(
"composition"
);
expect(controller.layoutPanels).toHaveBeenCalledWith(
mockComposition
);
});
it("Is robust to concurrent changes to composition", function () {
var secondMockComposition = ["a", "b", "c", "d"],
secondMockCompositionObjects = secondMockComposition.map(mockDomainObject),
firstCompositionCB,
secondCompositionCB;
spyOn(mockCompositionCapability, "then");
mockScope.$watchCollection.mostRecentCall.args[1]();
mockScope.$watchCollection.mostRecentCall.args[1]();
firstCompositionCB = mockCompositionCapability.then.calls[0].args[0];
secondCompositionCB = mockCompositionCapability.then.calls[1].args[0];
//Resolve promises in reverse order
secondCompositionCB(secondMockCompositionObjects);
firstCompositionCB(mockCompositionObjects);
//Expect the promise call that was initiated most recently to
// be the one used to populate scope, irrespective of order that
// it was eventually resolved
expect(mockScope.composition).toBe(secondMockCompositionObjects);
});
it("provides styles for frames, from configuration", function () {
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
mockScope.$watchCollection.mostRecentCall.args[1]();
expect(controller.getFrameStyle("a")).toEqual({
top: "320px",
left: "640px",
@@ -85,7 +147,7 @@ define(
var styleB, styleC;
// b and c do not have configured positions
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
mockScope.$watchCollection.mostRecentCall.args[1]();
styleB = controller.getFrameStyle("b");
styleC = controller.getFrameStyle("c");
@@ -102,7 +164,7 @@ define(
it("allows panels to be dragged", function () {
// Populate scope
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
mockScope.$watchCollection.mostRecentCall.args[1]();
// Verify precondtion
expect(testConfiguration.panels.b).not.toBeDefined();
@@ -121,7 +183,7 @@ define(
it("invokes commit after drag", function () {
// Populate scope
mockScope.$watch.mostRecentCall.args[1](testModel.composition);
mockScope.$watchCollection.mostRecentCall.args[1]();
// Do a drag
controller.startDrag("b", [1, 1], [0, 0]);
@@ -147,7 +209,6 @@ define(
expect(testConfiguration.panels.d).not.toBeDefined();
// Notify that a drop occurred
testModel.composition.push('d');
mockScope.$on.mostRecentCall.args[1](
mockEvent,
'd',
@@ -167,7 +228,6 @@ define(
mockEvent.defaultPrevented = true;
// Notify that a drop occurred
testModel.composition.push('d');
mockScope.$on.mostRecentCall.args[1](
mockEvent,
'd',
@@ -184,7 +244,7 @@ define(
// White-boxy; we know which watch is which
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
mockScope.$watch.calls[1].args[1](testModel.composition);
mockScope.$watchCollection.calls[0].args[1](testModel.composition);
styleB = controller.getFrameStyle("b");
@@ -201,7 +261,6 @@ define(
mockScope.$watch.calls[0].args[1](testModel.layoutGrid);
// Notify that a drop occurred
testModel.composition.push('d');
mockScope.$on.mostRecentCall.args[1](
mockEvent,
'd',
@@ -215,6 +274,23 @@ define(
expect(parseInt(style.width, 10)).toBeGreaterThan(63);
expect(parseInt(style.height, 10)).toBeGreaterThan(31);
});
it("updates positions of existing objects on a drop", function () {
var oldStyle;
mockScope.$watchCollection.mostRecentCall.args[1]();
oldStyle = controller.getFrameStyle("b");
expect(oldStyle).toBeDefined();
// ...drop event...
mockScope.$on.mostRecentCall
.args[1](mockEvent, 'b', { x: 300, y: 100 });
expect(controller.getFrameStyle("b"))
.not.toEqual(oldStyle);
});
});
}
);

View File

@@ -62,7 +62,7 @@
ng-show="representation.showControls"
ng-if="axes[1].options.length > 0">
<div class='form-control shell select'>
<select class="form-control input shell select"
<select class="form-control input shell"
ng-model="axes[1].active"
ng-options="option.name for option in axes[1].options">
</select>
@@ -160,12 +160,11 @@
{{axes[0].active.name}}
</div>
<div class="gl-plot-x-options gl-plot-local-controls"
ng-show="representation.showControls"
ng-if="axes[0].options.length > 0">
<div class='form-control shell select'>
<select class="form-control input shell select"
<select class="form-control input shell"
ng-model="axes[0].active"
ng-options="option.name for option in axes[0].options">
</select>

View File

@@ -146,6 +146,7 @@ define(
if (canvas.width !== canvas.offsetWidth ||
canvas.height !== canvas.offsetHeight) {
doDraw(scope.draw);
scope.$apply();
}
}
@@ -181,7 +182,7 @@ define(
canvas.addEventListener("webglcontextlost", fallbackFromWebGL);
// Check for resize, on a timer
activeInterval = $interval(drawIfResized, 1000);
activeInterval = $interval(drawIfResized, 1000, 0, false);
// Watch "draw" for external changes to the set of
// things to be drawn.

View File

@@ -45,8 +45,10 @@ define(
jasmine.createSpy("$interval");
mockLog =
jasmine.createSpyObj("$log", ["warn", "info", "debug"]);
mockScope =
jasmine.createSpyObj("$scope", ["$watchCollection", "$on"]);
mockScope = jasmine.createSpyObj(
"$scope",
["$watchCollection", "$on", "$apply"]
);
mockElement =
jasmine.createSpyObj("element", ["find", "html"]);
mockInterval.cancel = jasmine.createSpy("cancelInterval");
@@ -152,7 +154,9 @@ define(
// Should track canvas size in an interval
expect(mockInterval).toHaveBeenCalledWith(
jasmine.any(Function),
jasmine.any(Number)
jasmine.any(Number),
0,
false
);
// Verify pre-condition

View File

@@ -57,7 +57,7 @@
"properties": [
{
"name": "Start date/time",
"control": "datetime",
"control": "timeline-datetime",
"required": true,
"property": [ "start" ],
"options": [ "SET" ]
@@ -83,7 +83,7 @@
"properties": [
{
"name": "Start date/time",
"control": "datetime",
"control": "timeline-datetime",
"required": true,
"property": [ "start" ],
"options": [ "SET" ]
@@ -271,7 +271,7 @@
],
"controls": [
{
"key": "datetime",
"key": "timeline-datetime",
"templateUrl": "templates/controls/datetime.html"
},
{

View File

@@ -79,6 +79,9 @@ define(
// Used to choose which form control to use
key: "=",
// Allow controls to trigger blur-like events
ngBlur: "&",
// The state of the form value itself
ngModel: "=",

View File

@@ -0,0 +1,12 @@
{
"extensions": {
"components": [
{
"provides": "persistenceService",
"type": "aggregator",
"depends": [ "$q" ],
"implementation": "PersistenceAggregator.js"
}
]
}
}

View File

@@ -0,0 +1,89 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,window*/
define(
[],
function () {
'use strict';
// Return values to use when a persistence space is unknown,
// and there is no appropriate provider to route to.
var METHOD_DEFAULTS = {
createObject: false,
readObject: undefined,
listObjects: [],
updateObject: false,
deleteObject: false
};
/**
* Aggregates multiple persistence providers, such that they can be
* utilized as if they were a single object. This is achieved by
* routing persistence calls to an appropriate provider; the space
* specified at call time is matched with the first provider (per
* priority order) which reports that it provides persistence for
* this space.
*
* @memberof platform/persistence/aggregator
* @constructor
* @implements {PersistenceService}
* @param $q Angular's $q, for promises
* @param {PersistenceService[]} providers the providers to aggregate
*/
function PersistenceAggregator($q, providers) {
var providerMap = {};
function addToMap(provider) {
return provider.listSpaces().then(function (spaces) {
spaces.forEach(function (space) {
providerMap[space] = providerMap[space] || provider;
});
});
}
this.providerMapPromise = $q.all(providers.map(addToMap))
.then(function () { return providerMap; });
}
PersistenceAggregator.prototype.listSpaces = function () {
return this.providerMapPromise.then(function (map) {
return Object.keys(map);
});
};
Object.keys(METHOD_DEFAULTS).forEach(function (method) {
PersistenceAggregator.prototype[method] = function (space) {
var delegateArgs = Array.prototype.slice.apply(arguments, []);
return this.providerMapPromise.then(function (map) {
var provider = map[space];
return provider ?
provider[method].apply(provider, delegateArgs) :
METHOD_DEFAULTS[method];
});
};
});
return PersistenceAggregator;
}
);

View File

@@ -0,0 +1,103 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
define(
['../src/PersistenceAggregator'],
function (PersistenceAggregator) {
'use strict';
var PERSISTENCE_SERVICE_METHODS = [
'listSpaces',
'listObjects',
'createObject',
'readObject',
'updateObject',
'deleteObject'
],
WRAPPED_METHODS = PERSISTENCE_SERVICE_METHODS.filter(function (m) {
return m !== 'listSpaces';
});
function fakePromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return fakePromise(callback(value));
}
};
}
describe("PersistenceAggregator", function () {
var mockQ,
mockProviders,
mockCallback,
testSpaces,
aggregator;
beforeEach(function () {
testSpaces = ['a', 'b', 'c'];
mockQ = jasmine.createSpyObj("$q", ['all']);
mockProviders = testSpaces.map(function (space) {
var mockProvider = jasmine.createSpyObj(
'provider-' + space,
PERSISTENCE_SERVICE_METHODS
);
PERSISTENCE_SERVICE_METHODS.forEach(function (m) {
mockProvider[m].andReturn(fakePromise(true));
});
mockProvider.listSpaces.andReturn(fakePromise([space]));
return mockProvider;
});
mockCallback = jasmine.createSpy();
mockQ.all.andCallFake(function (fakePromises) {
var result = [];
fakePromises.forEach(function (p) {
p.then(function (v) { result.push(v); });
});
return fakePromise(result);
});
aggregator = new PersistenceAggregator(mockQ, mockProviders);
});
it("exposes spaces for all providers", function () {
aggregator.listSpaces().then(mockCallback);
expect(mockCallback).toHaveBeenCalledWith(testSpaces);
});
WRAPPED_METHODS.forEach(function (m) {
it("redirects " + m + " calls to an appropriate provider", function () {
testSpaces.forEach(function (space, index) {
var key = 'key-' + space,
value = 'val-' + space;
expect(aggregator[m](space, key, value))
.toEqual(mockProviders[index][m]());
expect(mockProviders[index][m])
.toHaveBeenCalledWith(space, key, value);
});
});
});
});
}
);

View File

@@ -0,0 +1,3 @@
[
"PersistenceAggregator"
]

View File

@@ -80,7 +80,7 @@ define(
// Update the indicator initially, and start polling.
updateIndicator();
$interval(updateIndicator, interval, false);
$interval(updateIndicator, interval, 0, false);
}
ElasticIndicator.prototype.getGlyph = function () {

View File

@@ -55,6 +55,7 @@ define(
expect(mockInterval).toHaveBeenCalledWith(
jasmine.any(Function),
testInterval,
0,
false
);
});

View File

@@ -68,6 +68,20 @@
"agentService"
]
}
],
"runs": [
{
"priority": "mandatory",
"implementation": "TemplatePrefetcher.js",
"depends": [
"templateLinker",
"templates[]",
"views[]",
"representations[]",
"controls[]",
"containers[]"
]
}
]
}
}

View File

@@ -96,7 +96,7 @@ define(
toClear = [], // Properties to clear out of scope on change
counter = 0,
couldRepresent = false,
lastId,
lastIdPath = [],
lastKey,
changeTemplate = templateLinker.link($scope, element);
@@ -143,11 +143,27 @@ define(
});
}
function unchanged(canRepresent, id, key) {
function unchanged(canRepresent, idPath, key) {
return canRepresent &&
couldRepresent &&
id === lastId &&
key === lastKey;
key === lastKey &&
idPath.length === lastIdPath.length &&
idPath.every(function (id, i) {
return id === lastIdPath[i];
});
}
function getIdPath(domainObject) {
if (!domainObject) {
return [];
}
if (!domainObject.hasCapability('context')) {
return [domainObject.getId()];
}
return domainObject.getCapability('context')
.getPath().map(function (pathObject) {
return pathObject.getId();
});
}
// General-purpose refresh mechanism; should set up the scope
@@ -159,10 +175,10 @@ define(
path = representation && getPath(representation),
uses = ((representation || {}).uses || []),
canRepresent = !!(path && domainObject),
id = domainObject && domainObject.getId(),
idPath = getIdPath(domainObject),
key = $scope.key;
if (unchanged(canRepresent, id, key)) {
if (unchanged(canRepresent, idPath, key)) {
return;
}
@@ -190,7 +206,7 @@ define(
// To allow simplified change detection next time around
couldRepresent = canRepresent;
lastId = id;
lastIdPath = idPath;
lastKey = key;
// Populate scope with fields associated with the current

View File

@@ -54,7 +54,6 @@ define(
* @param {string} the URL for the template
* @returns {Promise.<string>} a promise for the HTML content of
* the template
* @private
*/
TemplateLinker.prototype.load = function (templateUrl) {
return this.$templateRequest(

View File

@@ -0,0 +1,51 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
define(
function () {
'use strict';
/**
* Loads all templates when the application is started.
* @param {platform/representation.TemplateLinker} templateLinker
* the `templateLinker` service, used to load and cache
* template extensions
* @param {...Array.<{templateUrl: string}>} extensions arrays
* of template or template-like extensions
*/
function TemplatePrefetcher(templateLinker, extensions) {
Array.prototype.slice.apply(arguments, [1])
.reduce(function (a, b) {
return a.concat(b);
}, [])
.map(function (ext) {
return templateLinker.getPath(ext);
})
.forEach(function (path) {
templateLinker.load(path);
});
}
return TemplatePrefetcher;
}
);

View File

@@ -247,6 +247,54 @@ define(
mockScope.$watch.calls[0].args[1]();
expect(mockScope.testCapability).toBeUndefined();
});
it("detects changes among linked instances", function () {
var mockContext = jasmine.createSpyObj('context', ['getPath']),
mockContext2 = jasmine.createSpyObj('context', ['getPath']),
mockLink = jasmine.createSpyObj(
'linkedObject',
DOMAIN_OBJECT_METHODS
),
mockParent = jasmine.createSpyObj(
'parentObject',
DOMAIN_OBJECT_METHODS
),
callCount;
mockDomainObject.getCapability.andCallFake(function (c) {
return c === 'context' && mockContext;
});
mockLink.getCapability.andCallFake(function (c) {
return c === 'context' && mockContext2;
});
mockDomainObject.hasCapability.andCallFake(function (c) {
return c === 'context';
});
mockLink.hasCapability.andCallFake(function (c) {
return c === 'context';
});
mockLink.getModel.andReturn({});
mockContext.getPath.andReturn([mockDomainObject]);
mockContext2.getPath.andReturn([mockParent, mockLink]);
mockLink.getId.andReturn('test-id');
mockDomainObject.getId.andReturn('test-id');
mockParent.getId.andReturn('parent-id');
mockScope.key = "abc";
mockScope.domainObject = mockDomainObject;
mockScope.$watch.calls[0].args[1]();
callCount = mockChangeTemplate.calls.length;
mockScope.domainObject = mockLink;
mockScope.$watch.calls[0].args[1]();
expect(mockChangeTemplate.calls.length)
.toEqual(callCount + 1);
});
});
}
);

View File

@@ -0,0 +1,76 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/TemplatePrefetcher"],
function (TemplatePrefetcher) {
'use strict';
describe("TemplatePrefetcher", function () {
var mockTemplateLinker,
testExtensions,
testPathPrefix,
prefetcher;
beforeEach(function () {
testPathPrefix = "some/path/";
mockTemplateLinker = jasmine.createSpyObj(
'templateLinker',
[ 'getPath', 'load' ]
);
mockTemplateLinker.getPath.andCallFake(function (ext) {
return testPathPrefix + ext.templateUrl;
});
testExtensions = ['a', 'b', 'c'].map(function (category) {
return ['x', 'y', 'z'].map(function (ext) {
return {
templateUrl: category + '/' + ext + '.html'
};
});
});
prefetcher = new TemplatePrefetcher(
mockTemplateLinker,
testExtensions[0],
testExtensions[1],
testExtensions[2]
);
});
it("loads all templates when run", function () {
testExtensions.forEach(function (category) {
category.forEach(function (extension) {
expect(mockTemplateLinker.load).toHaveBeenCalledWith(
mockTemplateLinker.getPath(extension)
);
});
});
});
});
}
);

View File

@@ -8,5 +8,6 @@
"services/DndService",
"MCTInclude",
"MCTRepresentation",
"TemplateLinker"
"TemplateLinker",
"TemplatePrefetcher"
]

View File

@@ -0,0 +1,2 @@
Facilitates tracking states associated with specific domain
objects.

View File

@@ -0,0 +1,23 @@
{
"extensions": {
"representers": [
{
"implementation": "StatusRepresenter.js"
}
],
"capabilities": [
{
"key": "status",
"implementation": "StatusCapability.js",
"depends": [ "statusService" ]
}
],
"services": [
{
"key": "statusService",
"implementation": "StatusService.js",
"depends": [ "topic" ]
}
]
}
}

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