Compare commits

...

230 Commits

Author SHA1 Message Date
Victor Woeltjen
d385e55e76 [Build] Remove snapshot suffix
Closes sprint Heinlein,
https://github.com/nasa/openmct/milestones/Heinlein
2016-04-22 10:46:07 -07:00
Victor Woeltjen
abb511521b Merge pull request #837 from nasa/open794_fix
[Edit Mode] #794 Modified policy to show remove action in context for non-editable domain object types
2016-04-21 12:23:45 -07:00
Victor Woeltjen
3a9b1ee901 Merge pull request #839 from nasa/revert-822-open769
Revert "[Tables] Fix to correct sorting in realtime tables"
2016-04-21 09:21:12 -07:00
Andrew Henry
8b390e7fb9 Revert "[Tables] Fix to correct sorting in realtime tables" 2016-04-20 19:31:54 -07:00
Andrew Henry
29bce69eea Merge pull request #822 from nasa/open769
[Tables] Fix to correct sorting in realtime tables
2016-04-20 19:30:04 -07:00
Henry
aac5a6d250 #769 - Removed empty code block and addressed some excessive guard code 2016-04-20 19:18:27 -07:00
Henry
06436c488a [Edit Mode] #794 Modified policy to show remove action in context for non-editable domain object types 2016-04-18 19:05:46 -07:00
Victor Woeltjen
8b7af43d6c Merge pull request #823 from nasa/version-process-725
[Documentation] Add Version Guide
2016-04-14 17:30:55 -07:00
Victor Woeltjen
abb47eed36 [Documentation] Remove superfluous space
ddc241c0d0 (r59808305)
2016-04-14 16:30:17 -07:00
Andrew Henry
027d86ef4b Merge pull request #828 from nasa/build-win-827
[Build] Fix build on Windows
2016-04-14 16:23:42 -07:00
Andrew Henry
6cb9619fbe Merge pull request #829 from nasa/open630
[Edit mode] Simplify SaveAction
2016-04-14 16:11:49 -07:00
Henry
8c3616da32 Addressed code review points 2016-04-14 16:04:15 -07:00
Victor Woeltjen
ffd5faf9a2 [Persistence] Remove obsolete caching decorator
#831
2016-04-14 10:15:40 -07:00
Victor Woeltjen
00bf05c929 Merge pull request #830 from nasa/time-conductor-ux
Time Conductor updates query on blur, mobile support
2016-04-14 10:04:17 -07:00
Pete Richards
b682cf8340 [Style] Remove outdated comments 2016-04-13 17:41:24 -07:00
Pete Richards
22a5122ab7 [Conductor] Style for Phone and Tablet
Specify styles for time conductor on phone an tablet to hide the slider and
utilize space better.

https://github.com/nasa/openmct/issues/318
2016-04-13 17:17:52 -07:00
Pete Richards
7a7877d7c4 [Conductor] Add basic style for phone
Add styling for time conductor on mobile that removes slider and rearranges
inputs to utilize space more effectively.

https://github.com/nasa/openmct/issues/318
2016-04-13 16:17:17 -07:00
Pete Richards
69c059c943 [Conductor] Update inner bound on blur
The time conductor updates the inner and outer bounds when the input is
blurred, which results in the query updating without dragging.

Also allows time conductor to be utilized on mobile devices by entering
dates directly.

https://github.com/nasa/openmct/issues/318

User request:
https://github.jpl.nasa.gov/MissionControl/vista/issues/175
2016-04-13 13:49:23 -07:00
Pete Richards
6d58f23c0c [Style] Switch to prototype
Switch TimeRangeController to prototype style, and update tests
and template to utilize new style.
2016-04-13 13:23:33 -07:00
Henry
26e368f52d [Edit mode] Simplify SaveAction 2016-04-12 14:40:19 -07:00
Victor Woeltjen
1d78af8f1d [Build] Fix build on Windows
* In the prepublish step, run bower and gulp via node, instead of
  relying on shebang interpretation. (Forward-slash path separators
  appear to get normalized by node itself before executing the scripts.)
* In the gulp build, replace hard-coded *nix-style separators with
  path.sep; this allows stylesheets to be output to expected locations
  when building on Windows.

Addresses #827.
2016-04-12 13:02:48 -07:00
Victor Woeltjen
d48871f204 Merge pull request #783 from nasa/open635
[Edit Mode] #635 Removed Edit-related concerns from ContextMenuGesture
2016-04-12 09:40:14 -07:00
Henry
519a9333ab Updated tests 2016-04-11 17:10:35 -07:00
Henry
2fe7ba982f Added 'Open in New Tab' to context menu in edit mode 2016-04-11 17:06:37 -07:00
Henry
7f108c3b24 [Edit Mode] #635 Removed Edit-related concerns from ContextMenuGesture 2016-04-11 15:39:35 -07:00
Henry
6322964dec Addressed comments from code review of #822 2016-04-11 14:30:21 -07:00
Henry
1bb6e17829 Minor code change to improve clarity 2016-04-11 13:37:31 -07:00
Henry
f34e8ba61b Modified code to call resize on every row add. Removed optimization to only resize when needed, because in fact resuze is necessary on every update in order to set vertical scroll size 2016-04-11 13:09:02 -07:00
Henry
2fb9b65652 Made comment a little more accurate 2016-04-11 12:57:27 -07:00
Henry
0c6b4a5a23 [Tables] Fix to correct sorting in realtime tables 2016-04-11 12:57:27 -07:00
Henry
20672ad028 [Tables] #801 Documented MctTable directive 2016-04-11 12:55:56 -07:00
Henry
99ba9edb95 Merged
Resolved merge conflicts

Resolved merge conflicts
2016-04-11 12:55:53 -07:00
Henry
23a8c305c1 [Table] #798 Simplified markup, moved styles to external stylesheet 2016-04-11 12:23:36 -07:00
Pete Richards
c591ade479 Merge remote-tracking branch 'origin/781' 2016-04-06 10:35:40 -07:00
Victor Woeltjen
8f4f0cb78e Merge pull request #785 from nasa/open677_cleanup
[Timelines] #677 Removed temporary markup
2016-04-05 12:24:58 -07:00
Victor Woeltjen
e87280aa15 Merge pull request #821 from nasa/show-selected-color
[Control] Color input shows selected color
2016-04-05 12:20:14 -07:00
Pete Richards
e0a2d02d23 [Control] Color input shows selected color
Update color input to show selected color when expanded.
2016-04-05 11:57:45 -07:00
Victor Woeltjen
ddc241c0d0 [Documentation] Add Version Guide
Migrate relevant information from existing version guide;
add instructions for incrementing versions per #725
2016-04-05 11:55:15 -07:00
Victor Woeltjen
73012233b8 [Build] Bump version number
...to begin sprint Heinlein,
https://github.com/nasa/openmct/milestones/Heinlein
2016-04-04 09:33:58 -07:00
Victor Woeltjen
339916ccd4 [Build] Remove SNAPSHOT status
...to tag end of release Gibson,
https://github.com/nasa/openmct/milestones/Gibson
2016-04-04 09:32:21 -07:00
Victor Woeltjen
70acef6905 [Instantiation] Ensure new models have modified timestamp
...to avoid https://github.com/nasa/openmct/issues/745#issuecomment-204561163
2016-04-01 14:27:26 -07:00
Victor Woeltjen
da09ffd3fa [Persistence] Don't evict models on persist
https://github.com/nasa/openmct/issues/745#issuecomment-204559209
2016-04-01 13:38:13 -07:00
Pete Richards
5b98da6681 Merge pull request #807 from nasa/timeline-model-717
[Timeline] Add default values to model
2016-04-01 10:10:15 -07:00
Andrew Henry
2040abb768 Merge pull request #808 from nasa/revert-open-793
Revert "Merge remote-tracking branch 'origin/open793'"
2016-03-31 16:37:18 -07:00
Pete Richards
d35fccbbe8 Revert "Merge remote-tracking branch 'origin/open793'"
This reverts commit f49552779a, reversing
changes made to e068173f3e.
2016-03-31 16:30:35 -07:00
Victor Woeltjen
06c6832676 [Timeline] Add default values to model
Add default values to model, such that editing which occurs
before user supplies these properties does not cause errors
to occur. Directly addresses #717, indirectly addresses
remaining errant behavior associated with #790.
2016-03-31 15:46:56 -07:00
Pete Richards
f49552779a Merge remote-tracking branch 'origin/open793' 2016-03-31 14:14:08 -07:00
Henry
200a426f17 [Tables] Addressed style concerns from code review 2016-03-31 12:56:29 -07:00
Pete Richards
e068173f3e Merge remote-tracking branch 'origin/move-copy-policy-792' 2016-03-31 12:49:06 -07:00
Victor Woeltjen
4441e88769 Merge pull request #803 from nasa/drag-drop-688
[Firefox] Invoke preventDefault on drop
2016-03-31 11:02:26 -07:00
Victor Woeltjen
254a944d7a [Firefox] Invoke preventDefault on drop
...such that Firefox does not try to treat drop as a new URL
to navigate to. Addresses #688 and #527
2016-03-31 10:34:24 -07:00
Henry
0c00061cbc Added mutation listener 2016-03-31 10:26:34 -07:00
Andrew Henry
dee0613b81 Merge pull request #800 from nasa/timeline-reorder-789
[Timeline] Fix reordering behavior in timelines
2016-03-31 09:39:17 -07:00
Andrew Henry
6b6bada700 Merge pull request #788 from nasa/open445b
Review and integrate open445b
2016-03-31 09:36:03 -07:00
Victor Woeltjen
530b940a64 [Timeline] Fix reordering
Fix reordering behavior when dragging-and-dropping within timelines;
addresses #789.
2016-03-29 19:46:30 -07:00
Victor Woeltjen
e23bf5ed39 [Entanglement] Test CopyPolicy 2016-03-29 19:26:18 -07:00
Victor Woeltjen
6ecea9950d [Entanglement] Test MovePolicy 2016-03-29 19:22:22 -07:00
Victor Woeltjen
4816dddf41 [Entanglement] Wire in copy/move policies
#792
2016-03-29 13:14:08 -07:00
Victor Woeltjen
cae775f9bc [Entanglement] Add policies for Copy and Move
...to ensure that these are only performed on creatable and
mutable targets, respectively.
2016-03-29 13:10:35 -07:00
Henry
a4b79cdb5b [Tables] #793 Added fix for tables not appearing on refresh
Fixed failing tests
2016-03-28 17:48:01 -07:00
Henry
012a38cccd [Tables] Fix for table columns not being populated 2016-03-28 17:31:10 -07:00
Charles Hacskaylo
a01f7ddd2d [Frontend] Refinements to .loading and related
#445
Markup enhanced in wait-node.html;
More wait-spinner constants added;
Normalized appearance between tree-based
.loading and .s-status-pending;
Fixed .s-status-pending to work now that
mct-representation is gone from tree;
2016-03-24 15:10:22 -07:00
Charles Hacskaylo
e7e91e21fc [Frontend] Markup and CSS for loading tree items
#445
New wait-spinner constants;
Markup fixed in wait-node.html;
Styles for .loading when applied to
.tree-item.wait-node;
Changed from percent-of-parent-
width sizing of spinner to fixed size;
2016-03-24 15:10:02 -07:00
Pete Richards
cbea842c8b Merge branch 'timeline-highlight-767' 2016-03-24 13:33:56 -07:00
Pete Richards
cc5d14deec Merge branch '755a' 2016-03-24 13:21:59 -07:00
Pete Richards
4c5217d646 [Style] Standardize indentation 2016-03-24 13:20:49 -07:00
Pete Richards
5e54b193ca [Style] remove unnecessary parenthesis
See comment https://github.com/nasa/openmct/pull/782/files#r57380540
2016-03-24 13:14:53 -07:00
Pete Richards
cd7ff8ad85 Merge remote-tracking branch 'origin/timestamps-776' 2016-03-24 13:09:32 -07:00
Pete Richards
fa5d59bff8 Merge branch 'timeline-save-770b' 2016-03-24 13:06:53 -07:00
Pete Richards
ddbb72b88a [CacheService] Don't track ids twice
Track whether an object is in the cache based on whether it is
in the cache instead of utilizing a separate object for tracking
contents of cache.

See comment on https://github.com/nasa/openmct/pull/773/files
2016-03-24 12:57:53 -07:00
Charles Hacskaylo
88784d37fd [Frontend] Added priority
#787
2016-03-24 12:05:10 -07:00
Andrew Henry
700e605bbd Merge pull request #775 from nasa/timeline-drag-drop-679
[Timeline] Move (instead of link) when dragging and dropping within a timeline
2016-03-23 20:00:48 -07:00
Charles Hacskaylo
594f3b8ec2 [Frontend] Corrected wrong unicode value
#781
2016-03-23 19:30:20 -07:00
Charles Hacskaylo
b08d00ef3e [Frontend] Removed tab character
#781
2016-03-23 19:25:25 -07:00
Charles Hacskaylo
0643fb1f3f [Frontend] Updated icomoon project file
#781
2016-03-23 19:17:39 -07:00
Charles Hacskaylo
289debf19d [Frontend] Fixed hover problem with menu items
#781
#187
Noticed a problem with <a> tags in
Create menu items and fixed with display: block;
2016-03-23 19:10:59 -07:00
Charles Hacskaylo
7da1a4b2a3 [Frontend] Updated glyph defs and descriptions
#781
#187
Converted many glyph char defs to
their JSON unicode equivalents;
Updated descriptions for many domain
objects;
2016-03-23 19:04:32 -07:00
Charles Hacskaylo
528169de2c [Frontend] Updated glyphs
#781
Added multiple new and updated glyphs;
Updated glyph defs for Historic and
Real-Time Tables;
2016-03-23 17:42:58 -07:00
Victor Woeltjen
c13231b8e8 [Timeline] Remove NULL_ACTION, clarify logic
Per code review feedback,
https://github.com/nasa/openmct/pull/775/files#r57229759
2016-03-23 15:34:05 -07:00
Andrew Henry
3e4a3aeb9b Merge pull request #779 from nasa/precision-778b
[Data Formats] Format numeric values with full precision
2016-03-23 12:15:26 -07:00
Henry
650ef9bfa4 [Timelines] #677 Removed temporary markup 2016-03-23 11:27:40 -07:00
Victor Woeltjen
dd053f7e6e [Timeline] Invoke $apply from mct-swimlane-drop
...and add some checks to ensure this is necessary, to avoid
triggering a ton of digest cycles while dragging.
2016-03-22 17:16:41 -07:00
Victor Woeltjen
cb655d486b [Timeline] Test reordering within parent 2016-03-22 17:06:58 -07:00
Victor Woeltjen
3c52ceb71a [Timeline] Remove unused function
Removal of domain objects is handled by using the move action.
2016-03-22 17:01:45 -07:00
Victor Woeltjen
b2337dea97 [Timeline] Update failing specs
...and remove obsolete test case for handling drops in a timeline
2016-03-22 16:59:09 -07:00
Victor Woeltjen
dea6554e04 [Timeline] Allow drops from tree
Don't assume that all drops will be dropped swimlanes.
2016-03-22 12:26:01 -07:00
Victor Woeltjen
31d8c9a48f [Timeline] Allow linking during edit
...in cases where it is safe to do so (specifically, when the
linked-to object has already been persisted.)
2016-03-22 12:04:50 -07:00
Victor Woeltjen
f8682a7a29 Merge pull request #780 from nasa/open715
[Timelines] #715 Added a check to prevent mutation when modes are unchanged
2016-03-22 09:24:57 -07:00
Henry
e5544615cc [Timelines] #715 Added a check to prevent mutation when modes are unchanged 2016-03-21 17:01:38 -07:00
Victor Woeltjen
ec0cc572f6 [Add] Test model cache 2016-03-21 16:11:40 -07:00
Victor Woeltjen
6c2a28aba2 [Add] Add JSDoc to model cache 2016-03-21 16:05:05 -07:00
Victor Woeltjen
baccd005dc [Add] Update persistence capability spec
...to reflect removal of cached domain object models.
2016-03-21 15:08:27 -07:00
Victor Woeltjen
1e4ff5a73f [Add] Use cacheService from decorator spec 2016-03-21 15:05:28 -07:00
Victor Woeltjen
9f29382e18 [Add] Update spec for Instantiate
...to reflect usage of a model cache for #770
2016-03-21 15:04:07 -07:00
Victor Woeltjen
5f6b4adcda [Plot] Normalize number of digits
Use consistent number of digits for displayed plot values, to avoid
unreadable plot legends due to fix for #778
2016-03-21 14:45:00 -07:00
Victor Woeltjen
d6ab70447e [Data Format] Don't truncate data values 2016-03-21 14:35:58 -07:00
Victor Woeltjen
a411bac331 [Time Format] Append Z instead of zone offset
...for brevity (reduce visual noise)
2016-03-21 14:29:24 -07:00
Victor Woeltjen
5624c7d545 [Time Formats] Display UTC with milliseconds
#776
2016-03-21 13:04:59 -07:00
Victor Woeltjen
007741b4e7 [Timeline] Add move policy
...to restore suppression of Move for objects being edited
(relaxed for the specific case of moving one object being
edited into another object being edited, for use in Timelines.)
2016-03-21 12:07:19 -07:00
Victor Woeltjen
e0a69744e5 [Timeline] Deinline null action
...used for cases when no action is needed for timeline move
(and ids will just be reordered.)
2016-03-21 11:53:10 -07:00
Victor Woeltjen
e7a6c34bcc [Timeline] Handle drops for reordering
...as these would be disallowed by Move, normally.
2016-03-21 11:51:51 -07:00
Victor Woeltjen
7f3ac4077c [Timeline] Drop to correct targets 2016-03-21 11:43:02 -07:00
Victor Woeltjen
7eaffdc34a [Timeline] Don't suppress move during editing
...to allow this action to be used to support Timeline
drag-and-drop.
2016-03-21 11:42:33 -07:00
Victor Woeltjen
5034e88656 [Timeline] Use move action on drag-drop
...to avoid creating links when desired behavior is a move,
#679.
2016-03-21 11:18:18 -07:00
Charles Hacskaylo
aa48044345 [Frontend] Form styling
#772
Added ".l-controls-under" styling to allow
channel-selector layout;
Added new hint color constants and refined
style defs;
2016-03-21 11:13:43 -07:00
Victor Woeltjen
d12111d9b8 [Add] Fix promise chaining in AddAction 2016-03-21 10:32:02 -07:00
Victor Woeltjen
9c9db3c24f [Add] Remove obsolete variable reference
The cache has been externalized to allow writing to it
upon domain object instantiation.
2016-03-21 10:31:38 -07:00
Victor Woeltjen
3fe41575bd [Add] Add missing dependency
...to support caching of domain objects created during edit mode.
2016-03-21 10:31:09 -07:00
Victor Woeltjen
8fa030437e [Add] Remove edit awareness
Remove step where Added objects are persisted via the editor
capability; instead, persist via the usual persistence capability,
such that Edit mode may intervene (or not) as necessary.
As instantiated models are cached at least until persisted,
this workaround to allow newly-created models to be available
during editing is no longer necessary (and undesired consequences
such as #770 no longer occur)
2016-03-21 10:22:25 -07:00
Victor Woeltjen
17faf000b0 [Add] Cache models on instantiation
...to remove need for Edit to persist these immediately, which in
turn causes #770 and #678
2016-03-21 10:20:14 -07:00
Charles Hacskaylo
90c82f6ef2 [Frontend] Timeline tooltip and field input tweaks
#750
Refined tooltip for Resource Graphing;
Increased size of Activity Link input field;
2016-03-21 10:08:59 -07:00
Charles Hacskaylo
5e6fe16b93 [Frontend] Adding tooltips
#750
2016-03-17 16:21:04 -07:00
Charles Hacskaylo
f0ca6fdfdb [Frontend] Added tooltips
#750
Added tooltips to Timeline header elements;
2016-03-17 15:10:42 -07:00
Andrew Henry
ad4c456ca2 Merge pull request #763 from nasa/restrict-requirejs-version
[Package] Specify require minor version
2016-03-17 14:38:02 -07:00
Pete Richards
b0476edb8c [Package] Specify require minor version
Specify requirejs minor version of 2.1, as 2.2 is not compatible
with karma-requirejs.

Fixes build problems that appeared after latest requirejs version bump.
2016-03-17 14:28:22 -07:00
Pete Richards
8f6a287fb8 Merge remote-tracking branch 'origin/tree-refresh-745' 2016-03-17 11:40:53 -07:00
Victor Woeltjen
07d554d114 Merge pull request #759 from nasa/700a
Review and integrate 700a
2016-03-17 11:02:22 -07:00
Andrew Henry
24d2cecdcd Merge pull request #761 from nasa/open757
[Tables] #757 Added max row limit to streaming tables
2016-03-17 10:19:04 -07:00
Henry
8efa9c6aac [Tables] #757 Fixed code style issues 2016-03-17 10:09:59 -07:00
Henry
22e98274ca [Tables] #757 Added max row limit to streaming tables 2016-03-16 18:59:52 -07:00
Charles Hacskaylo
471b57f47c [Frontend] CSS tweaks
#750
Moved l-plot-resource cursor: pointer
to a more specific selector;
Added user-select: none to l-header;
Fixed s-status-editing styling so
that tabular labels only appear draggable
while editing;
2016-03-16 18:19:44 -07:00
Charles Hacskaylo
9c775c6715 [Frontend] Changed cursor property
#755
Changed s-timeline-gantt.mid to
use cursor: move instead of
ew-resize; Need to verify on Linux;
2016-03-16 17:36:07 -07:00
Charles Hacskaylo
1f09b7b0ac [Frontend] Fix for scrollbar flicker
#748
Was able to observe problem in Mac
Chrome. Moved body, html overflow: hidden
into startup-base.scss and change seems
to have fixed the problem;
2016-03-16 17:34:28 -07:00
Andrew Henry
b0cf9bbd29 Merge pull request #758 from nasa/error-message-753
[Tree] Don't assume context capability is present
2016-03-16 15:33:59 -07:00
Andrew Henry
4a1ca25e17 Merge pull request #754 from nasa/tree-status-styling-749
[Tree] Add status classes during editing
2016-03-16 15:26:40 -07:00
Charles Hacskaylo
cc97e567b6 [Frontend] Further style cleanups
#689
#740
Tweaked scrollbar thumb color;
Fixed color of icons in s-menu-btn
menus, particularly for Snow theme;
Removed commented code;
2016-03-16 15:17:08 -07:00
Charles Hacskaylo
53f03cddb7 [Frontend] Further cleanups to form elements
#689
Removed commented code;
2016-03-16 14:49:37 -07:00
Charles Hacskaylo
da1e6750a0 [Frontend] Removed reset.css and refs to modernizr
#700
Removed reset.css; Removed refs to
modernizr from licenses and readme.md;
2016-03-16 14:44:01 -07:00
Charles Hacskaylo
3258342783 [Frontend] Further cleanups to form elements
#700
#689
#740
Removed _selects.scss and moved classes
into _controls.scss;
Reorg'd _controls;
Moved classes into _elems.scss;
Added and fixed cssclass defs in multiple
bundle.js files to allow better field widths
in overlay dialogs;
Fixed overlay custom scrollbar colors;
Fixed alignment of required glyphs in forms;
2016-03-16 14:40:06 -07:00
Victor Woeltjen
73b7365ae2 [Tree] Don't assume context capability is present
Addresses #753 (newly-created objects may not have context,
causing errors when these are encountered by TreeNodeView)
2016-03-16 14:10:58 -07:00
Charles Hacskaylo
32a42bd679 [Frontend] CSS tweaks to fix required glyph positioning
#700
CSS modded to allow better cross-browser
positioning of 'required' form-row glyphs;
Other elem's CSS adjusted as a result;
2016-03-16 09:43:59 -07:00
Victor Woeltjen
324c2cac03 [Tree] Refresh properly on mutation
...by removing the incorrect expectation that a domain object
(and not just its model) will be passed in when mutation occurs.
Addresses #745.
2016-03-15 12:23:46 -07:00
Victor Woeltjen
42ac657105 [Tree] Add status classes during editing
Addresses #749
2016-03-15 12:16:58 -07:00
Pete Richards
d30532a8bc Merge remote-tracking branch 'origin/open742' 2016-03-14 16:37:58 -07:00
Pete Richards
936079da92 Merge remote-tracking branch 'origin/tree-732' 2016-03-14 16:15:05 -07:00
Andrew Henry
4e89ffbe07 Merge pull request #735 from nasa/open729
Review and integrate open729
2016-03-14 16:12:18 -07:00
Henry
f9ed73c55e [Table] #742 Fixed digest-related bug in RTTelemetryController
Fixed failing test
2016-03-14 16:00:36 -07:00
Charles Hacskaylo
bf3b964ad2 Removed commented code
#729
#735
2016-03-14 15:45:10 -07:00
Victor Woeltjen
55ae755522 [Tree] Fix error in test case
Correctly expect both arguments to $watch
2016-03-14 15:04:58 -07:00
Victor Woeltjen
d522570c0b [Tree] Add spec for mct-tree 2016-03-14 14:54:57 -07:00
Victor Woeltjen
d72aaf54ca [Tree] Test inner tree creation 2016-03-14 14:40:46 -07:00
Victor Woeltjen
8f94751a35 [Tree] Add capabilities to child objects for testing 2016-03-14 14:14:34 -07:00
Andrew Henry
dfb0a570a3 Merge pull request #728 from nasa/warp135b
[Timelines] Export as CSV
2016-03-14 13:20:28 -07:00
Pete Richards
5d06979866 Merge remote-tracking branch 'origin/open707' 2016-03-14 13:05:59 -07:00
Victor Woeltjen
8b51ae32d2 [Tree] Begin testing selection change 2016-03-14 13:04:46 -07:00
Victor Woeltjen
ecb37c54be [Tree] Add TreeView test cases 2016-03-14 12:52:33 -07:00
Victor Woeltjen
43492d31ba [Tree] Begin writing spec for TreeView 2016-03-14 12:22:09 -07:00
Victor Woeltjen
0e1df444df [Tree] Update test configuration
...to account for new dependency on Zepto (and its necessary
shim.)
2016-03-14 12:21:58 -07:00
Victor Woeltjen
f2c040367b [Timeline] Rename TimelineCSVExporter
...to TimelineColumnizer, clarifying its role/responsibilities in the
context of the CSV export task;
https://github.com/nasa/openmctweb/pull/728#discussion_r56031331
2016-03-14 12:00:31 -07:00
Victor Woeltjen
0ff360ced3 [Timelines] Remove excessive ternaries
...to improve readability of logic to determine which columns
are needed for a given group of domain objects for CSV export,
as requested during code review,
https://github.com/nasa/openmctweb/pull/728#discussion_r55910477
2016-03-14 11:53:28 -07:00
Henry
fc08df4f6f [Tables] #733 Made code style changes for conformance with style guide 2016-03-14 11:25:26 -07:00
Henry
c5de90a951 [Tables] Changed the way that new rows are added to table
Fixed failing tests
2016-03-13 20:15:47 -07:00
Henry
ea0b86fe72 [Tables] Fixed issue with historical tables composed of multiple objects 2016-03-13 19:12:55 -07:00
Victor Woeltjen
d789e91c18 [Tree] Add wait spinner 2016-03-11 18:00:58 -08:00
Victor Woeltjen
f7ba24c0b6 [Tree] Enable gestures on labels 2016-03-11 17:43:18 -08:00
Victor Woeltjen
02ec6db104 [Tree] Trigger digest on tree selection change 2016-03-11 17:37:11 -08:00
Victor Woeltjen
a3a9393d1b [Tree] Change selection on click 2016-03-11 17:32:57 -08:00
Victor Woeltjen
217e697079 [Tree] Display selection state 2016-03-11 17:26:00 -08:00
Victor Woeltjen
82b6166408 [Tree] Begin wiring in selection 2016-03-11 17:09:17 -08:00
Victor Woeltjen
03ab3bddc4 [Tree] Begin handling selection state 2016-03-11 17:00:55 -08:00
Andrew Henry
abd5913f02 Merge pull request #727 from nasa/open377
[Search] Index directly on mutation
2016-03-11 15:39:43 -08:00
Victor Woeltjen
107ecfe687 [Search] Don't index objects being edited
https://github.com/nasa/openmctweb/pull/727#issuecomment-195570183
2016-03-11 14:55:16 -08:00
Victor Woeltjen
4a8222a152 [Tree] Update labels on mutation 2016-03-11 14:47:50 -08:00
Victor Woeltjen
7ee8d0a3f7 [Tree] Display tree correctly 2016-03-11 14:40:04 -08:00
Victor Woeltjen
dc2b3e85cc [Tree] Show tree with toggle 2016-03-11 14:33:05 -08:00
Victor Woeltjen
d4b15525ca [Tree] Begin using mct-tree for tree representation 2016-03-11 14:23:08 -08:00
Victor Woeltjen
cbd9509260 [Tree] Use TreeView from mct-tree 2016-03-11 14:13:14 -08:00
Victor Woeltjen
c5ab6c6c97 [Tree] Implement label for tree 2016-03-11 14:10:30 -08:00
Andrew Henry
cd84a017b8 Merge pull request #723 from nasa/open672
[Build] Enforce code coverage threshold
2016-03-11 13:34:26 -08:00
Andrew Henry
d39dea971f Merge pull request #721 from nasa/open716
[Info Bubble] Fix bug with arrow positioning
2016-03-11 13:13:49 -08:00
Victor Woeltjen
4f293f22a6 [Tree] Add Zepto dependency
...to support implementation of a jQuery-less tree.
2016-03-11 12:38:40 -08:00
Victor Woeltjen
cebf9f73da [Tree] Begin adding tree label 2016-03-11 12:29:24 -08:00
Victor Woeltjen
37e6b5a352 [Tree] Continue breaking apart tree view 2016-03-11 11:39:10 -08:00
Victor Woeltjen
ece8f7fded [Tree] Begin separating out TreeView 2016-03-11 11:12:43 -08:00
Victor Woeltjen
3b0a3733b4 [Tree] Begin adding controller for refactored tree 2016-03-11 10:23:06 -08:00
Victor Woeltjen
baab0be5af [Tree] Begin adding mct-tree directive
...to reduce watch counts associated with the tree;
#732 and #315
2016-03-11 10:04:33 -08:00
Victor Woeltjen
d14a2a6366 Merge pull request #736 from nasa/open718
Review and integrate open718
2016-03-11 09:52:18 -08:00
Charles Hacskaylo
377d533ec7 [Frontend] Fixed markup
open #718
Removed class from markup;
2016-03-10 18:11:10 -08:00
Charles Hacskaylo
a4c5854561 [Frontend] Bug fixing
open #729
open #498
Fixed markup to use proper CSS classes
to allow tree items in Inspector Elements to
ellipsize properly, and to apply scroll regions
to the proper elements;
2016-03-10 14:33:01 -08:00
Victor Woeltjen
5296255fa6 [Representation] Test for false-positives on refresh
#732
2016-03-10 14:26:20 -08:00
Victor Woeltjen
5d084c2618 [Representation] Fix unchanged check
Fix logic in unchanged check; compare booleans to detect if
they have changed, instead of just anding them. Partially
addresses #732
2016-03-10 14:21:20 -08:00
Henry
5208631528 [Tables] #707 removed redundant bundles 2016-03-10 13:55:59 -08:00
Henry
a56edb9ff4 [table] #707 Fixed sorting on insert for numbers
Added metadata to event generator
2016-03-10 13:39:16 -08:00
Henry
7da1a218ba [Tables] #707 Added auto-scroll, addressed race condition in Sinewave and event telemetry providers
Fixed issue with visible padding row

Incremental improvements

Added tests

Added tests for sorted insert, and fixed lint errors
2016-03-10 13:21:57 -08:00
Henry
a4eb9d6a94 [Tables] #707 Supporting realtime telemetry tables
Added real-time table type
2016-03-10 13:21:57 -08:00
Henry
20f1dcef45 Fixed scrolling 2016-03-10 13:21:01 -08:00
Charles Hacskaylo
4983d35ca6 [Frontend] Cleanups to Inspector config elements
open #729
Spacing tweaks; set PlotOptionsForm.js > Autoscale
to not use control-first layout;
Checked in snow theme;
2016-03-10 13:18:57 -08:00
Charles Hacskaylo
7171fd01e3 [Frontend] Cleanups to Inspector config elements
open #729
In-progress
Moved CSS def to be more globally applicable;
Simplified layout obj props location display;
2016-03-10 11:07:26 -08:00
Charles Hacskaylo
0957fbc6f9 [Frontend] Cleanups to Inspector config elements
open #729
In-progress
Moved reduced-min-width into _inspector.scss;
Removed <style> defs in markup files;
2016-03-10 10:50:00 -08:00
Charles Hacskaylo
bdbb045005 [Frontend] Cleanups to Inspector config elements
open #729
In-progress!
Markup and CSS mods continued;
Config params added to PlotOptionsForm.js to
allow control-first layout per form row;
Changed titles of Inspector parts;
2016-03-10 10:31:05 -08:00
Charles Hacskaylo
318df9878d [Frontend] Cleanups to Inspector config elements
open #729
In-progress!
Markup and CSS modified to cleanup control layout
and styling in Plot and Table config options;
gulpfile.js modified to include SASS source line numbers
in rendered CSS;
2016-03-09 17:22:41 -08:00
Victor Woeltjen
406a31889e [Timeline] Add specs for remaining columns 2016-03-08 12:34:08 -08:00
Victor Woeltjen
9e4e3e9c43 [Timeline] Add JSDoc
Add JSDoc to classes implemented Export Timeline as CSV
2016-03-08 11:59:53 -08:00
Victor Woeltjen
bd7cb98a4c [Timeline] Add missing semicolon
...to pass code style checks
2016-03-08 11:40:54 -08:00
Victor Woeltjen
0d419fa5fd [Timeline] Test TimelineTraverser 2016-03-08 11:30:26 -08:00
Victor Woeltjen
5ee5e7fea1 [Timeline] Add capabilities to test inputs 2016-03-08 10:47:01 -08:00
Victor Woeltjen
66b1a92554 [Timeline] Add test cases for TimelineTraverser 2016-03-08 10:43:13 -08:00
Victor Woeltjen
c23c2b84bf [Timeline] Test inclusion of timespan properties
...in prepared data for CSV export
2016-03-08 10:31:31 -08:00
Victor Woeltjen
0c2285719e [Timeline] Test inclusion of metadata headers 2016-03-08 10:27:50 -08:00
Victor Woeltjen
fd92c5f970 [Timeline] Add more tests for rows 2016-03-08 10:22:46 -08:00
Victor Woeltjen
938c266b4e [Timeline] Add Id column to CSV export 2016-03-08 10:20:25 -08:00
Victor Woeltjen
9e6e33983b [Timeline] Add more objects to test case 2016-03-08 10:17:10 -08:00
Victor Woeltjen
40895ec1b9 [Timelines] Begin spec for exporter 2016-03-08 10:07:21 -08:00
Victor Woeltjen
43db52fd70 [Timeline] Simplify interface
...such that responsibility for knowing exportService interface
is more localized.
2016-03-08 10:04:09 -08:00
Victor Woeltjen
75d6803c9f [Timeline] Test mode columns in CSV Export 2016-03-08 09:59:54 -08:00
Victor Woeltjen
ed679756b3 [Timelines] Test metadata columns in CSV Export
...and additionally refactor to run in a test environment
(don't use Array.prototype.find)
2016-03-08 09:56:21 -08:00
Victor Woeltjen
dd66cb60d8 [Timeline] Test export task 2016-03-08 09:47:09 -08:00
Victor Woeltjen
d5283d57e4 [Timeline] Add missing semicolon 2016-03-07 16:35:40 -08:00
Victor Woeltjen
7c140c06dc [Timeline] Test CSV Export action itself 2016-03-07 16:33:03 -08:00
Victor Woeltjen
f9ff9921a9 [Timelines] Continue testing CSV Export
...with initial test cases for the action itself.
2016-03-07 16:22:39 -08:00
Victor Woeltjen
cdac0ad67f [Timeline] Add test cases for CSV Export 2016-03-07 16:17:19 -08:00
Victor Woeltjen
5d771edcf7 [Timeline] Begin testing CSV Export 2016-03-07 16:13:23 -08:00
Victor Woeltjen
c4f1c4ad1f [Timeline] Show progress notification during export 2016-03-07 16:09:23 -08:00
Victor Woeltjen
14b8e02f27 [Timeline] Format exported start/end times 2016-03-07 16:02:33 -08:00
Victor Woeltjen
b383921f2a [Timeline] Export start/end to CSV 2016-03-07 16:00:13 -08:00
Victor Woeltjen
a509dfb840 [Timelines] Remove unused TaskService
https://developer.nasa.gov/mct/warp/issues/135
2016-03-07 15:30:57 -08:00
Victor Woeltjen
b7a44a7557 Merge branch 'master' into warp135b 2016-03-07 15:21:28 -08:00
Victor Woeltjen
2d305415b3 [Search] Index directly on mutation
Pass model directly when indexing is triggered via object mutation,
to avoid issuing an extra, unnecessary request to the server.

Additionally supports indexing of objects which have been created
but not yet persisted.

Addresses #377.
2016-03-07 14:46:36 -08:00
Victor Woeltjen
18167eddf8 [Build] Enforce code coverage threshold
Addresses #672
2016-03-03 17:14:04 -08:00
Victor Woeltjen
f302bd6cb2 [Info Bubble] Test arrow class application
#716
2016-03-03 16:17:01 -08:00
Victor Woeltjen
071a908c10 [Info Bubble] Don't clobber arrow classes
#716
2016-03-03 15:58:28 -08:00
Victor Woeltjen
273cf1c14f [Timeline] Fix columns exported 2016-02-08 18:07:03 -08:00
Victor Woeltjen
303e870b0d Merge branch 'open649' into warp135 2016-02-08 17:42:30 -08:00
Victor Woeltjen
b42ccebd5a [Timeline] Fix imports, dependencies
Fix imports and dependencies needed by Export Timeline as CSV
2016-02-08 17:42:26 -08:00
Victor Woeltjen
a444fc01ad [Timeline] Fix column module definitions 2016-02-08 17:34:10 -08:00
Victor Woeltjen
a126e43286 [Timelines] Handle columns during CSV export 2016-02-08 16:11:00 -08:00
Victor Woeltjen
32fc50bbd3 [Timelines] Begin sketching in taskService
...to separate out immediate commonality with other long-running
actions which need to show a blocking progress dialog.
2016-02-08 15:04:39 -08:00
Victor Woeltjen
4adb075a2b [Timelines] Separate out timeline traversal
...from rest of CSV export.
2016-02-08 13:59:34 -08:00
Victor Woeltjen
d8b1e570d9 [CSV Export] Begin implementing
Begin implementing initial step, wherein timelines composition
is traversed to build up a list of objects to export.
2016-02-08 13:36:25 -08:00
Victor Woeltjen
5033e2cdbb [Timeline] Begin adding Export as CSV
Sketch in solution for
https://developer.nasa.gov/mct/warp/issues/135
2016-02-08 13:04:41 -08:00
204 changed files with 8096 additions and 20537 deletions

View File

@@ -309,30 +309,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
---
### Modernizr
#### Info
* Link: http://modernizr.com
* Version: 2.6.2
* Author: Faruk Ateş
* Description: Browser/device capability finding
#### License
Copyright (c) 20092015
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Normalize.css
#### Info
@@ -476,6 +452,44 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
---
### Zepto
#### Info
* Link: http://zeptojs.com/
* Version: 1.1.6
* Authors: Thomas Fuchs
* Description: DOM manipulation
#### License
Copyright (c) 2010-2016 Thomas Fuchs
http://zeptojs.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
### Json.NET
#### Info

View File

@@ -17,6 +17,7 @@
"screenfull": "^3.0.0",
"node-uuid": "^1.4.7",
"comma-separated-values": "^3.6.4",
"FileSaver.js": "^0.0.2"
"FileSaver.js": "^0.0.2",
"zepto": "^1.1.6"
}
}

View File

@@ -151,11 +151,9 @@ emphasis on testing.
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
* [__Ship.__](version.md) Tag a code snapshot that has passed release/sprint
testing and deploy that version. (Only true if relevant
testing has passed by this point; if 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

@@ -3,8 +3,10 @@
The process used to develop Open MCT Web is described in the following
documents:
* [Development Cycle](cycle.md): Describes how and when specific
* The [Development Cycle](cycle.md) describes how and when specific
process points are repeated during development.
* The [Version Guide](version.md) describes version numbering for
Open MCT (both semantics and process.)
* Testing is described in two documents:
* The [Test Plan](testing/plan.md) summarizes the approaches used
to test Open MCT Web.

142
docs/src/process/version.md Normal file
View File

@@ -0,0 +1,142 @@
# Version Guide
This document describes semantics and processes for providing version
numbers for Open MCT, and additionally provides guidelines for dependent
projects developed by the same team.
Versions are incremented at specific points in Open MCT's
[Development Cycle](cycle.md); see that document for a description of
sprints and releases.
## Audience
Individuals interested in consuming version numbers can be categorized as
follows:
* _Users_: Generally disinterested, occasionally wish to identify version
to cross-reference against documentation, or to report issues.
* _Testers_: Want to identify which version of the software they are
testing, e.g. to file issues for defects.
* _Internal developers_: Often, inverse of testers; want to identify which
version of software was/is in use when certain behavior is observed. Want
to be able to correlate versions in use with “streams” of development
(e.g. dev vs. prod), when possible.
* _External developers_: Need to understand which version of software is
in use when developing/maintaining plug-ins, in order to ensure
compatibility of their software.
## Version Reporting
Software versions should be reflected in the user interface of the
application in three ways:
* _Version number_: A semantic version (see below) which serves both to
uniquely identify releases, as well as to inform plug-in developers
about compatibility with previous releases.
* _Revision identifier_: While using git, the commit hash. Supports
internal developers and testers by uniquely identifying client
software snapshots.
* _Branding_: Identifies which variant is in use. (Typically, Open MCT
is re-branded when deployed for a specific mission or center.)
## Version Numbering
Open MCT shall provide version numbers consistent with
[Semantic Versioning 2.0.0](http://semver.org/). In summary, versions
are expressed in a "major.minor.patch" form, and incremented based on
nature of changes to external API. Breaking changes require a "major"
version increment; backwards-compatible changes require a "minor"
version increment; neutral changes (such as bug fixes) require a "patch"
version increment. A hyphen-separated suffix indicates a pre-release
version, which may be unstable or may not fully meet compatibility
requirements.
Additionally, the following project-specific standards will be used:
* During development, a "-SNAPSHOT" suffix shall be appended to the
version number. The version number before the suffix shall reflect
the next expected version number for release.
* Prior to a 1.0.0 release, the _minor_ version will be incremented
on a per-release basis; the _patch_ version will be incremented on a
per-sprint basis.
* Starting at version 1.0.0, version numbers will be updated with each
completed sprint. The version number for the sprint shall be
determined relative to the previous released version; the decision
to increment the _major_, _minor_, or _patch_ version should be
made based on the nature of changes during that release. (It is
recommended that these numbers are incremented as changes are
introduced, such that at end of release the version number may
be chosen by simply removing the suffix.)
* The first three sprints in a release may be unstable; in these cases, a
unique version identifier should still be generated, but a suffix
should be included to indicate that the version is not necessarily
production-ready. Recommended suffixes are:
Sprint | Suffix
:------:|:--------:
1 | `-alpha`
2 | `-beta`
3 | `-rc`
### Scope of External API
"External API" refers to the API exposed to, documented for, and used by
plug-in developers. Changes to interfaces used internally by Open MCT
(or otherwise not documented for use externally) require only a _patch_
version bump.
## Incrementing Versions
At the end of a sprint, the [project manager](cycle.md#roles)
should update (or delegate the task of updating) Open MCT version
numbers by the following process:
1. Update version number in `package.json`
1. Remove `-SNAPSHOT` suffix.
2. Verify that resulting version number meets semantic versioning
requirements relative to previous stable version. Increment if
necessary.
3. If version is considered unstable (which may be the case during
the first three sprints of a release), apply a new suffix per
[Version Numbering](#version-numbering) guidance above.
2. Tag the release.
1. Commit changes to `package.json` on the `master` branch.
The commit message should reference the sprint being closed,
preferably by a URL reference to the associated Milestone in
GitHub.
2. Verify that build still completes, that application passes
smoke-testing, and that only differences from tested versions
are the changes to version number above.
3. Push the `master` branch.
4. Tag this commit with the version number, prepending the letter "v".
(e.g. `git tag v0.9.3-alpha`)
5. Push the tag to GitHub. (e.g. `git push origin v0.9.3-alpha`).
3. Upload a release archive.
1. Run `npm pack` to generate the archive.
2. Use the [GitHub release interface](https://github.com/nasa/openmct/releases)
to draft a new release.
3. Choose the existing tag for the new version (created and pushed above.)
Enter the tag name as the release name as well; see existing releases
for examples.
4. Attach the release archive.
5. Designate the release as a "pre-release" as appropriate (for instance,
when the version number has been suffixed as unstable, or when
the version number is below 1.0.0.)
4. Restore snapshot status in `package.json`
1. Remove any suffix from the version number, or increment the
_patch_ version if there is no suffix.
2. Append a `-SNAPSHOT` suffix.
3. Commit changes to `package.json` on the `master` branch.
The commit message should reference the sprint being opened,
preferably by a URL reference to the associated Milestone in
GitHub.
4. Verify that build still completes, that application passes
smoke-testing.
5. Push the `master` branch.
Projects dependent on Open MCT being co-developed by the Open MCT
team should follow a similar process, except that they should
additionally update their dependency on Open MCT to point to the
latest archive when removing their `-SNAPSHOT` status, and
that they should be pointed back to the `master` branch after
this has completed.

View File

@@ -32,7 +32,7 @@ define([
legacyRegistry.register("example/eventGenerator", {
"name": "Event Message Generator",
"description": "Example of a component that produces event data.",
"description": "For development use. Creates sample event message data that mimics a live data stream.",
"extensions": {
"components": [
{
@@ -49,16 +49,26 @@ define([
{
"key": "eventGenerator",
"name": "Event Message Generator",
"glyph": "f",
"description": "An event message generator",
"glyph": "\u0066",
"description": "For development use. Creates sample event message data that mimics a live data stream.",
"priority": 10,
"features": "creation",
"model": {
"telemetry": {}
},
"telemetry": {
"source": "eventGenerator",
"domains": [
{
"key": "time",
"name": "Time",
"format": "utc"
}
],
"ranges": [
{
"key": "message",
"name": "Message",
"format": "string"
}
]

View File

@@ -37,7 +37,8 @@ define(
var
subscriptions = [],
genInterval = 1000,
startTime = Date.now();
generating = false,
id = Math.random() * 100000;
//
function matchesSource(request) {
@@ -79,11 +80,13 @@ define(
}
function startGenerating() {
generating = true;
$timeout(function () {
//console.log("startGenerating... " + Date.now());
handleSubscriptions();
if (subscriptions.length > 0) {
if (generating && subscriptions.length > 0) {
startGenerating();
} else {
generating = false;
}
}, genInterval);
}
@@ -93,7 +96,6 @@ define(
callback: callback,
requests: requests
};
function unsubscribe() {
subscriptions = subscriptions.filter(function (s) {
return s !== subscription;
@@ -101,8 +103,7 @@ define(
}
subscriptions.push(subscription);
if (subscriptions.length === 1) {
if (!generating) {
startGenerating();
}

View File

@@ -36,7 +36,7 @@ define([
legacyRegistry.register("example/generator", {
"name": "Sine Wave Generator",
"description": "Example of a component that produces dataa.",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"extensions": {
"components": [
{
@@ -86,8 +86,9 @@ define([
{
"key": "generator",
"name": "Sine Wave Generator",
"glyph": "T",
"description": "A sine wave generator",
"glyph": "\u0054",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"priority": 10,
"features": "creation",
"model": {
"telemetry": {
@@ -126,7 +127,7 @@ define([
{
"name": "Period",
"control": "textfield",
"cssclass": "l-small l-numeric",
"cssclass": "l-input-sm l-numeric",
"key": "period",
"required": true,
"property": [

View File

@@ -34,7 +34,8 @@ define(
* @constructor
*/
function SinewaveTelemetryProvider($q, $timeout) {
var subscriptions = [];
var subscriptions = [],
generating = false;
//
function matchesSource(request) {
@@ -75,10 +76,13 @@ define(
}
function startGenerating() {
generating = true;
$timeout(function () {
handleSubscriptions();
if (subscriptions.length > 0) {
if (generating && subscriptions.length > 0) {
startGenerating();
} else {
generating = false;
}
}, 1000);
}
@@ -97,7 +101,7 @@ define(
subscriptions.push(subscription);
if (subscriptions.length === 1) {
if (!generating) {
startGenerating();
}

View File

@@ -49,8 +49,10 @@ define([
{
"key": "imagery",
"name": "Example Imagery",
"glyph": "T",
"glyph": "\u00e3",
"features": "creation",
"description": "For development use. Creates example imagery data that mimics a live imagery stream.",
"priority": 10,
"model": {
"telemetry": {}
},

View File

@@ -54,7 +54,7 @@ define([
{
"name": "Measurement",
"key": "msl.measurement",
"glyph": "T",
"glyph": "\u0054",
"model": {"telemetry": {}},
"telemetry": {
"source": "rems.source",

View File

@@ -80,9 +80,10 @@ define([
"types": [
{
"key": "plot",
"name": "Telemetry Plot",
"glyph": "t",
"description": "A plot for displaying telemetry",
"name": "Example Telemetry Plot",
"glyph": "\u0074",
"description": "For development use. A plot for displaying telemetry.",
"priority": 10,
"delegates": [
"telemetry"
],

View File

@@ -60,7 +60,8 @@ var gulp = require('gulp'),
singleRun: true
},
sass: {
includePaths: bourbon.includePaths
includePaths: bourbon.includePaths,
sourceComments: true
},
replace: {
variables: {
@@ -90,7 +91,8 @@ gulp.task('stylesheets', function () {
.pipe(sourcemaps.init())
.pipe(sass(options.sass).on('error', sass.logError))
.pipe(rename(function (file) {
file.dirname = file.dirname.replace('/sass', '/css');
file.dirname =
file.dirname.replace(path.sep + 'sass', path.sep + 'css');
return file;
}))
.pipe(sourcemaps.write('.'))

View File

@@ -81,7 +81,12 @@ module.exports = function(config) {
coverageReporter: {
dir: process.env.CIRCLE_ARTIFACTS ?
process.env.CIRCLE_ARTIFACTS + '/coverage' :
"dist/coverage"
"dist/coverage",
check: {
global: {
lines: 80
}
}
},
// HTML test reporting.

View File

@@ -33,7 +33,8 @@ requirejs.config({
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
"screenfull": "bower_components/screenfull/dist/screenfull.min",
"text": "bower_components/text/text",
"uuid": "bower_components/node-uuid/uuid"
"uuid": "bower_components/node-uuid/uuid",
"zepto": "bower_components/zepto/zepto.min"
},
"shim": {
"angular": {
@@ -44,6 +45,9 @@ requirejs.config({
},
"moment-duration-format": {
"deps": [ "moment" ]
},
"zepto": {
"exports": "Zepto"
}
}
});
@@ -70,12 +74,10 @@ define([
'./platform/exporters/bundle',
'./platform/telemetry/bundle',
'./platform/features/clock/bundle',
'./platform/features/events/bundle',
'./platform/features/imagery/bundle',
'./platform/features/layout/bundle',
'./platform/features/pages/bundle',
'./platform/features/plot/bundle',
'./platform/features/scrolling/bundle',
'./platform/features/timeline/bundle',
'./platform/features/table/bundle',
'./platform/forms/bundle',

View File

@@ -1,7 +1,7 @@
{
"name": "openmctweb",
"version": "0.9.3-SNAPSHOT",
"description": "The Open MCT Web core platform",
"version": "0.10.0",
"description": "The Open MCT core platform",
"dependencies": {
"express": "^4.13.1",
"minimist": "^1.1.1",
@@ -38,7 +38,7 @@
"moment": "^2.11.1",
"node-bourbon": "^4.2.3",
"phantomjs-prebuilt": "^2.1.0",
"requirejs": "^2.1.17",
"requirejs": "2.1.x",
"split": "^1.0.0"
},
"scripts": {
@@ -49,7 +49,7 @@
"jsdoc": "jsdoc -c jsdoc.json -r -d target/docs/api",
"otherdoc": "node docs/gendocs.js --in docs/src --out target/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
"docs": "npm run jsdoc ; npm run otherdoc",
"prepublish": "./node_modules/bower/bin/bower install && ./node_modules/gulp/bin/gulp.js install"
"prepublish": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
},
"repository": {
"type": "git",

View File

@@ -44,22 +44,7 @@
</div>
</div>
<div class="holder l-flex-col flex-elem grows l-object-wrapper">
<div ng-if="isEditable" class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
<!-- Toolbar and Save/Cancel buttons -->
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
<mct-representation key="'edit-action-buttons'"
mct-object="domainObject"
class='flex-elem conclude-editing'>
</mct-representation>
</div>
<mct-representation key="representation.selected.key"
mct-object="representation.selected.key && domainObject"
class="abs flex-elem grows object-holder-main scroll"
toolbar="toolbar">
</mct-representation>
</div>
<div ng-if="!isEditable" class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
<div class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
<!-- Toolbar and Save/Cancel buttons -->
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
<mct-representation key="'edit-action-buttons'"

View File

@@ -32,6 +32,7 @@
</li>
<li ng-if="contextutalParents.length > 0">
<em class="t-inspector-part-header" title="The location of this linked object.">Location</em>
<div ng-if="primaryParents.length > 0" class="section-header">This Object</div>
<span class="inspector-location"
ng-repeat="parent in contextutalParents"
ng-class="{ last:($index + 1) === contextualParents.length }">
@@ -44,7 +45,7 @@
</span>
</li>
<li ng-if="primaryParents.length > 0">
<em class="t-inspector-part-header" title="The location of the original object that this was linked from.">Original Location</em>
<div class="section-header">Object's Original</div>
<span class="inspector-location"
ng-repeat="parent in primaryParents"
ng-class="{ last:($index + 1) === primaryParents.length }">

View File

@@ -29,5 +29,5 @@
-->
<mct-representation mct-object="domainObject"
key="viewObjectTemplate || 'browse-object'"
class="abs holder holder-object">
class="abs holder">
</mct-representation>

View File

@@ -93,27 +93,23 @@ define(
return wizard.populateObjectFromInput(formValue, newObject);
}
function addToParent (populatedObject) {
parentObject.getCapability('composition').add(populatedObject);
return parentObject.getCapability('persistence').persist().then(function(){
return parentObject;
});
function persistAndReturn(domainObject) {
return domainObject.getCapability('persistence')
.persist()
.then(function () {
return domainObject;
});
}
function save(object) {
/*
It's necessary to persist the new sub-object in order
that it can be retrieved for composition in the parent.
Future refactoring that allows temporary objects to be
retrieved from object services will make this unnecessary.
*/
return object.getCapability('editor').save(true);
function addToParent (populatedObject) {
parentObject.getCapability('composition').add(populatedObject);
return persistAndReturn(parentObject);
}
return this.dialogService
.getUserInput(wizard.getFormStructure(false), wizard.getInitialFormValue())
.then(populateObjectFromInput)
.then(save)
.then(persistAndReturn)
.then(addToParent);
};

View File

@@ -32,9 +32,13 @@ define([
"./src/actions/PropertiesAction",
"./src/actions/RemoveAction",
"./src/actions/SaveAction",
"./src/actions/SaveAsAction",
"./src/actions/CancelAction",
"./src/policies/EditActionPolicy",
"./src/policies/EditableLinkPolicy",
"./src/policies/EditableMovePolicy",
"./src/policies/EditNavigationPolicy",
"./src/policies/EditContextualActionPolicy",
"./src/representers/EditRepresenter",
"./src/representers/EditToolbarRepresenter",
"text!./res/templates/library.html",
@@ -54,9 +58,13 @@ define([
PropertiesAction,
RemoveAction,
SaveAction,
SaveAsAction,
CancelAction,
EditActionPolicy,
EditableLinkPolicy,
EditableMovePolicy,
EditNavigationPolicy,
EditContextualActionPolicy,
EditRepresenter,
EditToolbarRepresenter,
libraryTemplate,
@@ -161,6 +169,15 @@ define([
"implementation": SaveAction,
"name": "Save",
"description": "Save changes made to these objects.",
"depends": [],
"priority": "mandatory"
},
{
"key": "save",
"category": "conclude-editing",
"implementation": SaveAsAction,
"name": "Save",
"description": "Save changes made to these objects.",
"depends": [
"$injector",
"policyService",
@@ -187,6 +204,19 @@ define([
"category": "action",
"implementation": EditActionPolicy
},
{
"category": "action",
"implementation": EditContextualActionPolicy,
"depends": ["navigationService", "editModeBlacklist", "nonEditContextBlacklist"]
},
{
"category": "action",
"implementation": EditableMovePolicy
},
{
"category": "action",
"implementation": EditableLinkPolicy
},
{
"category": "navigation",
"message": "There are unsaved changes.",
@@ -244,6 +274,16 @@ define([
{
"implementation": EditToolbarRepresenter
}
],
"constants": [
{
"key":"editModeBlacklist",
"value": ["copy", "follow", "window", "link", "locate"]
},
{
"key": "nonEditContextBlacklist",
"value": ["copy", "follow", "properties", "move", "link", "remove", "locate"]
}
]
}
});

View File

@@ -19,16 +19,19 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div ng-controller="ElementsController">
<div ng-controller="ElementsController" class="flex-elem l-flex-col holder grows">
<mct-include key="'input-filter'"
class="flex-elem holder"
ng-model="filterBy">
</mct-include>
<div class="current-elements abs" style="height: 100%;">
<div class="flex-elem grows vscroll">
<ul class="tree">
<li ng-repeat="containedObject in composition | filter:searchText">
<span class="tree-item">
<mct-representation key="'label'" mct-object="containedObject">
<mct-representation
class="rep-object-label"
key="'label'"
mct-object="containedObject">
</mct-representation>
</span>
</li>

View File

@@ -24,8 +24,8 @@
define(
['../../../browse/src/creation/CreateWizard'],
function (CreateWizard) {
[],
function () {
'use strict';
/**
@@ -37,31 +37,11 @@ define(
* @memberof platform/commonUI/edit
*/
function SaveAction(
$injector,
policyService,
dialogService,
creationService,
copyService,
context
) {
this.domainObject = (context || {}).domainObject;
this.injectObjectService = function(){
this.objectService = $injector.get("objectService");
};
this.policyService = policyService;
this.dialogService = dialogService;
this.creationService = creationService;
this.copyService = copyService;
}
SaveAction.prototype.getObjectService = function(){
// Lazily acquire object service (avoids cyclical dependency)
if (!this.objectService) {
this.injectObjectService();
}
return this.objectService;
};
/**
* Save changes and conclude editing.
*
@@ -70,9 +50,7 @@ define(
* @memberof platform/commonUI/edit.SaveAction#
*/
SaveAction.prototype.perform = function () {
var domainObject = this.domainObject,
copyService = this.copyService,
self = this;
var domainObject = this.domainObject;
function resolveWith(object){
return function () {
@@ -80,64 +58,13 @@ define(
};
}
function doWizardSave(parent) {
var context = domainObject.getCapability("context"),
wizard = new CreateWizard(
domainObject,
parent,
self.policyService
);
return self.dialogService
.getUserInput(
wizard.getFormStructure(true),
wizard.getInitialFormValue()
)
.then(wizard.populateObjectFromInput.bind(wizard));
}
function fetchObject(objectId){
return self.getObjectService().getObjects([objectId]).then(function(objects){
return objects[objectId];
});
}
function getParent(object){
return fetchObject(object.getModel().location);
}
function allowClone(objectToClone) {
return (objectToClone.getId() === domainObject.getId()) ||
objectToClone.getCapability('location').isOriginal();
}
function cloneIntoParent(parent) {
return copyService.perform(domainObject, parent, allowClone);
}
function cancelEditingAfterClone(clonedObject) {
return domainObject.getCapability("editor").cancel()
.then(resolveWith(clonedObject));
}
// Invoke any save behavior introduced by the editor capability;
// this is introduced by EditableDomainObject which is
// used to insulate underlying objects from changes made
// during editing.
function doSave() {
//This is a new 'virtual object' that has not been persisted
// yet.
if (domainObject.getModel().persisted === undefined){
return getParent(domainObject)
.then(doWizardSave)
.then(getParent)
.then(cloneIntoParent)
.then(cancelEditingAfterClone)
.catch(resolveWith(false));
} else {
return domainObject.getCapability("editor").save()
.then(resolveWith(domainObject.getOriginalObject()));
}
return domainObject.getCapability("editor").save()
.then(resolveWith(domainObject.getOriginalObject()));
}
// Discard the current root view (which will be the editing
@@ -162,7 +89,8 @@ define(
SaveAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined &&
domainObject.hasCapability("editor");
domainObject.hasCapability("editor") &&
domainObject.getModel().persisted !== undefined;
};
return SaveAction;

View File

@@ -0,0 +1,169 @@
/*****************************************************************************
* 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*/
/*jslint es5: true */
define(
['../../../browse/src/creation/CreateWizard'],
function (CreateWizard) {
'use strict';
/**
* The "Save" action; the action triggered by clicking Save from
* Edit Mode. Exits the editing user interface and invokes object
* capabilities to persist the changes that have been made.
* @constructor
* @implements {Action}
* @memberof platform/commonUI/edit
*/
function SaveAsAction(
$injector,
policyService,
dialogService,
creationService,
copyService,
context
) {
this.domainObject = (context || {}).domainObject;
this.injectObjectService = function(){
this.objectService = $injector.get("objectService");
};
this.policyService = policyService;
this.dialogService = dialogService;
this.creationService = creationService;
this.copyService = copyService;
}
/**
* @private
*/
SaveAsAction.prototype.createWizard = function (parent) {
return new CreateWizard(
this.domainObject,
parent,
this.policyService
);
};
/**
* @private
*/
SaveAsAction.prototype.getObjectService = function(){
// Lazily acquire object service (avoids cyclical dependency)
if (!this.objectService) {
this.injectObjectService();
}
return this.objectService;
};
function resolveWith(object){
return function () {
return object;
};
}
/**
* Save changes and conclude editing.
*
* @returns {Promise} a promise that will be fulfilled when
* cancellation has completed
* @memberof platform/commonUI/edit.SaveAction#
*/
SaveAsAction.prototype.perform = function () {
// Discard the current root view (which will be the editing
// UI, which will have been pushed atop the Browse UI.)
function returnToBrowse(object) {
if (object) {
object.getCapability("action").perform("navigate");
}
return object;
}
return this.save().then(returnToBrowse);
};
/**
* @private
*/
SaveAsAction.prototype.save = function () {
var self = this,
domainObject = this.domainObject,
copyService = this.copyService;
function doWizardSave(parent) {
var wizard = self.createWizard(parent);
return self.dialogService
.getUserInput(wizard.getFormStructure(true),
wizard.getInitialFormValue()
).then(wizard.populateObjectFromInput.bind(wizard));
}
function fetchObject(objectId){
return self.getObjectService().getObjects([objectId]).then(function(objects){
return objects[objectId];
});
}
function getParent(object){
return fetchObject(object.getModel().location);
}
function allowClone(objectToClone) {
return (objectToClone.getId() === domainObject.getId()) ||
objectToClone.getCapability('location').isOriginal();
}
function cloneIntoParent(parent) {
return copyService.perform(domainObject, parent, allowClone);
}
function cancelEditingAfterClone(clonedObject) {
return domainObject.getCapability("editor").cancel()
.then(resolveWith(clonedObject));
}
return getParent(domainObject)
.then(doWizardSave)
.then(getParent)
.then(cloneIntoParent)
.then(cancelEditingAfterClone)
.catch(resolveWith(false));
};
/**
* Check if this action is applicable in a given context.
* This will ensure that a domain object is present in the context,
* and that this domain object is in Edit mode.
* @returns true if applicable
*/
SaveAsAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined &&
domainObject.hasCapability("editor") &&
domainObject.getModel().persisted === undefined;
};
return SaveAsAction;
}
);

View File

@@ -38,14 +38,6 @@ define(
this.policyService = policyService;
}
function applicableView(key){
return ['plot', 'scrolling'].indexOf(key) >= 0;
}
function editableType(key){
return key === 'telemetry.panel';
}
/**
* Get a count of views which are not flagged as non-editable.
* @private
@@ -65,7 +57,8 @@ define(
// A view is editable unless explicitly flagged as not
(views || []).forEach(function (view) {
if (view.editable === true || (applicableView(view.key) && editableType(type.getKey()))) {
if (view.editable === true ||
(view.key === 'plot' && type.getKey() === 'telemetry.panel')) {
count++;
}
});

View File

@@ -0,0 +1,74 @@
/*****************************************************************************
* 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";
/**
* Policy controlling whether the context menu is visible when
* objects are being edited
* @param navigationService
* @param editModeBlacklist A blacklist of actions disallowed from
* context menu when navigated object is being edited
* @param nonEditContextBlacklist A blacklist of actions disallowed
* from context menu of non-editable objects, when navigated object
* is being edited
* @constructor
*/
function EditContextualActionPolicy(navigationService, editModeBlacklist, nonEditContextBlacklist) {
this.navigationService = navigationService;
//The list of objects disallowed on target object when in edit mode
this.editModeBlacklist = editModeBlacklist;
//The list of objects disallowed on target object that is not in
// edit mode (ie. the context menu in the tree on the LHS).
this.nonEditContextBlacklist = nonEditContextBlacklist;
}
function isParentEditable(object) {
var parent = object.hasCapability("context") && object.getCapability("context").getParent();
return !!parent && parent.hasCapability("editor");
}
EditContextualActionPolicy.prototype.allow = function (action, context) {
var selectedObject = context.domainObject,
navigatedObject = this.navigationService.getNavigation(),
actionMetadata = action.getMetadata ? action.getMetadata() : {};
if (navigatedObject.hasCapability('editor')) {
if (selectedObject.hasCapability('editor') || isParentEditable(selectedObject)){
return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
} else {
//Target is in the context menu
return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
}
} else {
return true;
}
};
return EditContextualActionPolicy;
}
);

View File

@@ -19,37 +19,34 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/*global define*/
/**
* Module defining NameColumn. Created by vwoeltje on 11/18/14.
*/
define(
[],
function () {
"use strict";
define([], function () {
"use strict";
/**
* A column which will report the name of the domain object
* which exposed specific telemetry values.
*
* @memberof platform/features/scrolling
* @implements {platform/features/scrolling.ScrollingColumn}
* @constructor
*/
function NameColumn() {
/**
* Policy suppressing links when the linked-to domain object is in
* edit mode. Domain objects being edited may not have been persisted,
* so creating links to these can result in inconsistent state.
*
* @memberof platform/commonUI/edit
* @constructor
* @implements {Policy.<View, DomainObject>}
*/
function EditableLinkPolicy() {
}
EditableLinkPolicy.prototype.allow = function (action, context) {
var key = action.getMetadata().key;
if (key === 'link') {
return !((context.selectedObject || context.domainObject)
.hasCapability('editor'));
}
NameColumn.prototype.getTitle = function () {
return "Name";
};
// Like all policies, allow by default.
return true;
};
NameColumn.prototype.getValue = function (domainObject) {
return {
text: domainObject.getModel().name
};
};
return NameColumn;
}
);
return EditableLinkPolicy;
});

View File

@@ -21,29 +21,31 @@
*****************************************************************************/
/*global define*/
define([
"./src/CachingPersistenceDecorator",
'legacyRegistry'
], function (
CachingPersistenceDecorator,
legacyRegistry
) {
define([], function () {
"use strict";
legacyRegistry.register("platform/persistence/cache", {
"name": "Persistence cache",
"description": "Cache to improve availability of persisted objects.",
"extensions": {
"components": [
{
"provides": "persistenceService",
"type": "decorator",
"implementation": CachingPersistenceDecorator,
"depends": [
"PERSISTENCE_SPACE"
]
}
]
/**
* Policy suppressing move actions among editable and non-editable
* domain objects.
* @memberof platform/commonUI/edit
* @constructor
* @implements {Policy.<View, DomainObject>}
*/
function EditableMovePolicy() {
}
EditableMovePolicy.prototype.allow = function (action, context) {
var domainObject = context.domainObject,
selectedObject = context.selectedObject,
key = action.getMetadata().key;
if (key === 'move' && domainObject.hasCapability('editor')) {
return !!selectedObject && selectedObject.hasCapability('editor');
}
});
// Like all policies, allow by default.
return true;
};
return EditableMovePolicy;
});

View File

@@ -118,8 +118,6 @@ define(
// Track the represented object
this.domainObject = representedObject;
this.scope.isEditable = representedObject.getCapability('status').get('editing');
// Ensure existing watches are released
this.destroy();

View File

@@ -27,11 +27,11 @@ define(
"use strict";
describe("The Save action", function () {
var mockLocation,
mockDomainObject,
var mockDomainObject,
mockEditorCapability,
mockUrlService,
actionContext,
mockActionCapability,
capabilities = {},
action;
function mockPromise(value) {
@@ -43,65 +43,62 @@ define(
}
beforeEach(function () {
mockLocation = jasmine.createSpyObj(
"$location",
[ "path" ]
);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[ "getCapability", "hasCapability" ]
[
"getCapability",
"hasCapability",
"getModel",
"getOriginalObject"
]
);
mockEditorCapability = jasmine.createSpyObj(
"editor",
[ "save", "cancel" ]
);
mockUrlService = jasmine.createSpyObj(
"urlService",
["urlForLocation"]
mockActionCapability = jasmine.createSpyObj(
"actionCapability",
[ "perform"]
);
capabilities.editor = mockEditorCapability;
capabilities.action = mockActionCapability;
actionContext = {
domainObject: mockDomainObject
};
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andReturn(mockEditorCapability);
mockDomainObject.getCapability.andCallFake(function (capability) {
return capabilities[capability];
});
mockDomainObject.getModel.andReturn({persisted: 0});
mockEditorCapability.save.andReturn(mockPromise(true));
mockDomainObject.getOriginalObject.andReturn(mockDomainObject);
action = new SaveAction(mockLocation, mockUrlService, actionContext);
action = new SaveAction(actionContext);
});
it("only applies to domain object with an editor capability", function () {
expect(SaveAction.appliesTo(actionContext)).toBeTruthy();
expect(SaveAction.appliesTo(actionContext)).toBe(true);
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
mockDomainObject.hasCapability.andReturn(false);
mockDomainObject.getCapability.andReturn(undefined);
expect(SaveAction.appliesTo(actionContext)).toBeFalsy();
expect(SaveAction.appliesTo(actionContext)).toBe(false);
});
//TODO: Disabled for NEM Beta
xit("invokes the editor capability's save functionality when performed", function () {
// Verify precondition
expect(mockEditorCapability.save).not.toHaveBeenCalled();
action.perform();
// Should have called cancel
expect(mockEditorCapability.save).toHaveBeenCalled();
// Also shouldn't call cancel
expect(mockEditorCapability.cancel).not.toHaveBeenCalled();
it("only applies to domain object that has already been persisted",
function () {
mockDomainObject.getModel.andReturn({persisted: undefined});
expect(SaveAction.appliesTo(actionContext)).toBe(false);
});
//TODO: Disabled for NEM Beta
xit("returns to browse when performed", function () {
action.perform();
expect(mockLocation.path).toHaveBeenCalledWith(
mockUrlService.urlForLocation("browse", mockDomainObject)
);
});
it("uses the editor capability to save the object",
function () {
action.perform();
expect(mockEditorCapability.save).toHaveBeenCalled();
});
});
}
);

View File

@@ -0,0 +1,174 @@
/*****************************************************************************
* 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,xit,xdescribe*/
define(
["../../src/actions/SaveAsAction"],
function (SaveAsAction) {
"use strict";
describe("The Save As action", function () {
var mockDomainObject,
mockEditorCapability,
mockActionCapability,
mockObjectService,
mockDialogService,
mockCopyService,
mockParent,
mockUrlService,
actionContext,
capabilities = {},
action;
function noop () {}
function mockPromise(value) {
return (value || {}).then ? value :
{
then: function (callback) {
return mockPromise(callback(value));
},
catch: function (callback) {
return mockPromise(callback(value));
}
} ;
}
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[
"getCapability",
"hasCapability",
"getModel"
]
);
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andCallFake(function (capability) {
return capabilities[capability];
});
mockDomainObject.getModel.andReturn({location: 'a', persisted: undefined});
mockParent = jasmine.createSpyObj(
"parentObject",
[
"getCapability",
"hasCapability",
"getModel"
]
);
mockEditorCapability = jasmine.createSpyObj(
"editor",
[ "save", "cancel" ]
);
mockEditorCapability.cancel.andReturn(mockPromise(undefined));
mockEditorCapability.save.andReturn(mockPromise(true));
capabilities.editor = mockEditorCapability;
mockActionCapability = jasmine.createSpyObj(
"action",
["perform"]
);
capabilities.action = mockActionCapability;
mockObjectService = jasmine.createSpyObj(
"objectService",
["getObjects"]
);
mockObjectService.getObjects.andReturn(mockPromise({'a': mockParent}));
mockDialogService = jasmine.createSpyObj(
"dialogService",
[
"getUserInput"
]
);
mockDialogService.getUserInput.andReturn(mockPromise(undefined));
mockCopyService = jasmine.createSpyObj(
"copyService",
[
"perform"
]
);
mockUrlService = jasmine.createSpyObj(
"urlService",
["urlForLocation"]
);
actionContext = {
domainObject: mockDomainObject
};
action = new SaveAsAction(undefined, undefined, mockDialogService, undefined, mockCopyService, actionContext);
spyOn(action, "getObjectService");
action.getObjectService.andReturn(mockObjectService);
spyOn(action, "createWizard");
action.createWizard.andReturn({
getFormStructure: noop,
getInitialFormValue: noop,
populateObjectFromInput: function() {
return mockDomainObject;
}
});
});
it("only applies to domain object with an editor capability", function () {
expect(SaveAsAction.appliesTo(actionContext)).toBe(true);
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
mockDomainObject.hasCapability.andReturn(false);
mockDomainObject.getCapability.andReturn(undefined);
expect(SaveAsAction.appliesTo(actionContext)).toBe(false);
});
it("only applies to domain object that has not already been" +
" persisted", function () {
expect(SaveAsAction.appliesTo(actionContext)).toBe(true);
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
mockDomainObject.getModel.andReturn({persisted: 0});
expect(SaveAsAction.appliesTo(actionContext)).toBe(false);
});
it("returns to browse after save", function () {
spyOn(action, "save");
action.save.andReturn(mockPromise(mockDomainObject));
action.perform();
expect(mockActionCapability.perform).toHaveBeenCalledWith(
"navigate"
);
});
it("prompts the user for object details", function () {
action.perform();
expect(mockDialogService.getUserInput).toHaveBeenCalled();
});
});
}
);

View File

@@ -35,19 +35,43 @@ define(
mockDomainObject,
mockEditAction,
mockPropertiesAction,
mockTypeCapability,
mockStatusCapability,
capabilities,
plotView,
policy;
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
'domainObject',
[ 'useCapability' ]
[
'useCapability',
'hasCapability',
'getCapability'
]
);
mockStatusCapability = jasmine.createSpyObj('statusCapability', ['get']);
mockStatusCapability.get.andReturn(false);
mockTypeCapability = jasmine.createSpyObj('type', ['getKey']);
capabilities = {
'status': mockStatusCapability,
'type': mockTypeCapability
};
mockEditAction = jasmine.createSpyObj('edit', ['getMetadata']);
mockPropertiesAction = jasmine.createSpyObj('edit', ['getMetadata']);
mockDomainObject.getCapability.andCallFake(function(capability){
return capabilities[capability];
});
mockDomainObject.hasCapability.andCallFake(function(capability){
return !!capabilities[capability];
});
editableView = { editable: true };
nonEditableView = { editable: false };
undefinedView = { someKey: "some value" };
plotView = { key: "plot", editable: false };
testViews = [];
mockDomainObject.useCapability.andCallFake(function (c) {
@@ -66,38 +90,53 @@ define(
policy = new EditActionPolicy();
});
//TODO: Disabled for NEM Beta
xit("allows the edit action when there are editable views", function () {
it("allows the edit action when there are editable views", function () {
testViews = [ editableView ];
expect(policy.allow(mockEditAction, testContext)).toBeTruthy();
// No edit flag defined; should be treated as editable
testViews = [ undefinedView, undefinedView ];
expect(policy.allow(mockEditAction, testContext)).toBeTruthy();
expect(policy.allow(mockEditAction, testContext)).toBe(true);
});
//TODO: Disabled for NEM Beta
xit("allows the edit properties action when there are no editable views", function () {
it("allows the edit properties action when there are no editable views", function () {
testViews = [ nonEditableView, nonEditableView ];
expect(policy.allow(mockPropertiesAction, testContext)).toBeTruthy();
expect(policy.allow(mockPropertiesAction, testContext)).toBe(true);
});
//TODO: Disabled for NEM Beta
xit("disallows the edit action when there are no editable views", function () {
it("disallows the edit action when there are no editable views", function () {
testViews = [ nonEditableView, nonEditableView ];
expect(policy.allow(mockEditAction, testContext)).toBeFalsy();
expect(policy.allow(mockEditAction, testContext)).toBe(false);
});
//TODO: Disabled for NEM Beta
xit("disallows the edit properties action when there are" +
it("disallows the edit properties action when there are" +
" editable views", function () {
testViews = [ editableView ];
expect(policy.allow(mockPropertiesAction, testContext)).toBeFalsy();
expect(policy.allow(mockPropertiesAction, testContext)).toBe(false);
});
it("disallows the edit action when object is already being" +
" edited", function () {
testViews = [ editableView ];
mockStatusCapability.get.andReturn(true);
expect(policy.allow(mockEditAction, testContext)).toBe(false);
});
it("allows editing of panels in plot view", function () {
testViews = [ plotView ];
mockTypeCapability.getKey.andReturn('telemetry.panel');
expect(policy.allow(mockEditAction, testContext)).toBe(true);
});
it("disallows editing of plot view when object not a panel type", function () {
testViews = [ plotView ];
mockTypeCapability.getKey.andReturn('something.else');
expect(policy.allow(mockEditAction, testContext)).toBe(false);
});
it("allows the edit properties outside of the 'view-control' category", function () {
testViews = [ nonEditableView ];
testContext.category = "something-else";
expect(policy.allow(mockPropertiesAction, testContext)).toBeTruthy();
expect(policy.allow(mockPropertiesAction, testContext)).toBe(true);
});
});
}

View File

@@ -0,0 +1,109 @@
/*****************************************************************************
* 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,xit,xdescribe*/
define(
["../../src/policies/EditContextualActionPolicy"],
function (EditContextualActionPolicy) {
"use strict";
describe("The Edit contextual action policy", function () {
var policy,
navigationService,
mockAction,
context,
navigatedObject,
mockDomainObject,
metadata,
editModeBlacklist = ["copy", "follow", "window", "link", "locate"],
nonEditContextBlacklist = ["copy", "follow", "properties", "move", "link", "remove", "locate"];
beforeEach(function () {
navigatedObject = jasmine.createSpyObj("navigatedObject", ["hasCapability"]);
navigatedObject.hasCapability.andReturn(false);
mockDomainObject = jasmine.createSpyObj("domainObject", ["hasCapability", "getCapability"]);
mockDomainObject.hasCapability.andReturn(false);
navigationService = jasmine.createSpyObj("navigationService", ["getNavigation"]);
navigationService.getNavigation.andReturn(navigatedObject);
metadata = {key: "move"};
mockAction = jasmine.createSpyObj("action", ["getMetadata"]);
mockAction.getMetadata.andReturn(metadata);
context = {domainObject: mockDomainObject};
policy = new EditContextualActionPolicy(navigationService, editModeBlacklist, nonEditContextBlacklist);
});
it('Allows all actions when navigated object not in edit mode', function() {
expect(policy.allow(mockAction, context)).toBe(true);
});
it('Allows "window" action when navigated object in edit mode,' +
' but selected object not in edit mode ', function() {
navigatedObject.hasCapability.andReturn(true);
metadata.key = "window";
expect(policy.allow(mockAction, context)).toBe(true);
});
it('Allows "remove" action when navigated object in edit mode,' +
' and selected object not editable, but its parent is.',
function() {
var mockParent = jasmine.createSpyObj("parentObject", ["hasCapability"]),
mockContextCapability = jasmine.createSpyObj("contextCapability", ["getParent"]);
mockParent.hasCapability.andReturn(true);
mockContextCapability.getParent.andReturn(mockParent);
navigatedObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andReturn(mockContextCapability);
mockDomainObject.hasCapability.andCallFake(function (capability) {
switch (capability) {
case "editor": return false;
case "context": return true;
}
});
metadata.key = "remove";
expect(policy.allow(mockAction, context)).toBe(true);
});
it('Disallows "move" action when navigated object in edit mode,' +
' but selected object not in edit mode ', function() {
navigatedObject.hasCapability.andReturn(true);
metadata.key = "move";
expect(policy.allow(mockAction, context)).toBe(false);
});
it('Disallows copy action when navigated object and' +
' selected object in edit mode', function() {
navigatedObject.hasCapability.andReturn(true);
mockDomainObject.hasCapability.andReturn(true);
metadata.key = "copy";
expect(policy.allow(mockAction, context)).toBe(false);
});
});
}
);

View File

@@ -28,9 +28,10 @@ define([
) {
"use strict";
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss",
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss.SSS",
DATE_FORMATS = [
DATE_FORMAT,
"YYYY-MM-DD HH:mm:ss",
"YYYY-MM-DD HH:mm",
"YYYY-MM-DD"
];
@@ -48,7 +49,7 @@ define([
}
UTCTimeFormat.prototype.format = function (value) {
return moment.utc(value).format(DATE_FORMAT);
return moment.utc(value).format(DATE_FORMAT) + "Z";
};
UTCTimeFormat.prototype.parse = function (text) {

View File

@@ -40,6 +40,12 @@ define(
expect(moment.utc(formatted).valueOf()).toEqual(timestamp);
});
it("displays with millisecond precision", function () {
var timestamp = 12345670789,
formatted = format.format(timestamp);
expect(moment.utc(formatted).valueOf()).toEqual(timestamp);
});
it("validates time inputs", function () {
expect(format.validate("1977-05-25 11:21:22")).toBe(true);
expect(format.validate("garbage text")).toBe(false);

View File

@@ -49,6 +49,7 @@ define([
"./src/directives/MCTScroll",
"./src/directives/MCTSplitPane",
"./src/directives/MCTSplitter",
"./src/directives/MCTTree",
"text!./res/templates/bottombar.html",
"text!./res/templates/controls/action-button.html",
"text!./res/templates/controls/input-filter.html",
@@ -97,6 +98,7 @@ define([
MCTScroll,
MCTSplitPane,
MCTSplitter,
MCTTree,
bottombarTemplate,
actionButtonTemplate,
inputFilterTemplate,
@@ -175,10 +177,6 @@ define([
{
"stylesheetUrl": "css/normalize.min.css",
"priority": "mandatory"
},
{
"stylesheetUrl": "css/reset.css",
"priority": "mandatory"
}
],
"templates": [
@@ -389,6 +387,11 @@ define([
{
"key": "mctSplitter",
"implementation": MCTSplitter
},
{
"key": "mctTree",
"implementation": MCTTree,
"depends": [ '$parse', 'gestureService' ]
}
],
"constants": [
@@ -516,16 +519,6 @@ define([
}
],
"licenses": [
{
"name": "Modernizr",
"version": "2.6.2",
"description": "Browser/device capability finding",
"author": "Faruk Ateş",
"website": "http://modernizr.com",
"copyright": "Copyright (c) 20092015",
"license": "license-mit",
"link": "http://modernizr.com/license/"
},
{
"name": "Normalize.css",
"version": "1.1.2",
@@ -535,6 +528,16 @@ define([
"copyright": "Copyright (c) Nicolas Gallagher and Jonathan Neal",
"license": "license-mit",
"link": "https://github.com/necolas/normalize.css/blob/v1.1.2/LICENSE.md"
},
{
"name": "Zepto",
"version": "1.1.6",
"description": "DOM manipulation",
"author": "Thomas Fuchs",
"website": "http://zeptojs.com/",
"copyright": "Copyright (c) 2010-2016 Thomas Fuchs",
"license": "license-mit",
"link": "https://github.com/madrobby/zepto/blob/master/MIT-LICENSE"
}
]
}

File diff suppressed because one or more lines are too long

View File

@@ -80,7 +80,7 @@
<glyph unicode="&#xe601;" glyph-name="icon-datatable" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.8 0-512 86-512 192v-512c0-106 229.2-192 512-192s512 86 512 192v512c0-106-229.2-192-512-192zM896 385v-256c-36.6-15.6-79.8-28.8-128-39.4v256c48.2 10.6 91.4 23.8 128 39.4zM256 345.6v-256c-48.2 10.4-91.4 23.8-128 39.4v256c36.6-15.6 79.8-28.8 128-39.4zM384 70v256c41-4 83.8-6 128-6s87 2.2 128 6v-256c-41-4-83.8-6-128-6s-87 2.2-128 6z" />
<glyph unicode="&#xe602;" glyph-name="icon-tabular-scrolling" d="M64 960c-35.2 0-64-28.8-64-64v-192h448v256h-384zM1024 704v192c0 35.2-28.8 64-64 64h-384v-256h448zM0 576v-192c0-35.2 28.8-64 64-64h384v256h-448zM960 320c35.2 0 64 28.8 64 64v192h-448v-256h384zM512-64l-256 256h512z" />
<glyph unicode="&#xe603;" glyph-name="icon-alert-triangle" d="M998.208 111.136l-422.702 739.728c-34.928 61.124-92.084 61.124-127.012 0l-422.702-739.728c-34.928-61.126-5.906-111.136 64.494-111.136h843.428c70.4 0 99.422 50.010 64.494 111.136zM512 128c-35.2 0-64 28.8-64 64s28.8 64 64 64 64-28.8 64-64c0-35.2-28.8-64-64-64zM627.448 577.242l-38.898-194.486c-6.902-34.516-41.35-62.756-76.55-62.756s-69.648 28.24-76.552 62.758l-38.898 194.486c-6.902 34.516 16.25 62.756 51.45 62.756h128c35.2 0 58.352-28.24 51.448-62.758z" />
<glyph unicode="&#xe604;" glyph-name="icon-tabular" d="M0 896v-192h448v256h-384c-35.2 0-64-28.8-64-64zM960 960h-384v-256h448v192c0 35.2-28.8 64-64 64zM576 576h448v-256h-448v256zM0 576h448v-256h-448v256zM0 0c0-35.2 28.8-64 64-64h384v256h-448v-192zM576-64h384c35.2 0 64 28.8 64 64v192h-448v-256z" />
<glyph unicode="&#xe604;" glyph-name="icon-tabular" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM640 512h-256v192h256v-192zM384 448h256v-192h-256v192zM320 256h-256v192h256v-192zM320 704v-192h-256v192h256zM128 0c-17 0-33 6.6-45.2 18.8s-18.8 28.2-18.8 45.2v128h256v-192h-192zM384 0v192h256v-192h-256zM960 64c0-17-6.6-33-18.8-45.2s-28.2-18.8-45.2-18.8h-192v192h256v-128zM960 256h-256v192h256v-192zM960 512h-256v192h256v-192z" />
<glyph unicode="&#xe605;" glyph-name="icon-calendar" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM640 512h-256v192h256v-192zM384 448h256v-192h-256v192zM320 256h-256v192h256v-192zM320 704v-192h-256v192h256zM128 0c-17 0-33 6.6-45.2 18.8s-18.8 28.2-18.8 45.2v128h256v-192h-192zM384 0v192h256v-192h-256zM960 64c0-17-6.6-33-18.8-45.2s-28.2-18.8-45.2-18.8h-192v192h256v-128zM960 256h-256v192h256v-192zM960 512h-256v192h256v-192z" />
<glyph unicode="&#xe606;" glyph-name="icon-paint-bucket" d="M544 736v-224c0-88.4-71.6-160-160-160s-160 71.6-160 160v97.2l-197.4-196.4c-50-50-12.4-215.2 112.4-340s290-162.4 340-112.4l417 423.6-352 352zM896-64c70.6 0 128 57.4 128 128 0 108.6-128 192-128 192s-128-83.4-128-192c0-70.6 57.4-128 128-128zM384 448c-35.4 0-64 28.6-64 64v384c0 35.4 28.6 64 64 64s64-28.6 64-64v-384c0-35.4-28.6-64-64-64z" />
<glyph unicode="&#xe607;" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
@@ -94,8 +94,11 @@
<glyph unicode="&#xe614;" glyph-name="icon-collapse-pane-right" d="M768 960h256v-1024h-256c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192zM512 640l-512-320v640z" />
<glyph unicode="&#xe615;" glyph-name="icon-eye-open" d="M512 896c-261 0-480.6-195.4-512-448 31.4-252.6 251-448 512-448s480.6 195.4 512 448c-31.4 252.6-251 448-512 448zM768.2 225.4c-71.4-62.8-162.8-97.4-257.6-97.4s-186.2 34.6-257.6 97.4c-66.6 58.6-110.6 137.2-125 222.6 0 0 0 0.2 0 0.2 76.8 154 220.8 257.6 384 257.6s307.2-103.8 384-257.6c0 0 0-0.2 0-0.2-14.4-85.4-61.2-164-127.8-222.6zM512 672c-123.8 0-224-100.2-224-224s100.2-224 224-224 224 100.2 224 224-100.2 224-224 224z" />
<glyph unicode="&#xe616;" glyph-name="icon-eye-open-no-gleam" d="M512 896c-261 0-480.6-195.4-512-448 31.4-252.6 251-448 512-448s480.6 195.4 512 448c-31.4 252.6-251 448-512 448zM768.2 225.4c-71.4-62.8-162.8-97.4-257.6-97.4s-186.2 34.6-257.6 97.4c-66.6 58.6-110.6 137.2-125 222.6 0 0 0 0.2 0 0.2 76.8 154 220.8 257.6 384 257.6s307.2-103.8 384-257.6c0 0 0-0.2 0-0.2-14.4-85.4-61.2-164-127.8-222.6zM512 672c-123.8 0-224-100.2-224-224s100.2-224 224-224 224 100.2 224 224-100.2 224-224 224zM576 416c-53 0-96 43-96 96s43 96 96 96 96-43 96-96c0-53-43-96-96-96z" />
<glyph unicode="&#xe617;" glyph-name="icon-topic" d="M546.4 528.8l32 24c31.6 23.8 91.6 23.8 123.2 0l32-24c10.8-8 22.2-15.2 34.4-21.4v201.2c-38 19.6-82.2 30-128 30-60.4 0-118.2-18.2-162.4-51.4l-32-24c-31.6-23.8-91.6-23.8-123.2 0l-32 24c-10.8 8-22.2 15.2-34.4 21.4v-201.2c38-19.6 82.2-30 128-30 60.4 0 118.2 18.2 162.4 51.4zM640 418.6c-60.4 0-118.2-18.2-162.4-51.4l-32-24c-31.6-23.8-91.6-23.8-123.2 0l-32 24c-10.8 8-22.2 15.2-34.4 21.4v-201.2c38-19.6 82.2-30 128-30 60.4 0 118.2 18.2 162.4 51.4l32 24c31.6 23.8 91.6 23.8 123.2 0l32-24c10.8-8 22.2-15.2 34.4-21.4v201.2c-38 19.6-82.2 30-128 30zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM320 128h-127.6c-0.2 0-0.2 0.2-0.4 0.4v639.4c0 0.2 0.2 0.2 0.4 0.4h127.6v191.8h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192z" />
<glyph unicode="&#xe618;" glyph-name="icon-session" d="M923 521.8l-151 100.6c-36 24-103.8 24-139.8 0l-151-100.6c-44.6-29.8-102.6-46.2-163-46.2s-118.4 16.4-163 46.2l-151.4 100.6c-1.8 1.2-3.8 2.4-5.8 3.6v-208c36.6-7.4 70.6-20.8 99-39.8l151-100.6c36-24 103.8-24 139.8 0l151 100.6c44.6 29.8 102.6 46.2 163 46.2s118.4-16.4 163-46.2l151-100.6c1.8-1.2 3.8-2.4 5.8-3.6v208c-36.2 7.2-70.2 20.8-98.6 39.8zM923 137.8l-151 100.6c-36 24-103.8 24-139.8 0l-151-100.6c-44.6-29.8-102.6-46.2-163-46.2s-118.4 16.4-163 46.2l-151.4 100.6c-1.8 1.2-3.8 2.4-5.8 3.6v-112c0-105.6 86.4-192 192-192h640c94.8 0 174.2 69.8 189.4 160.4-35.6 7.4-68.6 20.8-96.4 39.4zM97 762.2l151-100.6c36-24 103.8-24 139.8 0l151 100.6c44.8 29.8 102.6 46.2 163.2 46.2s118.4-16.4 163-46.2l151-100.6c1.8-1.2 3.8-2.4 5.8-3.6v112c0 105.6-86.4 192-192 192h-639.8c-94.8 0-174.2-69.8-189.4-160.4 35.6-7.4 68.6-20.8 96.4-39.4z" />
<glyph unicode="&#xe617;" glyph-name="icon-topic" d="M454.36 483.36l86.3 86.3c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c19.328-19.358 42.832-34.541 69.047-44.082l1.313 171.722-57.64 57.64c-34.407 34.33-81.9 55.558-134.35 55.558s-99.943-21.228-134.354-55.562l-86.296-86.297c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-28.674 28.654v-172.14c19.045-7.022 41.040-11.084 63.984-11.084 52.463 0 99.966 21.239 134.379 55.587zM505.64 412.64l-86.3-86.3c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-86.294 86.294c-2 2-4.2 4-6.36 6v-197.36c33.664-30.72 78.65-49.537 128.031-49.537 52.44 0 99.923 21.22 134.333 55.541l86.296 86.296c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c2-2 4.2-4 6.36-6v197.36c-33.664 30.72-78.65 49.537-128.031 49.537-52.44 0-99.923-21.22-134.333-55.541zM832 960h-128v-192h127.66l0.34-0.34v-639.32l-0.34-0.34h-127.66v-192h128c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM320 128h-127.66l-0.34 0.34v639.32l0.34 0.34h127.66v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192z" />
<glyph unicode="&#xe618;" glyph-name="icon-session" d="M635.6 435.6c6.6-4.2 13.2-8.6 19.2-13.6l120.4-96.4c29.6-23.8 83.8-23.8 113.4 0l135.2 108c0.2 4.8 0.2 9.4 0.2 14.2 0 52.2-7.8 102.4-22.2 149.8l-154.8-123.6c-58.2-46.6-140.2-59.2-211.4-38.4zM248.6 325.8l120.4 96.4c58 46.4 140 59.2 211.2 38.4-6.6 4.2-13.2 8.6-19.2 13.6l-120.4 96.4c-29.6 23.8-83.8 23.8-113.4 0l-120.2-96.6c-40-32-91.4-48-143-48-21.6 0-43 2.8-63.8 8.4 0-0.6 0-1.2 0-1.6 5-3.4 10-6.8 14.6-10.6l120.4-96.4c29.8-23.8 83.8-23.8 113.4 0zM120.6 581.8l120.4 96.4c80.2 64.2 205.6 64.2 285.8 0l120.4-96.4c29.6-23.8 83.8-23.8 113.4 0l181 144.8c-91.2 140.4-249.6 233.4-429.6 233.4-238.6 0-439.2-163.2-496-384.2 30.8-17.6 77.8-15.6 104.6 6zM689 218l-120.4 96.4c-29.6 23.8-83.8 23.8-113.4 0l-120.2-96.4c-40-32-91.4-48-143-48-47.8 0-95.4 13.8-134.2 41.4 85.6-163.6 256.8-275.4 454.2-275.4s368.6 111.8 454.2 275.4c-80.4-57.4-199.8-55.2-277.2 6.6z" />
<glyph unicode="&#xe619;" glyph-name="icon-bullet" d="M832 208c0-44-36-80-80-80h-480c-44 0-80 36-80 80v480c0 44 36 80 80 80h480c44 0 80-36 80-80v-480z" />
<glyph unicode="&#xe620;" glyph-name="icon-tabular-realtime" d="M896 960h-768c-70.606-0.215-127.785-57.394-128-127.979v-768.021c0.215-70.606 57.394-127.785 127.979-128h768.021c70.606 0.215 127.785 57.394 128 127.979v768.021c-0.215 70.606-57.394 127.785-127.979 128zM448 668l25.060-25.32c7.916-7.922 18.856-12.822 30.94-12.822s23.024 4.9 30.94 12.822l75.5 76.3c29.97 30.338 71.571 49.128 117.56 49.128s87.59-18.79 117.544-49.112l50.456-50.997v-152.2c-24.111 8.83-44.678 22.255-61.542 39.342l-75.518 76.318c-7.916 7.922-18.856 12.822-30.94 12.822s-23.024-4.9-30.94-12.822l-75.5-76.3c-29.971-30.343-71.575-49.137-117.568-49.137-20.084 0-39.331 3.584-57.137 10.146l1.145 151.831zM320 0h-192c-35.26 0.214-63.786 28.74-64 63.98v128.020h256v-192zM320 256h-256v192h256v-192zM320 512h-256v192h256v-192zM640 0h-256v192h256v-192zM448 323.38v174.5c1.88-1.74 3.74-3.5 5.56-5.34l75.5-76.3c7.916-7.922 18.856-12.822 30.94-12.822s23.024 4.9 30.94 12.822l75.5 76.3c29.966 30.333 71.56 49.119 117.542 49.119 43.28 0 82.673-16.644 112.128-43.879l-0.11-174.399c-1.88 1.74-3.74 3.5-5.56 5.34l-75.5 76.3c-7.916 7.922-18.856 12.822-30.94 12.822s-23.024-4.9-30.94-12.822l-75.5-76.3c-29.966-30.333-71.56-49.119-117.542-49.119-43.28 0-82.673 16.644-112.128 43.879zM960 64c-0.214-35.26-28.74-63.786-63.98-64h-192.020v192h256v-128z" />
<glyph unicode="&#xe621;" glyph-name="icon-tabular-lad" d="M896 960h-768c-70.606-0.215-127.785-57.394-128-127.979v-768.021c0.215-70.606 57.394-127.785 127.979-128h768.021c70.606 0.215 127.785 57.394 128 127.979v768.021c-0.215 70.606-57.394 127.785-127.979 128zM64 704h256v-192h-256v192zM64 448h256v-192h-256v192zM128 0c-35.26 0.214-63.786 28.74-64 63.98v128.020h256v-192h-192zM384 0v192h256v-192h-256zM960 64c-0.214-35.26-28.74-63.786-63.98-64h-192.020v192h256v-128zM960 448v-192h-576v192h64v64h-64v192h576v-192h-64v-64h64zM782.32 412.62l-110.32 55.16v172.22c0 17.673-14.327 32-32 32s-32-14.327-32-32v-211.78l145.68-72.84c4.172-2.133 9.1-3.383 14.32-3.383 17.675 0 32.003 14.328 32.003 32.003 0 12.454-7.114 23.247-17.501 28.536z" />
<glyph unicode="&#xe622;" glyph-name="icon-tabular-lad-set" d="M128 192v576c-70.606-0.215-127.785-57.394-128-127.979v-576.021c0.215-70.606 57.394-127.785 127.979-128h576.021c70.606 0.215 127.785 57.394 128 127.979l-576 0.021c-70.606 0.215-127.785 57.394-128 127.979zM896 960h-576c-70.606-0.215-127.785-57.394-128-127.979v-576.021c0.215-70.606 57.394-127.785 127.979-128h576.021c70.606 0.215 127.785 57.394 128 127.979v576.021c-0.215 70.606-57.394 127.785-127.979 128zM256 768h192v-128h-192v128zM256 576h192v-192h-192v192zM320 192c-35.26 0.214-63.786 28.74-64 63.98v64.020h192v-128h-128zM512 192v128h192v-128h-192zM960 256c-0.214-35.26-28.74-63.786-63.98-64h-128.020v128h192v-64zM960 384h-448v384h448v-384zM832 480c0.002 0 0.005 0 0.007 0 17.673 0 32 14.327 32 32 0 14.055-9.062 25.994-21.662 30.293l-74.345 24.767v104.94c0 17.673-14.327 32-32 32s-32-14.327-32-32v-151.060l117.88-39.3c3.018-1.040 6.495-1.64 10.113-1.64 0.003 0 0.005 0 0.008 0z" />
<glyph unicode="&#xe642;" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -98,6 +98,11 @@ $bubbleMaxW: 300px;
$reqSymbolW: 15px;
$reqSymbolM: $interiorMargin * 2;
$reqSymbolFontSize: 0.7em;
// Wait Spinner Defaults
$waitSpinnerD: 32px;
$waitSpinnerTreeD: 20px;
$waitSpinnerBorderW: 5px;
$waitSpinnerTreeBorderW: 4px;
/************************** CONTROLS */
$controlDisabledOpacity: 0.3;

View File

@@ -53,7 +53,6 @@ body, html {
font-weight: 200;
height: 100%;
width: 100%;
overflow: hidden;
}
em {
@@ -85,6 +84,8 @@ p {
margin-bottom: $interiorMarginLg;
}
ol, ul { padding-left: 0; }
mct-container {
display: block;
}

View File

@@ -61,9 +61,24 @@
.l-inspector-part {
box-sizing: border-box;
padding-right: $interiorMargin;
.form {
.tree .form {
margin-left: $treeVCW + $interiorMarginLg;
margin-bottom: $interiorMarginLg;
}
.section-header {
background: none;
color: $colorInspectorPropName;
border-radius: unset;
font-size: inherit;
padding: $interiorMarginSm 0;
}
mct-form:not(:last-child) .form {
border-bottom: 1px solid $colorInspectorSectionHeaderBg;
}
.form {
margin-bottom: $interiorMarginSm;
padding-bottom: $interiorMarginLg;
.form-section {
margin-bottom: 0;
&:not(.first) {
@@ -72,7 +87,14 @@
.form-row {
@include align-items(center);
border: none;
padding: 0;
padding: $interiorMarginSm 0;
.label {
min-width: 80px;
}
input[type='text'],
input[type='search'] {
width: 100%;
}
}
}
}

View File

@@ -45,7 +45,6 @@
/********************************* FORMS */
@import "forms/elems";
@import "forms/selects";
@import "forms/channel-selector";
@import "forms/datetime";
@import "forms/validation";

View File

@@ -35,15 +35,15 @@
}
}
mct-representation {
mct-representation,
.rep-object-label {
&.s-status-pending {
.t-object-label {
.t-item-icon {
&:before {
$spinBW: 4px;
@include spinner($spinBW);
@include spinner($waitSpinnerTreeBorderW, $colorLoadingFg);
content: "";
padding: 30%;
height: $waitSpinnerTreeD; width: $waitSpinnerTreeD;
}
.t-item-icon-glyph {
display: none;
@@ -57,7 +57,10 @@ mct-representation {
}
}
.selected mct-representation.s-status-pending .t-object-label .t-item-icon:before {
border-color: rgba($colorItemTreeSelectedFg, 0.25) !important;
border-top-color: rgba($colorItemTreeSelectedFg, 1.0) !important;
.selected mct-representation,
.selected .rep-object-label {
.s-status-pending .t-object-label .t-item-icon:before {
border-color: rgba($colorItemTreeSelectedFg, 0.25) !important;
border-top-color: rgba($colorItemTreeSelectedFg, 1.0) !important;
}
}

View File

@@ -76,6 +76,11 @@ $pad: $interiorMargin * $baseRatio;
font-family: symbolsfont;
margin-right: $interiorMarginSm;
}
&.t-save-as:before {
content:'\e612';
font-family: symbolsfont;
margin-right: $interiorMarginSm;
}
&.t-cancel {
.title-label { display: none; }
&:before {

View File

@@ -74,6 +74,12 @@
.l-composite-control {
vertical-align: middle;
&:not(.l-inline) {
margin-bottom: $interiorMargin;
}
&.l-inline {
display: inline-block;
}
&.l-checkbox {
.composite-control-label {
line-height: 18px;
@@ -108,12 +114,14 @@
font-size: 0.7rem;
}
/******************************************************** CUSTOM CHECKBOXES */
label.checkbox.custom,
label.radio.custom {
$bg: pullForward($colorBodyBg, 10%);
$d: $formRowCtrlsH;
cursor: pointer;
display: inline-block;
line-height: 120%;
margin-right: $interiorMargin * 4;
padding-left: $d + $interiorMargin;
position: relative;
@@ -161,7 +169,40 @@ label.radio.custom {
label.checkbox.custom input:checked ~ em:before { content: "\32"; }
label.radio.custom input:checked ~ em:before { content: "\e619"; }
.s-menu-btn label.checkbox.custom {
margin-left: 5px;
}
.item .checkbox {
&.checked label {
box-shadow: none;
border-bottom: none;
}
}
label.form-control.checkbox {
input {
margin-right: $interiorMargin;
vertical-align: top;
}
}
/******************************************************** INPUTS */
input[type="text"],
input[type="search"] {
@include nice-input();
&.numeric {
text-align: right;
}
}
.l-input-lg input[type="text"] { width: 100% !important; }
.l-input-med input[type="text"] { width: 200px !important; }
.l-input-sm input[type="text"] { width: 50px !important; }
.l-numeric input[type="text"] { text-align: right; }
.input-labeled {
// Used in toolbar
margin-left: $interiorMargin;
label {
display: inline-block;
@@ -175,28 +216,36 @@ label.radio.custom input:checked ~ em:before { content: "\e619"; }
}
}
.s-menu-btn label.checkbox.custom {
margin-left: 5px;
}
.item .checkbox {
&.checked label {
box-shadow: none;
border-bottom: none;
/******************************************************** SELECTS */
.select {
@include btnSubtle($colorSelectBg);
@if $shdwBtns != none {
margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
}
}
.context-available,
.s-icon-btn {
$c: $colorKey;
color: $c;
&:hover {
color: lighten($c, 10%);
padding: 0 $interiorMargin;
overflow: hidden;
position: relative;
line-height: $formInputH;
select {
@include appearance(none);
box-sizing: border-box;
background: none;
color: $colorSelectFg;
cursor: pointer;
border: none !important;
padding: 4px 25px 2px 0px;
width: 130%;
option {
margin: $interiorMargin 0; // Firefox
}
}
&:after {
@include contextArrow();
pointer-events: none;
color: rgba($colorSelectFg, percentToDecimal($contrastInvokeMenuPercent));
position: absolute;
right: $interiorMargin; top: 0;
}
}
.view-switcher {
@include trans-prop-nice-fade($controlFadeMs);
}
/******************************************************** OBJECT-HEADER */
@@ -330,7 +379,6 @@ body.desktop .object-header {
}
/******************************************************** SLIDERS */
.slider {
$knobH: 100%;
.slot {
@@ -424,7 +472,7 @@ body.desktop .object-header {
border-top: 1px solid $colorInteriorBorder
}
.l-time-selects {
line-height: $formInputH;
line-height: inherit;
}
}
@@ -478,11 +526,31 @@ body.desktop .object-header {
}
}
/******************************************************** BROWSER ELEMENTS */
/******************************************************** TEXTAREA */
textarea {
@include nice-textarea($colorInputBg, $colorInputFg);
position: absolute;
height: 100%;
width: 100%;
}
/******************************************************** MISC */
.context-available,
.s-icon-btn {
$c: $colorKey;
color: $c;
&:hover {
color: lighten($c, 10%);
}
}
.view-switcher {
@include trans-prop-nice-fade($controlFadeMs);
}
/******************************************************** BROWSER ELEMENTS */
body.desktop {
::-webkit-scrollbar {
border-radius: 2px;
box-sizing: border-box;
box-shadow: inset $scrollbarTrackShdw;
background-color: $scrollbarTrackColorBg;
@@ -491,15 +559,15 @@ body.desktop {
}
::-webkit-scrollbar-thumb {
$bg: $scrollbarThumbColor;
$hc: $scrollbarThumbColorHov;
$gr: 5%;
@include background-image(linear-gradient(lighten($bg, $gr), $bg 20px));
border-radius: 2px;
box-sizing: border-box;
&:hover {
@include background-image(linear-gradient(lighten($hc, $gr), $hc 20px));
}
background: $scrollbarThumbColor;
&:hover { background: $scrollbarThumbColorHov; }
}
.overlay ::-webkit-scrollbar-thumb {
$lr: 15%;
background: $scrollbarThumbColorOverlay;
&:hover { background: $scrollbarThumbColorOverlayHov; }
}
::-webkit-scrollbar-corner {

View File

@@ -51,9 +51,6 @@
.title-label {
font-size: 1rem;
}
//&:after {
// color: rgba($colorInvokeMenu, 0.5);
//}
}
.menu {
@@ -113,12 +110,13 @@
.menu,
.context-menu,
.super-menu {
.super-menu,
.s-menu-btn .menu {
pointer-events: auto;
ul li {
//padding-left: 25px;
a {
color: $colorMenuFg;
display: block;
}
.icon {
color: $colorMenuIc;
@@ -126,9 +124,6 @@
.type-icon {
left: $interiorMargin;
}
&:hover .icon {
//color: lighten($colorMenuIc, 5%);
}
}
}
@@ -146,7 +141,7 @@
height: $d;
width: $d;
&:before {
font-size: 7px !important;// $d/2;
font-size: 7px !important;
height: $d;
width: $d;
line-height: $d;
@@ -173,7 +168,6 @@
.pane {
box-sizing: border-box;
&.left {
//@include test();
border-right: 1px solid pullForward($colorMenuBg, 10%);
left: 0;
padding-right: $interiorMargin;
@@ -190,7 +184,6 @@
}
}
&.right {
//@include test(red);
left: auto;
right: 0;
padding: $interiorMargin * 5;
@@ -216,7 +209,6 @@
margin-bottom: 0.5em;
}
&.description {
//color: lighten($colorMenuBg, 30%);
color: $colorCreateMenuText;
font-size: 0.8em;
line-height: 1.5em;
@@ -258,4 +250,4 @@
left: auto;
right: 0;
width: auto;
}
}

View File

@@ -1,54 +1,42 @@
@mixin toiLineHovEffects() {
//@include pulse(.25s);
&:before,
&:after {
background-color: $timeControllerToiLineColorHov;
}
}
mct-include.l-time-controller {
.l-time-controller {
$minW: 500px;
$knobHOffset: 0px;
$knobM: ($sliderKnobW + $knobHOffset) * -1;
$rangeValPad: $interiorMargin;
$rangeValOffset: $sliderKnobW;
//$knobCr: $sliderKnobW;
$timeRangeSliderLROffset: 130px + $sliderKnobW + $rangeValOffset;
$r1H: nth($ueTimeControlH,1);
$r2H: nth($ueTimeControlH,2);
$r3H: nth($ueTimeControlH,3);
//@include absPosDefault();
//@include test();
display: block;
//top: auto;
height: $r1H + $r2H + $r3H + ($interiorMargin * 2);
min-width: $minW;
font-size: 0.8rem;
.l-time-range-inputs-holder,
.l-time-range-slider {
//font-size: 0.8em;
}
.l-time-range-inputs-holder,
.l-time-range-slider-holder,
.l-time-range-ticks-holder
{
//@include test();
@include absPosDefault(0, visible);
box-sizing: border-box;
top: auto;
}
.l-time-range-slider,
.l-time-range-ticks {
//@include test(red, 0.1);
@include absPosDefault(0, visible);
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
}
.l-time-range-inputs-holder {
//@include test(red);
height: $r1H; bottom: $r2H + $r3H + ($interiorMarginSm * 2);
padding-top: $interiorMargin;
border-top: 1px solid $colorInteriorBorder;
@@ -70,7 +58,6 @@ mct-include.l-time-controller {
}
.l-time-range-slider-holder {
//@include test(green);
height: $r2H; bottom: $r3H + ($interiorMarginSm * 1);
.range-holder {
box-shadow: none;
@@ -82,7 +69,6 @@ mct-include.l-time-controller {
$myW: 8px;
@include transform(translateX(50%));
position: absolute;
//@include test();
top: 0; right: 0; bottom: 0px; left: auto;
width: $myW;
height: auto;
@@ -97,7 +83,6 @@ mct-include.l-time-controller {
// Vert line
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
width: 2px;
//top: 0; right: 3px; bottom: 0; left: 3px;
}
&:after {
// Circle element
@@ -114,7 +99,6 @@ mct-include.l-time-controller {
}
}
&:not(:active) {
//@include test(#ff00cc);
.knob,
.range {
@include transition-property(left, right);
@@ -155,7 +139,6 @@ mct-include.l-time-controller {
.knob {
z-index: 2;
.range-value {
//@include test($sliderColorRange);
@include trans-prop-nice-fade(.25s);
padding: 0 $rangeValOffset;
position: absolute;
@@ -167,7 +150,6 @@ mct-include.l-time-controller {
color: $sliderColorKnobHov;
}
&.knob-l {
//border-bottom-left-radius: $knobCr; // MOVED TO _CONTROLS.SCSS
margin-left: $knobM;
.range-value {
text-align: right;
@@ -175,7 +157,6 @@ mct-include.l-time-controller {
}
}
&.knob-r {
//border-bottom-right-radius: $knobCr;
margin-right: $knobM;
.range-value {
left: $rangeValOffset;
@@ -185,15 +166,189 @@ mct-include.l-time-controller {
}
}
}
.l-time-domain-selector {
position: absolute;
right: 0px;
bottom: 46px;
}
}
//.slot.range-holder {
// background-color: $sliderColorRangeHolder;
//}
.s-time-range-val {
//@include test();
border-radius: $controlCr;
background-color: $colorInputBg;
padding: 1px 1px 0 $interiorMargin;
}
}
@include phoneandtablet {
.l-time-controller, .l-time-range-inputs-holder {
min-width: 0px;
}
.l-time-controller {
.l-time-domain-selector {
select {
height: 25px;
margin-bottom: 0px;
}
}
.l-time-range-slider-holder, .l-time-range-ticks-holder {
display: none;
}
.time-range-start, .time-range-end, {
width: 100%;
}
.l-time-range-inputs-holder {
.l-time-range-input {
display: block;
.s-btn {
padding-right: 18px;
white-space: nowrap;
input {
width: 100%;
}
}
}
.l-time-range-inputs-elem {
}
}
}
}
@include phone {
.l-time-controller {
height: 48px;
.l-time-range-inputs-holder {
bottom: 24px;
}
.l-time-domain-selector {
width: 33%;
bottom: -9px;
}
.l-time-range-inputs-holder {
.l-time-range-input {
margin-bottom: 5px;
.s-btn {
width: 66%;
}
}
.l-time-range-inputs-elem {
&.ui-symbol {
display: none;
}
&.lbl {
width: 33%;
right: 0px;
top: 5px;
display: block;
height: 25px;
margin: 0;
line-height: 25px;
position: absolute;
}
}
}
}
}
@include tablet {
.l-time-controller {
height: 17px;
.l-time-range-inputs-holder {
bottom: -7px;
left: -5px;
}
.l-time-domain-selector {
width: 23%;
right: -4px;
bottom: -10px;
}
.l-time-range-inputs-holder {
.l-time-range-input {
float: left;
.s-btn {
width: 100%;
padding-left: 4px;
}
}
}
}
}
@include tabletLandscape {
.l-time-controller {
height: 17px;
.l-time-range-inputs-holder {
bottom: -7px;
}
.l-time-domain-selector {
width: 23%;
right: auto;
bottom: -10px;
left: 391px;
}
.l-time-range-inputs-holder {
.l-time-range-inputs-elem {
&.ui-symbol, &.lbl {
display: block;
float: left;
line-height: 25px;
}
}
}
}
.pane-tree-hidden .l-time-controller {
.l-time-domain-selector {
left: 667px;
}
.l-time-range-inputs-holder {
padding-left: 277px;
}
}
}
@include tabletPortrait {
.l-time-controller {
height: 17px;
.l-time-range-inputs-holder {
bottom: -7px;
left: -5px;
}
.l-time-domain-selector {
width: 23%;
right: -4px;
bottom: -10px;
}
.l-time-range-inputs-holder {
.l-time-range-input {
width: 38%;
float: left;
}
.l-time-range-inputs-elem {
&.ui-symbol, &.lbl {
display: none;
}
}
}
}
}

View File

@@ -20,13 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
.section-header {
border-radius: $basicCr;
background: $colorFormSectionHeader;
$c: lighten($colorBodyFg, 20%);
color: $c;
font-size: 0.8em;
padding: $formTBPad $formLRPad;
text-transform: uppercase;
text-transform: uppercase;
}
.form {
@@ -37,12 +31,20 @@
margin-bottom: $interiorMarginLg * 2;
}
.section-header {
border-radius: $basicCr;
background: $colorFormSectionHeader;
$c: lighten($colorBodyFg, 20%);
color: $c;
font-size: 0.8em;
padding: $formTBPad $formLRPad;
}
.form-row {
$m: $interiorMargin;
box-sizing: border-box;
@include clearfix;
border-top: 1px solid $colorFormLines;
margin-top: $m;
padding: $formTBPad 0;
position: relative;
&.first {
@@ -52,10 +54,7 @@
>.label,
>.controls {
box-sizing: border-box;
@include clearfix;
font-size: 0.8rem;
line-height: $formInputH;
min-height: $formInputH;
}
>.label {
@@ -83,27 +82,12 @@
margin-right: 5px;
}
}
.l-med input[type="text"] {
width: 200px;
}
.l-small input[type="text"] {
width: 50px;
}
.l-numeric input[type="text"] {
text-align: right;
}
.select {
margin-right: $interiorMargin;
}
}
.field-hints {
color: darken($colorBodyFg, 20%);
}
.hint, .field-hints { color: $colorFieldHint; }
.selector-list {
// Used in create overlay to display tree view
@@ -124,25 +108,31 @@
}
}
.l-controls-first {
.form .form-row {
margin-top: $interiorMarginSm;
>.label,
>.controls {
line-height: inherit;
min-height: inherit;;
}
>.label {
@include flex(1 1 auto);
min-width: 0;
width: auto;
order: 2;
}
>.controls {
@include flex(0 0 auto);
margin-right: $interiorMargin;
order: 1;
}
.l-controls-first .form .form-row,
.form .form-row.l-controls-first {
>.label,
>.controls {
line-height: inherit;
min-height: inherit;;
}
>.label {
@include flex(1 1 auto);
min-width: 0;
width: auto;
order: 2;
}
>.controls {
@include flex(0 0 auto);
margin-right: $interiorMargin;
order: 1;
}
}
.l-controls-under.l-flex-row {
// Change to use column layout
@include flex-direction(column);
.flex-elem {
margin-bottom: $interiorMarginLg;
}
}
@@ -155,13 +145,6 @@
}
}
label.form-control.checkbox {
input {
margin-right: $interiorMargin;
vertical-align: top;
}
}
.hint,
.s-hint {
font-size: 0.9em;
@@ -181,19 +164,4 @@ label.form-control.checkbox {
color: lighten($colorFormInvalid, 30%);
padding: $interiorMargin;
}
}
input[type="text"],
input[type="search"] {
@include nice-input();
&.numeric {
text-align: right;
}
}
textarea {
@include nice-textarea($colorInputBg, $colorInputFg);
position: absolute;
height: 100%;
width: 100%;
}

View File

@@ -23,9 +23,13 @@
> .label {
padding-right: $reqSymbolM; // Keep room for validation element
&::after {
float: right;
position: absolute;
right: $interiorMargin;
font-family: symbolsfont;
font-size: $reqSymbolFontSize;
height: 100%;
line-height: 200%;
}
}
&.invalid,

View File

@@ -28,7 +28,7 @@
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
}
@mixin spinner($b: 5px, $c: $colorKey) {
@mixin spinner($b: 5px, $c: $colorKey) {
@include transform-origin(center);
@include animation-name(rotation-centered);
@include animation-duration(0.5s);
@@ -46,10 +46,7 @@
}
.wait-spinner {
$d: 5%;
@include spinner(0.5em, $colorKey);
height: auto; width: auto;
padding: $d; // Will size object based on parent container WIDTH
@include spinner($waitSpinnerBorderW, $colorKey);
pointer-events: none;
z-index: 2;
&.inline {
@@ -60,15 +57,6 @@
}
}
.treeview .wait-spinner {
// Only used in subtree.html, which I don't think this is actually being used
$d: 10px;
height: $d; width: $d;
margin: 0 !important;
padding: 0 !important;
top: 2px; left: 0;
}
.loading {
// Can be applied to any block element with height and width
pointer-events: none;
@@ -77,8 +65,8 @@
content: '';
}
&:before {
@include spinner(5px, $colorLoadingFg);
padding: 5%;
@include spinner($waitSpinnerBorderW, $colorLoadingFg);
height: $waitSpinnerD; width: $waitSpinnerD;
z-index: 10;
}
&:after {
@@ -87,8 +75,22 @@
display: block;
z-index: 9;
}
&.tree-item:before {
padding: $menuLineH / 4;
border-width: 2px;
&.tree-item.t-wait-node {
$d: $waitSpinnerTreeD;
$spinnerL: $treeVCW + $interiorMargin + 3px + $d/2;
padding-left: $spinnerL + $d/2 + $interiorMargin;
.t-title-label {
font-style: italic;
opacity: 0.6;
}
&:before {
height: $d;
width: $d;
border-width: 4px;
left: $spinnerL;
}
&:after {
display: none;
}
}
}
}

View File

@@ -35,7 +35,6 @@
z-index: 100;
}
> .holder {
//$i: 15%;
@include containerSubtle($colorOvrBg, $colorOvrFg);
border-radius: $basicCr * 3;
color: $colorOvrFg;
@@ -57,15 +56,8 @@
right: $m;
bottom: $m;
left: $m;
//.top-bar,
//.editor,
//.bottom-bar {
// @include absPosDefault();
//}
}
}
.title {
@include ellipsize();
font-size: 1.2em;
@@ -73,9 +65,7 @@
margin-bottom: $interiorMargin;
}
.hint {
color: pushBack($colorOvrFg, 20%);
}
.hint, .field-hints { color: $colorFieldHintOverlay !important; }
.abs.top-bar {
height: $ovrTopBarH;
@@ -88,7 +78,7 @@
left: 0;
right: 0;
overflow: auto;
.field.l-med {
.field.l-input-med {
input[type='text'] {
width: 100%;
}
@@ -120,7 +110,6 @@
bottom: 0;
left: 0;
overflow: visible;
//font-size: 1em;
height: $ovrFooterH;
}
@@ -132,11 +121,14 @@
margin: .5em 0;
width: 100%;
}
.select {
box-shadow: $shdwBtnsOverlay;
}
}
.t-dialog-sm .overlay > .holder {
// Used for blocker and in-progress dialogs, modal alerts, etc.
//@include test(red);
$h: 225px;
min-height: $h;
height: $h;

View File

@@ -26,6 +26,10 @@
top: $m; right: $m * 1.25; bottom: $m; left: $m * 1.25;
}
body, html {
overflow: hidden;
}
.l-splash-holder {
// Main outer holder.
@include transition-property(opacity);

View File

@@ -19,15 +19,18 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div ng-controller="TimeRangeController">
<div ng-controller="TimeRangeController as trCtrl">
<form class="l-time-range-inputs-holder"
ng-submit="updateBoundsFromForm()">
ng-submit="trCtrl.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, validate: validateStart }"
structure="{
format: parameters.format,
validate: trCtrl.validateStart
}"
ng-model="formModel"
ng-blur="updateBoundsFromForm()"
ng-blur="trCtrl.updateBoundsFromForm()"
field="'start'"
class="time-range-start">
</mct-control>
@@ -37,9 +40,12 @@
<span class="l-time-range-input" ng-controller="ToggleController as t2">
<mct-control key="'datetime-field'"
structure="{ format: parameters.format, validate: validateEnd }"
structure="{
format: parameters.format,
validate: trCtrl.validateEnd
}"
ng-model="formModel"
ng-blur="updateBoundsFromForm()"
ng-blur="trCtrl.updateBoundsFromForm()"
field="'end'"
class="time-range-end">
</mct-control>&nbsp;
@@ -53,22 +59,25 @@
<div class="slider"
mct-resize="spanWidth = bounds.width">
<div class="knob knob-l"
mct-drag-down="startLeftDrag()"
mct-drag="leftDrag(delta[0])"
mct-drag-down="trCtrl.startLeftDrag()"
mct-drag="trCtrl.leftDrag(delta[0])"
ng-style="{ left: startInnerPct }">
<div class="range-value">{{startInnerText}}</div>
</div>
<div class="knob knob-r"
mct-drag-down="startRightDrag()"
mct-drag="rightDrag(delta[0])"
mct-drag-down="trCtrl.startRightDrag()"
mct-drag="trCtrl.rightDrag(delta[0])"
ng-style="{ right: endInnerPct }">
<div class="range-value">{{endInnerText}}</div>
</div>
<div class="slot range-holder">
<div class="range"
mct-drag-down="startMiddleDrag()"
mct-drag="middleDrag(delta[0])"
ng-style="{ left: startInnerPct, right: endInnerPct}">
mct-drag-down="trCtrl.startMiddleDrag()"
mct-drag="trCtrl.middleDrag(delta[0])"
ng-style="{
left: startInnerPct,
right: endInnerPct
}">
<div class="toi-line"></div>
</div>
</div>

View File

@@ -40,7 +40,7 @@
<mct-representation
key="'edit-elements'"
mct-object="domainObject"
class="flex-elem holder grows vscroll current-elements">
class="flex-elem l-flex-col holder grows current-elements">
</mct-representation>
</div>
</div>

View File

@@ -19,18 +19,6 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<ul class="tree">
<li ng-if="!composition">
<span class="tree-item">
<span class="icon wait-spinner"></span>
<span class="title-label">Loading...</span>
</span>
</li>
<li ng-repeat="child in composition">
<mct-representation key="'tree-node'"
mct-object="child"
parameters="parameters"
ng-model="ngModel">
</mct-representation>
</li>
</ul>
<mct-tree mct-object="domainObject" mct-model="ngModel.selectedObject">
</mct-tree>

View File

@@ -0,0 +1,4 @@
<span class="tree-item menus-to-left">
</span>
<span class="tree-item-subtree">
</span>

View File

@@ -0,0 +1,2 @@
<span class='ui-symbol view-control flex-elem'>
</span>

View File

@@ -0,0 +1,8 @@
<span class="rep-object-label">
<div class="t-object-label l-flex-row flex-elem grows">
<div class="t-item-icon flex-elem">
<div class="t-item-icon-glyph"></div>
</div>
<div class='t-title-label flex-elem grows'></div>
</div>
</span>

View File

@@ -19,11 +19,6 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="w1">
<div class="w2"
ng-controller="RTEventListController as rtevent">
<mct-rt-data-table headers="rtevent.headers()" rows="rtevent.rows()" ascending-scroll="true"></mct-rt-data-table>
</div>
</div>
<li class='tree-item t-wait-node loading'>
<span class="t-title-label">Loading...</span>
</li>

View File

@@ -19,247 +19,289 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/*global define*/
define(
['moment'],
function (moment) {
"use strict";
define([
var TICK_SPACING_PX = 150;
], function () {
"use strict";
var TICK_SPACING_PX = 150;
/**
* Controller used by the `time-controller` template.
* @memberof platform/commonUI/general
* @constructor
* @param $scope the Angular scope for this controller
* @param {FormatService} formatService the service to user to format
* domain values
* @param {string} defaultFormat the format to request when no
* format has been otherwise specified
* @param {Function} now a function to return current system time
*/
function TimeRangeController($scope, formatService, defaultFormat, now) {
var tickCount = 2,
innerMinimumSpan = 1000, // 1 second
outerMinimumSpan = 1000, // 1 second
initialDragValue,
formatter = formatService.getFormat(defaultFormat);
function formatTimestamp(ts) {
return formatter.format(ts);
}
// From 0.0-1.0 to "0%"-"100%"
function toPercent(p) {
return (100 * p) + "%";
}
function updateTicks() {
var i, p, ts, start, end, span;
end = $scope.ngModel.outer.end;
start = $scope.ngModel.outer.start;
span = end - start;
$scope.ticks = [];
for (i = 0; i < tickCount; i += 1) {
p = i / (tickCount - 1);
ts = p * span + start;
$scope.ticks.push(formatTimestamp(ts));
}
}
function updateSpanWidth(w) {
tickCount = Math.max(Math.floor(w / TICK_SPACING_PX), 2);
updateTicks();
}
function updateViewForInnerSpanFromModel(ngModel) {
var span = ngModel.outer.end - ngModel.outer.start;
// Expose readable dates for the knobs
$scope.startInnerText = formatTimestamp(ngModel.inner.start);
$scope.endInnerText = formatTimestamp(ngModel.inner.end);
// And positions for the knobs
$scope.startInnerPct =
toPercent((ngModel.inner.start - ngModel.outer.start) / span);
$scope.endInnerPct =
toPercent((ngModel.outer.end - ngModel.inner.end) / span);
}
function defaultBounds() {
var t = now();
return {
start: t - 24 * 3600 * 1000, // One day
end: t
};
}
function copyBounds(bounds) {
return { start: bounds.start, end: bounds.end };
}
function updateViewFromModel(ngModel) {
ngModel = ngModel || {};
ngModel.outer = ngModel.outer || defaultBounds();
ngModel.inner = ngModel.inner || copyBounds(ngModel.outer);
// Stick it back is scope (in case we just set defaults)
$scope.ngModel = ngModel;
updateViewForInnerSpanFromModel(ngModel);
updateTicks();
}
function startLeftDrag() {
initialDragValue = $scope.ngModel.inner.start;
}
function startRightDrag() {
initialDragValue = $scope.ngModel.inner.end;
}
function startMiddleDrag() {
initialDragValue = {
start: $scope.ngModel.inner.start,
end: $scope.ngModel.inner.end
};
}
function toMillis(pixels) {
var span =
$scope.ngModel.outer.end - $scope.ngModel.outer.start;
return (pixels / $scope.spanWidth) * span;
}
function clamp(value, low, high) {
return Math.max(low, Math.min(high, value));
}
function leftDrag(pixels) {
var delta = toMillis(pixels);
$scope.ngModel.inner.start = clamp(
initialDragValue + delta,
$scope.ngModel.outer.start,
$scope.ngModel.inner.end - innerMinimumSpan
);
updateViewFromModel($scope.ngModel);
}
function rightDrag(pixels) {
var delta = toMillis(pixels);
$scope.ngModel.inner.end = clamp(
initialDragValue + delta,
$scope.ngModel.inner.start + innerMinimumSpan,
$scope.ngModel.outer.end
);
updateViewFromModel($scope.ngModel);
}
function middleDrag(pixels) {
var delta = toMillis(pixels),
edge = delta < 0 ? 'start' : 'end',
opposite = delta < 0 ? 'end' : 'start';
// Adjust the position of the edge in the direction of drag
$scope.ngModel.inner[edge] = clamp(
initialDragValue[edge] + delta,
$scope.ngModel.outer.start,
$scope.ngModel.outer.end
);
// Adjust opposite knob to maintain span
$scope.ngModel.inner[opposite] = $scope.ngModel.inner[edge] +
initialDragValue[opposite] - initialDragValue[edge];
updateViewFromModel($scope.ngModel);
}
function updateFormModel() {
$scope.formModel = {
start: (($scope.ngModel || {}).outer || {}).start,
end: (($scope.ngModel || {}).outer || {}).end
};
}
function updateOuterStart(t) {
var ngModel = $scope.ngModel;
ngModel.inner.start =
Math.max(ngModel.outer.start, ngModel.inner.start);
ngModel.inner.end = Math.max(
ngModel.inner.start + innerMinimumSpan,
ngModel.inner.end
);
updateFormModel();
updateViewForInnerSpanFromModel(ngModel);
updateTicks();
}
function updateOuterEnd(t) {
var ngModel = $scope.ngModel;
ngModel.inner.end =
Math.min(ngModel.outer.end, ngModel.inner.end);
ngModel.inner.start = Math.min(
ngModel.inner.end - innerMinimumSpan,
ngModel.inner.start
);
updateFormModel();
updateViewForInnerSpanFromModel(ngModel);
updateTicks();
}
function updateFormat(key) {
formatter = formatService.getFormat(key || defaultFormat);
updateViewForInnerSpanFromModel($scope.ngModel);
updateTicks();
}
function updateBoundsFromForm() {
var start = $scope.formModel.start,
end = $scope.formModel.end;
if (end >= start + outerMinimumSpan) {
$scope.ngModel = $scope.ngModel || {};
$scope.ngModel.outer = { start: start, end: end };
}
}
function validateStart(startValue) {
return startValue <= $scope.formModel.end - outerMinimumSpan;
}
function validateEnd(endValue) {
return endValue >= $scope.formModel.start + outerMinimumSpan;
}
$scope.startLeftDrag = startLeftDrag;
$scope.startRightDrag = startRightDrag;
$scope.startMiddleDrag = startMiddleDrag;
$scope.leftDrag = leftDrag;
$scope.rightDrag = rightDrag;
$scope.middleDrag = middleDrag;
$scope.updateBoundsFromForm = updateBoundsFromForm;
$scope.validateStart = validateStart;
$scope.validateEnd = validateEnd;
$scope.ticks = [];
// Initialize scope to defaults
updateViewFromModel($scope.ngModel);
updateFormModel();
$scope.$watchCollection("ngModel", updateViewFromModel);
$scope.$watch("spanWidth", updateSpanWidth);
$scope.$watch("ngModel.outer.start", updateOuterStart);
$scope.$watch("ngModel.outer.end", updateOuterEnd);
$scope.$watch("parameters.format", updateFormat);
}
return TimeRangeController;
/* format number as percent; 0.0-1.0 to "0%"-"100%" */
function toPercent(p) {
return (100 * p) + "%";
}
);
function clamp(value, low, high) {
return Math.max(low, Math.min(high, value));
}
function copyBounds(bounds) {
return {
start: bounds.start,
end: bounds.end
};
}
/**
* Controller used by the `time-controller` template.
* @memberof platform/commonUI/general
* @constructor
* @param $scope the Angular scope for this controller
* @param {FormatService} formatService the service to user to format
* domain values
* @param {string} defaultFormat the format to request when no
* format has been otherwise specified
* @param {Function} now a function to return current system time
*/
function TimeRangeController($scope, formatService, defaultFormat, now) {
this.$scope = $scope;
this.formatService = formatService;
this.defaultFormat = defaultFormat;
this.now = now;
this.tickCount = 2;
this.innerMinimumSpan = 1000; // 1 second
this.outerMinimumSpan = 1000; // 1 second
this.initialDragValue = undefined;
this.formatter = formatService.getFormat(defaultFormat);
this.formStartChanged = false;
this.formEndChanged = false;
this.$scope.ticks = [];
this.updateViewFromModel(this.$scope.ngModel);
this.updateFormModel();
[
'updateViewFromModel',
'updateSpanWidth',
'updateOuterStart',
'updateOuterEnd',
'updateFormat',
'validateStart',
'validateEnd',
'onFormStartChange',
'onFormEndChange'
].forEach(function (boundFn) {
this[boundFn] = this[boundFn].bind(this);
}, this);
this.$scope.$watchCollection("ngModel", this.updateViewFromModel);
this.$scope.$watch("spanWidth", this.updateSpanWidth);
this.$scope.$watch("ngModel.outer.start", this.updateOuterStart);
this.$scope.$watch("ngModel.outer.end", this.updateOuterEnd);
this.$scope.$watch("parameters.format", this.updateFormat);
this.$scope.$watch("formModel.start", this.onFormStartChange);
this.$scope.$watch("formModel.end", this.onFormEndChange);
}
TimeRangeController.prototype.formatTimestamp = function (ts) {
return this.formatter.format(ts);
};
TimeRangeController.prototype.updateTicks = function () {
var i, p, ts, start, end, span;
end = this.$scope.ngModel.outer.end;
start = this.$scope.ngModel.outer.start;
span = end - start;
this.$scope.ticks = [];
for (i = 0; i < this.tickCount; i += 1) {
p = i / (this.tickCount - 1);
ts = p * span + start;
this.$scope.ticks.push(this.formatTimestamp(ts));
}
};
TimeRangeController.prototype.updateSpanWidth = function (w) {
this.tickCount = Math.max(Math.floor(w / TICK_SPACING_PX), 2);
this.updateTicks();
};
TimeRangeController.prototype.updateViewForInnerSpanFromModel = function (
ngModel
) {
var span = ngModel.outer.end - ngModel.outer.start;
// Expose readable dates for the knobs
this.$scope.startInnerText = this.formatTimestamp(ngModel.inner.start);
this.$scope.endInnerText = this.formatTimestamp(ngModel.inner.end);
// And positions for the knobs
this.$scope.startInnerPct =
toPercent((ngModel.inner.start - ngModel.outer.start) / span);
this.$scope.endInnerPct =
toPercent((ngModel.outer.end - ngModel.inner.end) / span);
};
TimeRangeController.prototype.defaultBounds = function () {
var t = this.now();
return {
start: t - 24 * 3600 * 1000, // One day
end: t
};
};
TimeRangeController.prototype.updateViewFromModel = function (ngModel) {
ngModel = ngModel || {};
ngModel.outer = ngModel.outer || this.defaultBounds();
ngModel.inner = ngModel.inner || copyBounds(ngModel.outer);
// Stick it back is scope (in case we just set defaults)
this.$scope.ngModel = ngModel;
this.updateViewForInnerSpanFromModel(ngModel);
this.updateTicks();
};
TimeRangeController.prototype.startLeftDrag = function () {
this.initialDragValue = this.$scope.ngModel.inner.start;
};
TimeRangeController.prototype.startRightDrag = function () {
this.initialDragValue = this.$scope.ngModel.inner.end;
};
TimeRangeController.prototype.startMiddleDrag = function () {
this.initialDragValue = {
start: this.$scope.ngModel.inner.start,
end: this.$scope.ngModel.inner.end
};
};
TimeRangeController.prototype.toMillis = function (pixels) {
var span =
this.$scope.ngModel.outer.end - this.$scope.ngModel.outer.start;
return (pixels / this.$scope.spanWidth) * span;
};
TimeRangeController.prototype.leftDrag = function (pixels) {
var delta = this.toMillis(pixels);
this.$scope.ngModel.inner.start = clamp(
this.initialDragValue + delta,
this.$scope.ngModel.outer.start,
this.$scope.ngModel.inner.end - this.innerMinimumSpan
);
this.updateViewFromModel(this.$scope.ngModel);
};
TimeRangeController.prototype.rightDrag = function (pixels) {
var delta = this.toMillis(pixels);
this.$scope.ngModel.inner.end = clamp(
this.initialDragValue + delta,
this.$scope.ngModel.inner.start + this.innerMinimumSpan,
this.$scope.ngModel.outer.end
);
this.updateViewFromModel(this.$scope.ngModel);
};
TimeRangeController.prototype.middleDrag = function (pixels) {
var delta = this.toMillis(pixels),
edge = delta < 0 ? 'start' : 'end',
opposite = delta < 0 ? 'end' : 'start';
// Adjust the position of the edge in the direction of drag
this.$scope.ngModel.inner[edge] = clamp(
this.initialDragValue[edge] + delta,
this.$scope.ngModel.outer.start,
this.$scope.ngModel.outer.end
);
// Adjust opposite knob to maintain span
this.$scope.ngModel.inner[opposite] =
this.$scope.ngModel.inner[edge] +
this.initialDragValue[opposite] -
this.initialDragValue[edge];
this.updateViewFromModel(this.$scope.ngModel);
};
TimeRangeController.prototype.updateFormModel = function () {
this.$scope.formModel = {
start: ((this.$scope.ngModel || {}).outer || {}).start,
end: ((this.$scope.ngModel || {}).outer || {}).end
};
};
TimeRangeController.prototype.updateOuterStart = function () {
var ngModel = this.$scope.ngModel;
ngModel.inner.start =
Math.max(ngModel.outer.start, ngModel.inner.start);
ngModel.inner.end = Math.max(
ngModel.inner.start + this.innerMinimumSpan,
ngModel.inner.end
);
this.updateFormModel();
this.updateViewForInnerSpanFromModel(ngModel);
this.updateTicks();
};
TimeRangeController.prototype.updateOuterEnd = function () {
var ngModel = this.$scope.ngModel;
ngModel.inner.end =
Math.min(ngModel.outer.end, ngModel.inner.end);
ngModel.inner.start = Math.min(
ngModel.inner.end - this.innerMinimumSpan,
ngModel.inner.start
);
this.updateFormModel();
this.updateViewForInnerSpanFromModel(ngModel);
this.updateTicks();
};
TimeRangeController.prototype.updateFormat = function (key) {
this.formatter = this.formatService.getFormat(key || this.defaultFormat);
this.updateViewForInnerSpanFromModel(this.$scope.ngModel);
this.updateTicks();
};
TimeRangeController.prototype.updateBoundsFromForm = function () {
if (this.formStartChanged) {
this.$scope.ngModel.outer.start =
this.$scope.ngModel.inner.start =
this.$scope.formModel.start;
this.formStartChanged = false;
}
if (this.formEndChanged) {
this.$scope.ngModel.outer.end =
this.$scope.ngModel.inner.end =
this.$scope.formModel.end;
this.formEndChanged = false;
}
};
TimeRangeController.prototype.onFormStartChange = function (
newValue,
oldValue
) {
if (!this.formStartChanged && newValue !== oldValue) {
this.formStartChanged = true;
}
};
TimeRangeController.prototype.onFormEndChange = function (
newValue,
oldValue
) {
if (!this.formEndChanged && newValue !== oldValue) {
this.formEndChanged = true;
}
};
TimeRangeController.prototype.validateStart = function (startValue) {
return startValue <=
this.$scope.formModel.end - this.outerMinimumSpan;
};
TimeRangeController.prototype.validateEnd = function (endValue) {
return endValue >=
this.$scope.formModel.start + this.outerMinimumSpan;
};
return TimeRangeController;
});

View File

@@ -19,40 +19,36 @@
* 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,waitsFor,jasmine*/
/*global define*/
/**
* MergeModelsSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../src/NameColumn"],
function (NameColumn) {
"use strict";
describe("A name column", function () {
var mockDomainObject,
column;
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[ "getModel" ]
);
mockDomainObject.getModel.andReturn({
name: "Test object name"
define([
'angular',
'../ui/TreeView'
], function (angular, TreeView) {
function MCTTree($parse, gestureService) {
function link(scope, element, attrs) {
var treeView = new TreeView(gestureService),
expr = $parse(attrs.mctModel),
unobserve = treeView.observe(function (domainObject) {
if (domainObject !== expr(scope.$parent)) {
expr.assign(scope.$parent, domainObject);
scope.$apply();
}
});
column = new NameColumn();
});
it("reports a column header", function () {
expect(column.getTitle()).toEqual("Name");
});
element.append(angular.element(treeView.elements()));
it("looks up name from an object's model", function () {
expect(column.getValue(mockDomainObject).text)
.toEqual("Test object name");
});
scope.$parent.$watch(attrs.mctModel, treeView.value.bind(treeView));
scope.$watch('mctObject', treeView.model.bind(treeView));
scope.$on('$destroy', unobserve);
}
});
return {
restrict: "E",
link: link,
scope: { mctObject: "=" }
};
}
);
return MCTTree;
});

View File

@@ -0,0 +1,65 @@
/*****************************************************************************
* 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([
'zepto',
'text!../../res/templates/tree/toggle.html'
], function ($, toggleTemplate) {
function ToggleView(state) {
this.expanded = !!state;
this.callbacks = [];
this.el = $(toggleTemplate);
this.el.on('click', function () {
this.value(!this.expanded);
}.bind(this));
}
ToggleView.prototype.value = function (state) {
this.expanded = state;
if (state) {
this.el.addClass('expanded');
} else {
this.el.removeClass('expanded');
}
this.callbacks.forEach(function (callback) {
callback(state);
});
};
ToggleView.prototype.observe = function (callback) {
this.callbacks.push(callback);
return function () {
this.callbacks = this.callbacks.filter(function (c) {
return c !== callback;
});
}.bind(this);
};
ToggleView.prototype.elements = function () {
return this.el;
};
return ToggleView;
});

View File

@@ -0,0 +1,90 @@
/*****************************************************************************
* 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([
'zepto',
'text!../../res/templates/tree/tree-label.html'
], function ($, labelTemplate) {
'use strict';
function TreeLabelView(gestureService) {
this.el = $(labelTemplate);
this.gestureService = gestureService;
}
function getGlyph(domainObject) {
var type = domainObject.getCapability('type');
return type.getGlyph();
}
function isLink(domainObject) {
var location = domainObject.getCapability('location');
return location.isLink();
}
TreeLabelView.prototype.updateView = function (domainObject) {
var titleEl = this.el.find('.t-title-label'),
glyphEl = this.el.find('.t-item-icon-glyph'),
iconEl = this.el.find('.t-item-icon');
titleEl.text(domainObject ? domainObject.getModel().name : "");
glyphEl.text(domainObject ? getGlyph(domainObject) : "");
if (domainObject && isLink(domainObject)) {
iconEl.addClass('l-icon-link');
} else {
iconEl.removeClass('l-icon-link');
}
};
TreeLabelView.prototype.model = function (domainObject) {
if (this.unlisten) {
this.unlisten();
delete this.unlisten;
}
if (this.activeGestures) {
this.activeGestures.destroy();
delete this.activeGestures;
}
this.updateView(domainObject);
if (domainObject) {
this.unlisten = domainObject.getCapability('mutation')
.listen(this.updateView.bind(this, domainObject));
this.activeGestures = this.gestureService.attachGestures(
this.elements(),
domainObject,
[ 'info', 'menu', 'drag' ]
);
}
};
TreeLabelView.prototype.elements = function () {
return this.el;
};
return TreeLabelView;
});

View File

@@ -0,0 +1,157 @@
/*****************************************************************************
* 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([
'zepto',
'text!../../res/templates/tree/node.html',
'./ToggleView',
'./TreeLabelView'
], function ($, nodeTemplate, ToggleView, TreeLabelView) {
'use strict';
function TreeNodeView(gestureService, subtreeFactory, selectFn) {
this.li = $('<li>');
this.statusClasses = [];
this.toggleView = new ToggleView(false);
this.toggleView.observe(function (state) {
if (state) {
if (!this.subtreeView) {
this.subtreeView = subtreeFactory();
this.subtreeView.model(this.activeObject);
this.li.find('.tree-item-subtree').eq(0)
.append($(this.subtreeView.elements()));
}
$(this.subtreeView.elements()).removeClass('hidden');
} else if (this.subtreeView) {
$(this.subtreeView.elements()).addClass('hidden');
}
}.bind(this));
this.labelView = new TreeLabelView(gestureService);
$(this.labelView.elements()).on('click', function () {
selectFn(this.activeObject);
}.bind(this));
this.li.append($(nodeTemplate));
this.li.find('span').eq(0)
.append($(this.toggleView.elements()))
.append($(this.labelView.elements()));
this.model(undefined);
}
TreeNodeView.prototype.updateStatusClasses = function (statuses) {
this.statusClasses.forEach(function (statusClass) {
this.li.removeClass(statusClass);
}.bind(this));
this.statusClasses = statuses.map(function (status) {
return 's-status-' + status;
});
this.statusClasses.forEach(function (statusClass) {
this.li.addClass(statusClass);
}.bind(this));
};
TreeNodeView.prototype.model = function (domainObject) {
if (this.unlisten) {
this.unlisten();
}
this.activeObject = domainObject;
if (domainObject && domainObject.hasCapability('composition')) {
$(this.toggleView.elements()).addClass('has-children');
} else {
$(this.toggleView.elements()).removeClass('has-children');
}
if (domainObject && domainObject.hasCapability('status')) {
this.unlisten = domainObject.getCapability('status')
.listen(this.updateStatusClasses.bind(this));
this.updateStatusClasses(
domainObject.getCapability('status').list()
);
}
this.labelView.model(domainObject);
if (this.subtreeView) {
this.subtreeView.model(domainObject);
}
};
function getIdPath(domainObject) {
var context = domainObject && domainObject.getCapability('context');
function getId(domainObject) {
return domainObject.getId();
}
return context ? context.getPath().map(getId) : [];
}
TreeNodeView.prototype.value = function (domainObject) {
var activeIdPath = getIdPath(this.activeObject),
selectedIdPath = getIdPath(domainObject);
if (this.onSelectionPath) {
this.li.find('.tree-item').eq(0).removeClass('selected');
if (this.subtreeView) {
this.subtreeView.value(undefined);
}
}
this.onSelectionPath =
!!domainObject &&
!!this.activeObject &&
(activeIdPath.length <= selectedIdPath.length) &&
activeIdPath.every(function (id, index) {
return selectedIdPath[index] === id;
});
if (this.onSelectionPath) {
if (activeIdPath.length === selectedIdPath.length) {
this.li.find('.tree-item').eq(0).addClass('selected');
} else {
// Expand to reveal the selection
this.toggleView.value(true);
this.subtreeView.value(domainObject);
}
}
};
/**
*
* @returns {HTMLElement[]}
*/
TreeNodeView.prototype.elements = function () {
return this.li;
};
return TreeNodeView;
});

View File

@@ -0,0 +1,141 @@
/*****************************************************************************
* 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([
'zepto',
'./TreeNodeView',
'text!../../res/templates/tree/wait-node.html'
], function ($, TreeNodeView, spinnerTemplate) {
'use strict';
function TreeView(gestureService, selectFn) {
this.ul = $('<ul class="tree"></ul>');
this.nodeViews = [];
this.callbacks = [];
this.selectFn = selectFn || this.value.bind(this);
this.gestureService = gestureService;
this.pending = false;
}
TreeView.prototype.newTreeView = function () {
return new TreeView(this.gestureService, this.selectFn);
};
TreeView.prototype.setSize = function (sz) {
var nodeView;
while (this.nodeViews.length < sz) {
nodeView = new TreeNodeView(
this.gestureService,
this.newTreeView.bind(this),
this.selectFn
);
this.nodeViews.push(nodeView);
this.ul.append($(nodeView.elements()));
}
while (this.nodeViews.length > sz) {
nodeView = this.nodeViews.pop();
$(nodeView.elements()).remove();
}
};
TreeView.prototype.loadComposition = function () {
var self = this,
domainObject = this.activeObject;
function addNode(domainObject, index) {
self.nodeViews[index].model(domainObject);
}
function addNodes(domainObjects) {
if (self.pending) {
self.pending = false;
self.nodeViews = [];
self.ul.empty();
}
if (domainObject === self.activeObject) {
self.setSize(domainObjects.length);
domainObjects.forEach(addNode);
self.updateNodeViewSelection();
}
}
domainObject.useCapability('composition')
.then(addNodes);
};
TreeView.prototype.model = function (domainObject) {
if (this.unlisten) {
this.unlisten();
}
this.activeObject = domainObject;
this.ul.empty();
if (domainObject && domainObject.hasCapability('composition')) {
this.pending = true;
this.ul.append($(spinnerTemplate));
this.unlisten = domainObject.getCapability('mutation')
.listen(this.loadComposition.bind(this));
this.loadComposition(domainObject);
} else {
this.setSize(0);
}
};
TreeView.prototype.updateNodeViewSelection = function () {
this.nodeViews.forEach(function (nodeView) {
nodeView.value(this.selectedObject);
}.bind(this));
};
TreeView.prototype.value = function (domainObject) {
this.selectedObject = domainObject;
this.updateNodeViewSelection();
this.callbacks.forEach(function (callback) {
callback(domainObject);
});
};
TreeView.prototype.observe = function (callback) {
this.callbacks.push(callback);
return function () {
this.callbacks = this.callbacks.filter(function (c) {
return c !== callback;
});
}.bind(this);
};
/**
*
* @returns {HTMLElement[]}
*/
TreeView.prototype.elements = function () {
return this.ul;
};
return TreeView;
});

View File

@@ -94,18 +94,18 @@ define(
it("exposes start time validator", function () {
var testValue = 42000000;
mockScope.formModel = { end: testValue };
expect(mockScope.validateStart(testValue + 1))
expect(controller.validateStart(testValue + 1))
.toBe(false);
expect(mockScope.validateStart(testValue - 60 * 60 * 1000 - 1))
expect(controller.validateStart(testValue - 60 * 60 * 1000 - 1))
.toBe(true);
});
it("exposes end time validator", function () {
var testValue = 42000000;
mockScope.formModel = { start: testValue };
expect(mockScope.validateEnd(testValue - 1))
expect(controller.validateEnd(testValue - 1))
.toBe(false);
expect(mockScope.validateEnd(testValue + 60 * 60 * 1000 + 1))
expect(controller.validateEnd(testValue + 60 * 60 * 1000 + 1))
.toBe(true);
});
@@ -119,25 +119,87 @@ define(
start: DAY * 10000,
end: DAY * 11000
};
// These watches may not exist, but Angular would fire
// them if they did.
});
it('updates all changed bounds when requested', function () {
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.inner.start)
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.not.toEqual(mockScope.formModel.end);
expect(mockScope.ngModel.inner.end)
.not.toEqual(mockScope.formModel.end);
controller.updateBoundsFromForm();
expect(mockScope.ngModel.outer.start)
.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.inner.start)
.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.toEqual(mockScope.formModel.end);
expect(mockScope.ngModel.inner.end)
.toEqual(mockScope.formModel.end);
});
it('updates changed start bound when requested', function () {
fireWatchCollection("formModel", mockScope.formModel);
fireWatch("formModel.start", mockScope.formModel.start);
expect(mockScope.ngModel.outer.start)
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.inner.start)
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.not.toEqual(mockScope.formModel.end);
expect(mockScope.ngModel.inner.end)
.not.toEqual(mockScope.formModel.end);
controller.updateBoundsFromForm();
expect(mockScope.ngModel.outer.start)
.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.inner.start)
.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.not.toEqual(mockScope.formModel.end);
expect(mockScope.ngModel.inner.end)
.not.toEqual(mockScope.formModel.end);
});
it("updates model bounds on request", function () {
mockScope.updateBoundsFromForm();
it('updates changed end bound when requested', function () {
fireWatchCollection("formModel", mockScope.formModel);
fireWatch("formModel.end", mockScope.formModel.end);
expect(mockScope.ngModel.outer.start)
.toEqual(mockScope.formModel.start);
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.inner.start)
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.not.toEqual(mockScope.formModel.end);
expect(mockScope.ngModel.inner.end)
.not.toEqual(mockScope.formModel.end);
controller.updateBoundsFromForm();
expect(mockScope.ngModel.outer.start)
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.inner.start)
.not.toEqual(mockScope.formModel.start);
expect(mockScope.ngModel.outer.end)
.toEqual(mockScope.formModel.end);
expect(mockScope.ngModel.inner.end)
.toEqual(mockScope.formModel.end);
});
});
@@ -160,27 +222,27 @@ define(
});
it("updates the start time for left drags", function () {
mockScope.startLeftDrag();
mockScope.leftDrag(250);
controller.startLeftDrag();
controller.leftDrag(250);
expect(mockScope.ngModel.inner.start)
.toEqual(DAY * 1000 + HOUR * 9);
});
it("updates the end time for right drags", function () {
mockScope.startRightDrag();
mockScope.rightDrag(-250);
controller.startRightDrag();
controller.rightDrag(-250);
expect(mockScope.ngModel.inner.end)
.toEqual(DAY * 1000 + HOUR * 15);
});
it("updates both start and end for middle drags", function () {
mockScope.startMiddleDrag();
mockScope.middleDrag(-125);
controller.startMiddleDrag();
controller.middleDrag(-125);
expect(mockScope.ngModel.inner).toEqual({
start: DAY * 1000,
end: DAY * 1000 + HOUR * 18
});
mockScope.middleDrag(250);
controller.middleDrag(250);
expect(mockScope.ngModel.inner).toEqual({
start: DAY * 1000 + HOUR * 6,
end: DAY * 1001
@@ -188,8 +250,8 @@ define(
});
it("enforces a minimum inner span", function () {
mockScope.startRightDrag();
mockScope.rightDrag(-9999999);
controller.startRightDrag();
controller.rightDrag(-9999999);
expect(mockScope.ngModel.inner.end)
.toBeGreaterThan(mockScope.ngModel.inner.start);
});

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,describe,beforeEach,jasmine,it,expect*/
define([
'../../src/directives/MCTTree'
], function (MCTTree) {
describe("The mct-tree directive", function () {
var mockParse,
mockGestureService,
mockExpr,
mctTree;
beforeEach(function () {
mockGestureService = jasmine.createSpyObj(
'gestureService',
[ 'attachGestures' ]
);
mockParse = jasmine.createSpy('$parse');
mockExpr = jasmine.createSpy('expr');
mockExpr.assign = jasmine.createSpy('assign');
mockParse.andReturn(mockExpr);
mctTree = new MCTTree(mockParse, mockGestureService);
});
it("is applicable as an element", function () {
expect(mctTree.restrict).toEqual("E");
});
it("two-way binds to mctObject", function () {
expect(mctTree.scope).toEqual({ mctObject: "=" });
});
describe("link", function () {
var mockScope,
mockElement,
testAttrs;
beforeEach(function () {
mockScope = jasmine.createSpyObj('$scope', ['$watch', '$on']);
mockElement = jasmine.createSpyObj('element', ['append']);
testAttrs = { mctModel: "some-expression" };
mockScope.$parent =
jasmine.createSpyObj('$scope', ['$watch', '$on']);
mctTree.link(mockScope, mockElement, testAttrs);
});
it("populates the mct-tree element", function () {
expect(mockElement.append).toHaveBeenCalled();
});
it("watches for mct-model's expression in the parent", function () {
expect(mockScope.$parent.$watch).toHaveBeenCalledWith(
testAttrs.mctModel,
jasmine.any(Function)
);
});
it("watches for changes to mct-object", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
"mctObject",
jasmine.any(Function)
);
});
it("listens for the $destroy event", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
"$destroy",
jasmine.any(Function)
);
});
});
});
});

View File

@@ -0,0 +1,313 @@
/*****************************************************************************
* 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,jasmine,it,expect*/
define([
'../../src/ui/TreeView',
'zepto'
], function (TreeView, $) {
'use strict';
describe("TreeView", function () {
var mockGestureService,
mockGestureHandle,
mockDomainObject,
mockMutation,
mockUnlisten,
testCapabilities,
treeView;
function makeMockDomainObject(id, model, capabilities) {
var mockDomainObject = jasmine.createSpyObj(
'domainObject-' + id,
[
'getId',
'getModel',
'getCapability',
'hasCapability',
'useCapability'
]
);
mockDomainObject.getId.andReturn(id);
mockDomainObject.getModel.andReturn(model);
mockDomainObject.hasCapability.andCallFake(function (c) {
return !!(capabilities[c]);
});
mockDomainObject.getCapability.andCallFake(function (c) {
return capabilities[c];
});
mockDomainObject.useCapability.andCallFake(function (c) {
return capabilities[c] && capabilities[c].invoke();
});
return mockDomainObject;
}
beforeEach(function () {
mockGestureService = jasmine.createSpyObj(
'gestureService',
[ 'attachGestures' ]
);
mockGestureHandle = jasmine.createSpyObj('gestures', ['destroy']);
mockGestureService.attachGestures.andReturn(mockGestureHandle);
mockMutation = jasmine.createSpyObj('mutation', ['listen']);
mockUnlisten = jasmine.createSpy('unlisten');
mockMutation.listen.andReturn(mockUnlisten);
testCapabilities = { mutation: mockMutation };
mockDomainObject =
makeMockDomainObject('parent', {}, testCapabilities);
treeView = new TreeView(mockGestureService);
});
describe("elements", function () {
var elements;
beforeEach(function () {
elements = treeView.elements();
});
it("is an unordered list", function () {
expect(elements[0].tagName.toLowerCase())
.toEqual('ul');
});
});
describe("model", function () {
var mockComposition;
function makeGenericCapabilities() {
var mockContext =
jasmine.createSpyObj('context', [ 'getPath' ]),
mockType =
jasmine.createSpyObj('type', [ 'getGlyph' ]),
mockLocation =
jasmine.createSpyObj('location', [ 'isLink' ]),
mockMutation =
jasmine.createSpyObj('mutation', [ 'listen' ]),
mockStatus =
jasmine.createSpyObj('status', [ 'listen', 'list' ]);
mockStatus.list.andReturn([]);
return {
context: mockContext,
type: mockType,
mutation: mockMutation,
location: mockLocation,
status: mockStatus
};
}
function waitForCompositionCallback() {
var calledBack = false;
testCapabilities.composition.invoke().then(function (c) {
calledBack = true;
});
waitsFor(function () {
return calledBack;
});
}
beforeEach(function () {
mockComposition = ['a', 'b', 'c'].map(function (id) {
var testCapabilities = makeGenericCapabilities(),
mockChild =
makeMockDomainObject(id, {}, testCapabilities);
testCapabilities.context.getPath
.andReturn([mockDomainObject, mockChild]);
return mockChild;
});
testCapabilities.composition =
jasmine.createSpyObj('composition', ['invoke']);
testCapabilities.composition.invoke
.andReturn(Promise.resolve(mockComposition));
treeView.model(mockDomainObject);
waitForCompositionCallback();
});
it("adds one node per composition element", function () {
expect(treeView.elements()[0].childElementCount)
.toEqual(mockComposition.length);
});
it("listens for mutation", function () {
expect(testCapabilities.mutation.listen)
.toHaveBeenCalledWith(jasmine.any(Function));
});
describe("when mutation occurs", function () {
beforeEach(function () {
mockComposition.pop();
testCapabilities.mutation.listen
.mostRecentCall.args[0](mockDomainObject.getModel());
waitForCompositionCallback();
});
it("continues to show one node per composition element", function () {
expect(treeView.elements()[0].childElementCount)
.toEqual(mockComposition.length);
});
});
describe("when replaced with a non-compositional domain object", function () {
beforeEach(function () {
delete testCapabilities.composition;
treeView.model(mockDomainObject);
});
it("stops listening for mutation", function () {
expect(mockUnlisten).toHaveBeenCalled();
});
it("removes all tree nodes", function () {
expect(treeView.elements()[0].childElementCount)
.toEqual(0);
});
});
describe("when selection state changes", function () {
var selectionIndex = 1;
beforeEach(function () {
treeView.value(mockComposition[selectionIndex]);
});
it("communicates selection state to an appropriate node", function () {
var selected = $(treeView.elements()[0]).find('.selected');
expect(selected.length).toEqual(1);
});
});
describe("when a context-less object is selected", function () {
beforeEach(function () {
var testCapabilities = makeGenericCapabilities(),
mockDomainObject =
makeMockDomainObject('xyz', {}, testCapabilities);
delete testCapabilities.context;
treeView.value(mockDomainObject);
});
it("clears all selection state", function () {
var selected = $(treeView.elements()[0]).find('.selected');
expect(selected.length).toEqual(0);
});
});
describe("when children contain children", function () {
beforeEach(function () {
var newCapabilities = makeGenericCapabilities(),
gcCapabilities = makeGenericCapabilities(),
mockNewChild =
makeMockDomainObject('d', {}, newCapabilities),
mockGrandchild =
makeMockDomainObject('gc', {}, gcCapabilities),
calledBackInner = false;
newCapabilities.composition =
jasmine.createSpyObj('composition', [ 'invoke' ]);
newCapabilities.composition.invoke
.andReturn(Promise.resolve([mockGrandchild]));
mockComposition.push(mockNewChild);
newCapabilities.context.getPath.andReturn([
mockDomainObject,
mockNewChild
]);
gcCapabilities.context.getPath.andReturn([
mockDomainObject,
mockNewChild,
mockGrandchild
]);
testCapabilities.mutation.listen
.mostRecentCall.args[0](mockDomainObject);
waitForCompositionCallback();
runs(function () {
// Select the innermost object to force expansion,
// such that we can verify the subtree is present.
treeView.value(mockGrandchild);
newCapabilities.composition.invoke().then(function () {
calledBackInner = true;
});
});
waitsFor(function () {
return calledBackInner;
});
});
it("creates inner trees", function () {
expect($(treeView.elements()[0]).find('ul').length)
.toEqual(1);
});
});
describe("when status changes", function () {
var testStatuses;
beforeEach(function () {
var mockStatus = mockComposition[1].getCapability('status');
testStatuses = [ 'foo' ];
mockStatus.list.andReturn(testStatuses);
mockStatus.listen.mostRecentCall.args[0](testStatuses);
});
it("reflects the status change in the tree", function () {
expect($(treeView.elements()).find('.s-status-foo').length)
.toEqual(1);
});
});
});
describe("observe", function () {
var mockCallback,
unobserve;
beforeEach(function () {
mockCallback = jasmine.createSpy('callback');
unobserve = treeView.observe(mockCallback);
});
it("notifies listeners when value is changed", function () {
treeView.value(mockDomainObject);
expect(mockCallback).toHaveBeenCalledWith(mockDomainObject);
});
it("does not notify listeners when deactivated", function () {
unobserve();
treeView.value(mockDomainObject);
expect(mockCallback).not.toHaveBeenCalled();
});
});
});
});

View File

@@ -85,7 +85,6 @@ define(
popup.goesUp() ? 'arw-btm' : 'arw-top',
popup.goesLeft() ? 'arw-right' : 'arw-left'
].join(' ');
scope.bubbleLayout = 'arw-top arw-left';
// Create the info bubble, now that we know how to
// point the arrow...

View File

@@ -109,6 +109,35 @@ define(
);
});
[ false, true ].forEach(function (goesLeft) {
[ false, true].forEach(function (goesUp) {
var vertical = goesUp ? "up" : "down",
horizontal = goesLeft ? "left" : "right",
location = [ vertical, horizontal].join('-');
describe("when bubble goes " + location, function () {
var expectedLocation = [
goesUp ? "bottom" : "top",
goesLeft ? "right" : "left"
].join('-');
beforeEach(function () {
mockPopup.goesUp.andReturn(goesUp);
mockPopup.goesDown.andReturn(!goesUp);
mockPopup.goesLeft.andReturn(goesLeft);
mockPopup.goesRight.andReturn(!goesLeft);
service.display('', '', {}, [ 10, 10 ]);
});
it("positions the arrow in the " + expectedLocation, function () {
expect(mockScope.bubbleLayout).toEqual([
goesUp ? "arw-btm" : "arw-top",
goesLeft ? "arw-right" : "arw-left"
].join(' '));
});
});
});
});
});
}
);

View File

@@ -27,6 +27,7 @@ $colorBtnIcon: $colorKey;
$colorInvokeMenu: #fff;
$contrastInvokeMenuPercent: 20%;
$shdwBtns: rgba(black, 0.2) 0 1px 2px;
$shdwBtnsOverlay: rgba(black, 0.5) 0 1px 5px;
$sliderColorBase: $colorKey;
$sliderColorRangeHolder: rgba(black, 0.1);
$sliderColorRange: rgba($sliderColorBase, 0.3);
@@ -76,6 +77,7 @@ $colorInputBg: rgba(#000, 0.1);
$colorInputFg: pullForward($colorBodyFg, 20%);
$colorFormText: rgba(#fff, 0.5);
$colorInputIcon: pushBack($colorBodyFg, 15%);
$colorFieldHint: pullForward($colorBodyFg, 20%);
// Inspector
$colorInspectorBg: pullForward($colorBodyBg, 3%);
@@ -124,6 +126,7 @@ $colorOvrBg: pullForward($colorBodyBg, 10%);
$colorOvrFg: pullForward($colorBodyFg, 30%);
$colorOvrBtnBg: pullForward($colorOvrBg, 20%);
$colorOvrBtnFg: #fff;
$colorFieldHintOverlay: pullForward($colorOvrBg, 30%);
// Items
$colorItemBg: lighten($colorBodyBg, 5%);
@@ -173,6 +176,8 @@ $scrollbarTrackShdw: rgba(#000, 0.7) 0 1px 5px;
$scrollbarTrackColorBg: rgba(#000, 0.4);
$scrollbarThumbColor: lighten($colorBodyBg, 10%);
$scrollbarThumbColorHov: lighten($scrollbarThumbColor, 2%);
$scrollbarThumbColorOverlay: lighten($colorOvrBg, 10%);
$scrollbarThumbColorOverlayHov: lighten($scrollbarThumbColorOverlay, 2%);
// Splitter
$splitterD: 25px; // splitterD and HandleD should both be odd, or even

View File

@@ -27,6 +27,7 @@ $colorBtnIcon: #eee;
$colorInvokeMenu: #000;
$contrastInvokeMenuPercent: 40%;
$shdwBtns: none;
$shdwBtnsOverlay: none;
$sliderColorBase: $colorKey;
$sliderColorRangeHolder: rgba(black, 0.07);
$sliderColorRange: rgba($sliderColorBase, 0.2);
@@ -76,6 +77,7 @@ $colorInputBg: $colorGenBg;
$colorInputFg: $colorBodyFg;
$colorFormText: pushBack($colorBodyFg, 10%);
$colorInputIcon: pushBack($colorBodyFg, 25%);
$colorFieldHint: pullForward($colorBodyFg, 40%);
// Inspector
$colorInspectorBg: pullForward($colorBodyBg, 5%);
@@ -124,6 +126,7 @@ $colorOvrBg: $colorBodyBg;
$colorOvrFg: $colorBodyFg;
$colorOvrBtnBg: pullForward($colorOvrBg, 40%);
$colorOvrBtnFg: #fff;
$colorFieldHintOverlay: pullForward($colorOvrBg, 40%);
// Items
$colorItemBg: #ddd;
@@ -170,9 +173,11 @@ $shdwItemTreeIcon: none;
// Scrollbar
$scrollbarTrackSize: 10px;
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
$scrollbarTrackColorBg: rgba(#000, 0.1);
$scrollbarThumbColor: darken($colorBodyBg, 50%);//
$scrollbarTrackColorBg: rgba(#000, 0.2);
$scrollbarThumbColor: darken($colorBodyBg, 50%);
$scrollbarThumbColorHov: $colorKey;
$scrollbarThumbColorOverlay: darken($colorOvrBg, 50%);
$scrollbarThumbColorOverlayHov: $scrollbarThumbColorHov;
// Splitter
$splitterD: 24px;

View File

@@ -27,6 +27,7 @@ define([
"./src/models/StaticModelProvider",
"./src/models/RootModelProvider",
"./src/models/ModelAggregator",
"./src/models/ModelCacheService",
"./src/models/PersistedModelProvider",
"./src/models/CachingModelDecorator",
"./src/models/MissingModelDecorator",
@@ -58,6 +59,7 @@ define([
StaticModelProvider,
RootModelProvider,
ModelAggregator,
ModelCacheService,
PersistedModelProvider,
CachingModelDecorator,
MissingModelDecorator,
@@ -182,7 +184,10 @@ define([
{
"provides": "modelService",
"type": "decorator",
"implementation": CachingModelDecorator
"implementation": CachingModelDecorator,
"depends": [
"cacheService"
]
},
{
"provides": "modelService",
@@ -248,21 +253,22 @@ define([
"property": "name",
"pattern": "\\S+",
"required": true,
"cssclass": "l-med"
"cssclass": "l-input-lg"
}
]
},
{
"key": "root",
"name": "Root",
"glyph": "F"
"glyph": "\u0046"
},
{
"key": "folder",
"name": "Folder",
"glyph": "F",
"glyph": "\u0046",
"features": "creation",
"description": "Useful for storing and organizing domain objects.",
"description": "Create folders to organize other objects or links to objects.",
"priority": 1000,
"model": {
"composition": []
}
@@ -270,11 +276,11 @@ define([
{
"key": "unknown",
"name": "Unknown Type",
"glyph": "?"
"glyph": "\u003f"
},
{
"name": "Unknown Type",
"glyph": "?"
"glyph": "\u003f"
}
],
"capabilities": [
@@ -319,6 +325,7 @@ define([
"key": "persistence",
"implementation": PersistenceCapability,
"depends": [
"cacheService",
"persistenceService",
"identifierService",
"notificationService",
@@ -349,11 +356,16 @@ define([
"implementation": InstantiationCapability,
"depends": [
"$injector",
"identifierService"
"identifierService",
"now"
]
}
],
"services": [
{
"key": "cacheService",
"implementation": ModelCacheService
},
{
"key": "now",
"implementation": Now
@@ -384,7 +396,8 @@ define([
"implementation": Instantiate,
"depends": [
"capabilityService",
"identifierService"
"identifierService",
"cacheService"
]
}
],

View File

@@ -28,7 +28,7 @@ define(
[],
function () {
"use strict";
var DISALLOWED_ACTIONS = ["move", "copy", "link", "window", "follow"];
/**
* The ActionCapability allows applicable Actions to be retrieved and
* performed for specific domain objects, e.g.:
@@ -54,37 +54,22 @@ define(
this.domainObject = domainObject;
}
function isEditable(domainObject){
return domainObject.getCapability('status').get('editing');
}
function hasEditableAncestor(domainObject){
return domainObject.hasCapability('context') &&
domainObject
.getCapability('context')
.getPath()
.some(function isEditable (ancestor){
return ancestor.getCapability('status').get('editing');
});
}
/**
* Retrieve the actions applicable to the domain object in the given
* context.
* Perform an action. This will find and perform the
* first matching action available for the specified
* context or key.
*
* @param {ActionContext|string} context the context in which
* to assess the applicability of the available actions; this is
* passed along to the action service to match against available
* to perform the action; this is passed along to
* the action service to match against available
* actions. The "domainObject" field will automatically
* be populated with the domain object that exposed
* this capability. If given as a string, this will
* be taken as the "key" field to match against
* specific actions.
*
* Additionally, this function will limit the actions
* available for an object in Edit Mode
* @returns {Array<Action>} The actions applicable to this domain
* object in the given context
* @returns {Promise} the result of the action that was
* performed, or undefined if no matching action
* was found.
* @memberof platform/core.ActionCapability#
*/
ActionCapability.prototype.getActions = function (context) {
@@ -93,19 +78,11 @@ define(
// but additionally adds a domainObject field.
var baseContext = typeof context === 'string' ?
{ key: context } : (context || {}),
actionContext = Object.create(baseContext),
actions;
actionContext = Object.create(baseContext);
actionContext.domainObject = this.domainObject;
actions = this.actionService.getActions(actionContext) || [];
if (isEditable(this.domainObject) || hasEditableAncestor(this.domainObject)){
return actions.filter(function(action){
return DISALLOWED_ACTIONS.indexOf(action.getMetadata().key) === -1;
});
} else {
return actions;
}
return this.actionService.getActions(actionContext);
};
/**

View File

@@ -35,10 +35,16 @@ define(
* @param $injector Angular's `$injector`
* @implements {Capability}
*/
function InstantiationCapability($injector, identifierService, domainObject) {
function InstantiationCapability(
$injector,
identifierService,
now,
domainObject
) {
this.$injector = $injector;
this.identifierService = identifierService;
this.domainObject = domainObject;
this.now = now;
}
/**
@@ -57,6 +63,8 @@ define(
space = parsedId.getDefinedSpace(),
id = this.identifierService.generate(space);
model.modified = this.now();
// Lazily initialize; instantiate depends on capabilityService,
// which depends on all capabilities, including this one.
this.instantiateFn = this.instantiateFn ||

View File

@@ -46,6 +46,7 @@ define(
* @implements {Capability}
*/
function PersistenceCapability(
cacheService,
persistenceService,
identifierService,
notificationService,
@@ -56,6 +57,7 @@ define(
this.modified = domainObject.getModel().modified;
this.domainObject = domainObject;
this.cacheService = cacheService;
this.identifierService = identifierService;
this.persistenceService = persistenceService;
this.notificationService = notificationService;
@@ -130,6 +132,7 @@ define(
domainObject = this.domainObject,
model = domainObject.getModel(),
modified = model.modified,
cacheService = this.cacheService,
persistenceService = this.persistenceService,
persistenceFn = model.persisted !== undefined ?
this.persistenceService.updateObject :

View File

@@ -35,9 +35,8 @@ define(
* @param {ModelService} modelService this service to decorate
* @implements {ModelService}
*/
function CachingModelDecorator(modelService) {
this.cache = {};
this.cached = {};
function CachingModelDecorator(cacheService, modelService) {
this.cacheService = cacheService;
this.modelService = modelService;
}
@@ -51,17 +50,16 @@ define(
}
CachingModelDecorator.prototype.getModels = function (ids) {
var cache = this.cache,
cached = this.cached,
var cacheService = this.cacheService,
neededIds = ids.filter(function notCached(id) {
return !cached[id];
return !cacheService.has(id);
});
// Update the cached instance of a model to a new value.
// We update in-place to ensure there is only ever one instance
// of any given model exposed by the modelService as a whole.
function updateModel(id, model) {
var oldModel = cache[id];
var oldModel = cacheService.get(id);
// Same object instance is a possibility, so don't copy
if (oldModel === model) {
@@ -71,7 +69,7 @@ define(
// If we'd previously cached an undefined value, or are now
// seeing undefined, replace the item in the cache entirely.
if (oldModel === undefined || model === undefined) {
cache[id] = model;
cacheService.put(id, model);
return model;
}
@@ -91,15 +89,15 @@ define(
// Store the provided models in our cache
function cacheAll(models) {
Object.keys(models).forEach(function (id) {
cache[id] = cached[id] ?
var model = cacheService.has(id) ?
updateModel(id, models[id]) : models[id];
cached[id] = true;
cacheService.put(id, model);
});
}
// Expose the cache (for promise chaining)
function giveCache() {
return cache;
return cacheService.all();
}
// Look up if we have unknown IDs
@@ -110,7 +108,7 @@ define(
}
// Otherwise, just expose the cache directly
return fastPromise(cache);
return fastPromise(cacheService.all());
};
return CachingModelDecorator;

View File

@@ -0,0 +1,83 @@
/*****************************************************************************
* 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';
/**
* Provides a cache for domain object models which exist in memory,
* but may or may not exist in backing persistene stores.
* @constructor
* @memberof platform/core
*/
function ModelCacheService() {
this.cache = {};
}
/**
* Put a domain object model in the cache.
* @param {string} id the domain object's identifier
* @param {object} model the domain object's model
*/
ModelCacheService.prototype.put = function (id, model) {
this.cache[id] = model;
};
/**
* Retrieve a domain object model from the cache.
* @param {string} id the domain object's identifier
* @returns {object} the domain object's model
*/
ModelCacheService.prototype.get = function (id) {
return this.cache[id];
};
/**
* Check if a domain object model is in the cache.
* @param {string} id the domain object's identifier
* @returns {boolean} true if present; false if not
*/
ModelCacheService.prototype.has = function (id) {
return this.cache.hasOwnProperty(id);
};
/**
* Remove a domain object model from the cache.
* @param {string} id the domain object's identifier
*/
ModelCacheService.prototype.remove = function (id) {
delete this.cache[id];
};
/**
* Retrieve all cached domain object models. These are given
* as an object containing key-value pairs, where keys are
* domain object identifiers and values are domain object models.
* @returns {object} all domain object models
*/
ModelCacheService.prototype.all = function () {
return this.cache;
};
return ModelCacheService;
});

View File

@@ -44,10 +44,15 @@ define(
* @param {IdentifierService} identifierService service to generate
* new identifiers
*/
function Instantiate(capabilityService, identifierService) {
function Instantiate(
capabilityService,
identifierService,
cacheService
) {
return function (model, id) {
var capabilities = capabilityService.getCapabilities(model);
id = id || identifierService.generate();
cacheService.put(id, model);
return new DomainObjectImpl(id, model, capabilities);
};
}

View File

@@ -19,8 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise,describe,xdescribe,it,expect,beforeEach,waitsFor,
jasmine*/
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
/**
* ActionCapabilitySpec. Created by vwoeltje on 11/6/14.
@@ -29,8 +28,8 @@ define(
["../../src/actions/ActionCapability"],
function (ActionCapability) {
"use strict";
//TODO: Disabled for NEM beta
xdescribe("The action capability", function () {
describe("The action capability", function () {
var mockQ,
mockAction,
mockActionService,

View File

@@ -31,6 +31,7 @@ define(
mockIdentifierService,
mockInstantiate,
mockIdentifier,
mockNow,
mockDomainObject,
instantiation;
@@ -57,9 +58,13 @@ define(
mockIdentifierService.parse.andReturn(mockIdentifier);
mockIdentifierService.generate.andReturn("some-id");
mockNow = jasmine.createSpy();
mockNow.andReturn(1234321);
instantiation = new InstantiationCapability(
mockInjector,
mockIdentifierService,
mockNow,
mockDomainObject
);
});
@@ -81,7 +86,10 @@ define(
expect(instantiation.instantiate(testModel))
.toBe(mockDomainObject);
expect(mockInstantiate)
.toHaveBeenCalledWith(testModel, jasmine.any(String));
.toHaveBeenCalledWith({
someKey: "some value",
modified: mockNow()
}, jasmine.any(String));
});
});

View File

@@ -36,6 +36,7 @@ define(
mockDomainObject,
mockIdentifier,
mockNofificationService,
mockCacheService,
mockQ,
id = "object id",
model,
@@ -81,6 +82,10 @@ define(
"notificationService",
["error"]
);
mockCacheService = jasmine.createSpyObj(
"cacheService",
[ "get", "put", "remove", "all" ]
);
mockDomainObject = {
getId: function () { return id; },
@@ -96,6 +101,7 @@ define(
mockIdentifierService.parse.andReturn(mockIdentifier);
mockIdentifier.getSpace.andReturn(SPACE);
persistence = new PersistenceCapability(
mockCacheService,
mockPersistenceService,
mockIdentifierService,
mockNofificationService,
@@ -171,6 +177,7 @@ define(
expect(mockNofificationService.error).not.toHaveBeenCalled();
});
});
describe("unsuccessful persistence", function() {
var sadPromise = {
then: function(callback){

View File

@@ -22,8 +22,11 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../../src/models/CachingModelDecorator"],
function (CachingModelDecorator) {
[
"../../src/models/CachingModelDecorator",
"../../src/models/ModelCacheService"
],
function (CachingModelDecorator, ModelCacheService) {
"use strict";
describe("The caching model decorator", function () {
@@ -67,7 +70,10 @@ define(
b: { someOtherKey: "some other value" }
};
mockModelService.getModels.andReturn(asPromise(testModels));
decorator = new CachingModelDecorator(mockModelService);
decorator = new CachingModelDecorator(
new ModelCacheService(),
mockModelService
);
});
it("loads models from its wrapped model service", function () {
@@ -150,4 +156,4 @@ define(
});
}
);
);

View File

@@ -0,0 +1,69 @@
/*****************************************************************************
* 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/models/ModelCacheService'], function (ModelCacheService) {
'use strict';
describe("ModelCacheService", function () {
var testIds,
testModels,
cacheService;
beforeEach(function () {
testIds = [ 'a', 'b', 'c', 'd' ];
testModels = testIds.reduce(function (models, id) {
models[id] = { someKey: "some value for " + id };
return models;
}, {});
cacheService = new ModelCacheService();
});
describe("when populated with models", function () {
beforeEach(function () {
testIds.forEach(function (id) {
cacheService.put(id, testModels[id]);
});
});
it("indicates that it has these models", function () {
testIds.forEach(function (id) {
expect(cacheService.has(id)).toBe(true);
});
});
it("provides all of these models", function () {
expect(cacheService.all()).toEqual(testModels);
});
it("allows models to be retrieved", function () {
testIds.forEach(function (id) {
expect(cacheService.get(id)).toEqual(testModels[id]);
});
});
it("allows models to be removed", function () {
cacheService.remove('a');
expect(cacheService.has('a')).toBe(false);
});
});
});
});

View File

@@ -32,8 +32,7 @@ define(
mockIdentifierService,
mockCapabilityConstructor,
mockCapabilityInstance,
mockCapabilities,
mockIdentifier,
mockCacheService,
idCounter,
testModel,
instantiate,
@@ -62,11 +61,17 @@ define(
"some-id-" + (idCounter += 1);
});
mockCacheService = jasmine.createSpyObj(
'cacheService',
[ 'get', 'put', 'remove', 'all' ]
);
testModel = { someKey: "some value" };
instantiate = new Instantiate(
mockCapabilityService,
mockIdentifierService
mockIdentifierService,
mockCacheService
);
domainObject = instantiate(testModel);
});
@@ -92,6 +97,13 @@ define(
expect(instantiate(testModel).getId())
.not.toEqual(domainObject.getId());
});
it("caches the instantiated model", function () {
expect(mockCacheService.put).toHaveBeenCalledWith(
domainObject.getId(),
testModel
);
});
});
}

View File

@@ -29,7 +29,9 @@ define([
"./src/actions/SetPrimaryLocationAction",
"./src/services/LocatingCreationDecorator",
"./src/services/LocatingObjectDecorator",
"./src/policies/CopyPolicy",
"./src/policies/CrossSpacePolicy",
"./src/policies/MovePolicy",
"./src/capabilities/LocationCapability",
"./src/services/MoveService",
"./src/services/LinkService",
@@ -44,7 +46,9 @@ define([
SetPrimaryLocationAction,
LocatingCreationDecorator,
LocatingObjectDecorator,
CopyPolicy,
CrossSpacePolicy,
MovePolicy,
LocationCapability,
MoveService,
LinkService,
@@ -140,6 +144,14 @@ define([
{
"category": "action",
"implementation": CrossSpacePolicy
},
{
"category": "action",
"implementation": CopyPolicy
},
{
"category": "action",
"implementation": MovePolicy
}
],
"capabilities": [

View File

@@ -19,33 +19,39 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
.select {
@include btnSubtle($colorSelectBg);
@if $shdwBtns != none {
margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
/*global define */
define([], function () {
'use strict';
/**
* Disallow duplication when the object to be duplicated is not
* creatable.
* @constructor
* @implements {Policy}
* @memberof platform/entanglement
*/
function CopyPolicy() {
}
padding: 0 $interiorMargin;
overflow: hidden;
position: relative;
line-height: $formInputH;
select {
@include appearance(none);
box-sizing: border-box;
background: none;
color: $colorSelectFg;
cursor: pointer;
border: none !important;
padding: 4px 25px 2px 0px;
width: 130%;
option {
margin: $interiorMargin 0; // Firefox
function allowCreation(domainObject) {
var type = domainObject && domainObject.getCapability('type');
return !!(type && type.hasFeature('creation'));
}
function selectedObject(context) {
return context.selectedObject || context.domainObject;
}
CopyPolicy.prototype.allow = function (action, context) {
var key = action.getMetadata().key;
if (key === 'copy') {
return allowCreation(selectedObject(context));
}
}
&:after {
@include contextArrow();
pointer-events: none;
color: rgba($colorSelectFg, percentToDecimal($contrastInvokeMenuPercent));
position: absolute;
right: $interiorMargin; top: 0;
}
}
return true;
};
return CopyPolicy;
});

View File

@@ -0,0 +1,63 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define */
define([], function () {
'use strict';
/**
* Disallow moves when either the parent or the child are not
* modifiable by users.
* @constructor
* @implements {Policy}
* @memberof platform/entanglement
*/
function MovePolicy() {
}
function parentOf(domainObject) {
var context = domainObject.getCapability('context');
return context && context.getParent();
}
function allowMutation(domainObject) {
var type = domainObject && domainObject.getCapability('type');
return !!(type && type.hasFeature('creation'));
}
function selectedObject(context) {
return context.selectedObject || context.domainObject;
}
MovePolicy.prototype.allow = function (action, context) {
var key = action.getMetadata().key;
if (key === 'move') {
return allowMutation(selectedObject(context)) &&
allowMutation(parentOf(selectedObject(context)));
}
return true;
};
return MovePolicy;
});

View File

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

View File

@@ -0,0 +1,127 @@
/*****************************************************************************
* 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/MovePolicy',
'../DomainObjectFactory'
], function (MovePolicy, domainObjectFactory) {
'use strict';
describe("MovePolicy", function () {
var testMetadata,
testContext,
mockDomainObject,
mockParent,
mockParentType,
mockType,
mockAction,
policy;
beforeEach(function () {
var mockContextCapability =
jasmine.createSpyObj('context', ['getParent']);
mockType =
jasmine.createSpyObj('type', ['hasFeature']);
mockParentType =
jasmine.createSpyObj('parent-type', ['hasFeature']);
testMetadata = {};
mockDomainObject = domainObjectFactory({
capabilities: {
context: mockContextCapability,
type: mockType
}
});
mockParent = domainObjectFactory({
capabilities: {
type: mockParentType
}
});
mockContextCapability.getParent.andReturn(mockParent);
mockType.hasFeature.andCallFake(function (feature) {
return feature === 'creation';
});
mockParentType.hasFeature.andCallFake(function (feature) {
return feature === 'creation';
});
mockAction = jasmine.createSpyObj('action', ['getMetadata']);
mockAction.getMetadata.andReturn(testMetadata);
testContext = { domainObject: mockDomainObject };
policy = new MovePolicy();
});
describe("for move actions", function () {
beforeEach(function () {
testMetadata.key = 'move';
});
describe("when an object is non-modifiable", function () {
beforeEach(function () {
mockType.hasFeature.andReturn(false);
});
it("disallows the action", function () {
expect(policy.allow(mockAction, testContext)).toBe(false);
});
});
describe("when a parent is non-modifiable", function () {
beforeEach(function () {
mockParentType.hasFeature.andReturn(false);
});
it("disallows the action", function () {
expect(policy.allow(mockAction, testContext)).toBe(false);
});
});
describe("when an object and its parent are modifiable", function () {
it("allows the action", function () {
expect(policy.allow(mockAction, testContext)).toBe(true);
});
});
});
describe("for other actions", function () {
beforeEach(function () {
testMetadata.key = 'foo';
});
it("simply allows the action", function () {
expect(policy.allow(mockAction, testContext)).toBe(true);
mockType.hasFeature.andReturn(false);
expect(policy.allow(mockAction, testContext)).toBe(true);
mockParentType.hasFeature.andReturn(false);
expect(policy.allow(mockAction, testContext)).toBe(true);
});
});
});
});

View File

@@ -157,7 +157,9 @@ define([
{
"key": "clock",
"name": "Clock",
"glyph": "C",
"glyph": "\u0043",
"description": "A UTC-based clock that supports a variety of display formats. Clocks can be added to Display Layouts.",
"priority": 101,
"features": [
"creation"
],
@@ -182,7 +184,8 @@ define([
"value": "hh:mm:ss",
"name": "hh:mm:ss"
}
]
],
"cssclass": "l-inline"
},
{
"control": "select",
@@ -195,7 +198,8 @@ define([
"value": "clock24",
"name": "24hr"
}
]
],
"cssclass": "l-inline"
}
]
}
@@ -210,7 +214,9 @@ define([
{
"key": "timer",
"name": "Timer",
"glyph": "õ",
"glyph": "\u00f5",
"description": "A timer that counts up or down to a datetime. Timers can be started, stopped and reset whenever needed, and support a variety of display formats. Each Timer displays the same value to all users. Timers can be added to Display Layouts.",
"priority": 100,
"features": [
"creation"
],
@@ -223,6 +229,7 @@ define([
{
"key": "timerFormat",
"control": "select",
"name": "Display Format",
"options": [
{
"value": "long",

View File

@@ -6,6 +6,6 @@
ng-model='ngModel'
field="'domain'"
options="ngModel.options"
style="position: absolute; right: 0px; bottom: 46px;"
class="l-time-domain-selector"
>
</mct-control>

View File

@@ -1,83 +0,0 @@
/*****************************************************************************
* 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([
"./src/EventListController",
"./src/directives/MCTDataTable",
"./src/policies/MessagesViewPolicy",
"text!./res/templates/messages.html",
'legacyRegistry'
], function (
EventListController,
MCTDataTable,
MessagesViewPolicy,
messagesTemplate,
legacyRegistry
) {
"use strict";
legacyRegistry.register("platform/features/events", {
"name": "Event Messages",
"description": "List of time-ordered event messages",
"extensions": {
"views": [
{
"key": "messages",
"name": "Messages",
"glyph": "5",
"description": "Scrolling list of messages.",
"template": messagesTemplate,
"needs": [
"telemetry"
],
"delegation": true
}
],
"controllers": [
{
"key": "EventListController",
"implementation": EventListController,
"depends": [
"$scope",
"telemetryFormatter"
]
}
],
"directives": [
{
"key": "mctDataTable",
"implementation": MCTDataTable,
"depends": [
"$window"
]
}
],
"policies": [
{
"category": "view",
"implementation": MessagesViewPolicy
}
]
}
});
});

View File

@@ -1,37 +0,0 @@
<!--
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.
-->
<table class="tabular">
<thead>
<tr>
<th ng-repeat="header in headers">
{{header}}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows">
<td ng-repeat="cell in row">
{{cell}}
</td>
</tr>
</tbody>
</table>

View File

@@ -1,29 +0,0 @@
<!--
Open MCT Web, Copyright (c) 2014-2015, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT Web is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT Web includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div class="w1" ng-controller="TelemetryController as telemetry">
<div class="w2"
ng-controller="EventListController">
<mct-data-table headers="headers" rows="rows" ascending-scroll="true"></mct-data-table>
</div>
</div>

View File

@@ -1,63 +0,0 @@
/*****************************************************************************
* 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,moment*/
/**
* Module defining DomainColumn. Created by vwoeltje on 11/18/14.
*/
define(
[],
function () {
"use strict";
/**
* A column which will report telemetry domain values
* (typically, timestamps.) Used by the ScrollingListController.
*
* @memberof platform/features/events
* @constructor
* @implements {platform/features/events.EventsColumn}
* @param domainMetadata an object with the machine- and human-
* readable names for this domain (in `key` and `name`
* fields, respectively.)
* @param {TelemetryFormatter} telemetryFormatter the telemetry
* formatting service, for making values human-readable.
*/
function DomainColumn(domainMetadata, telemetryFormatter) {
this.domainMetadata = domainMetadata;
this.telemetryFormatter = telemetryFormatter;
}
DomainColumn.prototype.getTitle = function () {
return this.domainMetadata.name;
};
DomainColumn.prototype.getValue = function (domainObject, data, index) {
var domainKey = this.domainMetadata.key;
return this.telemetryFormatter.formatDomainValue(
data.getDomainValue(index, domainKey)
);
};
return DomainColumn;
}
);

View File

@@ -1,164 +0,0 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
/*
* Module defining EventListController.
* Created by chacskaylo on 06/18/2015.
* Modified by shale on 06/23/2015.
*/
/**
* This bundle implements the "Events" view of string telemetry.
* @namespace platform/features/events
*/
define(
["./DomainColumn", "./RangeColumn", "./EventListPopulator"],
function (DomainColumn, RangeColumn, EventListPopulator) {
"use strict";
var ROW_COUNT = 100;
/**
* The EventListController is responsible for populating
* the contents of the event list view.
* @memberof platform/features/events
* @constructor
*/
function EventListController($scope, formatter) {
var populator;
// Get a set of populated, ready-to-display rows for the
// latest data values.
function getRows(telemetry) {
var datas = telemetry.getResponse(),
objects = telemetry.getTelemetryObjects();
return populator.getRows(datas, objects, ROW_COUNT);
}
// Update the contents
function updateRows() {
var telemetry = $scope.telemetry;
$scope.rows = telemetry ? getRows(telemetry) : [];
}
// Set up columns based on telemetry metadata. This will
// include one column for each domain and range type, as
// well as a column for the domain object name.
function setupColumns(telemetry) {
var domainKeys = {},
rangeKeys = {},
columns = [],
metadata;
// Add a domain to the set of columns, if a domain
// with the same key has not yet been inclued.
function addDomain(domain) {
var key = domain.key;
if (key && !domainKeys[key]) {
domainKeys[key] = true;
columns.push(new DomainColumn(domain, formatter));
}
}
// Add a range col to the set of columns, if a range
// with the same key has not yet been included.
function addRange(range) {
var key = range.key;
if (key && !rangeKeys[key]) {
rangeKeys[key] = true;
columns.push(new RangeColumn(range, formatter));
}
}
// We cannot proceed if the telemetry controller
// is not available; clear all rows/columns.
if (!telemetry) {
columns = [];
$scope.rows = [];
$scope.headers = [];
return;
}
// Add domain, range, event msg columns
metadata = telemetry.getMetadata();
(metadata || []).forEach(function (metadata) {
(metadata.domains || []).forEach(addDomain);
});
(metadata || []).forEach(function (metadata) {
(metadata.ranges || []).forEach(addRange);
});
// Add default domain and range columns if none
// were described in metadata.
if (Object.keys(domainKeys).length < 1) {
columns.push(new DomainColumn({name: "Time"}, formatter));
}
if (Object.keys(rangeKeys).length < 1) {
columns.push(new RangeColumn({name: "Message"}, formatter));
}
// We have all columns now; use them to initializer
// the populator, which will use them to generate
// actual rows and headers.
populator = new EventListPopulator(columns);
// Initialize headers
$scope.headers = populator.getHeaders();
// Fill in the contents of the rows.
updateRows();
}
$scope.$on("telemetryUpdate", updateRows);
$scope.$watch("telemetry", setupColumns);
}
return EventListController;
/**
* A description of how to display a certain column of data in an
* Events view.
* @interface platform/features/events.EventColumn
* @private
*/
/**
* Get the title to display in this column's header.
* @returns {string} the title to display
* @method platform/features/events.EventColumn#getTitle
*/
/**
* Get the text to display inside a row under this
* column.
* @param {DomainObject} domainObject the domain object associated
* with this row
* @param {TelemetrySeries} series the telemetry data associated
* with this row
* @param {number} index the index of the telemetry datum associated
* with this row
* @returns {string} the text to display
* @method platform/features/events.EventColumn#getValue
*/
}
);

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