Merge branch 'open-master' into open1051b

Merge in latest to add license headers, WTD-1051
This commit is contained in:
Victor Woeltjen 2015-05-13 12:42:47 -07:00
commit 28fbc5be09
72 changed files with 3042 additions and 656 deletions

342
LICENSES.md Normal file
View File

@ -0,0 +1,342 @@
# Open MCT Web Licenses
Open MCT Web, Copyright (c) 2009-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 as follows.
## Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
## Software Components Licenses
This software includes components released under the following licenses:
### Blanket.js
#### Info
* Link: http://blanketjs.org/
* Version: 1.1.5
* Author: Alex Seville
* Description: Code coverage measurement and reporting
#### License
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.
---
### Jasmine
#### Info
* Link: http://jasmine.github.io/
* Version: 1.3.1
* Author: Pivotal Labs
* Description: Unit testing
#### License
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.
---
### RequireJS
#### Info
* Link: http://requirejs.org/
* Version: 2.1.9
* Author: The Dojo Foundation
* Description: Script loader
#### License
Copyright (c) 2010-2015, The Dojo Foundation
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.
---
### AngularJS
#### Info
* Link: http://angularjs.org/
* Version: 1.2.26
* Author: Google
* Description: Client-side web application framework
#### License
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
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.
---
### Angular-Route
#### Info
* Link: http://angularjs.org/
* Version: 1.2.26
* Author: Google
* Description: Client-side view routing
#### License
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
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.
---
### ES6-Promise
#### Info
* Link: https://github.com/jakearchibald/es6-promise
* Version: 2.0.0
* Authors: Yehuda Katz, Tom Dale, Stefan Penner and contributors
* Description: Promise polyfill for pre-ECMAScript 6 browsers
#### License
Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
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.
---
### screenfull.js
#### Info
* Link: https://github.com/sindresorhus/screenfull.js/
* Version: 1.2.0
* Author: Sindre Sorhus
* Description: Wrapper for cross-browser usage of fullscreen API
#### License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
---
### Math.uuid.js
#### Info
* Link: https://github.com/broofa/node-uuid
* Version: 1.4
* Author: Robert Kieffer
* Description: Unique identifer generation (code adapted.)
#### License
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.
---
### 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
* Link: http://necolas.github.io/normalize.css/
* Version: 1.1.2
* Authors: Nicolas Gallagher, Jonathan Neal
* Description: Browser style normalization
#### License
Copyright (c) Nicolas Gallagher and Jonathan Neal
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.
---
### Moment.js
#### Info
* Link: http://momentjs.com
* Version: 2.7.0
* Authors: Tim Wood, Iskren Chernev, Moment.js contributors
* Description: Time/date parsing/formatting
#### License
Copyright (c) 2011-2014 Tim Wood, Iskren Chernev, Moment.js contributors
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.
---

View File

@ -10,6 +10,7 @@
"platform/containment",
"platform/telemetry",
"platform/features/layout",
"platform/features/pages",
"platform/features/plot",
"platform/features/scrolling",
"platform/forms",

View File

@ -19,6 +19,14 @@
{
"key": "overlay-about",
"templateUrl": "templates/overlay-about.html"
},
{
"key": "license-apache",
"templateUrl": "templates/license-apache.html"
},
{
"key": "license-mit",
"templateUrl": "templates/license-mit.html"
}
],
"controllers": [
@ -42,6 +50,10 @@
{
"when": "/licenses",
"templateUrl": "templates/licenses.html"
},
{
"when": "/licenses-md",
"templateUrl": "templates/licenses-export-md.html"
}
]
}

View File

@ -1,13 +1,16 @@
<div class="abs t-about l-about t-about-openmctweb" ng-controller = "AboutController as about">
<div class="abs t-about l-about t-about-openmctweb s-about" ng-controller = "AboutController as about">
<div class="l-logo-holder s-logo-holder">
<div class="l-logo s-logo s-logo-nasa"></div>
<div class="l-logo l-logo-app s-logo s-logo-openmctweb"></div>
</div>
<div class="l-content">
<div class="s-text l-content">
<h1 class="l-title s-title">OpenMCT Web</h1>
<div class="l-description s-description">
<p>OpenMCT Web is a project of NASA's Ames Research Center. Copyright &copy;2015 NASA Ames Research Center, all rights reserved. <a ng-click="about.openLicenses()">Licensing information</a></p>
<p>Open MCT Web, Copyright &copy; 2009-2015, United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.</p>
<p>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 <a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>.</p>
<p>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.</p>
<p>Open MCT Web includes source code licensed under additional open source licenses. See the Open Source Licenses file included with this distribution or <a ng-click="about.openLicenses()">click here for licensing information</a>.</p>
</div>
<h2>Version Information</h2>
<ul class="t-info l-info s-info" ng-repeat = "version in about.versions()">

View File

@ -0,0 +1,178 @@
<!-- From http://www.apache.org/licenses/LICENSE-2.0 -->
<br>
<p>Version 2.0, January 2004</p>
<p><a href="http://www.apache.org/licenses/">http://www.apache.org/licenses/</a></p>
<h3>TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</h3>
<p><strong><a name="definitions">1. Definitions</a></strong>.</p>
<p>"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.</p>
<p>"Licensor" shall mean the copyright owner or entity authorized by the
copyright owner that is granting the License.</p>
<p>"Legal Entity" shall mean the union of the acting entity and all other
entities that control, are controlled by, or are under common control with
that entity. For the purposes of this definition, "control" means (i) the
power, direct or indirect, to cause the direction or management of such
entity, whether by contract or otherwise, or (ii) ownership of fifty
percent (50%) or more of the outstanding shares, or (iii) beneficial
ownership of such entity.</p>
<p>"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.</p>
<p>"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source,
and configuration files.</p>
<p>"Object" form shall mean any form resulting from mechanical transformation
or translation of a Source form, including but not limited to compiled
object code, generated documentation, and conversions to other media types.</p>
<p>"Work" shall mean the work of authorship, whether in Source or Object form,
made available under the License, as indicated by a copyright notice that
is included in or attached to the work (an example is provided in the
Appendix below).</p>
<p>"Derivative Works" shall mean any work, whether in Source or Object form,
that is based on (or derived from) the Work and for which the editorial
revisions, annotations, elaborations, or other modifications represent, as
a whole, an original work of authorship. For the purposes of this License,
Derivative Works shall not include works that remain separable from, or
merely link (or bind by name) to the interfaces of, the Work and Derivative
Works thereof.</p>
<p>"Contribution" shall mean any work of authorship, including the original
version of the Work and any modifications or additions to that Work or
Derivative Works thereof, that is intentionally submitted to Licensor for
inclusion in the Work by the copyright owner or by an individual or Legal
Entity authorized to submit on behalf of the copyright owner. For the
purposes of this definition, "submitted" means any form of electronic,
verbal, or written communication sent to the Licensor or its
representatives, including but not limited to communication on electronic
mailing lists, source code control systems, and issue tracking systems that
are managed by, or on behalf of, the Licensor for the purpose of discussing
and improving the Work, but excluding communication that is conspicuously
marked or otherwise designated in writing by the copyright owner as "Not a
Contribution."</p>
<p>"Contributor" shall mean Licensor and any individual or Legal Entity on
behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.</p>
<p><strong><a name="copyright">2. Grant of Copyright License</a></strong>. Subject to the
terms and conditions of this License, each Contributor hereby grants to You
a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of, publicly
display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.</p>
<p><strong><a name="patent">3. Grant of Patent License</a></strong>. Subject to the terms
and conditions of this License, each Contributor hereby grants to You a
perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made, use,
offer to sell, sell, import, and otherwise transfer the Work, where such
license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by
combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation against
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
that the Work or a Contribution incorporated within the Work constitutes
direct or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate as of the
date such litigation is filed.</p>
<p><strong><a name="redistribution">4. Redistribution</a></strong>. You may reproduce and
distribute copies of the Work or Derivative Works thereof in any medium,
with or without modifications, and in Source or Object form, provided that
You meet the following conditions:</p>
<ol style="list-style: lower-latin;">
<li>You must give any other recipients of the Work or Derivative Works a
copy of this License; and</li>
<li>You must cause any modified files to carry prominent notices stating
that You changed the files; and</li>
<li>You must retain, in the Source form of any Derivative Works that You
distribute, all copyright, patent, trademark, and attribution notices from
the Source form of the Work, excluding those notices that do not pertain to
any part of the Derivative Works; and</li>
<li>If the Work includes a "NOTICE" text file as part of its distribution,
then any Derivative Works that You distribute must include a readable copy
of the attribution notices contained within such NOTICE file, excluding
those notices that do not pertain to any part of the Derivative Works, in
at least one of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or documentation,
if provided along with the Derivative Works; or, within a display generated
by the Derivative Works, if and wherever such third-party notices normally
appear. The contents of the NOTICE file are for informational purposes only
and do not modify the License. You may add Your own attribution notices
within Derivative Works that You distribute, alongside or as an addendum to
the NOTICE text from the Work, provided that such additional attribution
notices cannot be construed as modifying the License.
<br>
<br>
You may add Your own copyright statement to Your modifications and may
provide additional or different license terms and conditions for use,
reproduction, or distribution of Your modifications, or for any such
Derivative Works as a whole, provided Your use, reproduction, and
distribution of the Work otherwise complies with the conditions stated in
this License.
</li>
</ol>
<p><strong><a name="contributions">5. Submission of Contributions</a></strong>. Unless You
explicitly state otherwise, any Contribution intentionally submitted for
inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the
terms of any separate license agreement you may have executed with Licensor
regarding such Contributions.</p>
<p><strong><a name="trademarks">6. Trademarks</a></strong>. This License does not grant
permission to use the trade names, trademarks, service marks, or product
names of the Licensor, except as required for reasonable and customary use
in describing the origin of the Work and reproducing the content of the
NOTICE file.</p>
<p><strong><a name="no-warranty">7. Disclaimer of Warranty</a></strong>. Unless required by
applicable law or agreed to in writing, Licensor provides the Work (and
each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You
are solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise
of permissions under this License.</p>
<p><strong><a name="no-liability">8. Limitation of Liability</a></strong>. In no event and
under no legal theory, whether in tort (including negligence), contract, or
otherwise, unless required by applicable law (such as deliberate and
grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a result
of this License or out of the use or inability to use the Work (including
but not limited to damages for loss of goodwill, work stoppage, computer
failure or malfunction, or any and all other commercial damages or losses),
even if such Contributor has been advised of the possibility of such
damages.</p>
<p><strong><a name="additional">9. Accepting Warranty or Additional Liability</a></strong>.
While redistributing the Work or Derivative Works thereof, You may choose
to offer, and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this License.
However, in accepting such obligations, You may act only on Your own behalf
and on Your sole responsibility, not on behalf of any other Contributor,
and only if You agree to indemnify, defend, and hold each Contributor
harmless for any liability incurred by, or claims asserted against, such
Contributor by reason of your accepting any such warranty or additional
liability.</p>
<h3>END OF TERMS AND CONDITIONS</h3>
<h3 id="apply">APPENDIX: How to apply the Apache License to your work</h3>
<p>To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included
on the same "printed page" as the copyright notice for easier
identification within third-party archives.</p>
<div class="codehilite"><pre>Copyright [yyyy] [name of copyright owner]
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.
</pre></div>

View File

@ -0,0 +1,3 @@
<p>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:</p>
<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>
<p>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.</p>

View File

@ -0,0 +1,21 @@
<div ng-controller="LicenseController as lc" class="abs l-about l-standalone s-text s-md-export">
<h1># Open MCT Web Licenses</h1>
<h2>## Apache License</h2>
<mct-include key="'license-apache'"></mct-include>
<h2>## Software Components Licenses</h2>
<p>This software includes components released under the following licenses:</p>
<div class="l-license-software" ng-repeat="license in lc.licenses()">
<p>### {{license.name}}</p>
<p>#### Info</p>
<p>* Link: {{license.website}}</p>
<p>* Version: {{license.version}}</p>
<p>* Author<span ng-show="license.author.indexOf(',') > 0">s</span>: {{license.author}}</p>
<p>* Description: {{license.description}}</p>
<p>#### License</p>
<p ng-show="license.copyright.length > 0">{{license.copyright}}</p>
<mct-include key="license.license"></mct-include>
<p>&nbsp;</p>
<p>---</p>
</div>
</div>

View File

@ -1,33 +1,23 @@
<style>
.licenses { padding: 1em; }
.licenses th { font-weight: bold; padding: 0.5em; }
.licenses td { padding: 0.5em; }
</style>
<div ng-controller="LicenseController as lc" class="abs l-standalone s-text l-about l-licenses s-about s-licenses">
<h1>OpenMCT Web Licenses</h1>
<h2>Apache License</h2>
<mct-include key="'license-apache'"></mct-include>
<div ng-controller="LicenseController as lc" class="licenses">
<p>
This software includes components released under the following licenses.
</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Version</th>
<th>Author</th>
<th>Description</th>
<th>License</th>
</tr>
</thead>
<tbody style="font-weight: normal;">
<tr ng-repeat="license in lc.licenses()">
<td><a ng-href="{{license.website}}">{{license.name}}</a></td>
<td>{{license.version}}</td>
<td>{{license.author}}</td>
<td>{{license.description}}</td>
<td><a ng-href="{{license.link}}">{{license.license}}</a></td>
</tr>
</tbody>
</table>
<h2>Software Components Licenses</h2>
<p>This software includes components released under the following licenses:</p>
<div class="l-licenses-software">
<div class="l-license-software" ng-repeat="license in lc.licenses()">
<h3><a target="_blank" ng-href="{{license.website}}">{{license.name}}</a></h3>
<p>
<em>Version</em> {{license.version}}
<em>&nbsp;|&nbsp;Author<span ng-show="license.author.indexOf(',') > 0">s</span></em> {{license.author}}
<em>&nbsp;|&nbsp;Description</em> {{license.description}}
</p>
<em>License</em>
<div class="s-license-text">
<p ng-show="license.copyright.length > 0">{{license.copyright}}</p>
<mct-include key="license.license"></mct-include>
</div>
</div>
</div>
</div>

View File

@ -85,7 +85,7 @@
{
"key": "window",
"implementation": "windowing/NewWindowAction.js",
"description": "Open this object in a new window.",
"description": "Open this object in a new window",
"category": "view-control",
"depends": [ "$window" ],
"group": "windowing",
@ -104,7 +104,7 @@
"key": "items",
"name": "Items",
"glyph": "9",
"description": "Grid of available items.",
"description": "Grid of available items",
"templateUrl": "templates/items/items.html",
"uses": [ "composition" ],
"gestures": [ "drop" ],
@ -125,10 +125,11 @@
{
"name": "screenfull.js",
"version": "1.2.0",
"description": "Wrapper for cross-browser usage of fullscreen API.",
"description": "Wrapper for cross-browser usage of fullscreen API",
"author": "Sindre Sorhus",
"website": "https://github.com/sindresorhus/screenfull.js/",
"license": "MIT",
"copyright": "Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)",
"license": "license-mit",
"link": "https://github.com/sindresorhus/screenfull.js/blob/gh-pages/license"
},
{
@ -137,7 +138,8 @@
"description": "Unique identifer generation (code adapted.)",
"author": "Robert Kieffer",
"website": "https://github.com/broofa/node-uuid",
"license": "MIT",
"copyright": "",
"license": "license-mit",
"link": "http://opensource.org/licenses/MIT"
}
]

View File

@ -1,6 +1,6 @@
<div content="jquery-wrapper" class="abs holder-all browse-mode">
<mct-include key="'topbar-browse'"></mct-include>
<div class="holder browse-area outline abs" ng-controller="BrowseController">
<div class="holder browse-area s-browse-area abs" ng-controller="BrowseController">
<div class='split-layout vertical contents abs'
ng-controller="SplitPaneController as splitter">
<div class='split-pane-component treeview pane'

View File

@ -2,7 +2,7 @@
mct-object="domainObject"
ng-model="representation">
</mct-representation>
<div class="holder edit-area outline abs"
<div class="holder edit-area abs"
ng-controller="SplitPaneController as vSplitter">
<mct-toolbar name="mctToolbar"
structure="toolbar.structure"

View File

@ -1,6 +1,6 @@
{
"name": "General UI elements",
"description": "General UI elements, meant to be reused across modes.",
"description": "General UI elements, meant to be reused across modes",
"resources": "res",
"extensions": {
"runs": [
@ -211,19 +211,21 @@
{
"name": "Modernizr",
"version": "2.6.2",
"description": "Browser/device capability finding.",
"description": "Browser/device capability finding",
"author": "Faruk Ateş",
"website": "http://modernizr.com",
"license": "MIT",
"copyright": "Copyright (c) 20092015",
"license": "license-mit",
"link": "http://modernizr.com/license/"
},
{
"name": "Normalize.css",
"version": "1.1.2",
"description": "Browser style normalization.",
"description": "Browser style normalization",
"author": "Nicolas Gallagher, Jonathan Neal",
"website": "http://necolas.github.io/normalize.css/",
"license": "MIT",
"copyright": "Copyright (c) Nicolas Gallagher and Jonathan Neal",
"license": "license-mit",
"link": "https://github.com/necolas/normalize.css/blob/master/LICENSE.md"
}
]

View File

@ -6,7 +6,7 @@
/* line 4, ../sass/items/_item.scss */
.items-holder .contents {
top: 0; }
/* line 6, ../sass/items/_item.scss */
/* line 8, ../sass/items/_item.scss */
.items-holder .item.grid-item {
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #595959), color-stop(100%, #4d4d4d));
background-image: -webkit-linear-gradient(#595959, #4d4d4d);
@ -43,56 +43,62 @@
background-image: -moz-linear-gradient(#737373, #595959);
background-image: -o-linear-gradient(#737373, #595959);
background-image: linear-gradient(#737373, #595959); }
/* line 19, ../sass/items/_item.scss */
/* line 21, ../sass/items/_item.scss */
.items-holder .item.grid-item:hover .item-main .item-type {
color: #0099cc !important; }
/* line 22, ../sass/items/_item.scss */
/* line 24, ../sass/items/_item.scss */
.items-holder .item.grid-item:hover .item-main .item-open {
display: block; }
/* line 27, ../sass/items/_item.scss */
/* line 28, ../sass/items/_item.scss */
.items-holder .item.grid-item .contents {
top: 5px;
right: 5px;
bottom: 5px;
left: 5px; }
/* line 32, ../sass/items/_item.scss */
.items-holder .item.grid-item .bar.top-bar.abs {
bottom: auto;
height: 20px;
line-height: 20px;
z-index: 5; }
/* line 32, ../sass/items/_item.scss */
/* line 37, ../sass/items/_item.scss */
.items-holder .item.grid-item .bar.top-bar.abs .left, .items-holder .item.grid-item .bar.top-bar.abs .right {
width: auto; }
/* line 34, ../sass/items/_item.scss */
/* line 39, ../sass/items/_item.scss */
.items-holder .item.grid-item .bar.top-bar.abs .left .icon, .items-holder .item.grid-item .bar.top-bar.abs .right .icon {
margin-left: 5px; }
/* line 39, ../sass/items/_item.scss */
/* line 44, ../sass/items/_item.scss */
.items-holder .item.grid-item .bar.bottom-bar.abs {
top: auto;
height: 40px;
padding: 5px; }
/* line 45, ../sass/items/_item.scss */
/* line 50, ../sass/items/_item.scss */
.items-holder .item.grid-item .item-main {
z-index: 1; }
/* line 53, ../sass/items/_item.scss */
/* line 58, ../sass/items/_item.scss */
.items-holder .item.grid-item .item-main .item-type {
color: #737373;
text-align: center;
font-size: 7em;
line-height: 180px; }
/* line 59, ../sass/items/_item.scss */
/* line 64, ../sass/items/_item.scss */
.items-holder .item.grid-item .item-main .item-open {
display: none;
font-size: 5em;
line-height: 180px;
left: auto;
width: 30px; }
/* line 67, ../sass/items/_item.scss */
/* line 72, ../sass/items/_item.scss */
.items-holder .item.grid-item .title {
text-shadow: rgba(0, 0, 0, 0.1) 0 1px 2px;
color: #cccccc;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; }
/* line 75, ../sass/items/_item.scss */
/* line 80, ../sass/items/_item.scss */
.items-holder .item.grid-item .details {
font-size: 0.8em; }
/* line 78, ../sass/items/_item.scss */
/* line 83, ../sass/items/_item.scss */
.items-holder .item.grid-item.selected {
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #00bfff), color-stop(100%, #00ace6));
background-image: -webkit-linear-gradient(#00bfff, #00ace6);
@ -127,15 +133,15 @@
background-image: -moz-linear-gradient(#66d9ff, #00bfff);
background-image: -o-linear-gradient(#66d9ff, #00bfff);
background-image: linear-gradient(#66d9ff, #00bfff); }
/* line 83, ../sass/items/_item.scss */
/* line 88, ../sass/items/_item.scss */
.items-holder .item.grid-item.selected .item-type, .items-holder .item.grid-item.selected .top-bar .icon:not(.alert) {
color: #80dfff; }
/* line 84, ../sass/items/_item.scss */
/* line 89, ../sass/items/_item.scss */
.items-holder .item.grid-item.selected .item-main .item-open {
color: #80dfff; }
/* line 85, ../sass/items/_item.scss */
/* line 90, ../sass/items/_item.scss */
.items-holder .item.grid-item.selected .title {
color: white; }
/* line 87, ../sass/items/_item.scss */
/* line 92, ../sass/items/_item.scss */
.items-holder .item.grid-item.selected:hover .item-main .item-type {
color: white !important; }

View File

@ -1,5 +1,5 @@
/* CONSTANTS */
/* line 17, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 17, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
@ -20,38 +20,38 @@ time, mark, audio, video {
font-size: 100%;
vertical-align: baseline; }
/* line 22, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html {
line-height: 1; }
/* line 24, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
ol, ul {
list-style: none; }
/* line 26, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
table {
border-collapse: collapse;
border-spacing: 0; }
/* line 28, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle; }
/* line 30, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
q, blockquote {
quotes: none; }
/* line 103, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 103, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after {
content: "";
content: none; }
/* line 32, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
a img {
border: none; }
/* line 116, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary {
display: block; }
@ -108,7 +108,6 @@ body, html {
/* line 20, ../sass/_global.scss */
em {
color: rgba(255, 255, 255, 0.2);
font-style: normal; }
/* line 25, ../sass/_global.scss */
@ -148,36 +147,45 @@ span {
width: auto; }
/* line 61, ../sass/_global.scss */
.code {
.code, .codehilite {
font-family: "Lucida Console", monospace;
font-size: 0.7em;
line-height: 150%;
white-space: pre; }
/* line 68, ../sass/_global.scss */
.codehilite {
background-color: rgba(255, 255, 255, 0.1);
padding: 1em; }
/* line 74, ../sass/_global.scss */
.align-right {
text-align: right; }
/* line 72, ../sass/_global.scss */
/* line 78, ../sass/_global.scss */
.centered {
text-align: center; }
/* line 76, ../sass/_global.scss */
/* line 82, ../sass/_global.scss */
.no-margin {
margin: 0; }
/* line 86, ../sass/_global.scss */
.colorKey {
color: #0099cc; }
/* line 80, ../sass/_global.scss */
/* line 90, ../sass/_global.scss */
.ds {
-webkit-box-shadow: rgba(0, 0, 0, 0.7) 0 4px 10px 2px;
-moz-box-shadow: rgba(0, 0, 0, 0.7) 0 4px 10px 2px;
box-shadow: rgba(0, 0, 0, 0.7) 0 4px 10px 2px; }
/* line 85, ../sass/_global.scss */
/* line 95, ../sass/_global.scss */
.hide,
.hidden {
display: none !important; }
/* line 89, ../sass/_global.scss */
/* line 99, ../sass/_global.scss */
.sep {
color: rgba(255, 255, 255, 0.2); }
@ -195,76 +203,55 @@ span {
.ui-symbol {
font-family: 'symbolsfont'; }
/* line 13, ../sass/user-environ/_layout.scss */
/* line 11, ../sass/user-environ/_layout.scss */
.holder-all {
top: 3px;
right: 3px;
bottom: 3px;
left: 3px; }
/* line 21, ../sass/user-environ/_layout.scss */
.browse-area,
.edit-area,
.editor {
position: absolute; }
/* line 25, ../sass/user-environ/_layout.scss */
.editor {
-webkit-border-radius: 4.5px;
-moz-border-radius: 4.5px;
-ms-border-radius: 4.5px;
-o-border-radius: 4.5px;
border-radius: 4.5px;
position: absolute; }
border-radius: 4.5px; }
/* line 24, ../sass/user-environ/_layout.scss */
.user-environ .browse-area,
.user-environ .edit-area,
.user-environ .editor {
top: 45px;
right: 5px;
bottom: 30px;
left: 5px; }
/* line 33, ../sass/user-environ/_layout.scss */
.user-environ .edit-area .tool-bar {
bottom: auto;
height: 35px;
line-height: 28px; }
/* line 38, ../sass/user-environ/_layout.scss */
.user-environ .edit-area .work-area {
top: 45px; }
/* line 43, ../sass/user-environ/_layout.scss */
.user-environ .bottom-bar {
top: auto;
right: 5px;
bottom: 5px;
left: 5px;
height: 20px; }
/* line 49, ../sass/user-environ/_layout.scss */
.user-environ .bottom-bar .status-holder {
right: 110px; }
/* line 52, ../sass/user-environ/_layout.scss */
.user-environ .bottom-bar .app-logo {
left: auto;
width: 105px; }
/* line 60, ../sass/user-environ/_layout.scss */
/* line 29, ../sass/user-environ/_layout.scss */
.contents {
box-sizing: border-box;
position: absolute;
top: 5px;
right: 5px;
bottom: 5px;
left: 5px; }
/* line 68, ../sass/user-environ/_layout.scss */
top: 0;
right: 0;
bottom: 0;
left: 0; }
/* line 37, ../sass/user-environ/_layout.scss */
.contents.nomargin {
right: 0px;
bottom: 0px;
left: 0px; }
/* line 77, ../sass/user-environ/_layout.scss */
/* line 46, ../sass/user-environ/_layout.scss */
.bar .icon.major {
margin-right: 5px; }
/* line 80, ../sass/user-environ/_layout.scss */
/* line 49, ../sass/user-environ/_layout.scss */
.bar.abs, .btn-menu span.bar.l-click-area {
text-wrap: none;
white-space: nowrap; }
/* line 84, ../sass/user-environ/_layout.scss */
/* line 53, ../sass/user-environ/_layout.scss */
.bar.abs.left, .btn-menu span.bar.left.l-click-area,
.bar.abs .left,
.btn-menu span.bar.l-click-area .left {
width: 45%;
right: auto; }
/* line 89, ../sass/user-environ/_layout.scss */
/* line 58, ../sass/user-environ/_layout.scss */
.bar.abs.right, .btn-menu span.bar.right.l-click-area,
.bar.abs .right,
.btn-menu span.bar.l-click-area .right {
@ -272,17 +259,53 @@ span {
left: auto;
right: 0;
text-align: right; }
/* line 94, ../sass/user-environ/_layout.scss */
/* line 63, ../sass/user-environ/_layout.scss */
.bar.abs.right .icon.major, .btn-menu span.bar.right.l-click-area .icon.major,
.bar.abs .right .icon.major,
.btn-menu span.bar.l-click-area .right .icon.major {
margin-left: 15px; }
/* line 104, ../sass/user-environ/_layout.scss */
/* line 76, ../sass/user-environ/_layout.scss */
.user-environ .browse-area,
.user-environ .edit-area,
.user-environ .editor {
top: 45px;
right: 5px;
bottom: 30px;
left: 5px; }
/* line 85, ../sass/user-environ/_layout.scss */
.user-environ .browse-area > .contents,
.user-environ .edit-area > .contents {
left: 0;
right: 0; }
/* line 93, ../sass/user-environ/_layout.scss */
.user-environ .edit-area .tool-bar {
bottom: auto;
height: 35px;
line-height: 28px; }
/* line 98, ../sass/user-environ/_layout.scss */
.user-environ .edit-area .work-area {
top: 45px; }
/* line 103, ../sass/user-environ/_layout.scss */
.user-environ .bottom-bar {
top: auto;
right: 5px;
bottom: 5px;
left: 5px;
height: 20px; }
/* line 109, ../sass/user-environ/_layout.scss */
.user-environ .bottom-bar .status-holder {
right: 110px; }
/* line 112, ../sass/user-environ/_layout.scss */
.user-environ .bottom-bar .app-logo {
left: auto;
width: 105px; }
/* line 119, ../sass/user-environ/_layout.scss */
.cols {
overflow: hidden;
*zoom: 1; }
/* line 106, ../sass/user-environ/_layout.scss */
/* line 121, ../sass/user-environ/_layout.scss */
.cols .col {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
@ -293,89 +316,89 @@ span {
margin-left: 1.5%;
padding-left: 5px;
position: relative; }
/* line 114, ../sass/user-environ/_layout.scss */
/* line 129, ../sass/user-environ/_layout.scss */
.cols .col:first-child {
margin-left: 0;
padding-left: 0; }
/* line 121, ../sass/user-environ/_layout.scss */
/* line 136, ../sass/user-environ/_layout.scss */
.cols.cols-2 .col-1 {
min-width: 250px;
width: 48.5%; }
/* line 127, ../sass/user-environ/_layout.scss */
/* line 142, ../sass/user-environ/_layout.scss */
.cols.cols-2-ff .col-100px {
width: 100px; }
/* line 134, ../sass/user-environ/_layout.scss */
/* line 149, ../sass/user-environ/_layout.scss */
.cols.cols-6 .col-1 {
min-width: 83.33333px;
width: 15.16667%; }
/* line 140, ../sass/user-environ/_layout.scss */
/* line 155, ../sass/user-environ/_layout.scss */
.cols.cols-16 .col-1 {
min-width: 31.25px;
width: 4.75%; }
/* line 143, ../sass/user-environ/_layout.scss */
/* line 158, ../sass/user-environ/_layout.scss */
.cols.cols-16 .col-2 {
min-width: 62.5px;
width: 11%; }
/* line 146, ../sass/user-environ/_layout.scss */
/* line 161, ../sass/user-environ/_layout.scss */
.cols.cols-16 .col-7 {
min-width: 218.75px;
width: 42.25%; }
/* line 152, ../sass/user-environ/_layout.scss */
/* line 167, ../sass/user-environ/_layout.scss */
.cols.cols-32 .col-2 {
min-width: 31.25px;
width: 4.75%; }
/* line 155, ../sass/user-environ/_layout.scss */
/* line 170, ../sass/user-environ/_layout.scss */
.cols.cols-32 .col-15 {
min-width: 234.375px;
width: 45.375%; }
/* line 159, ../sass/user-environ/_layout.scss */
/* line 174, ../sass/user-environ/_layout.scss */
.cols .l-row {
overflow: hidden;
*zoom: 1;
padding: 5px 0; }
/* line 165, ../sass/user-environ/_layout.scss */
/* line 180, ../sass/user-environ/_layout.scss */
.pane {
position: absolute; }
/* line 168, ../sass/user-environ/_layout.scss */
/* line 183, ../sass/user-environ/_layout.scss */
.pane.treeview .create-btn-holder {
bottom: auto;
height: 35px; }
/* line 171, ../sass/user-environ/_layout.scss */
/* line 186, ../sass/user-environ/_layout.scss */
.pane.treeview .tree-holder {
overflow: auto;
top: 40px; }
/* line 180, ../sass/user-environ/_layout.scss */
/* line 195, ../sass/user-environ/_layout.scss */
.pane.items .object-holder {
top: 40px; }
/* line 185, ../sass/user-environ/_layout.scss */
/* line 200, ../sass/user-environ/_layout.scss */
.pane.edit-main .object-holder {
top: 0; }
/* line 191, ../sass/user-environ/_layout.scss */
/* line 206, ../sass/user-environ/_layout.scss */
.pane .object-holder {
overflow: auto; }
/* line 199, ../sass/user-environ/_layout.scss */
/* line 214, ../sass/user-environ/_layout.scss */
.split-layout.horizontal > .pane {
margin-top: 5px; }
/* line 202, ../sass/user-environ/_layout.scss */
/* line 217, ../sass/user-environ/_layout.scss */
.split-layout.horizontal > .pane:first-child {
margin-top: 0; }
/* line 209, ../sass/user-environ/_layout.scss */
/* line 224, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane {
margin-left: 5px; }
/* line 211, ../sass/user-environ/_layout.scss */
/* line 226, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane > .holder {
left: 0;
right: 0; }
/* line 215, ../sass/user-environ/_layout.scss */
/* line 230, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane:first-child {
margin-left: 0; }
/* line 217, ../sass/user-environ/_layout.scss */
/* line 232, ../sass/user-environ/_layout.scss */
.split-layout.vertical > .pane:first-child .holder {
right: 5px; }
/* line 226, ../sass/user-environ/_layout.scss */
/* line 241, ../sass/user-environ/_layout.scss */
.vscroll {
overflow-y: auto; }
@ -388,33 +411,33 @@ span {
left: 0;
width: auto;
height: auto; }
/* line 8, ../sass/_fixed-position.scss */
/* line 12, ../sass/_fixed-position.scss */
.t-fixed-position.l-fixed-position .l-grid-holder {
position: relative;
height: 100%;
width: 100%; }
/* line 11, ../sass/_fixed-position.scss */
/* line 16, ../sass/_fixed-position.scss */
.t-fixed-position.l-fixed-position .l-grid-holder .l-grid {
position: absolute;
height: 100%;
width: 100%;
pointer-events: none;
z-index: 0; }
/* line 21, ../sass/_fixed-position.scss */
/* line 27, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item {
position: absolute;
border: 1px solid transparent; }
/* line 25, ../sass/_fixed-position.scss */
/* line 31, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item.s-selected {
-webkit-box-shadow: rgba(0, 0, 0, 0.7) 0 3px 10px;
-moz-box-shadow: rgba(0, 0, 0, 0.7) 0 3px 10px;
box-shadow: rgba(0, 0, 0, 0.7) 0 3px 10px;
border-color: #0099cc;
cursor: move; }
/* line 30, ../sass/_fixed-position.scss */
/* line 36, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item.s-not-selected {
opacity: 0.8; }
/* line 36, ../sass/_fixed-position.scss */
/* line 42, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-box,
.t-fixed-position .l-fixed-position-item .l-fixed-position-image,
.t-fixed-position .l-fixed-position-item .l-fixed-position-text {
@ -423,20 +446,20 @@ span {
box-sizing: border-box;
height: 100%;
width: 100%; }
/* line 44, ../sass/_fixed-position.scss */
/* line 51, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-image {
background-size: cover;
background-repeat: no-repeat;
background-position: center; }
/* line 50, ../sass/_fixed-position.scss */
/* line 57, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-text {
text-shadow: rgba(0, 0, 0, 0.1) 0 1px 2px;
border: 1px solid transparent;
font-size: 0.8rem; }
/* line 55, ../sass/_fixed-position.scss */
/* line 62, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-text.l-static-text {
padding: 3px; }
/* line 60, ../sass/_fixed-position.scss */
/* line 67, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-text.l-telemetry .l-elem {
overflow: hidden;
position: absolute;
@ -450,98 +473,142 @@ span {
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 50%; }
/* line 64, ../sass/_fixed-position.scss */
/* line 71, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-text.l-telemetry .l-elem.l-title {
right: auto;
left: 3px; }
/* line 68, ../sass/_fixed-position.scss */
/* line 75, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-text.l-telemetry .l-elem.l-value {
right: 3px;
left: auto;
text-align: right; }
/* line 73, ../sass/_fixed-position.scss */
/* line 80, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item .l-fixed-position-text.l-telemetry .l-elem.l-value.telem-only {
left: 3px;
width: auto; }
/* line 84, ../sass/_fixed-position.scss */
/* line 91, ../sass/_fixed-position.scss */
.t-fixed-position .l-fixed-position-item-handle {
background: rgba(0, 153, 204, 0.5);
cursor: crosshair;
border: 1px solid #0099cc;
position: absolute; }
/* line 98, ../sass/_fixed-position.scss */
/* line 105, ../sass/_fixed-position.scss */
.edit-mode .t-fixed-position.l-fixed-position .l-grid-holder .l-grid.l-grid-x {
background-image: -webkit-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-image: -moz-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-image: -o-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-image: linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-repeat: repeat-x; }
/* line 102, ../sass/_fixed-position.scss */
/* line 109, ../sass/_fixed-position.scss */
.edit-mode .t-fixed-position.l-fixed-position .l-grid-holder .l-grid.l-grid-y {
background-image: -webkit-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-image: -moz-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-image: -o-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-image: linear-gradient(0deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 100%);
background-repeat: repeat-y; }
/* line 110, ../sass/_fixed-position.scss */
.edit-mode .t-fixed-position .l-fixed-position-item:not(.s-selected):hover {
border: 1px dotted rgba(0, 153, 204, 0.5); }
/* line 117, ../sass/_fixed-position.scss */
.edit-mode .t-fixed-position .l-fixed-position-item:not(.s-selected) {
border: 1px dotted rgba(0, 153, 204, 0.75); }
/* line 119, ../sass/_fixed-position.scss */
.edit-mode .t-fixed-position .l-fixed-position-item:not(.s-selected):hover {
border: 1px dotted #0099cc; }
/* line 3, ../sass/_about.scss */
.t-about {
/* line 5, ../sass/_about.scss */
.l-about.abs, .btn-menu span.l-about.l-click-area {
overflow: auto; }
/* line 10, ../sass/_about.scss */
.l-about .l-logo-holder {
position: relative;
height: 45%; }
/* line 13, ../sass/_about.scss */
.l-about .l-logo-holder .l-logo {
position: absolute; }
/* line 16, ../sass/_about.scss */
.l-about .l-logo-holder .l-logo.l-logo-app {
top: 0;
right: 15%;
bottom: 0;
left: 15%; }
/* line 20, ../sass/_about.scss */
.l-about .l-logo-holder .l-logo.s-logo-nasa {
background-image: url("../images/logo-nasa.svg");
top: 10px;
right: auto;
bottom: auto;
left: 10px;
width: 10%;
height: auto;
padding-bottom: 5%;
padding-top: 5%; }
/* line 29, ../sass/_about.scss */
.l-about .l-content {
position: relative;
margin-top: 10px; }
/* line 36, ../sass/_about.scss */
.s-about {
line-height: 120%; }
/* line 7, ../sass/_about.scss */
.t-about .s-description,
.t-about .s-info {
font-size: 0.8em; }
/* line 10, ../sass/_about.scss */
.t-about .s-logo-holder {
/* line 40, ../sass/_about.scss */
.s-about a {
color: #84b3ff; }
/* line 47, ../sass/_about.scss */
.s-about .s-logo-holder {
background: url("../images/bg-about-openmctweb.jpg") no-repeat center;
background-size: cover; }
/* line 14, ../sass/_about.scss */
.t-about .s-logo {
/* line 51, ../sass/_about.scss */
.s-about .s-logo {
background-position: center;
background-repeat: no-repeat;
background-size: contain; }
/* line 20, ../sass/_about.scss */
.t-about .s-logo-openmctweb {
/* line 57, ../sass/_about.scss */
.s-about .s-logo-openmctweb {
background-image: url("../images/logo-openmctweb-shdw.svg"); }
/* line 23, ../sass/_about.scss */
.t-about h1, .t-about h2 {
/* line 60, ../sass/_about.scss */
.s-about .s-btn, .s-about .s-icon-btn {
line-height: 2em; }
/* line 64, ../sass/_about.scss */
.s-about .l-licenses-software .l-license-software {
border-top: 1px solid #4d4d4d;
padding: 0.5em 0; }
/* line 67, ../sass/_about.scss */
.s-about .l-licenses-software .l-license-software:first-child {
border-top: none; }
/* line 70, ../sass/_about.scss */
.s-about .l-licenses-software .l-license-software em {
color: #666666; }
/* line 77, ../sass/_about.scss */
.s-about .l-licenses-software .l-license-software h3 {
font-size: 1.25em; }
/* line 80, ../sass/_about.scss */
.s-about .l-licenses-software .l-license-software .s-license-text {
font-size: 0.9em; }
/* line 3, ../sass/_text.scss */
.abs.l-standalone, .btn-menu span.l-standalone.l-click-area {
padding: 5% 20%; }
/* line 8, ../sass/_text.scss */
.s-text {
font-size: 0.8em; }
/* line 10, ../sass/_text.scss */
.s-text ol, .s-text ul {
list-style: square;
margin-left: 1.5em; }
/* line 18, ../sass/_text.scss */
.s-text h1, .s-text h2, .s-text h3 {
color: #fff;
font-weight: normal !important; }
/* line 29, ../sass/_about.scss */
.t-about.l-about.abs, .btn-menu span.t-about.l-about.l-click-area {
overflow: auto; }
/* line 34, ../sass/_about.scss */
.t-about .l-logo-holder {
position: relative;
height: 45%; }
/* line 37, ../sass/_about.scss */
.t-about .l-logo-holder .l-logo {
position: absolute; }
/* line 40, ../sass/_about.scss */
.t-about .l-logo-holder .l-logo.l-logo-app {
top: 0;
right: 15%;
bottom: 0;
left: 15%; }
/* line 44, ../sass/_about.scss */
.t-about .l-logo-holder .l-logo.s-logo-nasa {
background-image: url("../images/logo-nasa.svg");
top: 10px;
right: auto;
bottom: auto;
left: 10px;
width: 10%;
height: auto;
padding-bottom: 5%;
padding-top: 5%; }
/* line 53, ../sass/_about.scss */
.t-about .l-content {
position: relative;
margin-top: 10px; }
font-weight: normal !important;
margin-bottom: 1em; }
/* line 24, ../sass/_text.scss */
.s-text h2 {
border-top: 1px solid #4d4d4d;
font-size: 1.5em;
margin-top: 2em;
padding-top: 1em; }
/* line 31, ../sass/_text.scss */
.s-text h3 {
margin-top: 2em; }
/* line 1, ../sass/_badges.scss */
.badge {
@ -2524,6 +2591,10 @@ input[type="text"] {
margin-left: 10px; }
/* line 53, ../sass/overlay/_overlay.scss */
.overlay .contents.l-dialog {
top: 5px;
right: 5px;
bottom: 5px;
left: 5px;
overflow: auto; }
/* line 4, ../sass/user-environ/_frame.scss */
@ -2540,8 +2611,14 @@ input[type="text"] {
/* line 18, ../sass/user-environ/_frame.scss */
.frame > .object-holder.abs, .btn-menu .frame > span.object-holder.l-click-area {
top: 23px; }
/* line 21, ../sass/user-environ/_frame.scss */
.frame .contents {
top: 5px;
right: 5px;
bottom: 5px;
left: 5px; }
/* line 24, ../sass/user-environ/_frame.scss */
/* line 31, ../sass/user-environ/_frame.scss */
.edit-main .frame.child-frame.panel:hover {
border-color: #0099cc;
-webkit-box-shadow: rgba(0, 0, 0, 0.7) 0 3px 10px;
@ -2553,27 +2630,28 @@ input[type="text"] {
line-height: 35px; }
/* line 7, ../sass/user-environ/_top-bar.scss */
.top-bar.browse, .top-bar.edit {
border-bottom: 1px solid #4d4d4d;
top: 5px;
right: 5px;
bottom: auto;
left: 5px;
height: 35px; }
/* line 15, ../sass/user-environ/_top-bar.scss */
/* line 16, ../sass/user-environ/_top-bar.scss */
.top-bar .title {
color: #fff; }
/* line 20, ../sass/user-environ/_top-bar.scss */
/* line 21, ../sass/user-environ/_top-bar.scss */
.top-bar .buttons-main {
font-size: 0.8em;
left: auto;
text-align: right; }
/* line 25, ../sass/user-environ/_top-bar.scss */
/* line 26, ../sass/user-environ/_top-bar.scss */
.top-bar .buttons-main .btn {
margin-left: 5px; }
/* line 33, ../sass/user-environ/_top-bar.scss */
/* line 34, ../sass/user-environ/_top-bar.scss */
.edit-mode .top-bar .buttons-main {
white-space: nowrap; }
/* line 37, ../sass/user-environ/_top-bar.scss */
/* line 38, ../sass/user-environ/_top-bar.scss */
.edit-mode .top-bar .buttons-main.abs, .edit-mode .top-bar .btn-menu span.buttons-main.l-click-area, .btn-menu .edit-mode .top-bar span.buttons-main.l-click-area {
bottom: auto;
left: auto; }
@ -2667,49 +2745,107 @@ input[type="text"] {
.tool-bar .input-labeled label {
font-size: 12.6px; }
/* line 1, ../sass/helpers/_bubbles.scss */
.bubble-wrapper {
/* line 6, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper {
-webkit-box-shadow: rgba(0, 0, 0, 0.4) 0 1px 5px;
-moz-box-shadow: rgba(0, 0, 0, 0.4) 0 1px 5px;
box-shadow: rgba(0, 0, 0, 0.4) 0 1px 5px;
position: absolute;
z-index: 10; }
/* line 8, ../sass/helpers/_bubbles.scss */
.bubble-wrapper .bubble {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
z-index: 70; }
/* line 11, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble {
display: inline-block;
background: #990000;
color: #ff9999;
font-size: 0.8rem;
font-style: italic;
max-width: 200px;
padding: 4px 8px; }
/* line 17, ../sass/helpers/_bubbles.scss */
.bubble-wrapper .bubble:before {
max-width: 250px;
padding: 5px 10px; }
/* line 15, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble:before {
content: "";
position: absolute;
width: 0;
height: 0; }
/* line 24, ../sass/helpers/_bubbles.scss */
.bubble-wrapper.arw-left .bubble:before {
right: 100%;
top: 50%;
margin-top: -7px;
border-top: 7px solid transparent;
border-bottom: 7px solid transparent;
border-right: 10.5px solid #990000; }
/* line 32, ../sass/helpers/_bubbles.scss */
.bubble-wrapper.arw-down .bubble:before {
left: 50%;
top: 100%;
margin-left: -7px;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 10.5px solid #990000; }
/* line 21, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table {
width: 100%; }
/* line 24, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table tr td {
padding: 2px 0;
vertical-align: top; }
/* line 31, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table tr td.label {
padding-right: 10px;
white-space: nowrap; }
/* line 35, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table tr td.value {
white-space: nowrap; }
/* line 39, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble table tr td.align-wrap {
white-space: normal; }
/* line 45, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper .l-infobubble .title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 5px; }
/* line 52, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left {
margin-left: 10px; }
/* line 54, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-left .l-infobubble::before {
right: 100%;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-right: 7.5px solid #dddddd; }
/* line 62, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right {
margin-right: 10px; }
/* line 64, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-right .l-infobubble::before {
left: 100%;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 7.5px solid #dddddd; }
/* line 73, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-top .l-infobubble::before {
top: 10px; }
/* line 79, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-btm .l-infobubble::before {
bottom: 10px; }
/* line 84, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-down {
margin-bottom: 10px; }
/* line 86, ../sass/helpers/_bubbles.scss */
.l-infobubble-wrapper.arw-down .l-infobubble::before {
left: 50%;
top: 100%;
margin-left: -5px;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 7.5px solid #dddddd; }
/* line 99, ../sass/helpers/_bubbles.scss */
.s-infobubble {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
background: #dddddd;
color: #666666;
font-size: 0.8rem; }
/* line 105, ../sass/helpers/_bubbles.scss */
.s-infobubble .title {
color: #333333;
font-weight: bold; }
/* line 110, ../sass/helpers/_bubbles.scss */
.s-infobubble tr td {
border-top: 1px solid #c4c4c4;
font-size: 0.9em; }
/* line 114, ../sass/helpers/_bubbles.scss */
.s-infobubble tr:first-child td {
border-top: none; }
/* line 118, ../sass/helpers/_bubbles.scss */
.s-infobubble .value {
color: #333333; }
/* line 8, ../sass/helpers/_splitter.scss */
.split-layout .splitter {
@ -2833,10 +2969,10 @@ input[type="text"] {
.wait-spinner {
display: block;
position: absolute;
-webkit-animation: rotation .6s infinite linear;
-moz-animation: rotation .6s infinite linear;
-o-animation: rotation .6s infinite linear;
animation: rotation .6s infinite linear;
-webkit-animation: rotation 0.6s infinite linear;
-moz-animation: rotation 0.6s infinite linear;
-o-animation: rotation 0.6s infinite linear;
animation: rotation 0.6s infinite linear;
border-color: rgba(0, 153, 204, 0.25);
border-top-color: #0099cc;
border-style: solid;
@ -2875,10 +3011,10 @@ input[type="text"] {
.treeview .wait-spinner {
display: block;
position: absolute;
-webkit-animation: rotation .6s infinite linear;
-moz-animation: rotation .6s infinite linear;
-o-animation: rotation .6s infinite linear;
animation: rotation .6s infinite linear;
-webkit-animation: rotation 0.6s infinite linear;
-moz-animation: rotation 0.6s infinite linear;
-o-animation: rotation 0.6s infinite linear;
animation: rotation 0.6s infinite linear;
border-color: rgba(0, 153, 204, 0.25);
border-top-color: #0099cc;
border-style: solid;
@ -2990,3 +3126,21 @@ input[type="text"] {
.autoflow .l-autoflow-items .l-autoflow-col:first-child {
border-left: none;
padding-left: 0; }
/* Styles for the iframe EmbeddedPageController element */
/* line 4, ../sass/_iframe.scss */
.l-iframe iframe {
display: block;
height: 100%;
width: 100%; }
/******************************** BROWSE */
/* line 6, ../sass/_hide-non-functional.scss */
.browse-mode .browse.top-bar {
display: none; }
/* line 11, ../sass/_hide-non-functional.scss */
.browse-mode .browse-area.holder {
top: 5px; }
/* line 18, ../sass/_hide-non-functional.scss */
.browse-mode .browse-area.holder > .contents.split-layout .object-browse-bar .t-btn.key-window {
display: none; }

View File

@ -2,7 +2,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg>
<metadata>
Created by FontForge 20110222 at Thu Mar 19 18:28:43 2015
Created by FontForge 20090622 at Tue Apr 28 20:52:23 2015
By deploy user
Copyright 2015 Adobe Systems Incorporated. All rights reserved.
</metadata>
@ -21,7 +21,7 @@ Copyright 2015 Adobe Systems Incorporated. All rights reserved.
bbox="-33 -19 1143 787"
underline-thickness="50"
underline-position="-50"
unicode-range="U+0020-2044"
unicode-range="U+0020-U+2044"
/>
<missing-glyph horiz-adv-x="500"
/>
@ -129,7 +129,7 @@ v-356zM635 88v356h-83v-356h83z" />
<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="742"
d="M373 602l-238 -237l237 -237l236 238zM373 731q39 0 66 -28l270 -270q29 -28 29 -67.5t-29 -67.5l-271 -271q-26 -27 -66 -27q-41 0 -68 27l-271 271q-27 27 -27 67t27 67l271 271q28 28 69 28z" />
<glyph glyph-name="backslash" unicode="\" horiz-adv-x="810"
d="M806 0h-178l-228 265q-20 -6 -41 -6q-65 0 -111 47t-46 112q0 34 12 63l-214 251h178l139 -162q23 5 42 5q65 0 112 -46t47 -111q0 -30 -14 -65zM286 418q0 -31 21 -53t52 -22t53 22t22 53t-22 52t-53 21t-52 -21t-21 -52z" />
d="M806 0h-178l-228 265q-19 -6 -41 -6q-65 0 -111 47t-46 112q0 34 12 63l-214 251h178l139 -162q23 5 42 5q65 0 112 -46t47 -111q0 -30 -14 -65zM286 418q0 -31 21 -53t52 -22t53 22t22 53t-22 52t-53 21t-52 -21t-21 -52z" />
<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="807"
d="M128 237l-61 61q-27 27 -27 67t27 67l271 271q28 28 69 28q39 0 67 -28l61 -60l-85 -85l-43 44l-238 -237l44 -44zM683 494l61 -61q28 -28 28 -67.5t-28 -67.5l-271 -271q-27 -27 -67 -27q-41 0 -68 27l-61 62l84 84l45 -45l237 238l-44 44zM697 731h149l-731 -731h-148z
" />
@ -185,7 +185,7 @@ v-170z" />
<glyph glyph-name="u" unicode="u" horiz-adv-x="809"
d="M405 396l-397 -396h794zM740 732q29 0 49 -20t20 -49v-122q0 -29 -20 -49.5t-49 -20.5h-671q-29 0 -49 20.5t-20 49.5v122q0 29 20 49t49 20h671z" />
<glyph glyph-name="v" unicode="v" horiz-adv-x="787"
d="M394 202l-394 377h787q-63 -61 -194.5 -187t-198.5 -190z" />
d="M394 202l-394 377h787z" />
<glyph glyph-name="x" unicode="x" horiz-adv-x="726"
d="M726 110q6 -6 6 -15t-6 -14l-72 -73q-6 -6 -15 -6t-14 6l-258 258l-257 -258q-6 -6 -15 -6t-15 6l-72 73q-6 5 -6 14t6 15l257 257l-257 258q-14 15 0 29l72 73q6 6 15 6t15 -6l257 -258l258 258q5 6 14 6t15 -6l72 -73q14 -14 0 -29l-257 -258z" />
<glyph glyph-name="y" unicode="y" horiz-adv-x="806"
@ -218,10 +218,12 @@ d="M656 750q39 0 66.5 -27.5t27.5 -66.5v-562q0 -39 -27.5 -66.5t-66.5 -27.5h-562q-
<glyph glyph-name="egrave" unicode="&#xe8;" horiz-adv-x="754"
d="M703 703q47 -48 47 -116t-47 -117l-94 -94q-48 -48 -117 -48q-41 0 -84 24l-8 -9q28 -47 21.5 -104t-46.5 -97l-94 -94q-48 -48 -117 -48q-68 0 -116 48q-47 49 -47 117t47 116l94 94q47 47 115 47q47 0 85 -22l9 9q-28 47 -21.5 103.5t46.5 96.5l94 94q47 47 116 47
q70 0 117 -47zM307 209q26 25 21 62l-41 -41q-14 -12 -30 -12q-15 0 -27 12q-12 10 -12 28t12 29l41 41h-14q-28 0 -48 -20l-94 -94q-20 -20 -20 -49t20 -49q21 -22 49 -22q29 0 50 22zM635 538q21 20 21 49t-21 49q-20 20 -49 20t-49 -20l-94 -94q-25 -24 -20 -62l41 41
q10 12 28 12t29 -12q12 -12 12 -29q0 -14 -12 -28l-41 -41q3 0 7 -0.5t5 -0.5q29 0 50 22z" />
q11 12 28 12q18 0 29 -12q12 -12 12 -29q0 -14 -12 -28l-41 -41q3 0 7 -0.5t5 -0.5q29 0 50 22z" />
<glyph glyph-name="eacute" unicode="&#xe9;"
d="M188 235h-160q-28 67 -28 140q0 156 110 265.5t265 109.5q88 0 164 -37t129 -103h-105q-39 0 -66.5 -27.5t-27.5 -66.5v-92v-2h-188q-39 0 -66 -27t-27 -67v-92v-1zM564 516h160q26 -62 26 -141q0 -155 -109.5 -265t-265.5 -110q-86 0 -162.5 38t-128.5 103h104
q39 0 66 27.5t27 66.5v93h2h186q39 0 66.5 27.5t27.5 66.5v94h1z" />
<glyph glyph-name="ecircumflex" unicode="&#xea;" horiz-adv-x="751"
d="M376 750v-375h375v-235q0 -58 -41.5 -99t-99.5 -41h-469q-58 0 -99 41t-41 99v469q0 58 41 99.5t99 41.5h235zM470 750l281 -281h-281v281z" />
<glyph glyph-name="fraction" unicode="&#x2044;" horiz-adv-x="761"
d="M380 751q158 0 269.5 -111.5t111.5 -268.5q0 -133 -82.5 -236.5t-209.5 -134.5l-4 491l-176 -490q-126 31 -207.5 134.5t-81.5 235.5q0 157 111.5 268.5t268.5 111.5zM168 488l55 20l-34 94l-56 -20zM410 530v100h-59v-100h59zM593 488l34 94l-55 20l-34 -94z" />
<glyph glyph-name="H.002" horiz-adv-x="803"

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,32 +1,8 @@
// General About dialog styling
.t-about {
// Styling
line-height: 120%;
.s-description,
.s-info {
font-size: 0.8em;
}
.s-logo-holder {
background: url($dirImgs + "bg-about-openmctweb.jpg") no-repeat center; // For OpenMCT Web.
background-size: cover;
}
.s-logo {
// @include txtShdwLarge(); // text-shadow doesn't work for svg
background-position: center;
background-repeat: no-repeat;
background-size: contain;
}
.s-logo-openmctweb {
background-image: url($dirImgs + 'logo-openmctweb-shdw.svg');
}
h1, h2 {
color: #fff;
font-weight: normal !important;
}
.l-about {
// Layout
&.l-about.abs {
&.abs {
// top: 20px;
overflow: auto;
}
@ -57,3 +33,54 @@
}
}
.s-about {
// Styling
line-height: 120%;
a {
color: #84b3ff;
}
.s-description,
.s-info {
// font-size: 0.8em;
}
.s-logo-holder {
background: url($dirImgs + "bg-about-openmctweb.jpg") no-repeat center; // For OpenMCT Web.
background-size: cover;
}
.s-logo {
// @include txtShdwLarge(); // text-shadow doesn't work for svg
background-position: center;
background-repeat: no-repeat;
background-size: contain;
}
.s-logo-openmctweb {
background-image: url($dirImgs + 'logo-openmctweb-shdw.svg');
}
.s-btn {
line-height: 2em;
}
.l-licenses-software {
.l-license-software {
border-top: 1px solid $colorInteriorBorder;
padding: 0.5em 0;
&:first-child {
border-top: none;
}
em {
color: darken($colorBodyFg, 20%);
// margin-left: 2em;
&:first-child {
// margin-left: 0;
}
}
h3 {
font-size: 1.25em;
}
.s-license-text {
font-size: 0.9em;
}
}
}
}

View File

@ -1,17 +1,23 @@
.t-fixed-position {
&.l-fixed-position {
// @include test(red);
// @include test(red);
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
width: auto; height: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: auto;
height: auto;
.l-grid-holder {
position: relative;
height: 100%; width: 100%;
height: 100%;
width: 100%;
.l-grid {
// @include test(orange);
// @include test(orange);
position: absolute;
height: 100%; width: 100%;
height: 100%;
width: 100%;
pointer-events: none;
z-index: 0;
}
@ -35,12 +41,13 @@
.l-fixed-position-image,
.l-fixed-position-text {
@include box-sizing(border-box);
height: 100%; width: 100%;
height: 100%;
width: 100%;
}
.l-fixed-position-box {
}
.l-fixed-position-image {
background-size: cover;
background-repeat: no-repeat;
@ -49,11 +56,11 @@
.l-fixed-position-text {
@include txtShdwSubtle();
border:1px solid transparent;
border: 1px solid transparent;
font-size: 0.8rem;
$p: $interiorMarginSm;
&.l-static-text {
// overflow: auto;
// overflow: auto;
padding: $p;
}
&.l-telemetry {
@ -66,12 +73,12 @@
left: $p;
}
&.l-value {
// @include test(blue);
// @include test(blue);
right: $p;
left: auto;
text-align: right;
&.telem-only {
// @include test(red);
// @include test(red);
left: $p;
width: auto;
}
@ -107,8 +114,11 @@
}
.l-fixed-position-item {
&:not(.s-selected):hover {
border: 1px dotted rgba($colorKey, 0.5);
&:not(.s-selected) {
border: 1px dotted rgba($colorKey, 0.75);
&:hover {
border: 1px dotted rgba($colorKey, 1.0);
}
}
}
}

View File

@ -18,7 +18,7 @@ body, html {
}
em {
color: rgba(white, 0.2);
// color: rgba(white, 0.2); Removed this as a global setting
font-style: normal;
}
@ -65,6 +65,12 @@ span {
white-space: pre;
}
.codehilite {
@extend .code;
background-color: rgba(#fff, 0.1);
padding: 1em;
}
.align-right {
text-align: right;
}
@ -73,6 +79,10 @@ span {
text-align: center;
}
.no-margin {
margin: 0;
}
.colorKey {
color: $colorKey;
}

View File

@ -0,0 +1,25 @@
// Styles to temporarily hide non-functional elements
/******************************** BROWSE */
.browse-mode {
.browse {
&.top-bar {
display: none;
}
}
.browse-area.holder {
// When .browse.top-bar is hidden, set the top of the browse-area holder
top: $interiorMargin;
> .contents.split-layout {
// Don't pad in from top and bottom
//top: 0; bottom: 0;
.object-browse-bar {
.t-btn.key-window {
// Hide the Open in New Window button
display: none;
}
}
}
}
}

View File

@ -0,0 +1,9 @@
/* Styles for the iframe EmbeddedPageController element */
.l-iframe {
iframe {
display: block;
height: 100%;
width: 100%;
}
}

View File

@ -11,6 +11,7 @@
@import "user-environ/layout";
@import "fixed-position";
@import "about";
@import "text";
@import "badges";
@import "icons";
@import "lists/tabular";
@ -39,3 +40,5 @@
@import "helpers/wait-spinner";
@import "properties";
@import "autoflow";
@import "iframe";
@import "hide-non-functional";

View File

@ -0,0 +1,35 @@
// Styles for extended text copy
.abs.l-standalone {
$d: 20%;
padding: $d/4 $d;
}
.s-text {
font-size: 0.8em;
ol, ul {
list-style: square;
margin-left: 1.5em;
li {
}
}
h1, h2, h3 {
color: #fff;
font-weight: normal !important;
margin-bottom: 1em;
}
h2 {
border-top: 1px solid $colorInteriorBorder;
font-size: 1.5em;
margin-top: 2em;
padding-top: 1em;
}
h3 {
margin-top: 2em;
}
}

View File

@ -1,40 +1,122 @@
.bubble-wrapper {
$arwSize: 7px;
$c: #990000;
@include box-shadow(rgba(black, 0.4) 0 1px 5px);
position: absolute;
//top: 200px; left: 200px;
z-index: 10;
.bubble {
@include border-radius($basicCr);
display: inline-block;
background: $c;
color: lighten($c, 50%);
font-size: 0.8rem;
font-style: italic;
max-width: 200px;
padding: 4px 8px;
&:before {
content:"";
position: absolute;
width: 0;
height: 0;
}
//************************************************* LAYOUT
$infoBubbleFg: #666;
$infoBubbleBg: #ddd;
.l-infobubble-wrapper {
$arwSize: 5px;
@include box-shadow(rgba(black, 0.4) 0 1px 5px);
position: absolute;
z-index: 70;
.l-infobubble {
display: inline-block;
max-width: 250px;
padding: 5px 10px;
&:before {
content:"";
position: absolute;
width: 0;
height: 0;
}
table {
width: 100%;
tr {
td {
//max-width: 150px;
padding: 2px 0;
vertical-align: top;
//white-space: nowrap;
//overflow: hidden;
//text-overflow: ellipsis;
&.label {
padding-right: $interiorMargin * 2;
white-space: nowrap;
}
&.value {
white-space: nowrap;
//width: 90%;
}
&.align-wrap {
white-space: normal;
}
}
}
}
.title {
@include ellipsize();
margin-bottom: $interiorMargin;
//max-width: 200px;
}
}
&.arw-left .bubble:before {
right: 100%;
top: 50%; // 26px;
margin-top: -1 * $arwSize;
border-top: $arwSize solid transparent;
border-bottom: $arwSize solid transparent;
border-right: ($arwSize * 1.5) solid $c;
}
&.arw-down .bubble:before {
left: 50%;
top: 100%;
margin-left: -1 * $arwSize;
border-left: $arwSize solid transparent;
border-right: $arwSize solid transparent;
border-top: ($arwSize * 1.5) solid $c;
}
&.arw-left {
margin-left: $arwSize*2;
.l-infobubble::before {
right: 100%;
border-top: $arwSize solid transparent;
border-bottom: $arwSize solid transparent;
border-right: ($arwSize * 1.5) solid $infoBubbleBg;
}
}
&.arw-right {
margin-right: $arwSize*2;
.l-infobubble::before {
left: 100%;
border-top: $arwSize solid transparent;
border-bottom: $arwSize solid transparent;
border-left: ($arwSize * 1.5) solid $infoBubbleBg;
}
}
&.arw-top {
.l-infobubble::before {
top: $arwSize * 2;
}
}
&.arw-btm {
.l-infobubble::before {
bottom: $arwSize * 2;
}
}
&.arw-down {
margin-bottom: $arwSize*2;
.l-infobubble::before {
left: 50%;
top: 100%;
margin-left: -1 * $arwSize;
border-left: $arwSize solid transparent;
border-right: $arwSize solid transparent;
border-top: ($arwSize * 1.5) solid $infoBubbleBg;
}
}
}
//************************************************* LOOK AND FEEL
.s-infobubble {
$emFg: darken($infoBubbleFg, 20%);
@include border-radius($basicCr);
background: $infoBubbleBg;
color: $infoBubbleFg;
font-size: 0.8rem;
.title {
color: $emFg;
font-weight: bold;
}
tr {
td {
border-top: 1px solid darken($infoBubbleBg, 10%);
font-size: 0.9em;
}
&:first-child td {
border-top: none;
}
}
.value {
color: $emFg;
}
}

View File

@ -1,7 +1,9 @@
.items-holder {
@include clearfix;
overflow-y: auto;
.contents { top: 0; }
.contents {
top: 0;
}
.item {
&.grid-item {
$d: $ueBrowseGridItemLg;
@ -23,6 +25,9 @@
display: block;
}
}
.contents {
top: $interiorMargin; right: $interiorMargin; bottom: $interiorMargin; left: $interiorMargin;
}
.bar {
&.top-bar.abs {
bottom: auto;

View File

@ -51,6 +51,11 @@
}
}
.contents.l-dialog {
$myM: $interiorMargin;
top: $myM;
right: $myM;
bottom: $myM;
left: $myM;
overflow: auto;
}
}

View File

@ -18,6 +18,13 @@
>.object-holder.abs {
top: $ohH + $interiorMarginSm;
}
.contents {
$myM: $interiorMargin;
top: $myM;
right: $myM;
bottom: $myM;
left: $myM;
}
}
.edit-main .frame.child-frame.panel {

View File

@ -8,57 +8,26 @@
}
}
.holder-all {
$myM: $interiorMarginSm;
top: $myM;
right: $myM;
bottom: $myM;
left: $myM;
}
.browse-area,
.edit-area,
.editor {
@include border-radius($basicCr * 1.5);
position: absolute;
.contents {
// overflow-y: auto;
}
}
.user-environ {
.browse-area,
.edit-area,
.editor {
top: $bodyMargin + $ueTopBarH + ($interiorMargin);
right: $bodyMargin;
bottom: $bodyMargin + $ueFooterH + $interiorMargin;
left: $bodyMargin;
}
.edit-area {
$tbH: $ueEditToolBarH;
.tool-bar {
bottom: auto;
height: $tbH;
line-height: $ueEditToolBarButtonH;
}
.work-area {
top: $tbH + $interiorMargin * 2;
}
}
.bottom-bar {
top: auto;
right: $bodyMargin;
bottom: $bodyMargin;
left: $bodyMargin;
height: $ueFooterH;
.status-holder {
right: $ueAppLogoW + $bodyMargin;
}
.app-logo {
left: auto;
width: $ueAppLogoW;
}
}
.editor {
@include border-radius($basicCr * 1.5);
}
.contents {
$myM: $interiorMargin;
$myM: 0; //$interiorMargin;
box-sizing: border-box;
position: absolute;
top: $myM;
@ -101,6 +70,52 @@
}
}
.user-environ {
.browse-area,
.edit-area,
.editor {
top: $bodyMargin + $ueTopBarH + ($interiorMargin);
right: $bodyMargin;
bottom: $bodyMargin + $ueFooterH + $interiorMargin;
left: $bodyMargin;
}
.browse-area,
.edit-area {
> .contents {
left: 0;
right: 0;
}
}
.edit-area {
$tbH: $ueEditToolBarH;
.tool-bar {
bottom: auto;
height: $tbH;
line-height: $ueEditToolBarButtonH;
}
.work-area {
top: $tbH + $interiorMargin * 2;
}
}
.bottom-bar {
top: auto;
right: $bodyMargin;
bottom: $bodyMargin;
left: $bodyMargin;
height: $ueFooterH;
.status-holder {
right: $ueAppLogoW + $bodyMargin;
}
.app-logo {
left: auto;
width: $ueAppLogoW;
}
}
}
.cols {
@include clearfix;
.col {

View File

@ -5,6 +5,7 @@
&.browse,
&.edit {
border-bottom: 1px solid $colorInteriorBorder;
top: $bodyMargin; right: $bodyMargin; bottom: auto; left: $bodyMargin;
height: $ueTopBarH;
}

View File

@ -1,4 +1,4 @@
<a class="t-btn l-btn s-btn s-icon-btn s-very-subtle"
<a class="t-btn l-btn s-btn s-icon-btn s-very-subtle key-{{parameters.action.getMetadata().key}}"
ng-class="{ labeled: parameters.labeled }"
title="{{parameters.action.getMetadata().description}}"
ng-click="parameters.action.perform()">

View File

@ -0,0 +1,21 @@
{
"extensions": {
"types": [
{
"key": "infobubble",
"name": "Info Bubble",
"glyph": "\u00EA",
"description": "Static markup for info bubbles",
"features": [ "creation" ]
}
],
"views": [
{
"templateUrl": "infobubble.html",
"name": "Info Bubble",
"type": "infobubble",
"key": "infobubble"
}
]
}
}

View File

@ -0,0 +1,50 @@
<div ng-init="
bubbles = [
{layout: 'arw-top arw-left'},
{layout: 'arw-top arw-right'},
{layout: 'arw-btm arw-left'},
{layout: 'arw-btm arw-right'}
];
titlex='Egress Scenario scelerisque mauris pid montes nunc ut aliquam elementum tincidunt phasellus 1';
title='Egress Scenario 1';
propertiesShort=[{label:'Type', value:'Timeline', align:'left'},
{label:'Start', value:'2015-04-27 00:00:00 UTC', align:'left'},
{label:'End', value:'2015-04-27 09:15:37 UTC', align:'left'},
{label:'ID', value:'WRP-T-89', align:'left'}];
properties=[{label:'Type', value:'Timeline', align:'left'},
{label:'Start', value:'2015-04-27 00:00:00 UTC', align:'left'},
{label:'End', value:'2015-04-27 06:07:26 UTC', align:'left'},
{label:'Duration', value:'06:07:26', align:'left'},
{label:'Created', value:'2015-04-26 12:27:00 UTC', align:'left'},
{label:'Modified', value:'2015-04-26 23:21:00 UTC', align:'left'},
{label:'Status', value:'Up to date', align:'left'},
{label:'URL', value:'http://www.logitech.com/en-us/product/bluetooth-mouse-m557?crid=7', align:'wrap'},
{label:'Description', value:'Enjoy exceptional battery life for a Bluetooth mouse, and work for up to a full year between battery changes, An On/Off switch helps conserve power, smart sleep mode extends battery life, and an indicator light helps to ensure that youll never be caught off guard.', align:'wrap'},
{label:'ID', value:'WRP-T-89', align:'left'}];
"></div>
<div
style="position: absolute"
ng-repeat="bubble in bubbles"
ng-style="{left: $index * 300 + 'px'}"
>
<div class="t-infobubble s-infobubble l-infobubble-wrapper {{bubble.layout}}">
<div class="l-infobubble">
<div
ng-show="title.length > 0"
class="title"
>{{title}}
</div>
<table>
<tr ng-repeat="property in properties">
<td class="label">{{property.label}}</td>
<td title="{{property.value}}" class="value align-{{property.align}}">{{property.value}}</td>
</tr>
</table>
</div>
</div>
</div>

View File

@ -7,6 +7,11 @@
"depends": [ "$injector" ],
"message": "Objects of this type cannot contain objects of that type."
},
{
"category": "composition",
"implementation": "CompositionMutabilityPolicy.js",
"message": "Objects of this type cannot be modified."
},
{
"category": "action",
"implementation": "ComposeActionPolicy.js",

View File

@ -0,0 +1,30 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* Disallow composition changes to objects which are not mutable.
* @constructor
*/
function CompositionMutabilityPolicy() {
return {
/**
* Is the type identified by the candidate allowed to
* contain the type described by the context?
* @param {Type} candidate the type of domain object
*/
allow: function (candidate) {
// Equate creatability with mutability; that is, users
// can only modify objects of types they can create, and
// vice versa.
return candidate.hasFeature('creation');
}
};
}
return CompositionMutabilityPolicy;
}
);

View File

@ -0,0 +1,26 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/CompositionMutabilityPolicy"],
function (CompositionMutabilityPolicy) {
"use strict";
describe("The composition mutability policy", function () {
var mockType,
policy;
beforeEach(function () {
mockType = jasmine.createSpyObj('type', ['hasFeature']);
policy = new CompositionMutabilityPolicy();
});
it("only allows composition for types which will have a composition capability", function () {
expect(policy.allow(mockType)).toBeFalsy();
mockType.hasFeature.andReturn(true);
expect(policy.allow(mockType)).toBeTruthy();
expect(mockType.hasFeature).toHaveBeenCalledWith('creation');
});
});
}
);

View File

@ -1,6 +1,7 @@
[
"CapabilityTable",
"ComposeActionPolicy",
"CompositionMutabilityPolicy",
"CompositionPolicy",
"ContainmentTable"
]

View File

@ -5,7 +5,7 @@
"views": [
{
"key": "layout",
"name": "Layout",
"name": "Display Layout",
"glyph": "L",
"type": "layout",
"templateUrl": "templates/layout.html",
@ -197,7 +197,7 @@
"types": [
{
"key": "layout",
"name": "Layout",
"name": "Display Layout",
"glyph": "L",
"description": "A layout in which multiple telemetry panels may be displayed.",
"features": "creation",

View File

@ -0,0 +1,37 @@
{
"extensions": {
"types": [
{
"key": "example.page",
"name": "Web Page",
"glyph": "\u00EA",
"description": "A component to display a web page or image with a valid URL. Can be added to a Display Layout.",
"features": [ "creation" ],
"properties": [
{
"key": "url",
"name": "URL",
"control": "textfield",
"pattern": "^(ftp|https?)\\:\\/\\/\\w+(\\.\\w+)*(\\:\\d+)?(\\/\\S*)*$",
"required": true
}
]
}
],
"views": [
{
"templateUrl": "iframe.html",
"name": "Page",
"type": "example.page",
"key": "example.page"
}
],
"controllers": [
{
"key": "EmbeddedPageController",
"implementation": "EmbeddedPageController.js",
"depends": ["$sce"]
}
]
}
}

View File

@ -0,0 +1,5 @@
<div class="abs l-iframe">
<iframe ng-controller="EmbeddedPageController as ctl"
ng-src="{{ctl.trust(model.url)}}">
</iframe>
</div>

View File

@ -0,0 +1,26 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* Controller for embedded web pages; serves simply as a
* wrapper for `$sce` to mark pages as trusted.
*/
function EmbeddedPageController($sce) {
return {
/**
* Alias of `$sce.trustAsResourceUrl`.
*/
trust: function (url) {
return $sce.trustAsResourceUrl(url);
}
};
}
return EmbeddedPageController;
}
);

View File

@ -0,0 +1,37 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/EmbeddedPageController"],
function (EmbeddedPageController) {
"use strict";
describe("The controller for embedded pages", function () {
var mockSCE,
controller;
beforeEach(function () {
mockSCE = jasmine.createSpyObj(
'$sce',
["trustAsResourceUrl"]
);
mockSCE.trustAsResourceUrl.andCallFake(function (v) {
return v;
});
controller = new EmbeddedPageController(mockSCE);
});
it("allows URLs to be marked as trusted", function () {
var testURL = "http://www.nasa.gov";
expect(controller.trust(testURL))
.toEqual(testURL);
expect(mockSCE.trustAsResourceUrl)
.toHaveBeenCalledWith(testURL);
});
});
}
);

View File

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

View File

@ -22,7 +22,7 @@
{
"key": "PlotController",
"implementation": "PlotController.js",
"depends": [ "$scope", "telemetryFormatter", "telemetrySubscriber" ]
"depends": [ "$scope", "telemetryFormatter", "telemetryHandler" ]
}
]
}

View File

@ -30,13 +30,13 @@ define(
*
* @constructor
*/
function PlotController($scope, telemetryFormatter, telemetrySubscriber) {
function PlotController($scope, telemetryFormatter, telemetryHandler) {
var subPlotFactory = new SubPlotFactory(telemetryFormatter),
modeOptions = new PlotModeOptions([], subPlotFactory),
subplots = [],
cachedObjects = [],
updater,
subscription,
handle,
domainOffset;
// Populate the scope with axis information (specifically, options
@ -77,7 +77,7 @@ define(
// new subscription.) This will clear the plot.
function recreateUpdater() {
updater = new PlotUpdater(
subscription,
handle,
($scope.axes[0].active || {}).key,
($scope.axes[1].active || {}).key
);
@ -85,8 +85,8 @@ define(
// Handle new telemetry data in this plot
function updateValues() {
if (subscription) {
setupModes(subscription.getTelemetryObjects());
if (handle) {
setupModes(handle.getTelemetryObjects());
}
if (updater) {
updater.update();
@ -95,29 +95,44 @@ define(
update();
}
// Display new historical data as it becomes available
function addHistoricalData(domainObject, series) {
updater.addHistorical(domainObject, series);
modeOptions.getModeHandler().plotTelemetry(updater);
update();
}
// Issue a new request for historical telemetry
function requestTelemetry() {
if (handle && updater) {
handle.request({}, addHistoricalData);
}
}
// Create a new subscription; telemetrySubscriber gets
// to do the meaningful work here.
function subscribe(domainObject) {
if (subscription) {
subscription.unsubscribe();
if (handle) {
handle.unsubscribe();
}
subscription = domainObject && telemetrySubscriber.subscribe(
handle = domainObject && telemetryHandler.handle(
domainObject,
updateValues,
true // Lossless
);
if (subscription) {
setupModes(subscription.getTelemetryObjects());
setupAxes(subscription.getMetadata());
if (handle) {
setupModes(handle.getTelemetryObjects());
setupAxes(handle.getMetadata());
recreateUpdater();
requestTelemetry();
}
}
// Release the current subscription (called when scope is destroyed)
function releaseSubscription() {
if (subscription) {
subscription.unsubscribe();
subscription = undefined;
if (handle) {
handle.unsubscribe();
handle = undefined;
}
}

View File

@ -0,0 +1,94 @@
/*global define,Float32Array*/
define(
['./PlotSeriesWindow'],
function (PlotSeriesWindow) {
"use strict";
function PlotLine(buffer) {
// Insert a time-windowed data series into the buffer
function insertSeriesWindow(seriesWindow) {
var count = seriesWindow.getPointCount();
function doInsert() {
var firstTimestamp = seriesWindow.getDomainValue(0),
lastTimestamp = seriesWindow.getDomainValue(count - 1),
startIndex = buffer.findInsertionIndex(firstTimestamp),
endIndex = buffer.findInsertionIndex(lastTimestamp);
// Does the whole series fit in between two adjacent indexes?
if ((startIndex === endIndex) && startIndex > -1) {
// Insert it in between
buffer.insert(seriesWindow, startIndex);
} else {
// Split it up, and add the two halves
seriesWindow.split().forEach(insertSeriesWindow);
}
}
// Only insert if there are points to insert
if (count > 0) {
doInsert();
}
}
function createWindow(series, domain, range) {
return new PlotSeriesWindow(
series,
domain,
range,
0,
series.getPointCount()
);
}
return {
/**
* Add a point to this plot line.
* @param {number} domainValue the domain value
* @param {number} rangeValue the range value
*/
addPoint: function (domainValue, rangeValue) {
var index;
// Make sure we got real/useful values here...
if (domainValue !== undefined && rangeValue !== undefined) {
index = buffer.findInsertionIndex(domainValue);
// Already in the buffer? Skip insertion
if (index < 0) {
return;
}
// Insert the point
if (!buffer.insertPoint(domainValue, rangeValue, index)) {
// If insertion failed, trim from the beginning...
buffer.trim(1);
// ...and try again.
buffer.insertPoint(domainValue, rangeValue, index);
}
}
},
/**
* Add a series of telemetry data to this plot line.
* @param {TelemetrySeries} series the data series
* @param {string} [domain] the key indicating which domain
* to use when looking up data from this series
* @param {string} [range] the key indicating which range
* to use when looking up data from this series
*/
addSeries: function (series, domain, range) {
// Should try to add via insertion if a
// clear insertion point is available;
// if not, should split and add each half.
// Insertion operation also needs to factor out
// redundant timestamps, for overlapping data
insertSeriesWindow(createWindow(series, domain, range));
}
};
}
return PlotLine;
}
);

View File

@ -0,0 +1,240 @@
/*global define,Float32Array*/
define(
[],
function () {
"use strict";
/**
* Contains the buffer used to draw a plot.
* @param {number} domainOffset number to subtract from domain values
* @param {number} initialSize initial buffer size
* @param {number} maxSize maximum buffer size
* @constructor
*/
function PlotLineBuffer(domainOffset, initialSize, maxSize) {
var buffer = new Float32Array(initialSize * 2),
rangeExtrema = [ Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ],
length = 0;
// Binary search for an insertion index
function binSearch(value, min, max) {
var mid = Math.floor((min + max) / 2),
found = buffer[mid * 2];
// Collisions are not wanted
if (found === value) {
return -1;
}
// Otherwise, if we're down to a single index,
// we've found our insertion point
if (min >= max) {
// Compare the found timestamp with the search
// value to decide if we'll insert after or before.
return min + ((found < value) ? 1 : 0);
}
// Finally, do the recursive step
if (found < value) {
return binSearch(value, mid + 1, max);
} else {
return binSearch(value, min, mid - 1);
}
}
// Increase the size of the buffer
function doubleBufferSize() {
var sz = Math.min(maxSize * 2, buffer.length * 2),
canDouble = sz > buffer.length,
doubled = canDouble && new Float32Array(sz);
if (canDouble) {
doubled.set(buffer); // Copy contents of original
buffer = doubled;
}
return canDouble;
}
// Decrease the size of the buffer
function halveBufferSize() {
var sz = Math.max(initialSize * 2, buffer.length / 2),
canHalve = sz < buffer.length;
if (canHalve) {
buffer = new Float32Array(buffer.subarray(0, sz));
}
return canHalve;
}
// Set a value in the buffer
function setValue(index, domainValue, rangeValue) {
buffer[index * 2] = domainValue - domainOffset;
buffer[index * 2 + 1] = rangeValue;
// Track min/max of range values (min/max for
// domain values can be read directly from buffer)
rangeExtrema[0] = Math.min(rangeExtrema[0], rangeValue);
rangeExtrema[1] = Math.max(rangeExtrema[1], rangeValue);
}
return {
/**
* Get the WebGL-displayable buffer of points to plot.
* @returns {Float32Array} displayable buffer for this line
*/
getBuffer: function () {
return buffer;
},
/**
* Get the number of points stored in this buffer.
* @returns {number} the number of points stored
*/
getLength: function () {
return length;
},
/**
* Get the min/max range values that are currently in this
* buffer. Unlike range extrema, these will change as the
* buffer gets trimmed.
* @returns {number[]} min, max domain values
*/
getDomainExtrema: function () {
// Since these are ordered in the buffer, assume
// these are the values at the first and last index
return [
buffer[0] + domainOffset,
buffer[length * 2 - 2] + domainOffset
];
},
/**
* Get the min/max range values that have been observed for this
* buffer. Note that these values may have been trimmed out at
* some point.
* @returns {number[]} min, max range values
*/
getRangeExtrema: function () {
return rangeExtrema;
},
/**
* Remove values from this buffer.
* Normally, values are removed from the start
* of the buffer; a truthy value in the second argument
* will cause values to be removed from the end.
* @param {number} count number of values to remove
* @param {boolean} [fromEnd] true if the most recent
* values should be removed
*/
trim: function (count, fromEnd) {
// If we're removing values from the start...
if (!fromEnd) {
// ...do so by shifting buffer contents over
buffer.set(buffer.subarray(2 * count));
}
// Reduce used buffer size accordingly
length -= count;
// Finally, if less than half of the buffer is being
// used, free up some memory.
if (length < buffer.length / 4) {
halveBufferSize();
}
},
/**
* Insert data from the provided series at the specified
* index. If this would exceed the buffer's maximum capacity,
* this operation fails and the buffer is unchanged.
* @param {TelemetrySeries} series the series to insert
* @param {number} index the index at which to insert this
* series
* @returns {boolean} true if insertion succeeded; otherwise
* false
*/
insert: function (series, index) {
var sz = series.getPointCount(),
i;
// Don't allow append after the end; that doesn't make sense
index = Math.min(index, length);
// Resize if necessary
while (sz > ((buffer.length / 2) - length)) {
if (!doubleBufferSize()) {
// Can't make room for this, insertion fails
return false;
}
}
// Shift data over if necessary
if (index < length) {
buffer.set(
buffer.subarray(index * 2, length * 2),
(index + sz) * 2
);
}
// Insert data into the set
for (i = 0; i < sz; i += 1) {
setValue(
i + index,
series.getDomainValue(i),
series.getRangeValue(i)
);
}
// Increase the length
length += sz;
// Indicate that insertion was successful
return true;
},
/**
* Append a single data point.
*/
insertPoint: function (domainValue, rangeValue, index) {
// Don't allow
index = Math.min(length, index);
// Ensure there is space for this point
if (length >= (buffer.length / 2)) {
if (!doubleBufferSize()) {
return false;
}
}
// Put the data in the buffer
setValue(length, domainValue, rangeValue);
// Update length
length += 1;
// Indicate that this was successful
return true;
},
/**
* Find an index for inserting data with this
* timestamp. The second argument indicates whether
* we are searching for insert-before or insert-after
* positions.
* Timestamps are meant to be unique, so if a collision
* occurs, this will return -1.
* @param {number} timestamp timestamp to insert
* @returns {number} the index for insertion (or -1)
*/
findInsertionIndex: function (timestamp) {
var value = timestamp - domainOffset;
// Handle empty buffer case and check for an
// append opportunity (which is most common case for
// real-time data so is optimized-for) before falling
// back to a binary search for the insertion point.
return (length < 1) ? 0 :
(value > buffer[length * 2 - 2]) ? length :
binSearch(value, 0, length - 1);
}
};
}
return PlotLineBuffer;
}
);

View File

@ -0,0 +1,47 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* Provides a window on a telemetry data series, to support
* insertion into a plot line.
*/
function PlotSeriesWindow(series, domain, range, start, end) {
return {
getPointCount: function () {
return end - start;
},
getDomainValue: function (index) {
return series.getDomainValue(index + start, domain);
},
getRangeValue: function (index) {
return series.getRangeValue(index + start, range);
},
split: function () {
var mid = Math.floor((end + start) / 2);
return ((end - start) > 1) ?
[
new PlotSeriesWindow(
series,
domain,
range,
start,
mid
),
new PlotSeriesWindow(
series,
domain,
range,
mid,
end
)
] : [];
}
};
}
return PlotSeriesWindow;
}
);

View File

@ -5,7 +5,8 @@
* the conversion from data API to displayable buffers.
*/
define(
function () {
['./PlotLine', './PlotLineBuffer'],
function (PlotLine, PlotLineBuffer) {
'use strict';
var MAX_POINTS = 86400,
@ -17,117 +18,182 @@ define(
* Float32Array for each trace, and tracks the boundaries of the
* data sets (since this is convenient to do during the same pass).
* @constructor
* @param {Telemetry[]} datas telemetry data objects
* @param {TelemetryHandle} handle the handle to telemetry access
* @param {string} domain the key to use when looking up domain values
* @param {string} range the key to use when looking up range values
*/
function PlotUpdater(subscription, domain, range, maxPoints) {
var max = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
x,
y,
domainOffset,
buffers = {},
lengths = {},
lengthArray = [],
bufferArray = [];
function PlotUpdater(handle, domain, range, maxPoints) {
var ids = [],
lines = {},
dimensions = [0, 0],
origin = [0, 0],
domainExtrema,
rangeExtrema,
bufferArray = [],
domainOffset;
// Double the size of a Float32Array
function doubleSize(buffer) {
var doubled = new Float32Array(buffer.length * 2);
doubled.set(buffer); // Copy contents of original
return doubled;
// Look up a domain object's id (for mapping, below)
function getId(domainObject) {
return domainObject.getId();
}
// Make sure there is enough space in a buffer to accomodate a
// new point at the specified index. This will updates buffers[id]
// if necessary.
function ensureBufferSize(buffer, id, index) {
// Check if we don't have enough room
if (index > (buffer.length / 2 - 1)) {
// If we don't, can we expand?
if (index < maxPoints) {
// Double the buffer size
buffer = buffers[id] = doubleSize(buffer);
} else {
// Just shift the existing buffer
buffer.set(buffer.subarray(2));
}
}
return buffer;
// Check if this set of ids matches the current set of ids
// (used to detect if line preparation can be skipped)
function idsMatch(nextIds) {
return nextIds.map(function (id, index) {
return ids[index] === id;
}).reduce(function (a, b) {
return a && b;
}, true);
}
// Add data to the plot.
function addData(obj) {
var id = obj.getId(),
index = lengths[id] || 0,
buffer = buffers[id],
domainValue = subscription.getDomainValue(obj, domain),
rangeValue = subscription.getRangeValue(obj, range);
// Prepare plot lines for this group of telemetry objects
function prepareLines(telemetryObjects) {
var nextIds = telemetryObjects.map(getId),
next = {};
// If we don't already have a data buffer for that ID,
// make one.
if (!buffer) {
buffer = new Float32Array(INITIAL_SIZE);
buffers[id] = buffer;
// Detect if we already have everything we need prepared
if (ids.length === nextIds.length && idsMatch(nextIds)) {
// Nothing to prepare, move on
return;
}
// Make sure there's data to add, and then add it
if (domainValue !== undefined && rangeValue !== undefined &&
(index < 1 || domainValue !== buffer[index * 2 - 2])) {
// Use the first observed domain value as a domainOffset
domainOffset = domainOffset !== undefined ?
domainOffset : domainValue;
// Ensure there is space for the new buffer
buffer = ensureBufferSize(buffer, id, index);
// Account for shifting that may have occurred
index = Math.min(index, maxPoints - 1);
// Update the buffer
buffer[index * 2] = domainValue - domainOffset;
buffer[index * 2 + 1] = rangeValue;
// Update length
lengths[id] = Math.min(index + 1, maxPoints);
// Observe max/min range values
max[1] = Math.max(max[1], rangeValue);
min[1] = Math.min(min[1], rangeValue);
// Built up a set of ids. Note that we can only
// create plot lines after our domain offset has
// been determined.
if (domainOffset !== undefined) {
// Update list of ids in use
ids = nextIds;
// Create buffers for these objects
bufferArray = ids.map(function (id) {
var buffer = new PlotLineBuffer(
domainOffset,
INITIAL_SIZE,
maxPoints
);
next[id] = lines[id] || new PlotLine(buffer);
return buffer;
});
}
return buffer;
// If there are no more lines, clear the domain offset
if (Object.keys(next).length < 1) {
domainOffset = undefined;
}
// Update to the current set of lines
lines = next;
}
// Update min/max domain values for these objects
function updateDomainExtrema(objects) {
max[0] = Number.NEGATIVE_INFINITY;
min[0] = Number.POSITIVE_INFINITY;
objects.forEach(function (obj) {
var id = obj.getId(),
buffer = buffers[id],
length = lengths[id],
low = buffer[0] + domainOffset,
high = buffer[length * 2 - 2] + domainOffset;
max[0] = Math.max(high, max[0]);
min[0] = Math.min(low, min[0]);
});
// Initialize the domain offset, based on these observed values
function initializeDomainOffset(values) {
domainOffset =
((domainOffset === undefined) && (values.length > 0)) ?
(values.reduce(function (a, b) {
return (a || 0) + (b || 0);
}, 0) / values.length) :
domainOffset;
}
// Used in the reduce step of updateExtrema
function reduceExtrema(a, b) {
return [ Math.min(a[0], b[0]), Math.max(a[1], b[1]) ];
}
// Convert a domain/range extrema to plot dimensions
function dimensionsOf(extrema) {
return extrema[1] - extrema[0];
}
// Convert a domain/range extrema to a plot origin
function originOf(extrema) {
return extrema[0];
}
// Update dimensions and origin based on extrema of plots
function updateExtrema() {
if (bufferArray.length > 0) {
domainExtrema = bufferArray.map(function (lineBuffer) {
return lineBuffer.getDomainExtrema();
}).reduce(reduceExtrema);
rangeExtrema = bufferArray.map(function (lineBuffer) {
return lineBuffer.getRangeExtrema();
}).reduce(reduceExtrema);
dimensions = (rangeExtrema[0] === rangeExtrema[1]) ?
[dimensionsOf(domainExtrema), 2.0 ] :
[dimensionsOf(domainExtrema), dimensionsOf(rangeExtrema)];
origin = [originOf(domainExtrema), originOf(rangeExtrema)];
}
}
// Add latest data for this domain object
function addPointFor(domainObject) {
var line = lines[domainObject.getId()];
if (line) {
line.addPoint(
handle.getDomainValue(domainObject, domain),
handle.getRangeValue(domainObject, range)
);
}
}
// Handle new telemetry data
function update() {
var objects = subscription.getTelemetryObjects();
bufferArray = objects.map(addData);
lengthArray = objects.map(function (obj) {
return lengths[obj.getId()];
});
updateDomainExtrema(objects);
var objects = handle.getTelemetryObjects();
// Initialize domain offset if necessary
if (domainOffset === undefined) {
initializeDomainOffset(objects.map(function (obj) {
return handle.getDomainValue(obj, domain);
}).filter(function (value) {
return typeof value === 'number';
}));
}
// Make sure lines are available
prepareLines(objects);
// Add new data
objects.forEach(addPointFor);
// Finally, update extrema
updateExtrema();
}
// Prepare buffers and related state for this object
function prepare(telemetryObject) {
var id = telemetryObject.getId();
lengths[id] = 0;
buffers[id] = new Float32Array(INITIAL_SIZE);
lengthArray.push(lengths[id]);
bufferArray.push(buffers[id]);
// Add historical data for this domain object
function setHistorical(domainObject, series) {
var count = series ? series.getPointCount() : 0,
line;
// Nothing to do if it's an empty series
if (count < 1) {
return;
}
// Initialize domain offset if necessary
if (domainOffset === undefined) {
initializeDomainOffset([
series.getDomainValue(0, domain),
series.getDomainValue(count - 1, domain)
]);
}
// Make sure lines are available
prepareLines(handle.getTelemetryObjects());
// Look up the line for this domain object
line = lines[domainObject.getId()];
// ...and put the data into it.
if (line) {
line.addSeries(series, domain, range);
}
// Finally, update extrema
updateExtrema();
}
// Use a default MAX_POINTS if none is provided
@ -136,7 +202,7 @@ define(
// Initially prepare state for these objects.
// Note that this may be an empty array at this time,
// so we also need to check during update cycles.
subscription.getTelemetryObjects().forEach(prepare);
update();
return {
/**
@ -146,10 +212,7 @@ define(
* @returns {number[]} the dimensions which bound this data set
*/
getDimensions: function () {
// Pad range if necessary
return (max[1] === min[1]) ?
[max[0] - min[0], 2.0 ] :
[max[0] - min[0], max[1] - min[1]];
return dimensions;
},
/**
* Get the origin of this data set's boundary.
@ -160,7 +223,7 @@ define(
*/
getOrigin: function () {
// Pad range if necessary
return (max[1] === min[1]) ? [ min[0], min[1] - 1.0 ] : min;
return origin;
},
/**
* Get the domain offset; this offset will have been subtracted
@ -189,23 +252,17 @@ define(
*
* @returns {Float32Array[]} the buffers for these traces
*/
getBuffers: function () {
getLineBuffers: function () {
return bufferArray;
},
/**
* Get the number of points in the buffer with the specified
* index. Buffers are padded to minimize memory allocations,
* so user code will need this information to know how much
* data to plot.
* @returns {number} the number of points in this buffer
*/
getLength: function (index) {
return lengthArray[index] || 0;
},
/**
* Update with latest data.
*/
update: update
update: update,
/**
* Fill in historical data.
*/
addHistorical: setHistorical
};
}

View File

@ -34,11 +34,11 @@ define(
subplot.setDomainOffset(prepared.getDomainOffset());
// Draw the buffers. Select color by index.
subplot.getDrawingObject().lines = prepared.getBuffers().map(function (buf, i) {
subplot.getDrawingObject().lines = prepared.getLineBuffers().map(function (buf, i) {
return {
buffer: buf,
buffer: buf.getBuffer(),
color: PlotPalette.getFloatColor(i),
points: prepared.getLength(i)
points: buf.getLength()
};
});

View File

@ -23,7 +23,7 @@ define(
});
function plotTelemetryTo(subplot, prepared, index) {
var buffer = prepared.getBuffers()[index];
var buffer = prepared.getLineBuffers()[index];
// Track the domain offset, used to bias domain values
// to minimize loss of precision when converted to 32-bit
@ -33,9 +33,9 @@ define(
// Draw the buffers. Always use the 0th color, because there
// is one line per plot.
subplot.getDrawingObject().lines = [{
buffer: buffer,
buffer: buffer.getBuffer(),
color: PlotPalette.getFloatColor(0),
points: prepared.getLength(index)
points: buffer.getLength()
}];
subplot.update();

View File

@ -11,9 +11,10 @@ define(
describe("The plot controller", function () {
var mockScope,
mockFormatter,
mockSubscriber,
mockSubscription,
mockHandler,
mockHandle,
mockDomainObject,
mockSeries,
controller;
@ -30,28 +31,33 @@ define(
"domainObject",
[ "getId", "getModel", "getCapability" ]
);
mockSubscriber = jasmine.createSpyObj(
mockHandler = jasmine.createSpyObj(
"telemetrySubscriber",
["subscribe"]
["handle"]
);
mockSubscription = jasmine.createSpyObj(
mockHandle = jasmine.createSpyObj(
"subscription",
[
"unsubscribe",
"getTelemetryObjects",
"getMetadata",
"getDomainValue",
"getRangeValue"
"getRangeValue",
"request"
]
);
mockSeries = jasmine.createSpyObj(
'series',
['getPointCount', 'getDomainValue', 'getRangeValue']
);
mockSubscriber.subscribe.andReturn(mockSubscription);
mockSubscription.getTelemetryObjects.andReturn([mockDomainObject]);
mockSubscription.getMetadata.andReturn([{}]);
mockSubscription.getDomainValue.andReturn(123);
mockSubscription.getRangeValue.andReturn(42);
mockHandler.handle.andReturn(mockHandle);
mockHandle.getTelemetryObjects.andReturn([mockDomainObject]);
mockHandle.getMetadata.andReturn([{}]);
mockHandle.getDomainValue.andReturn(123);
mockHandle.getRangeValue.andReturn(42);
controller = new PlotController(mockScope, mockFormatter, mockSubscriber);
controller = new PlotController(mockScope, mockFormatter, mockHandler);
});
it("provides plot colors", function () {
@ -71,7 +77,7 @@ define(
// Make an object available
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
// Should have subscribed
expect(mockSubscriber.subscribe).toHaveBeenCalledWith(
expect(mockHandler.handle).toHaveBeenCalledWith(
mockDomainObject,
jasmine.any(Function),
true // Lossless
@ -92,7 +98,7 @@ define(
expect(controller.getSubPlots().length > 0).toBeTruthy();
// Broadcast data
mockSubscriber.subscribe.mostRecentCall.args[1]();
mockHandler.handle.mostRecentCall.args[1]();
controller.getSubPlots().forEach(function (subplot) {
expect(subplot.getDrawingObject().lines)
@ -104,17 +110,17 @@ define(
// Make an object available
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
// Verify precondition - shouldn't unsubscribe yet
expect(mockSubscription.unsubscribe).not.toHaveBeenCalled();
expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
// Remove the domain object
mockScope.$watch.mostRecentCall.args[1](undefined);
// Should have unsubscribed
expect(mockSubscription.unsubscribe).toHaveBeenCalled();
expect(mockHandle.unsubscribe).toHaveBeenCalled();
});
it("changes modes depending on number of objects", function () {
// Act like one object is available
mockSubscription.getTelemetryObjects.andReturn([
mockHandle.getTelemetryObjects.andReturn([
mockDomainObject
]);
@ -124,7 +130,7 @@ define(
expect(controller.getModeOptions().length).toEqual(1);
// Act like one object is available
mockSubscription.getTelemetryObjects.andReturn([
mockHandle.getTelemetryObjects.andReturn([
mockDomainObject,
mockDomainObject,
mockDomainObject
@ -174,17 +180,26 @@ define(
expect(controller.isRequestPending()).toBeFalsy();
});
it("requests historical telemetry", function () {
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
expect(mockHandle.request).toHaveBeenCalled();
mockHandle.request.mostRecentCall.args[1](
mockDomainObject,
mockSeries
);
});
it("unsubscribes when destroyed", function () {
// Make an object available
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
// Make sure $destroy is what's listened for
expect(mockScope.$on.mostRecentCall.args[0]).toEqual('$destroy');
// Also verify precondition
expect(mockSubscription.unsubscribe).not.toHaveBeenCalled();
expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
// Destroy the scope
mockScope.$on.mostRecentCall.args[1]();
// Should have unsubscribed
expect(mockSubscription.unsubscribe).toHaveBeenCalled();
expect(mockHandle.unsubscribe).toHaveBeenCalled();
});
});
}

View File

@ -0,0 +1,151 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
/**
* MergeModelsSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/elements/PlotLineBuffer"],
function (PlotLineBuffer) {
"use strict";
var TEST_INITIAL_SIZE = 10,
TEST_MAX_SIZE = 40,
TEST_DOMAIN_OFFSET = 42;
describe("A plot line buffer", function () {
var mockSeries,
testDomainValues,
testRangeValues,
buffer;
beforeEach(function () {
testDomainValues = [ 1, 3, 7, 9, 14, 15 ];
testRangeValues = [ 8, 0, 3, 9, 8, 11 ];
mockSeries = jasmine.createSpyObj(
"series",
['getPointCount', 'getDomainValue', 'getRangeValue']
);
mockSeries.getPointCount.andCallFake(function () {
return testDomainValues.length;
});
mockSeries.getDomainValue.andCallFake(function (i) {
return testDomainValues[i];
});
mockSeries.getRangeValue.andCallFake(function (i) {
return testRangeValues[i];
});
buffer = new PlotLineBuffer(
TEST_DOMAIN_OFFSET,
TEST_INITIAL_SIZE,
TEST_MAX_SIZE
);
// Start with some data in there
buffer.insert(mockSeries, 0);
});
it("allows insertion of series data", function () {
// Convert to a regular array for checking.
// Verify that domain/ranges were interleaved and
// that domain offset was adjusted for.
expect(
Array.prototype.slice.call(buffer.getBuffer()).slice(0, 12)
).toEqual([ -41, 8, -39, 0, -35, 3, -33, 9, -28, 8, -27, 11]);
expect(buffer.getLength()).toEqual(6);
});
it("finds insertion indexes", function () {
expect(buffer.findInsertionIndex(0)).toEqual(0);
expect(buffer.findInsertionIndex(2)).toEqual(1);
expect(buffer.findInsertionIndex(5)).toEqual(2);
expect(buffer.findInsertionIndex(10)).toEqual(4);
expect(buffer.findInsertionIndex(14.5)).toEqual(5);
expect(buffer.findInsertionIndex(20)).toEqual(6);
// 9 is already in there, disallow insertion
expect(buffer.findInsertionIndex(9)).toEqual(-1);
});
it("allows insertion in the middle", function () {
var head = [ -41, 8, -39, 0, -35, 3 ],
tail = [ -33, 9, -28, 8, -27, 11];
buffer.insert(mockSeries, 3);
expect(
Array.prototype.slice.call(buffer.getBuffer()).slice(0, 24)
).toEqual(head.concat(head).concat(tail).concat(tail));
expect(buffer.getLength()).toEqual(12);
});
it("allows values to be trimmed from the start", function () {
buffer.trim(2);
expect(buffer.getLength()).toEqual(4);
expect(
Array.prototype.slice.call(buffer.getBuffer()).slice(0, 8)
).toEqual([ -35, 3, -33, 9, -28, 8, -27, 11]);
});
it("expands buffer when needed to accommodate more data", function () {
var i;
// Initial underlying buffer should be twice initial size...
// (Since each pair will take up two elements)
expect(buffer.getBuffer().length).toEqual(20);
// Should be able to insert 6 series of 6 points each
// (After that, we'll hit the test max of 40)
for (i = 1; i < 15; i += 1) {
expect(buffer.insertPoint(i * 10, Math.sin(i), i))
.toBeTruthy();
}
// Buffer should have expanded in the process
expect(buffer.getBuffer().length).toEqual(40);
// Push to maximum size just to make sure...
for (i = 1; i < 150; i += 1) {
buffer.insertPoint(i * 10, Math.sin(i), i);
}
expect(buffer.getBuffer().length).toEqual(80);
});
it("ensures a maximum size", function () {
var i;
// Should be able to insert 6 series of 6 points each
// (After that, we'll hit the test max of 40)
for (i = 1; i < 6; i += 1) {
expect(buffer.getLength()).toEqual(6 * i);
expect(buffer.insert(mockSeries, Number.POSITIVE_INFINITY))
.toBeTruthy();
}
// Should be maxed out now
expect(buffer.getLength()).toEqual(36);
expect(buffer.insert(mockSeries, Number.POSITIVE_INFINITY))
.toBeFalsy();
expect(buffer.getLength()).toEqual(36);
});
it("reduces buffer size when space is no longer needed", function () {
// Check that actual buffer is sized to the initial size
// (double TEST_INITIAL_SIZE, since two elements are needed per
// point; one for domain, one for range)
expect(buffer.getBuffer().length).toEqual(20);
// Should have 6 elements now... grow to 24
buffer.insert(mockSeries, Number.POSITIVE_INFINITY);
buffer.insert(mockSeries, Number.POSITIVE_INFINITY);
buffer.insert(mockSeries, Number.POSITIVE_INFINITY);
// This should have doubled the actual buffer size
expect(buffer.getBuffer().length).toEqual(80);
// Remove some values
buffer.trim(20);
// Actual buffer size should have been reduced accordingly
expect(buffer.getBuffer().length).toBeLessThan(80);
});
});
}
);

View File

@ -0,0 +1,114 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../../src/elements/PlotLine"],
function (PlotLine) {
"use strict";
describe("A plot line", function () {
var mockBuffer,
mockSeries,
testDomainBuffer,
testRangeBuffer,
testSeries,
line;
beforeEach(function () {
testDomainBuffer = [];
testRangeBuffer = [];
testSeries = [];
mockBuffer = jasmine.createSpyObj(
'buffer',
['findInsertionIndex', 'insert', 'insertPoint', 'trim']
);
mockSeries = jasmine.createSpyObj(
'series',
['getPointCount', 'getDomainValue', 'getRangeValue']
);
mockSeries.getPointCount.andCallFake(function () {
return testSeries.length;
});
mockSeries.getDomainValue.andCallFake(function (i) {
return (testSeries[i] || [])[0];
});
mockSeries.getRangeValue.andCallFake(function (i) {
return (testSeries[i] || [])[1];
});
// Function like PlotLineBuffer, to aid in testability
mockBuffer.findInsertionIndex.andCallFake(function (v) {
var index = 0;
if (testDomainBuffer.indexOf(v) !== -1) {
return -1;
}
while ((index < testDomainBuffer.length) &&
(testDomainBuffer[index] < v)) {
index += 1;
}
return index;
});
mockBuffer.insert.andCallFake(function (series, index) {
var domains = [], ranges = [], i;
for (i = 0; i < series.getPointCount(); i += 1) {
domains.push(series.getDomainValue(i));
ranges.push(series.getRangeValue(i));
}
testDomainBuffer = testDomainBuffer.slice(0, index)
.concat(domains)
.concat(testDomainBuffer.slice(index));
testRangeBuffer = testRangeBuffer.slice(0, index)
.concat(ranges)
.concat(testRangeBuffer.slice(index));
return true;
});
mockBuffer.insertPoint.andCallFake(function (dv, rv, index) {
testDomainBuffer.splice(index, 0, dv);
testRangeBuffer.splice(index, 0, rv);
return true;
});
line = new PlotLine(mockBuffer);
});
it("allows single point insertion", function () {
line.addPoint(100, 200);
line.addPoint(50, 42);
line.addPoint(150, 12321);
// Should have managed insertion index choices to get to...
expect(testDomainBuffer).toEqual([50, 100, 150]);
expect(testRangeBuffer).toEqual([42, 200, 12321]);
});
it("allows series insertion", function () {
testSeries = [ [ 50, 42 ], [ 100, 200 ], [ 150, 12321 ] ];
line.addSeries(mockSeries);
// Should have managed insertion index choices to get to...
expect(testDomainBuffer).toEqual([50, 100, 150]);
expect(testRangeBuffer).toEqual([42, 200, 12321]);
});
it("splits series insertion when necessary", function () {
testSeries = [ [ 50, 42 ], [ 100, 200 ], [ 150, 12321 ] ];
line.addPoint(75, 1);
line.addSeries(mockSeries);
// Should have managed insertion index choices to get to...
expect(testDomainBuffer).toEqual([50, 75, 100, 150]);
expect(testRangeBuffer).toEqual([42, 1, 200, 12321]);
});
it("attempts to remove points when insertion fails", function () {
// Verify precondition - normally doesn't try to trim
line.addPoint(1, 2);
expect(mockBuffer.trim).not.toHaveBeenCalled();
// But if insertPoint fails, it should trim
mockBuffer.insertPoint.andReturn(false);
line.addPoint(2, 3);
expect(mockBuffer.trim).toHaveBeenCalled();
});
});
}
);

View File

@ -0,0 +1,74 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../../src/elements/PlotSeriesWindow"],
function (PlotSeriesWindow) {
"use strict";
describe("A plot's window on a telemetry series", function () {
var mockSeries,
testSeries,
window;
beforeEach(function () {
testSeries = [
[ 0, 42 ],
[ 10, 1 ],
[ 20, 4 ],
[ 30, 9 ],
[ 40, 3 ]
];
mockSeries = jasmine.createSpyObj(
'series',
['getPointCount', 'getDomainValue', 'getRangeValue']
);
mockSeries.getPointCount.andCallFake(function () {
return testSeries.length;
});
mockSeries.getDomainValue.andCallFake(function (i) {
return testSeries[i][0];
});
mockSeries.getRangeValue.andCallFake(function (i) {
return testSeries[i][1];
});
window = new PlotSeriesWindow(
mockSeries,
"testDomain",
"testRange",
1,
testSeries.length
);
});
it("provides a window upon a data series", function () {
expect(window.getPointCount()).toEqual(4);
expect(window.getDomainValue(0)).toEqual(10);
expect(window.getRangeValue(0)).toEqual(1);
});
it("looks up using specific domain/range keys", function () {
window.getDomainValue(0);
window.getRangeValue(0);
expect(mockSeries.getDomainValue)
.toHaveBeenCalledWith(1, 'testDomain');
expect(mockSeries.getRangeValue)
.toHaveBeenCalledWith(1, 'testRange');
});
it("can be split into smaller windows", function () {
var windows = window.split();
expect(windows.length).toEqual(2);
expect(windows[0].getPointCount()).toEqual(2);
expect(windows[1].getPointCount()).toEqual(2);
expect(windows[0].getDomainValue(0)).toEqual(10);
expect(windows[1].getDomainValue(0)).toEqual(30);
expect(windows[0].getRangeValue(0)).toEqual(1);
expect(windows[1].getRangeValue(0)).toEqual(9);
});
});
}
);

View File

@ -14,6 +14,7 @@ define(
testRange,
testDomainValues,
testRangeValues,
mockSeries,
updater;
function makeMockDomainObject(id) {
@ -33,6 +34,10 @@ define(
"subscription",
[ "getDomainValue", "getRangeValue", "getTelemetryObjects" ]
);
mockSeries = jasmine.createSpyObj(
'series',
['getPointCount', 'getDomainValue', 'getRangeValue']
);
testDomain = "testDomain";
testRange = "testRange";
testDomainValues = { a: 3, b: 7, c: 13 };
@ -55,57 +60,14 @@ define(
});
it("provides one buffer per telemetry object", function () {
expect(updater.getBuffers().length).toEqual(3);
expect(updater.getLineBuffers().length).toEqual(3);
});
it("changes buffer count if telemetry object counts change", function () {
mockSubscription.getTelemetryObjects
.andReturn([makeMockDomainObject('a')]);
updater.update();
expect(updater.getBuffers().length).toEqual(1);
});
it("maintains a buffer of received telemetry", function () {
// Count should be large enough to trigger a buffer resize
var count = 750,
i;
// Increment values exposed by subscription
function increment() {
Object.keys(testDomainValues).forEach(function (k) {
testDomainValues[k] += 1;
testRangeValues[k] += 1;
});
}
// Simulate a lot of telemetry updates
for (i = 0; i < count; i += 1) {
updater.update();
expect(updater.getLength(0)).toEqual(i + 1);
expect(updater.getLength(1)).toEqual(i + 1);
expect(updater.getLength(2)).toEqual(i + 1);
increment();
}
// Domain offset should be lowest domain value
expect(updater.getDomainOffset()).toEqual(3);
// Test against initial values, offset by count,
// as was the case during each update
for (i = 0; i < count; i += 1) {
expect(updater.getBuffers()[0][i * 2])
.toEqual(3 + i - 3);
expect(updater.getBuffers()[0][i * 2 + 1])
.toEqual(123 + i);
expect(updater.getBuffers()[1][i * 2])
.toEqual(7 + i - 3);
expect(updater.getBuffers()[1][i * 2 + 1])
.toEqual(456 + i);
expect(updater.getBuffers()[2][i * 2])
.toEqual(13 + i - 3);
expect(updater.getBuffers()[2][i * 2 + 1])
.toEqual(789 + i);
}
expect(updater.getLineBuffers().length).toEqual(1);
});
it("can handle delayed telemetry object availability", function () {
@ -124,7 +86,7 @@ define(
);
// Should have 0 buffers for 0 objects
expect(updater.getBuffers().length).toEqual(0);
expect(updater.getLineBuffers().length).toEqual(0);
// Restore the three objects the test subscription would
// normally have.
@ -132,30 +94,79 @@ define(
updater.update();
// Should have 3 buffers for 3 objects
expect(updater.getBuffers().length).toEqual(3);
expect(updater.getLineBuffers().length).toEqual(3);
});
it("accepts historical telemetry updates", function () {
var mockObject = mockSubscription.getTelemetryObjects()[0];
it("shifts buffer upon expansion", function () {
// Count should be large enough to hit buffer's max size
var count = 1400,
i;
mockSeries.getPointCount.andReturn(3);
mockSeries.getDomainValue.andCallFake(function (i) {
return 1000 + i * 1000;
});
mockSeries.getRangeValue.andReturn(10);
// Initial update; should have 3 in first position
// (a's initial domain value)
// PlotLine & PlotLineBuffer are tested for most of the
// details here, so just check for some expected side
// effect; in this case, should see more points in the buffer
expect(updater.getLineBuffers()[0].getLength()).toEqual(1);
updater.addHistorical(mockObject, mockSeries);
expect(updater.getLineBuffers()[0].getLength()).toEqual(4);
});
it("clears the domain offset if no objects are present", function () {
mockSubscription.getTelemetryObjects.andReturn([]);
updater.update();
expect(updater.getBuffers()[0][1]).toEqual(123);
// Simulate a lot of telemetry updates
for (i = 0; i < count; i += 1) {
testDomainValues.a += 1;
testRangeValues.a += 1;
updater.update();
}
// Value at front of the buffer should have been pushed out
expect(updater.getBuffers()[0][1]).not.toEqual(123);
expect(updater.getDomainOffset()).toBeUndefined();
});
it("handles empty historical telemetry updates", function () {
// General robustness check for when a series is empty
var mockObject = mockSubscription.getTelemetryObjects()[0];
mockSeries.getPointCount.andReturn(0);
mockSeries.getDomainValue.andCallFake(function (i) {
return 1000 + i * 1000;
});
mockSeries.getRangeValue.andReturn(10);
// PlotLine & PlotLineBuffer are tested for most of the
// details here, so just check for some expected side
// effect; in this case, should see more points in the buffer
expect(updater.getLineBuffers()[0].getLength()).toEqual(1);
updater.addHistorical(mockObject, mockSeries);
expect(updater.getLineBuffers()[0].getLength()).toEqual(1);
});
it("can initialize domain offset from historical telemetry", function () {
var tmp = mockSubscription.getTelemetryObjects();
mockSubscription.getTelemetryObjects.andReturn([]);
// Reinstantiate with the empty subscription
updater = new PlotUpdater(
mockSubscription,
testDomain,
testRange
);
// Restore subscription, provide some historical data
mockSubscription.getTelemetryObjects.andReturn(tmp);
mockSeries.getPointCount.andReturn(3);
mockSeries.getDomainValue.andCallFake(function (i) {
return 1000 + i * 1000;
});
mockSeries.getRangeValue.andReturn(10);
// PlotLine & PlotLineBuffer are tested for most of the
// details here, so just check for some expected side
// effect; in this case, should see more points in the buffer
expect(updater.getDomainOffset()).toBeUndefined();
updater.addHistorical(tmp[0], mockSeries);
expect(updater.getDomainOffset()).toBeDefined();
});
});
}
);

View File

@ -57,18 +57,30 @@ define(
// Prepared telemetry data
mockPrepared = jasmine.createSpyObj(
"prepared",
[ "getDomainOffset", "getOrigin", "getDimensions", "getBuffers", "getLength" ]
[
"getDomainOffset",
"getOrigin",
"getDimensions",
"getLineBuffers"
]
);
mockSubPlotFactory.createSubPlot.andCallFake(createMockSubPlot);
// Act as if we have three buffers full of data
testBuffers = [["a"], ["b"], ["c"]];
mockPrepared.getBuffers.andReturn(testBuffers);
testBuffers = ['a', 'b', 'c'].map(function (id) {
var mockBuffer = jasmine.createSpyObj(
'buffer-' + id,
['getBuffer', 'getLength']
);
mockBuffer.getBuffer.andReturn([id]);
mockBuffer.getLength.andReturn(3);
return mockBuffer;
});
mockPrepared.getLineBuffers.andReturn(testBuffers);
mockPrepared.getDomainOffset.andReturn(1234);
mockPrepared.getOrigin.andReturn([10, 10]);
mockPrepared.getDimensions.andReturn([500, 500]);
mockPrepared.getLength.andReturn(3);
// Clear out drawing objects
testDrawingObjects = [];
@ -104,7 +116,7 @@ define(
// Make sure the right buffer was drawn to the
// right subplot.
testDrawingObject.lines.forEach(function (line, j) {
expect(line.buffer).toEqual(testBuffers[j]);
expect(line.buffer).toEqual(testBuffers[j].getBuffer());
});
});
});

View File

@ -57,18 +57,25 @@ define(
// Prepared telemetry data
mockPrepared = jasmine.createSpyObj(
"prepared",
[ "getDomainOffset", "getOrigin", "getDimensions", "getBuffers", "getLength" ]
[ "getDomainOffset", "getOrigin", "getDimensions", "getLineBuffers" ]
);
mockSubPlotFactory.createSubPlot.andCallFake(createMockSubPlot);
// Act as if we have three buffers full of data
testBuffers = [["a"], ["b"], ["c"]];
mockPrepared.getBuffers.andReturn(testBuffers);
testBuffers = ['a', 'b', 'c'].map(function (id) {
var mockBuffer = jasmine.createSpyObj(
'buffer-' + id,
['getBuffer', 'getLength']
);
mockBuffer.getBuffer.andReturn([id]);
mockBuffer.getLength.andReturn(3);
return mockBuffer;
});
mockPrepared.getLineBuffers.andReturn(testBuffers);
mockPrepared.getDomainOffset.andReturn(1234);
mockPrepared.getOrigin.andReturn([10, 10]);
mockPrepared.getDimensions.andReturn([500, 500]);
mockPrepared.getLength.andReturn(3);
// Objects that will be drawn to in sub-plots
testDrawingObjects = [];
@ -104,7 +111,7 @@ define(
// Make sure the right buffer was drawn to the
// right subplot.
expect(testDrawingObject.lines[0].buffer)
.toEqual(testBuffers[i]);
.toEqual(testBuffers[i].getBuffer());
});
});

View File

@ -6,11 +6,14 @@
"SubPlot",
"SubPlotFactory",
"elements/PlotAxis",
"elements/PlotLine",
"elements/PlotLineBuffer",
"elements/PlotPalette",
"elements/PlotPanZoomStack",
"elements/PlotPanZoomStackGroup",
"elements/PlotPosition",
"elements/PlotPreparer",
"elements/PlotSeriesWindow",
"elements/PlotTickGenerator",
"elements/PlotUpdater",
"modes/PlotModeOptions",

View File

@ -1,6 +1,6 @@
{
"name": "Open MCT Web Framework Component",
"description": "Framework layer for Open MCT Web; interprets bundle definitions and serves as an intermediary between Require and Angular.",
"description": "Framework layer for Open MCT Web; interprets bundle definitions and serves as an intermediary between Require and Angular",
"libraries": "lib",
"configuration": {
"paths": {
@ -17,57 +17,65 @@
{
"name": "Blanket.js",
"version": "1.1.5",
"description": "Code coverage measurement and reporting.",
"description": "Code coverage measurement and reporting",
"author": "Alex Seville",
"website": "http://blanketjs.org/",
"license": "MIT",
"copyright": "",
"license": "license-mit",
"link": "http://opensource.org/licenses/MIT"
},
{
"name": "Jasmine",
"version": "1.3.1",
"description": "Unit testing.",
"description": "Unit testing",
"author": "Pivotal Labs",
"website": "http://jasmine.github.io/",
"license": "MIT",
"copyright": "",
"license": "license-mit",
"link": "http://opensource.org/licenses/MIT"
},
{
"name": "RequireJS",
"version": "2.1.9",
"description": "Script loader.",
"description": "Script loader",
"author": "The Dojo Foundation",
"website": "http://requirejs.org/",
"license": "MIT",
"copyright": "Copyright (c) 2010-2015, The Dojo Foundation",
"license": "license-mit",
"link": "https://github.com/jrburke/requirejs/blob/master/LICENSE"
},
{
"name": "AngularJS",
"version": "1.2.26",
"description": "Client-side web application framework.",
"description": "Client-side web application framework",
"author": "Google",
"website": "http://angularjs.org/",
"license": "MIT",
"copyright": "Copyright (c) 2010-2015 Google, Inc. http://angularjs.org",
"license": "license-mit",
"link": "https://github.com/angular/angular.js/blob/master/LICENSE"
},
{
"name": "Angular-Route",
"version": "1.2.26",
"description": "Client-side view routing.",
"description": "Client-side view routing",
"author": "Google",
"website": "http://angularjs.org/",
"license": "MIT",
"copyright": "Copyright (c) 2010-2015 Google, Inc. http://angularjs.org",
"license": "license-mit",
"link": "https://github.com/angular/angular.js/blob/master/LICENSE"
},
{
"name": "ES6-Promise",
"version": "2.0.0",
"description": "Promise polyfill for pre-ECMAScript 6 browsers.",
"description": "Promise polyfill for pre-ECMAScript 6 browsers",
"author": "Yehuda Katz, Tom Dale, Stefan Penner and contributors",
"website": "https://github.com/jakearchibald/es6-promise",
"license": "MIT",
"copyright": "Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors",
"license": "license-mit",
"link": "https://github.com/jakearchibald/es6-promise/blob/master/LICENSE"
}
]
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "Data bundle",
"description": "Interfaces and infrastructure for real-time and historical data.",
"description": "Interfaces and infrastructure for real-time and historical data",
"configuration": {
"paths": {
"moment": "moment.min"
@ -43,6 +43,11 @@
"key": "telemetrySubscriber",
"implementation": "TelemetrySubscriber.js",
"depends": [ "$q", "$timeout" ]
},
{
"key": "telemetryHandler",
"implementation": "TelemetryHandler.js",
"depends": [ "$q", "telemetrySubscriber" ]
}
],
"licenses": [
@ -50,9 +55,10 @@
"name": "Moment.js",
"version": "2.7.0",
"author": "Tim Wood, Iskren Chernev, Moment.js contributors",
"description": "Time/date parsing/formatting.",
"description": "Time/date parsing/formatting",
"website": "http://momentjs.com",
"license": "MIT",
"copyright": "Copyright (c) 2011-2014 Tim Wood, Iskren Chernev, Moment.js contributors",
"license": "license-mit",
"link": "https://raw.githubusercontent.com/moment/moment/develop/LICENSE"
}
]

View File

@ -0,0 +1,45 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* Used to handle telemetry delegation associated with a
* given domain object.
*/
function TelemetryDelegator($q) {
return {
/**
* Promise telemetry-providing objects associated with
* this domain object (either the domain object itself,
* or the objects it delegates)
* @returns {Promise.<DomainObject[]>} domain objects with
* a telemetry capability
*/
promiseTelemetryObjects: function (domainObject) {
// If object has been cleared, there are no relevant
// telemetry-providing domain objects.
if (!domainObject) {
return $q.when([]);
}
// Otherwise, try delegation first, and attach the
// object itself if it has a telemetry capability.
return $q.when(domainObject.useCapability(
"delegation",
"telemetry"
)).then(function (result) {
var head = domainObject.hasCapability("telemetry") ?
[ domainObject ] : [],
tail = result || [];
return head.concat(tail);
});
}
};
}
return TelemetryDelegator;
}
);

View File

@ -0,0 +1,91 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* A telemetry handle acts as a helper in issuing requests for
* new telemetry as well as subscribing to real-time updates
* for the same telemetry series. This is exposed through the
* `telemetryHandler` service.
* @param $q Angular's $q, for promises
* @param {TelemetrySubscription} subscription a subscription
* to supplied telemetry
*/
function TelemetryHandle($q, subscription) {
var seriesMap = {},
self = Object.create(subscription);
// Request a telemetry series for this specific object
function requestSeries(telemetryObject, request, callback) {
var id = telemetryObject.getId(),
telemetry = telemetryObject.getCapability('telemetry');
function receiveSeries(series) {
// Store it for subsequent lookup
seriesMap[id] = series;
// Notify callback of new series data, if there is one
if (callback) {
callback(telemetryObject, series);
}
// Pass it along for promise-chaining
return series;
}
// Issue the request via the object's telemetry capability
return telemetry.requestData(request).then(receiveSeries);
}
/**
* Get the most recently obtained telemetry data series associated
* with this domain object.
* @param {DomainObject} the domain object which has telemetry
* data associated with it
* @return {TelemetrySeries} the most recent telemetry series
* (or undefined if there is not one)
*/
self.getSeries = function (domainObject) {
var id = domainObject.getId();
return seriesMap[id];
};
/**
* Change the request duration.
* @param {object|number} request the duration of historical
* data to look at; or, the request to issue
* @param {Function} [callback] a callback that will be
* invoked as new data becomes available, with the
* domain object for which new data is available.
*/
self.request = function (request, callback) {
// Issue (and handle) the new request from this object
function issueRequest(telemetryObject) {
return requestSeries(telemetryObject, request, callback);
}
// Map the request to all telemetry objects
function issueRequests(telemetryObjects) {
return $q.all(telemetryObjects.map(issueRequest));
}
// If the request is a simple number, treat it as a duration
request = (typeof request === 'number') ?
{ duration: request } : request;
// Look up telemetry-providing objects from the subscription,
// then issue new requests.
return subscription.promiseTelemetryObjects()
.then(issueRequests);
};
return self;
}
return TelemetryHandle;
}
);

View File

@ -0,0 +1,33 @@
/*global define*/
define(
['./TelemetryHandle'],
function (TelemetryHandle) {
"use strict";
/**
* A TelemetryRequester provides an easy interface to request
* telemetry associated with a set of domain objects.
*
* @constructor
* @param $q Angular's $q
*/
function TelemetryHandler($q, telemetrySubscriber) {
return {
handle: function (domainObject, callback, lossless) {
var subscription = telemetrySubscriber.subscribe(
domainObject,
callback,
lossless
);
return new TelemetryHandle($q, subscription);
}
};
}
return TelemetryHandler;
}
);

View File

@ -1,8 +1,8 @@
/*global define*/
define(
['./TelemetryQueue', './TelemetryTable'],
function (TelemetryQueue, TelemetryTable) {
['./TelemetryQueue', './TelemetryTable', './TelemetryDelegator'],
function (TelemetryQueue, TelemetryTable, TelemetryDelegator) {
"use strict";
@ -31,7 +31,9 @@ define(
* the callback once, with access to the latest data
*/
function TelemetrySubscription($q, $timeout, domainObject, callback, lossless) {
var unsubscribePromise,
var delegator = new TelemetryDelegator($q),
unsubscribePromise,
telemetryObjectPromise,
latestValues = {},
telemetryObjects = [],
pool = lossless ? new TelemetryQueue() : new TelemetryTable(),
@ -42,23 +44,7 @@ define(
// This will either be the object in view, or object that
// this object delegates its telemetry capability to.
function promiseRelevantObjects(domainObject) {
// If object has been cleared, there are no relevant
// telemetry-providing domain objects.
if (!domainObject) {
return $q.when([]);
}
// Otherwise, try delegation first, and attach the
// object itself if it has a telemetry capability.
return $q.when(domainObject.useCapability(
"delegation",
"telemetry"
)).then(function (result) {
var head = domainObject.hasCapability("telemetry") ?
[ domainObject ] : [],
tail = result || [];
return head.concat(tail);
});
return delegator.promiseTelemetryObjects(domainObject);
}
function updateValuesFromPool() {
@ -152,8 +138,8 @@ define(
// will be unsubscribe functions. (This must be a promise
// because delegation is supported, and retrieving delegate
// telemetry-capable objects may be an asynchronous operation.)
unsubscribePromise =
promiseRelevantObjects(domainObject)
telemetryObjectPromise = promiseRelevantObjects(domainObject);
unsubscribePromise = telemetryObjectPromise
.then(cacheObjectReferences)
.then(subscribeAll);
@ -239,6 +225,17 @@ define(
*/
getMetadata: function () {
return metadatas;
},
/**
* Get a promise for all telemetry-providing objects
* associated with this subscription.
* @returns {Promise.<DomainObject[]>} a promise for
* telemetry-providing objects
*/
promiseTelemetryObjects: function () {
// Unsubscribe promise is available after objects
// are loaded.
return telemetryObjectPromise;
}
};
}

View File

@ -0,0 +1,12 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/TelemetryDelegator"],
function (TelemetryDelegator) {
"use strict";
describe("The telemetry delegator", function () {
});
}
);

View File

@ -0,0 +1,88 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/TelemetryHandle"],
function (TelemetryHandle) {
"use strict";
describe("A telemetry handle", function () {
var mockQ,
mockSubscription,
mockDomainObject,
mockTelemetry,
mockSeries,
mockCallback,
handle;
function asPromise(v) {
return (v || {}).then ? v : {
then: function (callback) {
return asPromise(callback(v));
}
};
}
beforeEach(function () {
mockQ = jasmine.createSpyObj('$q', ['when', 'all']);
mockSubscription = jasmine.createSpyObj(
'subscription',
['unsubscribe', 'getTelemetryObjects', 'promiseTelemetryObjects']
);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getCapability']
);
mockTelemetry = jasmine.createSpyObj(
'telemetry',
['requestData']
);
mockSeries = jasmine.createSpyObj(
'series',
['getPointCount', 'getDomainValue', 'getRangeValue']
);
mockCallback = jasmine.createSpy('callback');
// Simulate $q.all, at least for asPromise-provided promises
mockQ.all.andCallFake(function (values) {
return values.map(function (v) {
var r;
asPromise(v).then(function (value) { r = value; });
return r;
});
});
mockQ.when.andCallFake(asPromise);
mockSubscription.getTelemetryObjects
.andReturn([mockDomainObject]);
mockSubscription.promiseTelemetryObjects
.andReturn(asPromise([mockDomainObject]));
mockDomainObject.getId.andReturn('testId');
mockDomainObject.getCapability.andReturn(mockTelemetry);
mockTelemetry.requestData.andReturn(asPromise(mockSeries));
handle = new TelemetryHandle(mockQ, mockSubscription);
});
it("exposes subscription API", function () {
// Should still expose methods from the provided subscription
expect(handle.unsubscribe)
.toBe(mockSubscription.unsubscribe);
expect(handle.getTelemetryObjects)
.toBe(mockSubscription.getTelemetryObjects);
});
it("provides an interface for historical requests", function () {
handle.request({}, mockCallback);
expect(mockCallback).toHaveBeenCalledWith(
mockDomainObject,
mockSeries
);
});
it("provides the latest series for domain objects", function () {
handle.request({});
expect(handle.getSeries(mockDomainObject))
.toEqual(mockSeries);
});
});
}
);

View File

@ -0,0 +1,64 @@
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../src/TelemetryHandler"],
function (TelemetryHandler) {
"use strict";
describe("The telemetry handler", function () {
// TelemetryHandler just provides a factory
// for TelemetryHandle, so most real testing
// should happen there.
var mockQ,
mockSubscriber,
mockDomainObject,
mockCallback,
mockSubscription,
handler;
beforeEach(function () {
mockQ = jasmine.createSpyObj("$q", ["when"]);
mockSubscriber = jasmine.createSpyObj(
'telemetrySubscriber',
['subscribe']
);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getCapability']
);
mockCallback = jasmine.createSpy('callback');
mockSubscription = jasmine.createSpyObj(
'subscription',
[
'unsubscribe',
'getTelemetryObjects',
'getRangeValue',
'getDomainValue'
]
);
mockSubscriber.subscribe.andReturn(mockSubscription);
handler = new TelemetryHandler(mockQ, mockSubscriber);
});
it("acts as a factory for subscription objects", function () {
var handle = handler.handle(
mockDomainObject,
mockCallback
);
// Just verify that this looks like a TelemetrySubscription
[
"unsubscribe",
"getTelemetryObjects",
"getRangeValue",
"getDomainValue",
"request"
].forEach(function (method) {
expect(handle[method]).toEqual(jasmine.any(Function));
});
});
});
}
);

View File

@ -184,6 +184,14 @@ define(
it("fires callback when telemetry objects are available", function () {
expect(mockCallback.calls.length).toEqual(1);
});
it("exposes a promise for telemetry objects", function () {
var mockCallback2 = jasmine.createSpy('callback');
subscription.promiseTelemetryObjects().then(mockCallback2);
expect(mockCallback2)
.toHaveBeenCalledWith([ mockDomainObject ]);
});
});
}
);

View File

@ -2,7 +2,10 @@
"TelemetryAggregator",
"TelemetryCapability",
"TelemetryController",
"TelemetryDelegator",
"TelemetryFormatter",
"TelemetryHandle",
"TelemetryHandler",
"TelemetryQueue",
"TelemetrySubscriber",
"TelemetrySubscription",

View File

@ -6,7 +6,7 @@
<groupId>gov.nasa.arc.wtd</groupId>
<artifactId>open-mct-web</artifactId>
<name>Open MCT Web</name>
<version>0.6.2-SNAPSHOT</version>
<version>0.7.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>